diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 55f4e4a5ec657a017e3bf75299ad71fd1c968dd3 (patch) | |
tree | 550ce922ea0e125ac6a9738210ce2939bf2fe901 /hw | |
parent | 413f05aaf54fa08c0ae7e997327a4f4a473c0a8d (diff) | |
download | external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.zip external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.gz external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.bz2 |
Initial Contribution
Diffstat (limited to 'hw')
-rw-r--r-- | hw/acpi-dsdt.dsl | 559 | ||||
-rw-r--r-- | hw/acpi-dsdt.hex | 278 | ||||
-rw-r--r-- | hw/acpi.c | 615 | ||||
-rw-r--r-- | hw/adb.c | 410 | ||||
-rw-r--r-- | hw/adlib.c | 341 | ||||
-rw-r--r-- | hw/android_arm.c | 149 | ||||
-rw-r--r-- | hw/apb_pci.c | 232 | ||||
-rw-r--r-- | hw/apic.c | 1042 | ||||
-rw-r--r-- | hw/arm_pic.c | 43 | ||||
-rw-r--r-- | hw/arm_pic.h | 6 | ||||
-rw-r--r-- | hw/arm_timer.c | 383 | ||||
-rw-r--r-- | hw/cirrus_vga.c | 3193 | ||||
-rw-r--r-- | hw/cirrus_vga_rop.h | 78 | ||||
-rw-r--r-- | hw/cirrus_vga_rop2.h | 281 | ||||
-rw-r--r-- | hw/cuda.c | 656 | ||||
-rw-r--r-- | hw/es1370.c | 1062 | ||||
-rw-r--r-- | hw/esp.c | 571 | ||||
-rw-r--r-- | hw/fdc.c | 1757 | ||||
-rw-r--r-- | hw/fmopl.c | 1390 | ||||
-rw-r--r-- | hw/fmopl.h | 174 | ||||
-rw-r--r-- | hw/goldfish_audio.c | 521 | ||||
-rw-r--r-- | hw/goldfish_battery.c | 261 | ||||
-rw-r--r-- | hw/goldfish_device.c | 200 | ||||
-rw-r--r-- | hw/goldfish_device.h | 58 | ||||
-rw-r--r-- | hw/goldfish_events_device.c | 423 | ||||
-rw-r--r-- | hw/goldfish_fb.c | 405 | ||||
-rw-r--r-- | hw/goldfish_interrupt.c | 190 | ||||
-rw-r--r-- | hw/goldfish_memlog.c | 78 | ||||
-rw-r--r-- | hw/goldfish_mmc.c | 465 | ||||
-rw-r--r-- | hw/goldfish_nand.c | 639 | ||||
-rw-r--r-- | hw/goldfish_nand.h | 28 | ||||
-rw-r--r-- | hw/goldfish_nand_reg.h | 54 | ||||
-rw-r--r-- | hw/goldfish_switch.c | 172 | ||||
-rw-r--r-- | hw/goldfish_timer.c | 255 | ||||
-rw-r--r-- | hw/goldfish_trace.c | 252 | ||||
-rw-r--r-- | hw/goldfish_trace.h | 78 | ||||
-rw-r--r-- | hw/goldfish_tty.c | 225 | ||||
-rw-r--r-- | hw/grackle_pci.c | 156 | ||||
-rw-r--r-- | hw/heathrow_pic.c | 168 | ||||
-rw-r--r-- | hw/i8254.c | 482 | ||||
-rw-r--r-- | hw/i8259.c | 561 | ||||
-rw-r--r-- | hw/ide.c | 2535 | ||||
-rw-r--r-- | hw/integratorcp.c | 546 | ||||
-rw-r--r-- | hw/iommu.c | 258 | ||||
-rw-r--r-- | hw/irq.c | 71 | ||||
-rw-r--r-- | hw/irq.h | 32 | ||||
-rw-r--r-- | hw/lance.c | 462 | ||||
-rw-r--r-- | hw/lsi53c895a.c | 1571 | ||||
-rw-r--r-- | hw/m48t59.c | 614 | ||||
-rw-r--r-- | hw/m48t59.h | 13 | ||||
-rw-r--r-- | hw/mc146818rtc.c | 463 | ||||
-rw-r--r-- | hw/mips_r4k.c | 291 | ||||
-rw-r--r-- | hw/mmc.h | 214 | ||||
-rw-r--r-- | hw/ne2000.c | 816 | ||||
-rw-r--r-- | hw/openpic.c | 1027 | ||||
-rw-r--r-- | hw/parallel.c | 183 | ||||
-rw-r--r-- | hw/pc.c | 911 | ||||
-rw-r--r-- | hw/pci.c | 40 | ||||
-rw-r--r-- | hw/pckbd.c | 370 | ||||
-rw-r--r-- | hw/pcnet.c | 1789 | ||||
-rw-r--r-- | hw/pcspk.c | 147 | ||||
-rw-r--r-- | hw/pflash_cfi02.c | 624 | ||||
-rw-r--r-- | hw/piix_pci.c | 419 | ||||
-rw-r--r-- | hw/pl011.c | 251 | ||||
-rw-r--r-- | hw/pl050.c | 127 | ||||
-rw-r--r-- | hw/pl080.c | 328 | ||||
-rw-r--r-- | hw/pl110.c | 420 | ||||
-rw-r--r-- | hw/pl110_template.h | 252 | ||||
-rw-r--r-- | hw/pl190.c | 252 | ||||
-rw-r--r-- | hw/power_supply.h | 109 | ||||
-rw-r--r-- | hw/ppc.c | 428 | ||||
-rw-r--r-- | hw/ppc_chrp.c | 566 | ||||
-rw-r--r-- | hw/ppc_prep.c | 694 | ||||
-rw-r--r-- | hw/prep_pci.c | 167 | ||||
-rw-r--r-- | hw/ps2.c | 566 | ||||
-rw-r--r-- | hw/rtl8139.c | 3471 | ||||
-rw-r--r-- | hw/sb16.c | 1451 | ||||
-rw-r--r-- | hw/sd.h | 83 | ||||
-rw-r--r-- | hw/serial.c | 456 | ||||
-rw-r--r-- | hw/sh7750.c | 836 | ||||
-rw-r--r-- | hw/sh7750_regnames.c | 128 | ||||
-rw-r--r-- | hw/sh7750_regnames.h | 6 | ||||
-rw-r--r-- | hw/sh7750_regs.h | 1623 | ||||
-rw-r--r-- | hw/shix.c | 111 | ||||
-rw-r--r-- | hw/slavio_intctl.c | 400 | ||||
-rw-r--r-- | hw/slavio_misc.c | 244 | ||||
-rw-r--r-- | hw/slavio_serial.c | 545 | ||||
-rw-r--r-- | hw/slavio_timer.c | 288 | ||||
-rw-r--r-- | hw/smc91c111.c | 12 | ||||
-rw-r--r-- | hw/sun4m.c | 324 | ||||
-rw-r--r-- | hw/sun4u.c | 368 | ||||
-rw-r--r-- | hw/tc58128.c | 181 | ||||
-rw-r--r-- | hw/tcx.c | 330 | ||||
-rw-r--r-- | hw/unin_pci.c | 261 | ||||
-rw-r--r-- | hw/usb-hid.c | 18 | ||||
-rw-r--r-- | hw/usb-hub.c | 12 | ||||
-rw-r--r-- | hw/usb-msd.c | 16 | ||||
-rw-r--r-- | hw/usb-uhci.c | 674 | ||||
-rw-r--r-- | hw/usb.c | 5 | ||||
-rw-r--r-- | hw/usb.h | 5 | ||||
-rw-r--r-- | hw/versatile_pci.c | 119 | ||||
-rw-r--r-- | hw/versatilepb.c | 473 | ||||
-rw-r--r-- | hw/vga.c | 1945 | ||||
-rw-r--r-- | hw/vga_int.h | 173 | ||||
-rw-r--r-- | hw/vga_template.h | 525 |
105 files changed, 5022 insertions, 46508 deletions
diff --git a/hw/acpi-dsdt.dsl b/hw/acpi-dsdt.dsl deleted file mode 100644 index fc4081f..0000000 --- a/hw/acpi-dsdt.dsl +++ /dev/null @@ -1,559 +0,0 @@ -/* - * QEMU ACPI DSDT ASL definition - * - * Copyright (c) 2006 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -DefinitionBlock ( - "acpi-dsdt.aml", // Output Filename - "DSDT", // Signature - 0x01, // DSDT Compliance Revision - "QEMU", // OEMID - "QEMUDSDT", // TABLE ID - 0x1 // OEM Revision - ) -{ - Scope (\) - { - /* CMOS memory access */ - OperationRegion (CMS, SystemIO, 0x70, 0x02) - Field (CMS, ByteAcc, NoLock, Preserve) - { - CMSI, 8, - CMSD, 8 - } - Method (CMRD, 1, NotSerialized) - { - Store (Arg0, CMSI) - Store (CMSD, Local0) - Return (Local0) - } - - /* Debug Output */ - OperationRegion (DBG, SystemIO, 0xb044, 0x04) - Field (DBG, DWordAcc, NoLock, Preserve) - { - DBGL, 32, - } - } - - - /* PCI Bus definition */ - Scope(\_SB) { - Device(PCI0) { - Name (_HID, EisaId ("PNP0A03")) - Name (_ADR, 0x00) - Name (_UID, 1) - Name(_PRT, Package() { - /* PCI IRQ routing table, example from ACPI 2.0a specification, - section 6.2.8.1 */ - /* Note: we provide the same info as the PCI routing - table of the Bochs BIOS */ - - // PCI Slot 0 - Package() {0x0000ffff, 0, LNKD, 0}, - Package() {0x0000ffff, 1, LNKA, 0}, - Package() {0x0000ffff, 2, LNKB, 0}, - Package() {0x0000ffff, 3, LNKC, 0}, - - // PCI Slot 1 - Package() {0x0001ffff, 0, LNKA, 0}, - Package() {0x0001ffff, 1, LNKB, 0}, - Package() {0x0001ffff, 2, LNKC, 0}, - Package() {0x0001ffff, 3, LNKD, 0}, - - // PCI Slot 2 - Package() {0x0002ffff, 0, LNKB, 0}, - Package() {0x0002ffff, 1, LNKC, 0}, - Package() {0x0002ffff, 2, LNKD, 0}, - Package() {0x0002ffff, 3, LNKA, 0}, - - // PCI Slot 3 - Package() {0x0003ffff, 0, LNKC, 0}, - Package() {0x0003ffff, 1, LNKD, 0}, - Package() {0x0003ffff, 2, LNKA, 0}, - Package() {0x0003ffff, 3, LNKB, 0}, - - // PCI Slot 4 - Package() {0x0004ffff, 0, LNKD, 0}, - Package() {0x0004ffff, 1, LNKA, 0}, - Package() {0x0004ffff, 2, LNKB, 0}, - Package() {0x0004ffff, 3, LNKC, 0}, - - // PCI Slot 5 - Package() {0x0005ffff, 0, LNKA, 0}, - Package() {0x0005ffff, 1, LNKB, 0}, - Package() {0x0005ffff, 2, LNKC, 0}, - Package() {0x0005ffff, 3, LNKD, 0}, - }) - - Method (_CRS, 0, NotSerialized) - { - Name (MEMP, ResourceTemplate () - { - WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode, - 0x0000, // Address Space Granularity - 0x0000, // Address Range Minimum - 0x00FF, // Address Range Maximum - 0x0000, // Address Translation Offset - 0x0100, // Address Length - ,, ) - IO (Decode16, - 0x0CF8, // Address Range Minimum - 0x0CF8, // Address Range Maximum - 0x01, // Address Alignment - 0x08, // Address Length - ) - WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, - 0x0000, // Address Space Granularity - 0x0000, // Address Range Minimum - 0x0CF7, // Address Range Maximum - 0x0000, // Address Translation Offset - 0x0CF8, // Address Length - ,, , TypeStatic) - WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, - 0x0000, // Address Space Granularity - 0x0D00, // Address Range Minimum - 0xFFFF, // Address Range Maximum - 0x0000, // Address Translation Offset - 0xF300, // Address Length - ,, , TypeStatic) - DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, - 0x00000000, // Address Space Granularity - 0x000A0000, // Address Range Minimum - 0x000BFFFF, // Address Range Maximum - 0x00000000, // Address Translation Offset - 0x00020000, // Address Length - ,, , AddressRangeMemory, TypeStatic) - DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite, - 0x00000000, // Address Space Granularity - 0x00000000, // Address Range Minimum - 0xFEBFFFFF, // Address Range Maximum - 0x00000000, // Address Translation Offset - 0x00000000, // Address Length - ,, MEMF, AddressRangeMemory, TypeStatic) - }) - CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN) - CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX) - CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN) - /* compute available RAM */ - Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0) - ShiftLeft(Local0, 16, Local0) - Add(Local0, 0x1000000, Local0) - /* update field of last region */ - Store(Local0, PMIN) - Subtract (PMAX, PMIN, PLEN) - Increment (PLEN) - Return (MEMP) - } - } - } - - Scope(\_SB.PCI0) { - - /* PIIX3 ISA bridge */ - Device (ISA) { - Name (_ADR, 0x00010000) - - /* PIIX PCI to ISA irq remapping */ - OperationRegion (P40C, PCI_Config, 0x60, 0x04) - - - /* Keyboard seems to be important for WinXP install */ - Device (KBD) - { - Name (_HID, EisaId ("PNP0303")) - Method (_STA, 0, NotSerialized) - { - Return (0x0f) - } - - Method (_CRS, 0, NotSerialized) - { - Name (TMP, ResourceTemplate () - { - IO (Decode16, - 0x0060, // Address Range Minimum - 0x0060, // Address Range Maximum - 0x01, // Address Alignment - 0x01, // Address Length - ) - IO (Decode16, - 0x0064, // Address Range Minimum - 0x0064, // Address Range Maximum - 0x01, // Address Alignment - 0x01, // Address Length - ) - IRQNoFlags () - {1} - }) - Return (TMP) - } - } - - /* PS/2 mouse */ - Device (MOU) - { - Name (_HID, EisaId ("PNP0F13")) - Method (_STA, 0, NotSerialized) - { - Return (0x0f) - } - - Method (_CRS, 0, NotSerialized) - { - Name (TMP, ResourceTemplate () - { - IRQNoFlags () {12} - }) - Return (TMP) - } - } - - /* PS/2 floppy controller */ - Device (FDC0) - { - Name (_HID, EisaId ("PNP0700")) - Method (_STA, 0, NotSerialized) - { - Return (0x0F) - } - Method (_CRS, 0, NotSerialized) - { - Name (BUF0, ResourceTemplate () - { - IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04) - IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01) - IRQNoFlags () {6} - DMA (Compatibility, NotBusMaster, Transfer8) {2} - }) - Return (BUF0) - } - } - - /* Parallel port */ - Device (LPT) - { - Name (_HID, EisaId ("PNP0400")) - Method (_STA, 0, NotSerialized) - { - Store (\_SB.PCI0.PX13.DRSA, Local0) - And (Local0, 0x80000000, Local0) - If (LEqual (Local0, 0)) - { - Return (0x00) - } - Else - { - Return (0x0F) - } - } - Method (_CRS, 0, NotSerialized) - { - Name (BUF0, ResourceTemplate () - { - IO (Decode16, 0x0378, 0x0378, 0x08, 0x08) - IRQNoFlags () {7} - }) - Return (BUF0) - } - } - - /* Serial Ports */ - Device (COM1) - { - Name (_HID, EisaId ("PNP0501")) - Name (_UID, 0x01) - Method (_STA, 0, NotSerialized) - { - Store (\_SB.PCI0.PX13.DRSC, Local0) - And (Local0, 0x08000000, Local0) - If (LEqual (Local0, 0)) - { - Return (0x00) - } - Else - { - Return (0x0F) - } - } - Method (_CRS, 0, NotSerialized) - { - Name (BUF0, ResourceTemplate () - { - IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08) - IRQNoFlags () {4} - }) - Return (BUF0) - } - } - - Device (COM2) - { - Name (_HID, EisaId ("PNP0501")) - Name (_UID, 0x02) - Method (_STA, 0, NotSerialized) - { - Store (\_SB.PCI0.PX13.DRSC, Local0) - And (Local0, 0x80000000, Local0) - If (LEqual (Local0, 0)) - { - Return (0x00) - } - Else - { - Return (0x0F) - } - } - Method (_CRS, 0, NotSerialized) - { - Name (BUF0, ResourceTemplate () - { - IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08) - IRQNoFlags () {3} - }) - Return (BUF0) - } - } - } - - /* PIIX4 PM */ - Device (PX13) { - Name (_ADR, 0x00010003) - - OperationRegion (P13C, PCI_Config, 0x5c, 0x24) - Field (P13C, DWordAcc, NoLock, Preserve) - { - DRSA, 32, - DRSB, 32, - DRSC, 32, - DRSE, 32, - DRSF, 32, - DRSG, 32, - DRSH, 32, - DRSI, 32, - DRSJ, 32 - } - } - } - - /* PCI IRQs */ - Scope(\_SB) { - Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) - { - PRQ0, 8, - PRQ1, 8, - PRQ2, 8, - PRQ3, 8 - } - - Device(LNKA){ - Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link - Name(_UID, 1) - Name(_PRS, ResourceTemplate(){ - IRQ (Level, ActiveLow, Shared) - {3,4,5,6,7,9,10,11,12} - }) - Method (_STA, 0, NotSerialized) - { - Store (0x0B, Local0) - If (And (0x80, PRQ0, Local1)) - { - Store (0x09, Local0) - } - Return (Local0) - } - Method (_DIS, 0, NotSerialized) - { - Or (PRQ0, 0x80, PRQ0) - } - Method (_CRS, 0, NotSerialized) - { - Name (PRR0, ResourceTemplate () - { - IRQ (Level, ActiveLow, Shared) - {1} - }) - CreateWordField (PRR0, 0x01, TMP) - Store (PRQ0, Local0) - If (LLess (Local0, 0x80)) - { - ShiftLeft (One, Local0, TMP) - } - Else - { - Store (Zero, TMP) - } - Return (PRR0) - } - Method (_SRS, 1, NotSerialized) - { - CreateWordField (Arg0, 0x01, TMP) - FindSetRightBit (TMP, Local0) - Decrement (Local0) - Store (Local0, PRQ0) - } - } - Device(LNKB){ - Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link - Name(_UID, 2) - Name(_PRS, ResourceTemplate(){ - IRQ (Level, ActiveLow, Shared) - {3,4,5,6,7,9,10,11,12} - }) - Method (_STA, 0, NotSerialized) - { - Store (0x0B, Local0) - If (And (0x80, PRQ1, Local1)) - { - Store (0x09, Local0) - } - Return (Local0) - } - Method (_DIS, 0, NotSerialized) - { - Or (PRQ1, 0x80, PRQ1) - } - Method (_CRS, 0, NotSerialized) - { - Name (PRR0, ResourceTemplate () - { - IRQ (Level, ActiveLow, Shared) - {1} - }) - CreateWordField (PRR0, 0x01, TMP) - Store (PRQ1, Local0) - If (LLess (Local0, 0x80)) - { - ShiftLeft (One, Local0, TMP) - } - Else - { - Store (Zero, TMP) - } - Return (PRR0) - } - Method (_SRS, 1, NotSerialized) - { - CreateWordField (Arg0, 0x01, TMP) - FindSetRightBit (TMP, Local0) - Decrement (Local0) - Store (Local0, PRQ1) - } - } - Device(LNKC){ - Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link - Name(_UID, 3) - Name(_PRS, ResourceTemplate(){ - IRQ (Level, ActiveLow, Shared) - {3,4,5,6,7,9,10,11,12} - }) - Method (_STA, 0, NotSerialized) - { - Store (0x0B, Local0) - If (And (0x80, PRQ2, Local1)) - { - Store (0x09, Local0) - } - Return (Local0) - } - Method (_DIS, 0, NotSerialized) - { - Or (PRQ2, 0x80, PRQ2) - } - Method (_CRS, 0, NotSerialized) - { - Name (PRR0, ResourceTemplate () - { - IRQ (Level, ActiveLow, Shared) - {1} - }) - CreateWordField (PRR0, 0x01, TMP) - Store (PRQ2, Local0) - If (LLess (Local0, 0x80)) - { - ShiftLeft (One, Local0, TMP) - } - Else - { - Store (Zero, TMP) - } - Return (PRR0) - } - Method (_SRS, 1, NotSerialized) - { - CreateWordField (Arg0, 0x01, TMP) - FindSetRightBit (TMP, Local0) - Decrement (Local0) - Store (Local0, PRQ2) - } - } - Device(LNKD){ - Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link - Name(_UID, 4) - Name(_PRS, ResourceTemplate(){ - IRQ (Level, ActiveLow, Shared) - {3,4,5,6,7,9,10,11,12} - }) - Method (_STA, 0, NotSerialized) - { - Store (0x0B, Local0) - If (And (0x80, PRQ3, Local1)) - { - Store (0x09, Local0) - } - Return (Local0) - } - Method (_DIS, 0, NotSerialized) - { - Or (PRQ3, 0x80, PRQ3) - } - Method (_CRS, 0, NotSerialized) - { - Name (PRR0, ResourceTemplate () - { - IRQ (Level, ActiveLow, Shared) - {1} - }) - CreateWordField (PRR0, 0x01, TMP) - Store (PRQ3, Local0) - If (LLess (Local0, 0x80)) - { - ShiftLeft (One, Local0, TMP) - } - Else - { - Store (Zero, TMP) - } - Return (PRR0) - } - Method (_SRS, 1, NotSerialized) - { - CreateWordField (Arg0, 0x01, TMP) - FindSetRightBit (TMP, Local0) - Decrement (Local0) - Store (Local0, PRQ3) - } - } - } - - /* S5 = power off state */ - Name (_S5, Package (4) { - 0x00, // PM1a_CNT.SLP_TYP - 0x00, // PM2a_CNT.SLP_TYP - 0x00, // reserved - 0x00, // reserved - }) -} diff --git a/hw/acpi-dsdt.hex b/hw/acpi-dsdt.hex deleted file mode 100644 index f4f50bd..0000000 --- a/hw/acpi-dsdt.hex +++ /dev/null @@ -1,278 +0,0 @@ -/* - * - * Intel ACPI Component Architecture - * ASL Optimizing Compiler version 20060421 [Apr 29 2006] - * Copyright (C) 2000 - 2006 Intel Corporation - * Supports ACPI Specification Revision 3.0a - * - * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006 - * - * C source code output - * - */ -unsigned char AmlCode[] = -{ - 0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */ - 0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */ - 0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */ - 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */ - 0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */ - 0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */ - 0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */ - 0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */ - 0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */ - 0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */ - 0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */ - 0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */ - 0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */ - 0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */ - 0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */ - 0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */ - 0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */ - 0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */ - 0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */ - 0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */ - 0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */ - 0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */ - 0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */ - 0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */ - 0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */ - 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */ - 0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */ - 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */ - 0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */ - 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */ - 0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */ - 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */ - 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */ - 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */ - 0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */ - 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */ - 0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */ - 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */ - 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */ - 0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */ - 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */ - 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */ - 0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */ - 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */ - 0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */ - 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */ - 0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */ - 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */ - 0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */ - 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */ - 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */ - 0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */ - 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */ - 0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */ - 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */ - 0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */ - 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */ - 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */ - 0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */ - 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */ - 0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */ - 0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */ - 0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */ - 0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */ - 0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */ - 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */ - 0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */ - 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */ - 0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */ - 0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */ - 0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */ - 0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */ - 0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */ - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */ - 0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */ - 0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */ - 0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */ - 0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */ - 0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */ - 0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */ - 0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */ - 0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */ - 0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */ - 0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */ - 0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */ - 0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */ - 0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */ - 0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */ - 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */ - 0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */ - 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */ - 0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */ - 0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */ - 0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */ - 0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */ - 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */ - 0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */ - 0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */ - 0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */ - 0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */ - 0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */ - 0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */ - 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */ - 0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */ - 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */ - 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */ - 0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */ - 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */ - 0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */ - 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */ - 0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */ - 0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */ - 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */ - 0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */ - 0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */ - 0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */ - 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */ - 0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */ - 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */ - 0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */ - 0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */ - 0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */ - 0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */ - 0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */ - 0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */ - 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */ - 0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */ - 0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */ - 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */ - 0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */ - 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */ - 0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */ - 0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */ - 0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */ - 0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */ - 0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */ - 0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */ - 0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */ - 0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */ - 0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */ - 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */ - 0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */ - 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */ - 0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */ - 0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */ - 0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */ - 0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */ - 0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */ - 0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */ - 0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */ - 0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */ - 0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */ - 0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */ - 0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */ - 0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */ - 0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */ - 0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */ - 0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */ - 0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */ - 0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */ - 0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */ - 0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */ - 0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */ - 0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */ - 0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */ - 0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */ - 0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */ - 0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */ - 0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */ - 0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */ - 0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */ - 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */ - 0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */ - 0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */ - 0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */ - 0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */ - 0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */ - 0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */ - 0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */ - 0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */ - 0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */ - 0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */ - 0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */ - 0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */ - 0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */ - 0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */ - 0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */ - 0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */ - 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */ - 0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */ - 0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */ - 0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */ - 0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */ - 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */ - 0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */ - 0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */ - 0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */ - 0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */ - 0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */ - 0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */ - 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */ - 0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */ - 0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */ - 0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */ - 0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */ - 0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */ - 0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */ - 0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */ - 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */ - 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */ - 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */ - 0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */ - 0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */ - 0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */ - 0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */ - 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */ - 0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */ - 0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */ - 0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */ - 0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */ - 0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */ - 0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */ - 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */ - 0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */ - 0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */ - 0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */ - 0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */ - 0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */ - 0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */ - 0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */ - 0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */ - 0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */ - 0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */ - 0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */ - 0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */ - 0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */ - 0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */ - 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */ - 0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */ - 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */ - 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */ - 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */ - 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */ - 0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */ - 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */ - 0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */ - 0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */ - 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */ - 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */ - 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */ - 0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */ - 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */ - 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */ - 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */ - 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */ - 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */ - 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */ - 0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */ - 0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */ - 0x00,0x00, -}; diff --git a/hw/acpi.c b/hw/acpi.c deleted file mode 100644 index 6c20a4e..0000000 --- a/hw/acpi.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * ACPI implementation - * - * Copyright (c) 2006 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2 as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "vl.h" - -//#define DEBUG - -/* i82731AB (PIIX4) compatible power management function */ -#define PM_FREQ 3579545 - -/* XXX: make them variable */ -#define PM_IO_BASE 0xb000 -#define SMI_CMD_IO_ADDR 0xb040 -#define ACPI_DBG_IO_ADDR 0xb044 - -typedef struct PIIX4PMState { - PCIDevice dev; - uint16_t pmsts; - uint16_t pmen; - uint16_t pmcntrl; - QEMUTimer *tmr_timer; - int64_t tmr_overflow_time; -} PIIX4PMState; - -#define RTC_EN (1 << 10) -#define PWRBTN_EN (1 << 8) -#define GBL_EN (1 << 5) -#define TMROF_EN (1 << 0) - -#define SCI_EN (1 << 0) - -#define SUS_EN (1 << 13) - -/* Note: only used for ACPI bios init. Could be deleted when ACPI init - is integrated in Bochs BIOS */ -static PIIX4PMState *piix4_pm_state; - -static uint32_t get_pmtmr(PIIX4PMState *s) -{ - uint32_t d; - d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec); - return d & 0xffffff; -} - -static int get_pmsts(PIIX4PMState *s) -{ - int64_t d; - int pmsts; - pmsts = s->pmsts; - d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec); - if (d >= s->tmr_overflow_time) - s->pmsts |= TMROF_EN; - return pmsts; -} - -static void pm_update_sci(PIIX4PMState *s) -{ - int sci_level, pmsts; - int64_t expire_time; - - pmsts = get_pmsts(s); - sci_level = (((pmsts & s->pmen) & - (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); - pci_set_irq(&s->dev, 0, sci_level); - /* schedule a timer interruption if needed */ - if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) { - expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ); - qemu_mod_timer(s->tmr_timer, expire_time); - } else { - qemu_del_timer(s->tmr_timer); - } -} - -static void pm_tmr_timer(void *opaque) -{ - PIIX4PMState *s = opaque; - pm_update_sci(s); -} - -static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) -{ - PIIX4PMState *s = opaque; - addr &= 0x3f; - switch(addr) { - case 0x00: - { - int64_t d; - int pmsts; - pmsts = get_pmsts(s); - if (pmsts & val & TMROF_EN) { - /* if TMRSTS is reset, then compute the new overflow time */ - d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec); - s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; - } - s->pmsts &= ~val; - pm_update_sci(s); - } - break; - case 0x02: - s->pmen = val; - pm_update_sci(s); - break; - case 0x04: - { - int sus_typ; - s->pmcntrl = val & ~(SUS_EN); - if (val & SUS_EN) { - /* change suspend type */ - sus_typ = (val >> 10) & 3; - switch(sus_typ) { - case 0: /* soft power off */ - qemu_system_shutdown_request(); - break; - default: - break; - } - } - } - break; - default: - break; - } -#ifdef DEBUG - printf("PM writew port=0x%04x val=0x%04x\n", addr, val); -#endif -} - -static uint32_t pm_ioport_readw(void *opaque, uint32_t addr) -{ - PIIX4PMState *s = opaque; - uint32_t val; - - addr &= 0x3f; - switch(addr) { - case 0x00: - val = get_pmsts(s); - break; - case 0x02: - val = s->pmen; - break; - case 0x04: - val = s->pmcntrl; - break; - default: - val = 0; - break; - } -#ifdef DEBUG - printf("PM readw port=0x%04x val=0x%04x\n", addr, val); -#endif - return val; -} - -static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - // PIIX4PMState *s = opaque; - addr &= 0x3f; -#ifdef DEBUG - printf("PM writel port=0x%04x val=0x%08x\n", addr, val); -#endif -} - -static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) -{ - PIIX4PMState *s = opaque; - uint32_t val; - - addr &= 0x3f; - switch(addr) { - case 0x08: - val = get_pmtmr(s); - break; - default: - val = 0; - break; - } -#ifdef DEBUG - printf("PM readl port=0x%04x val=0x%08x\n", addr, val); -#endif - return val; -} - -static void smi_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - PIIX4PMState *s = opaque; -#ifdef DEBUG - printf("SMI cmd val=0x%02x\n", val); -#endif - switch(val) { - case 0xf0: /* ACPI disable */ - s->pmcntrl &= ~SCI_EN; - break; - case 0xf1: /* ACPI enable */ - s->pmcntrl |= SCI_EN; - break; - } -} - -static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val) -{ -#if defined(DEBUG) - printf("ACPI: DBG: 0x%08x\n", val); -#endif -} - -/* XXX: we still add it to the PIIX3 and we count on the fact that - OSes are smart enough to accept this strange configuration */ -void piix4_pm_init(PCIBus *bus, int devfn) -{ - PIIX4PMState *s; - uint8_t *pci_conf; - uint32_t pm_io_base; - - s = (PIIX4PMState *)pci_register_device(bus, - "PM", sizeof(PIIX4PMState), - devfn, NULL, NULL); - pci_conf = s->dev.config; - pci_conf[0x00] = 0x86; - pci_conf[0x01] = 0x80; - pci_conf[0x02] = 0x13; - pci_conf[0x03] = 0x71; - pci_conf[0x08] = 0x00; // revision number - pci_conf[0x09] = 0x00; - pci_conf[0x0a] = 0x80; // other bridge device - pci_conf[0x0b] = 0x06; // bridge device - pci_conf[0x0e] = 0x00; // header_type - pci_conf[0x3d] = 0x01; // interrupt pin 1 - - pm_io_base = PM_IO_BASE; - pci_conf[0x40] = pm_io_base | 1; - pci_conf[0x41] = pm_io_base >> 8; - register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s); - register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s); - register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s); - register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s); - - register_ioport_write(SMI_CMD_IO_ADDR, 1, 1, smi_cmd_writeb, s); - register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s); - - /* XXX: which specification is used ? The i82731AB has different - mappings */ - pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10; - pci_conf[0x63] = 0x60; - pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) | - (serial_hds[1] != NULL ? 0x90 : 0); - - s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s); - piix4_pm_state = s; -} - -/* ACPI tables */ -/* XXX: move them in the Bochs BIOS ? */ - -/*************************************************/ - -/* Table structure from Linux kernel (the ACPI tables are under the - BSD license) */ - -#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \ - uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\ - uint32_t length; /* Length of table, in bytes, including header */\ - uint8_t revision; /* ACPI Specification minor version # */\ - uint8_t checksum; /* To make sum of entire table == 0 */\ - uint8_t oem_id [6]; /* OEM identification */\ - uint8_t oem_table_id [8]; /* OEM table identification */\ - uint32_t oem_revision; /* OEM revision number */\ - uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\ - uint32_t asl_compiler_revision; /* ASL compiler revision number */ - - -struct acpi_table_header /* ACPI common table header */ -{ - ACPI_TABLE_HEADER_DEF -}; - -struct rsdp_descriptor /* Root System Descriptor Pointer */ -{ - uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */ - uint8_t checksum; /* To make sum of struct == 0 */ - uint8_t oem_id [6]; /* OEM identification */ - uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */ - uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */ - uint32_t length; /* XSDT Length in bytes including hdr */ - uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */ - uint8_t extended_checksum; /* Checksum of entire table */ - uint8_t reserved [3]; /* Reserved field must be 0 */ -}; - -/* - * ACPI 1.0 Root System Description Table (RSDT) - */ -struct rsdt_descriptor_rev1 -{ - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - uint32_t table_offset_entry [2]; /* Array of pointers to other */ - /* ACPI tables */ -}; - -/* - * ACPI 1.0 Firmware ACPI Control Structure (FACS) - */ -struct facs_descriptor_rev1 -{ - uint8_t signature[4]; /* ACPI Signature */ - uint32_t length; /* Length of structure, in bytes */ - uint32_t hardware_signature; /* Hardware configuration signature */ - uint32_t firmware_waking_vector; /* ACPI OS waking vector */ - uint32_t global_lock; /* Global Lock */ - uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */ - uint32_t reserved1 : 31; /* Must be 0 */ - uint8_t resverved3 [40]; /* Reserved - must be zero */ -}; - - -/* - * ACPI 1.0 Fixed ACPI Description Table (FADT) - */ -struct fadt_descriptor_rev1 -{ - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - uint32_t firmware_ctrl; /* Physical address of FACS */ - uint32_t dsdt; /* Physical address of DSDT */ - uint8_t model; /* System Interrupt Model */ - uint8_t reserved1; /* Reserved */ - uint16_t sci_int; /* System vector of SCI interrupt */ - uint32_t smi_cmd; /* Port address of SMI command port */ - uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */ - uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */ - uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ - uint8_t reserved2; /* Reserved - must be zero */ - uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ - uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ - uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ - uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ - uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ - uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ - uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ - uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ - uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ - uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ - uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ - uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */ - uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ - uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ - uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */ - uint8_t reserved3; /* Reserved */ - uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ - uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ - uint16_t flush_size; /* Size of area read to flush caches */ - uint16_t flush_stride; /* Stride used in flushing caches */ - uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */ - uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */ - uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ - uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ - uint8_t century; /* Index to century in RTC CMOS RAM */ - uint8_t reserved4; /* Reserved */ - uint8_t reserved4a; /* Reserved */ - uint8_t reserved4b; /* Reserved */ -#if 0 - uint32_t wb_invd : 1; /* The wbinvd instruction works properly */ - uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ - uint32_t proc_c1 : 1; /* All processors support C1 state */ - uint32_t plvl2_up : 1; /* C2 state works on MP system */ - uint32_t pwr_button : 1; /* Power button is handled as a generic feature */ - uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */ - uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */ - uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */ - uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */ - uint32_t reserved5 : 23; /* Reserved - must be zero */ -#else - uint32_t flags; -#endif -}; - -/* - * MADT values and structures - */ - -/* Values for MADT PCATCompat */ - -#define DUAL_PIC 0 -#define MULTIPLE_APIC 1 - - -/* Master MADT */ - -struct multiple_apic_table -{ - ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - uint32_t local_apic_address; /* Physical address of local APIC */ -#if 0 - uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */ - uint32_t reserved1 : 31; -#else - uint32_t flags; -#endif -}; - - -/* Values for Type in APIC_HEADER_DEF */ - -#define APIC_PROCESSOR 0 -#define APIC_IO 1 -#define APIC_XRUPT_OVERRIDE 2 -#define APIC_NMI 3 -#define APIC_LOCAL_NMI 4 -#define APIC_ADDRESS_OVERRIDE 5 -#define APIC_IO_SAPIC 6 -#define APIC_LOCAL_SAPIC 7 -#define APIC_XRUPT_SOURCE 8 -#define APIC_RESERVED 9 /* 9 and greater are reserved */ - -/* - * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) - */ -#define APIC_HEADER_DEF /* Common APIC sub-structure header */\ - uint8_t type; \ - uint8_t length; - -/* Sub-structures for MADT */ - -struct madt_processor_apic -{ - APIC_HEADER_DEF - uint8_t processor_id; /* ACPI processor id */ - uint8_t local_apic_id; /* Processor's local APIC id */ -#if 0 - uint32_t processor_enabled: 1; /* Processor is usable if set */ - uint32_t reserved2 : 31; /* Reserved, must be zero */ -#else - uint32_t flags; -#endif -}; - -struct madt_io_apic -{ - APIC_HEADER_DEF - uint8_t io_apic_id; /* I/O APIC ID */ - uint8_t reserved; /* Reserved - must be zero */ - uint32_t address; /* APIC physical address */ - uint32_t interrupt; /* Global system interrupt where INTI - * lines start */ -}; - -#include "acpi-dsdt.hex" - -static int acpi_checksum(const uint8_t *data, int len) -{ - int sum, i; - sum = 0; - for(i = 0; i < len; i++) - sum += data[i]; - return (-sum) & 0xff; -} - -static void acpi_build_table_header(struct acpi_table_header *h, - char *sig, int len) -{ - memcpy(h->signature, sig, 4); - h->length = cpu_to_le32(len); - h->revision = 0; - memcpy(h->oem_id, "QEMU ", 6); - memcpy(h->oem_table_id, "QEMU", 4); - memcpy(h->oem_table_id + 4, sig, 4); - h->oem_revision = cpu_to_le32(1); - memcpy(h->asl_compiler_id, "QEMU", 4); - h->asl_compiler_revision = cpu_to_le32(1); - h->checksum = acpi_checksum((void *)h, len); -} - -#define ACPI_TABLES_BASE 0x000e8000 - -/* base_addr must be a multiple of 4KB */ -void acpi_bios_init(void) -{ - struct rsdp_descriptor *rsdp; - struct rsdt_descriptor_rev1 *rsdt; - struct fadt_descriptor_rev1 *fadt; - struct facs_descriptor_rev1 *facs; - struct multiple_apic_table *madt; - uint8_t *dsdt; - uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr; - uint32_t pm_io_base, acpi_tables_size, madt_addr, madt_size; - int i; - - /* compute PCI I/O addresses */ - pm_io_base = (piix4_pm_state->dev.config[0x40] | - (piix4_pm_state->dev.config[0x41] << 8)) & ~0x3f; - - base_addr = ACPI_TABLES_BASE; - - /* reserve memory space for tables */ - addr = base_addr; - rsdp = (void *)(phys_ram_base + addr); - addr += sizeof(*rsdp); - - rsdt_addr = addr; - rsdt = (void *)(phys_ram_base + addr); - addr += sizeof(*rsdt); - - fadt_addr = addr; - fadt = (void *)(phys_ram_base + addr); - addr += sizeof(*fadt); - - /* XXX: FACS should be in RAM */ - addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */ - facs_addr = addr; - facs = (void *)(phys_ram_base + addr); - addr += sizeof(*facs); - - dsdt_addr = addr; - dsdt = (void *)(phys_ram_base + addr); - addr += sizeof(AmlCode); - - addr = (addr + 7) & ~7; - madt_addr = addr; - madt_size = sizeof(*madt) + - sizeof(struct madt_processor_apic) * smp_cpus + - sizeof(struct madt_io_apic); - madt = (void *)(phys_ram_base + addr); - addr += madt_size; - - acpi_tables_size = addr - base_addr; - - cpu_register_physical_memory(base_addr, acpi_tables_size, - base_addr | IO_MEM_ROM); - - /* RSDP */ - memset(rsdp, 0, sizeof(*rsdp)); - memcpy(rsdp->signature, "RSD PTR ", 8); - memcpy(rsdp->oem_id, "QEMU ", 6); - rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr); - rsdp->checksum = acpi_checksum((void *)rsdp, 20); - - /* RSDT */ - rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr); - rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr); - acpi_build_table_header((struct acpi_table_header *)rsdt, - "RSDT", sizeof(*rsdt)); - - /* FADT */ - memset(fadt, 0, sizeof(*fadt)); - fadt->firmware_ctrl = cpu_to_le32(facs_addr); - fadt->dsdt = cpu_to_le32(dsdt_addr); - fadt->model = 1; - fadt->reserved1 = 0; - fadt->sci_int = cpu_to_le16(piix4_pm_state->dev.config[0x3c]); - fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR); - fadt->acpi_enable = 0xf1; - fadt->acpi_disable = 0xf0; - fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base); - fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04); - fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08); - fadt->pm1_evt_len = 4; - fadt->pm1_cnt_len = 2; - fadt->pm_tmr_len = 4; - fadt->plvl2_lat = cpu_to_le16(50); - fadt->plvl3_lat = cpu_to_le16(50); - fadt->plvl3_lat = cpu_to_le16(50); - /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */ - fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6)); - acpi_build_table_header((struct acpi_table_header *)fadt, "FACP", - sizeof(*fadt)); - - /* FACS */ - memset(facs, 0, sizeof(*facs)); - memcpy(facs->signature, "FACS", 4); - facs->length = cpu_to_le32(sizeof(*facs)); - - /* DSDT */ - memcpy(dsdt, AmlCode, sizeof(AmlCode)); - - /* MADT */ - { - struct madt_processor_apic *apic; - struct madt_io_apic *io_apic; - - memset(madt, 0, madt_size); - madt->local_apic_address = cpu_to_le32(0xfee00000); - madt->flags = cpu_to_le32(1); - apic = (void *)(madt + 1); - for(i=0;i<smp_cpus;i++) { - apic->type = APIC_PROCESSOR; - apic->length = sizeof(*apic); - apic->processor_id = i; - apic->local_apic_id = i; - apic->flags = cpu_to_le32(1); - apic++; - } - io_apic = (void *)apic; - io_apic->type = APIC_IO; - io_apic->length = sizeof(*io_apic); - io_apic->io_apic_id = smp_cpus; - io_apic->address = cpu_to_le32(0xfec00000); - io_apic->interrupt = cpu_to_le32(0); - - acpi_build_table_header((struct acpi_table_header *)madt, - "APIC", madt_size); - } -} diff --git a/hw/adb.c b/hw/adb.c deleted file mode 100644 index 8e08cb1..0000000 --- a/hw/adb.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * QEMU ADB support - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* ADB commands */ -#define ADB_BUSRESET 0x00 -#define ADB_FLUSH 0x01 -#define ADB_WRITEREG 0x08 -#define ADB_READREG 0x0c - -/* ADB device commands */ -#define ADB_CMD_SELF_TEST 0xff -#define ADB_CMD_CHANGE_ID 0xfe -#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd -#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00 - -/* ADB default device IDs (upper 4 bits of ADB command byte) */ -#define ADB_DONGLE 1 -#define ADB_KEYBOARD 2 -#define ADB_MOUSE 3 -#define ADB_TABLET 4 -#define ADB_MODEM 5 -#define ADB_MISC 7 - -/* error codes */ -#define ADB_RET_NOTPRESENT (-2) - -int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) -{ - ADBDevice *d; - int devaddr, cmd, i; - - cmd = buf[0] & 0xf; - if (cmd == ADB_BUSRESET) { - for(i = 0; i < s->nb_devices; i++) { - d = &s->devices[i]; - if (d->devreset) { - d->devreset(d); - } - } - return 0; - } - devaddr = buf[0] >> 4; - for(i = 0; i < s->nb_devices; i++) { - d = &s->devices[i]; - if (d->devaddr == devaddr) { - return d->devreq(d, obuf, buf, len); - } - } - return ADB_RET_NOTPRESENT; -} - -/* XXX: move that to cuda ? */ -int adb_poll(ADBBusState *s, uint8_t *obuf) -{ - ADBDevice *d; - int olen, i; - uint8_t buf[1]; - - olen = 0; - for(i = 0; i < s->nb_devices; i++) { - if (s->poll_index >= s->nb_devices) - s->poll_index = 0; - d = &s->devices[s->poll_index]; - buf[0] = ADB_READREG | (d->devaddr << 4); - olen = adb_request(s, obuf + 1, buf, 1); - /* if there is data, we poll again the same device */ - if (olen > 0) { - obuf[0] = buf[0]; - olen++; - break; - } - s->poll_index++; - } - return olen; -} - -ADBDevice *adb_register_device(ADBBusState *s, int devaddr, - ADBDeviceRequest *devreq, - ADBDeviceReset *devreset, - void *opaque) -{ - ADBDevice *d; - if (s->nb_devices >= MAX_ADB_DEVICES) - return NULL; - d = &s->devices[s->nb_devices++]; - d->bus = s; - d->devaddr = devaddr; - d->devreq = devreq; - d->devreset = devreset; - d->opaque = opaque; - return d; -} - -/***************************************************************/ -/* Keyboard ADB device */ - -typedef struct KBDState { - uint8_t data[128]; - int rptr, wptr, count; -} KBDState; - -static const uint8_t pc_to_adb_keycode[256] = { - 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, - 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, - 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, - 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, - 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, - 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0,110, 81, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,125, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 75, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,115, 62,116, 0, 59, 0, 60, 0,119, - 61,121,114,117, 0, 0, 0, 0, 0, 0, 0, 55,126, 0,127, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static void adb_kbd_put_keycode(void *opaque, int keycode) -{ - ADBDevice *d = opaque; - KBDState *s = d->opaque; - - if (s->count < sizeof(s->data)) { - s->data[s->wptr] = keycode; - if (++s->wptr == sizeof(s->data)) - s->wptr = 0; - s->count++; - } -} - -static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) -{ - static int ext_keycode; - KBDState *s = d->opaque; - int adb_keycode, keycode; - int olen; - - olen = 0; - for(;;) { - if (s->count == 0) - break; - keycode = s->data[s->rptr]; - if (++s->rptr == sizeof(s->data)) - s->rptr = 0; - s->count--; - - if (keycode == 0xe0) { - ext_keycode = 1; - } else { - if (ext_keycode) - adb_keycode = pc_to_adb_keycode[keycode | 0x80]; - else - adb_keycode = pc_to_adb_keycode[keycode & 0x7f]; - obuf[0] = adb_keycode | (keycode & 0x80); - /* NOTE: could put a second keycode if needed */ - obuf[1] = 0xff; - olen = 2; - ext_keycode = 0; - break; - } - } - return olen; -} - -static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, - const uint8_t *buf, int len) -{ - KBDState *s = d->opaque; - int cmd, reg, olen; - - if ((buf[0] & 0x0f) == ADB_FLUSH) { - /* flush keyboard fifo */ - s->wptr = s->rptr = s->count = 0; - return 0; - } - - cmd = buf[0] & 0xc; - reg = buf[0] & 0x3; - olen = 0; - switch(cmd) { - case ADB_WRITEREG: - switch(reg) { - case 2: - /* LED status */ - break; - case 3: - switch(buf[2]) { - case ADB_CMD_SELF_TEST: - break; - case ADB_CMD_CHANGE_ID: - case ADB_CMD_CHANGE_ID_AND_ACT: - case ADB_CMD_CHANGE_ID_AND_ENABLE: - d->devaddr = buf[1] & 0xf; - break; - default: - /* XXX: check this */ - d->devaddr = buf[1] & 0xf; - d->handler = buf[2]; - break; - } - } - break; - case ADB_READREG: - switch(reg) { - case 0: - olen = adb_kbd_poll(d, obuf); - break; - case 1: - break; - case 2: - obuf[0] = 0x00; /* XXX: check this */ - obuf[1] = 0x07; /* led status */ - olen = 2; - break; - case 3: - obuf[0] = d->handler; - obuf[1] = d->devaddr; - olen = 2; - break; - } - break; - } - return olen; -} - -static int adb_kbd_reset(ADBDevice *d) -{ - KBDState *s = d->opaque; - - d->handler = 1; - d->devaddr = ADB_KEYBOARD; - memset(s, 0, sizeof(KBDState)); - - return 0; -} - -void adb_kbd_init(ADBBusState *bus) -{ - ADBDevice *d; - KBDState *s; - s = qemu_mallocz(sizeof(KBDState)); - d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, - adb_kbd_reset, s); - adb_kbd_reset(d); - qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); -} - -/***************************************************************/ -/* Mouse ADB device */ - -typedef struct MouseState { - int buttons_state, last_buttons_state; - int dx, dy, dz; -} MouseState; - -static void adb_mouse_event(void *opaque, - int dx1, int dy1, int dz1, int buttons_state) -{ - ADBDevice *d = opaque; - MouseState *s = d->opaque; - - s->dx += dx1; - s->dy += dy1; - s->dz += dz1; - s->buttons_state = buttons_state; -} - - -static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) -{ - MouseState *s = d->opaque; - int dx, dy; - - if (s->last_buttons_state == s->buttons_state && - s->dx == 0 && s->dy == 0) - return 0; - - dx = s->dx; - if (dx < -63) - dx = -63; - else if (dx > 63) - dx = 63; - - dy = s->dy; - if (dy < -63) - dy = -63; - else if (dy > 63) - dy = 63; - - s->dx -= dx; - s->dy -= dy; - s->last_buttons_state = s->buttons_state; - - dx &= 0x7f; - dy &= 0x7f; - - if (!(s->buttons_state & MOUSE_EVENT_LBUTTON)) - dy |= 0x80; - if (!(s->buttons_state & MOUSE_EVENT_RBUTTON)) - dx |= 0x80; - - obuf[0] = dy; - obuf[1] = dx; - return 2; -} - -static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, - const uint8_t *buf, int len) -{ - MouseState *s = d->opaque; - int cmd, reg, olen; - - if ((buf[0] & 0x0f) == ADB_FLUSH) { - /* flush mouse fifo */ - s->buttons_state = s->last_buttons_state; - s->dx = 0; - s->dy = 0; - s->dz = 0; - return 0; - } - - cmd = buf[0] & 0xc; - reg = buf[0] & 0x3; - olen = 0; - switch(cmd) { - case ADB_WRITEREG: - switch(reg) { - case 2: - break; - case 3: - switch(buf[2]) { - case ADB_CMD_SELF_TEST: - break; - case ADB_CMD_CHANGE_ID: - case ADB_CMD_CHANGE_ID_AND_ACT: - case ADB_CMD_CHANGE_ID_AND_ENABLE: - d->devaddr = buf[1] & 0xf; - break; - default: - /* XXX: check this */ - d->devaddr = buf[1] & 0xf; - break; - } - } - break; - case ADB_READREG: - switch(reg) { - case 0: - olen = adb_mouse_poll(d, obuf); - break; - case 1: - break; - case 3: - obuf[0] = d->handler; - obuf[1] = d->devaddr; - olen = 2; - break; - } - break; - } - return olen; -} - -static int adb_mouse_reset(ADBDevice *d) -{ - MouseState *s = d->opaque; - - d->handler = 2; - d->devaddr = ADB_MOUSE; - memset(s, 0, sizeof(MouseState)); - - return 0; -} - -void adb_mouse_init(ADBBusState *bus) -{ - ADBDevice *d; - MouseState *s; - - s = qemu_mallocz(sizeof(MouseState)); - d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, - adb_mouse_reset, s); - adb_mouse_reset(d); - qemu_add_mouse_event_handler(adb_mouse_event, d, 0); -} diff --git a/hw/adlib.c b/hw/adlib.c deleted file mode 100644 index b47bc3e..0000000 --- a/hw/adlib.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * QEMU Proxy for OPL2/3 emulation by MAME team - * - * Copyright (c) 2004-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include <assert.h> -#include "vl.h" - -#define ADLIB_KILL_TIMERS 1 - -#define dolog(...) AUD_log ("adlib", __VA_ARGS__) -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif - -#ifdef HAS_YMF262 -#include "ymf262.h" -void YMF262UpdateOneQEMU (int which, INT16 *dst, int length); -#define SHIFT 2 -#else -#include "fmopl.h" -#define SHIFT 1 -#endif - -#define IO_READ_PROTO(name) \ - uint32_t name (void *opaque, uint32_t nport) -#define IO_WRITE_PROTO(name) \ - void name (void *opaque, uint32_t nport, uint32_t val) - -static struct { - int port; - int freq; -} conf = {0x220, 44100}; - -typedef struct { - QEMUSoundCard card; - int ticking[2]; - int enabled; - int active; - int bufpos; -#ifdef DEBUG - int64_t exp[2]; -#endif - int16_t *mixbuf; - uint64_t dexp[2]; - SWVoiceOut *voice; - int left, pos, samples; - QEMUAudioTimeStamp ats; -#ifndef HAS_YMF262 - FM_OPL *opl; -#endif -} AdlibState; - -static AdlibState glob_adlib; - -static void adlib_stop_opl_timer (AdlibState *s, size_t n) -{ -#ifdef HAS_YMF262 - YMF262TimerOver (0, n); -#else - OPLTimerOver (s->opl, n); -#endif - s->ticking[n] = 0; -} - -static void adlib_kill_timers (AdlibState *s) -{ - size_t i; - - for (i = 0; i < 2; ++i) { - if (s->ticking[i]) { - uint64_t delta; - - delta = AUD_get_elapsed_usec_out (s->voice, &s->ats); - ldebug ( - "delta = %f dexp = %f expired => %d\n", - delta / 1000000.0, - s->dexp[i] / 1000000.0, - delta >= s->dexp[i] - ); - if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) { - adlib_stop_opl_timer (s, i); - AUD_init_time_stamp_out (s->voice, &s->ats); - } - } - } -} - -static IO_WRITE_PROTO(adlib_write) -{ - AdlibState *s = opaque; - int a = nport & 3; - int status; - - s->active = 1; - AUD_set_active_out (s->voice, 1); - - adlib_kill_timers (s); - -#ifdef HAS_YMF262 - status = YMF262Write (0, a, val); -#else - status = OPLWrite (s->opl, a, val); -#endif -} - -static IO_READ_PROTO(adlib_read) -{ - AdlibState *s = opaque; - uint8_t data; - int a = nport & 3; - - adlib_kill_timers (s); - -#ifdef HAS_YMF262 - data = YMF262Read (0, a); -#else - data = OPLRead (s->opl, a); -#endif - return data; -} - -static void timer_handler (int c, double interval_Sec) -{ - AdlibState *s = &glob_adlib; - unsigned n = c & 1; -#ifdef DEBUG - double interval; - int64_t exp; -#endif - - if (interval_Sec == 0.0) { - s->ticking[n] = 0; - return; - } - - s->ticking[n] = 1; -#ifdef DEBUG - interval = ticks_per_sec * interval_Sec; - exp = qemu_get_clock (vm_clock) + interval; - s->exp[n] = exp; -#endif - - s->dexp[n] = interval_Sec * 1000000.0; - AUD_init_time_stamp_out (s->voice, &s->ats); -} - -static int write_audio (AdlibState *s, int samples) -{ - int net = 0; - int pos = s->pos; - - while (samples) { - int nbytes, wbytes, wsampl; - - nbytes = samples << SHIFT; - wbytes = AUD_write ( - s->voice, - s->mixbuf + (pos << (SHIFT - 1)), - nbytes - ); - - if (wbytes) { - wsampl = wbytes >> SHIFT; - - samples -= wsampl; - pos = (pos + wsampl) % s->samples; - - net += wsampl; - } - else { - break; - } - } - - return net; -} - -static void adlib_callback (void *opaque, int free) -{ - AdlibState *s = opaque; - int samples, net = 0, to_play, written; - - samples = free >> SHIFT; - if (!(s->active && s->enabled) || !samples) { - return; - } - - to_play = audio_MIN (s->left, samples); - while (to_play) { - written = write_audio (s, to_play); - - if (written) { - s->left -= written; - samples -= written; - to_play -= written; - s->pos = (s->pos + written) % s->samples; - } - else { - return; - } - } - - samples = audio_MIN (samples, s->samples - s->pos); - if (!samples) { - return; - } - -#ifdef HAS_YMF262 - YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples); -#else - YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples); -#endif - - while (samples) { - written = write_audio (s, samples); - - if (written) { - net += written; - samples -= written; - s->pos = (s->pos + written) % s->samples; - } - else { - s->left = samples; - return; - } - } -} - -static void Adlib_fini (AdlibState *s) -{ -#ifdef HAS_YMF262 - YMF262Shutdown (); -#else - if (s->opl) { - OPLDestroy (s->opl); - s->opl = NULL; - } -#endif - - if (s->mixbuf) { - qemu_free (s->mixbuf); - } - - s->active = 0; - s->enabled = 0; - AUD_remove_card (&s->card); -} - -int Adlib_init (AudioState *audio) -{ - AdlibState *s = &glob_adlib; - audsettings_t as; - - if (!audio) { - dolog ("No audio state\n"); - return -1; - } - -#ifdef HAS_YMF262 - if (YMF262Init (1, 14318180, conf.freq)) { - dolog ("YMF262Init %d failed\n", conf.freq); - return -1; - } - else { - YMF262SetTimerHandler (0, timer_handler, 0); - s->enabled = 1; - } -#else - s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq); - if (!s->opl) { - dolog ("OPLCreate %d failed\n", conf.freq); - return -1; - } - else { - OPLSetTimerHandler (s->opl, timer_handler, 0); - s->enabled = 1; - } -#endif - - as.freq = conf.freq; - as.nchannels = SHIFT; - as.fmt = AUD_FMT_S16; - as.endianness = AUDIO_HOST_ENDIANNESS; - - AUD_register_card (audio, "adlib", &s->card); - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "adlib", - s, - adlib_callback, - &as - ); - if (!s->voice) { - Adlib_fini (s); - return -1; - } - - s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT; - s->mixbuf = qemu_mallocz (s->samples << SHIFT); - - if (!s->mixbuf) { - dolog ("Could not allocate mixing buffer, %d samples (each %d bytes)\n", - s->samples, 1 << SHIFT); - Adlib_fini (s); - return -1; - } - - register_ioport_read (0x388, 4, 1, adlib_read, s); - register_ioport_write (0x388, 4, 1, adlib_write, s); - - register_ioport_read (conf.port, 4, 1, adlib_read, s); - register_ioport_write (conf.port, 4, 1, adlib_write, s); - - register_ioport_read (conf.port + 8, 2, 1, adlib_read, s); - register_ioport_write (conf.port + 8, 2, 1, adlib_write, s); - - return 0; -} diff --git a/hw/android_arm.c b/hw/android_arm.c new file mode 100644 index 0000000..7b1d446 --- /dev/null +++ b/hw/android_arm.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "arm_pic.h" +#include "goldfish_device.h" + +int android_audio_enabled; +char* audio_input_source = NULL; + +void goldfish_memlog_init(uint32_t base); + +static struct goldfish_device event0_device = { + .name = "goldfish_events", + .id = 0, + .size = 0x1000, + .irq_count = 1 +}; + +static struct goldfish_device nand_device = { + .name = "goldfish_nand", + .id = 0, + .size = 0x1000 +}; + +static struct goldfish_device trace_device = { + .name = "qemu_trace", + .id = -1, + .size = 0x1000 +}; + +/* Board init. */ + +#define TEST_SWITCH 1 +#if TEST_SWITCH +uint32_t switch_test_write(void *opaque, uint32_t state) +{ + goldfish_switch_set_state(opaque, state); + return state; +} +#endif + +static void android_arm_init(int ram_size, int vga_ram_size, + int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + CPUState *env; + qemu_irq *cpu_pic; + qemu_irq *goldfish_pic; + int i; + + env = cpu_init(); + cpu_arm_set_model(env, ARM_CPUID_ARM926); + + register_savevm( "cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load, env ); + + cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); + + cpu_pic = arm_pic_init_cpu(env); + goldfish_pic = goldfish_interrupt_init(0xff000000, cpu_pic[ARM_PIC_CPU_IRQ], cpu_pic[ARM_PIC_CPU_FIQ]); + goldfish_device_init(goldfish_pic, 0xff010000, 0x7f0000, 10, 22); + + goldfish_device_bus_init(0xff001000, 1); + + goldfish_timer_and_rtc_init(0xff003000, 3); + + goldfish_tty_add(serial_hds[0], 0, 0xff002000, 4); + for(i = 1; i < MAX_SERIAL_PORTS; i++) { + //printf("android_arm_init serial %d %x\n", i, serial_hds[i]); + if(serial_hds[i]) { + goldfish_tty_add(serial_hds[i], i, 0, 0); + } + } + + for(i = 0; i < MAX_NICS; i++) { + if (nd_table[i].vlan) { + if (nd_table[i].model == NULL + || strcmp(nd_table[i].model, "smc91c111") == 0) { + struct goldfish_device *smc_device; + smc_device = qemu_mallocz(sizeof(*smc_device)); + smc_device->name = "smc91x"; + smc_device->id = i; + smc_device->size = 0x1000; + smc_device->irq_count = 1; + goldfish_add_device_no_io(smc_device); + smc91c111_init(&nd_table[i], smc_device->base, goldfish_pic[smc_device->irq]); + } else { + fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); + exit (1); + } + } + } + + goldfish_fb_init(ds, 0); +#ifdef HAS_AUDIO + if (android_audio_enabled) { + AUD_init(); + goldfish_audio_init(0xff004000, 0, audio_input_source); + } +#endif + if (bs_table[0]) + goldfish_mmc_init(0xff005000, 0, bs_table[0]); + + goldfish_memlog_init(0xff006000); + + goldfish_battery_init(); + + goldfish_add_device_no_io(&event0_device); + events_dev_init(event0_device.base, goldfish_pic[event0_device.irq]); + +#ifdef CONFIG_NAND + goldfish_add_device_no_io(&nand_device); + nand_dev_init(nand_device.base); +#endif +#ifdef CONFIG_TRACE + extern const char *trace_filename; + if(trace_filename != NULL) { + goldfish_add_device_no_io(&trace_device); + trace_dev_init(trace_device.base); + } +#endif + +#if TEST_SWITCH + { + void *sw; + sw = goldfish_switch_add("test", NULL, NULL, 0); + goldfish_switch_set_state(sw, 1); + goldfish_switch_add("test2", switch_test_write, sw, 1); + } +#endif + + arm_load_kernel(ram_size, kernel_filename, kernel_cmdline, + initrd_filename, 1441); +} + +QEMUMachine android_arm_machine = { + "android_arm", + "ARM Android Emulator", + android_arm_init, +}; diff --git a/hw/apb_pci.c b/hw/apb_pci.c deleted file mode 100644 index 02e9824..0000000 --- a/hw/apb_pci.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * QEMU Ultrasparc APB PCI host - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -typedef target_phys_addr_t pci_addr_t; -#include "pci_host.h" - -typedef PCIHostState APBState; - -static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - APBState *s = opaque; - int i; - - for (i = 11; i < 32; i++) { - if ((val & (1 << i)) != 0) - break; - } - s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11); -} - -static uint32_t pci_apb_config_readl (void *opaque, - target_phys_addr_t addr) -{ - APBState *s = opaque; - uint32_t val; - int devfn; - - devfn = (s->config_reg >> 8) & 0xFF; - val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_config_write[] = { - &pci_apb_config_writel, - &pci_apb_config_writel, - &pci_apb_config_writel, -}; - -static CPUReadMemoryFunc *pci_apb_config_read[] = { - &pci_apb_config_readl, - &pci_apb_config_readl, - &pci_apb_config_readl, -}; - -static void apb_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - //PCIBus *s = opaque; - - switch (addr & 0x3f) { - case 0x00: // Control/Status - case 0x10: // AFSR - case 0x18: // AFAR - case 0x20: // Diagnostic - case 0x28: // Target address space - // XXX - default: - break; - } -} - -static uint32_t apb_config_readl (void *opaque, - target_phys_addr_t addr) -{ - //PCIBus *s = opaque; - uint32_t val; - - switch (addr & 0x3f) { - case 0x00: // Control/Status - case 0x10: // AFSR - case 0x18: // AFAR - case 0x20: // Diagnostic - case 0x28: // Target address space - // XXX - default: - val = 0; - break; - } - return val; -} - -static CPUWriteMemoryFunc *apb_config_write[] = { - &apb_config_writel, - &apb_config_writel, - &apb_config_writel, -}; - -static CPUReadMemoryFunc *apb_config_read[] = { - &apb_config_readl, - &apb_config_readl, - &apb_config_readl, -}; - -static CPUWriteMemoryFunc *pci_apb_write[] = { - &pci_host_data_writeb, - &pci_host_data_writew, - &pci_host_data_writel, -}; - -static CPUReadMemoryFunc *pci_apb_read[] = { - &pci_host_data_readb, - &pci_host_data_readw, - &pci_host_data_readl, -}; - -static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outb(NULL, addr & 0xffff, val); -} - -static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outw(NULL, addr & 0xffff, val); -} - -static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - cpu_outl(NULL, addr & 0xffff, val); -} - -static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inb(NULL, addr & 0xffff); - return val; -} - -static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inw(NULL, addr & 0xffff); - return val; -} - -static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - - val = cpu_inl(NULL, addr & 0xffff); - return val; -} - -static CPUWriteMemoryFunc *pci_apb_iowrite[] = { - &pci_apb_iowriteb, - &pci_apb_iowritew, - &pci_apb_iowritel, -}; - -static CPUReadMemoryFunc *pci_apb_ioread[] = { - &pci_apb_ioreadb, - &pci_apb_ioreadw, - &pci_apb_ioreadl, -}; - -/* ??? This is probably wrong. */ -static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) -{ - pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level); -} - -PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, - void *pic) -{ - APBState *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data, apb_config, pci_ioport; - - s = qemu_mallocz(sizeof(APBState)); - /* Ultrasparc APB main bus */ - s->bus = pci_register_bus(pci_apb_set_irq, pic, 0); - - pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, - pci_apb_config_write, s); - apb_config = cpu_register_io_memory(0, apb_config_read, - apb_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_apb_read, - pci_apb_write, s); - pci_ioport = cpu_register_io_memory(0, pci_apb_ioread, - pci_apb_iowrite, s); - - cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config); - cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config); - cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport); - cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom - - d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice), - -1, NULL, NULL); - d->config[0x00] = 0x8e; // vendor_id : Sun - d->config[0x01] = 0x10; - d->config[0x02] = 0x00; // device_id - d->config[0x03] = 0xa0; - d->config[0x04] = 0x06; // command = bus master, pci mem - d->config[0x05] = 0x00; - d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error - d->config[0x07] = 0x03; // status = medium devsel - d->config[0x08] = 0x00; // revision - d->config[0x09] = 0x00; // programming i/f - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - return s->bus; -} - - diff --git a/hw/apic.c b/hw/apic.c deleted file mode 100644 index 8f88cce..0000000 --- a/hw/apic.c +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * APIC support - * - * Copyright (c) 2004-2005 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include "vl.h" - -//#define DEBUG_APIC -//#define DEBUG_IOAPIC - -/* APIC Local Vector Table */ -#define APIC_LVT_TIMER 0 -#define APIC_LVT_THERMAL 1 -#define APIC_LVT_PERFORM 2 -#define APIC_LVT_LINT0 3 -#define APIC_LVT_LINT1 4 -#define APIC_LVT_ERROR 5 -#define APIC_LVT_NB 6 - -/* APIC delivery modes */ -#define APIC_DM_FIXED 0 -#define APIC_DM_LOWPRI 1 -#define APIC_DM_SMI 2 -#define APIC_DM_NMI 4 -#define APIC_DM_INIT 5 -#define APIC_DM_SIPI 6 -#define APIC_DM_EXTINT 7 - -/* APIC destination mode */ -#define APIC_DESTMODE_FLAT 0xf -#define APIC_DESTMODE_CLUSTER 1 - -#define APIC_TRIGGER_EDGE 0 -#define APIC_TRIGGER_LEVEL 1 - -#define APIC_LVT_TIMER_PERIODIC (1<<17) -#define APIC_LVT_MASKED (1<<16) -#define APIC_LVT_LEVEL_TRIGGER (1<<15) -#define APIC_LVT_REMOTE_IRR (1<<14) -#define APIC_INPUT_POLARITY (1<<13) -#define APIC_SEND_PENDING (1<<12) - -#define IOAPIC_NUM_PINS 0x18 - -#define ESR_ILLEGAL_ADDRESS (1 << 7) - -#define APIC_SV_ENABLE (1 << 8) - -#define MAX_APICS 255 -#define MAX_APIC_WORDS 8 - -typedef struct APICState { - CPUState *cpu_env; - uint32_t apicbase; - uint8_t id; - uint8_t arb_id; - uint8_t tpr; - uint32_t spurious_vec; - uint8_t log_dest; - uint8_t dest_mode; - uint32_t isr[8]; /* in service register */ - uint32_t tmr[8]; /* trigger mode register */ - uint32_t irr[8]; /* interrupt request register */ - uint32_t lvt[APIC_LVT_NB]; - uint32_t esr; /* error register */ - uint32_t icr[2]; - - uint32_t divide_conf; - int count_shift; - uint32_t initial_count; - int64_t initial_count_load_time, next_time; - QEMUTimer *timer; -} APICState; - -struct IOAPICState { - uint8_t id; - uint8_t ioregsel; - - uint32_t irr; - uint64_t ioredtbl[IOAPIC_NUM_PINS]; -}; - -static int apic_io_memory; -static APICState *local_apics[MAX_APICS + 1]; -static int last_apic_id = 0; - -static void apic_init_ipi(APICState *s); -static void apic_set_irq(APICState *s, int vector_num, int trigger_mode); -static void apic_update_irq(APICState *s); - -/* Find first bit starting from msb. Return 0 if value = 0 */ -static int fls_bit(uint32_t value) -{ - unsigned int ret = 0; - -#if defined(HOST_I386) - __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value)); - return ret; -#else - if (value > 0xffff) - value >>= 16, ret = 16; - if (value > 0xff) - value >>= 8, ret += 8; - if (value > 0xf) - value >>= 4, ret += 4; - if (value > 0x3) - value >>= 2, ret += 2; - return ret + (value >> 1); -#endif -} - -/* Find first bit starting from lsb. Return 0 if value = 0 */ -static int ffs_bit(uint32_t value) -{ - unsigned int ret = 0; - -#if defined(HOST_I386) - __asm__ __volatile__ ("bsf %1, %0\n" : "+r" (ret) : "rm" (value)); - return ret; -#else - if (!value) - return 0; - if (!(value & 0xffff)) - value >>= 16, ret = 16; - if (!(value & 0xff)) - value >>= 8, ret += 8; - if (!(value & 0xf)) - value >>= 4, ret += 4; - if (!(value & 0x3)) - value >>= 2, ret += 2; - if (!(value & 0x1)) - ret++; - return ret; -#endif -} - -static inline void set_bit(uint32_t *tab, int index) -{ - int i, mask; - i = index >> 5; - mask = 1 << (index & 0x1f); - tab[i] |= mask; -} - -static inline void reset_bit(uint32_t *tab, int index) -{ - int i, mask; - i = index >> 5; - mask = 1 << (index & 0x1f); - tab[i] &= ~mask; -} - -#define foreach_apic(apic, deliver_bitmask, code) \ -{\ - int __i, __j, __mask;\ - for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\ - __mask = deliver_bitmask[__i];\ - if (__mask) {\ - for(__j = 0; __j < 32; __j++) {\ - if (__mask & (1 << __j)) {\ - apic = local_apics[__i * 32 + __j];\ - if (apic) {\ - code;\ - }\ - }\ - }\ - }\ - }\ -} - -static void apic_bus_deliver(const uint32_t *deliver_bitmask, - uint8_t delivery_mode, - uint8_t vector_num, uint8_t polarity, - uint8_t trigger_mode) -{ - APICState *apic_iter; - - switch (delivery_mode) { - case APIC_DM_LOWPRI: - /* XXX: search for focus processor, arbitration */ - { - int i, d; - d = -1; - for(i = 0; i < MAX_APIC_WORDS; i++) { - if (deliver_bitmask[i]) { - d = i * 32 + ffs_bit(deliver_bitmask[i]); - break; - } - } - if (d >= 0) { - apic_iter = local_apics[d]; - if (apic_iter) { - apic_set_irq(apic_iter, vector_num, trigger_mode); - } - } - } - return; - - case APIC_DM_FIXED: - break; - - case APIC_DM_SMI: - case APIC_DM_NMI: - break; - - case APIC_DM_INIT: - /* normal INIT IPI sent to processors */ - foreach_apic(apic_iter, deliver_bitmask, - apic_init_ipi(apic_iter) ); - return; - - case APIC_DM_EXTINT: - /* handled in I/O APIC code */ - break; - - default: - return; - } - - foreach_apic(apic_iter, deliver_bitmask, - apic_set_irq(apic_iter, vector_num, trigger_mode) ); -} - -void cpu_set_apic_base(CPUState *env, uint64_t val) -{ - APICState *s = env->apic_state; -#ifdef DEBUG_APIC - printf("cpu_set_apic_base: %016" PRIx64 "\n", val); -#endif - s->apicbase = (val & 0xfffff000) | - (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); - /* if disabled, cannot be enabled again */ - if (!(val & MSR_IA32_APICBASE_ENABLE)) { - s->apicbase &= ~MSR_IA32_APICBASE_ENABLE; - env->cpuid_features &= ~CPUID_APIC; - s->spurious_vec &= ~APIC_SV_ENABLE; - } -} - -uint64_t cpu_get_apic_base(CPUState *env) -{ - APICState *s = env->apic_state; -#ifdef DEBUG_APIC - printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase); -#endif - return s->apicbase; -} - -void cpu_set_apic_tpr(CPUX86State *env, uint8_t val) -{ - APICState *s = env->apic_state; - s->tpr = (val & 0x0f) << 4; - apic_update_irq(s); -} - -uint8_t cpu_get_apic_tpr(CPUX86State *env) -{ - APICState *s = env->apic_state; - return s->tpr >> 4; -} - -/* return -1 if no bit is set */ -static int get_highest_priority_int(uint32_t *tab) -{ - int i; - for(i = 7; i >= 0; i--) { - if (tab[i] != 0) { - return i * 32 + fls_bit(tab[i]); - } - } - return -1; -} - -static int apic_get_ppr(APICState *s) -{ - int tpr, isrv, ppr; - - tpr = (s->tpr >> 4); - isrv = get_highest_priority_int(s->isr); - if (isrv < 0) - isrv = 0; - isrv >>= 4; - if (tpr >= isrv) - ppr = s->tpr; - else - ppr = isrv << 4; - return ppr; -} - -static int apic_get_arb_pri(APICState *s) -{ - /* XXX: arbitration */ - return 0; -} - -/* signal the CPU if an irq is pending */ -static void apic_update_irq(APICState *s) -{ - int irrv, ppr; - if (!(s->spurious_vec & APIC_SV_ENABLE)) - return; - irrv = get_highest_priority_int(s->irr); - if (irrv < 0) - return; - ppr = apic_get_ppr(s); - if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) - return; - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); -} - -static void apic_set_irq(APICState *s, int vector_num, int trigger_mode) -{ - set_bit(s->irr, vector_num); - if (trigger_mode) - set_bit(s->tmr, vector_num); - else - reset_bit(s->tmr, vector_num); - apic_update_irq(s); -} - -static void apic_eoi(APICState *s) -{ - int isrv; - isrv = get_highest_priority_int(s->isr); - if (isrv < 0) - return; - reset_bit(s->isr, isrv); - /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to - set the remote IRR bit for level triggered interrupts. */ - apic_update_irq(s); -} - -static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, - uint8_t dest, uint8_t dest_mode) -{ - APICState *apic_iter; - int i; - - if (dest_mode == 0) { - if (dest == 0xff) { - memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t)); - } else { - memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); - set_bit(deliver_bitmask, dest); - } - } else { - /* XXX: cluster mode */ - memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); - for(i = 0; i < MAX_APICS; i++) { - apic_iter = local_apics[i]; - if (apic_iter) { - if (apic_iter->dest_mode == 0xf) { - if (dest & apic_iter->log_dest) - set_bit(deliver_bitmask, i); - } else if (apic_iter->dest_mode == 0x0) { - if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) && - (dest & apic_iter->log_dest & 0x0f)) { - set_bit(deliver_bitmask, i); - } - } - } - } - } -} - - -static void apic_init_ipi(APICState *s) -{ - int i; - - for(i = 0; i < APIC_LVT_NB; i++) - s->lvt[i] = 1 << 16; /* mask LVT */ - s->tpr = 0; - s->spurious_vec = 0xff; - s->log_dest = 0; - s->dest_mode = 0xf; - memset(s->isr, 0, sizeof(s->isr)); - memset(s->tmr, 0, sizeof(s->tmr)); - memset(s->irr, 0, sizeof(s->irr)); - memset(s->lvt, 0, sizeof(s->lvt)); - s->esr = 0; - memset(s->icr, 0, sizeof(s->icr)); - s->divide_conf = 0; - s->count_shift = 0; - s->initial_count = 0; - s->initial_count_load_time = 0; - s->next_time = 0; -} - -/* send a SIPI message to the CPU to start it */ -static void apic_startup(APICState *s, int vector_num) -{ - CPUState *env = s->cpu_env; - if (!(env->hflags & HF_HALTED_MASK)) - return; - env->eip = 0; - cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, - 0xffff, 0); - env->hflags &= ~HF_HALTED_MASK; -} - -static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode, - uint8_t delivery_mode, uint8_t vector_num, - uint8_t polarity, uint8_t trigger_mode) -{ - uint32_t deliver_bitmask[MAX_APIC_WORDS]; - int dest_shorthand = (s->icr[0] >> 18) & 3; - APICState *apic_iter; - - switch (dest_shorthand) { - case 0: - apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); - break; - case 1: - memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask)); - set_bit(deliver_bitmask, s->id); - break; - case 2: - memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); - break; - case 3: - memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); - reset_bit(deliver_bitmask, s->id); - break; - } - - switch (delivery_mode) { - case APIC_DM_INIT: - { - int trig_mode = (s->icr[0] >> 15) & 1; - int level = (s->icr[0] >> 14) & 1; - if (level == 0 && trig_mode == 1) { - foreach_apic(apic_iter, deliver_bitmask, - apic_iter->arb_id = apic_iter->id ); - return; - } - } - break; - - case APIC_DM_SIPI: - foreach_apic(apic_iter, deliver_bitmask, - apic_startup(apic_iter, vector_num) ); - return; - } - - apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity, - trigger_mode); -} - -int apic_get_interrupt(CPUState *env) -{ - APICState *s = env->apic_state; - int intno; - - /* if the APIC is installed or enabled, we let the 8259 handle the - IRQs */ - if (!s) - return -1; - if (!(s->spurious_vec & APIC_SV_ENABLE)) - return -1; - - /* XXX: spurious IRQ handling */ - intno = get_highest_priority_int(s->irr); - if (intno < 0) - return -1; - reset_bit(s->irr, intno); - if (s->tpr && intno <= s->tpr) - return s->spurious_vec & 0xff; - set_bit(s->isr, intno); - apic_update_irq(s); - return intno; -} - -static uint32_t apic_get_current_count(APICState *s) -{ - int64_t d; - uint32_t val; - d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> - s->count_shift; - if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { - /* periodic */ - val = s->initial_count - (d % ((uint64_t)s->initial_count + 1)); - } else { - if (d >= s->initial_count) - val = 0; - else - val = s->initial_count - d; - } - return val; -} - -static void apic_timer_update(APICState *s, int64_t current_time) -{ - int64_t next_time, d; - - if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { - d = (current_time - s->initial_count_load_time) >> - s->count_shift; - if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { - d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1); - } else { - if (d >= s->initial_count) - goto no_timer; - d = (uint64_t)s->initial_count + 1; - } - next_time = s->initial_count_load_time + (d << s->count_shift); - qemu_mod_timer(s->timer, next_time); - s->next_time = next_time; - } else { - no_timer: - qemu_del_timer(s->timer); - } -} - -static void apic_timer(void *opaque) -{ - APICState *s = opaque; - - if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) { - apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE); - } - apic_timer_update(s, s->next_time); -} - -static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr) -{ - return 0; -} - -static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr) -{ - return 0; -} - -static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -} - -static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -} - -static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr) -{ - CPUState *env; - APICState *s; - uint32_t val; - int index; - - env = cpu_single_env; - if (!env) - return 0; - s = env->apic_state; - - index = (addr >> 4) & 0xff; - switch(index) { - case 0x02: /* id */ - val = s->id << 24; - break; - case 0x03: /* version */ - val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */ - break; - case 0x08: - val = s->tpr; - break; - case 0x09: - val = apic_get_arb_pri(s); - break; - case 0x0a: - /* ppr */ - val = apic_get_ppr(s); - break; - case 0x0d: - val = s->log_dest << 24; - break; - case 0x0e: - val = s->dest_mode << 28; - break; - case 0x0f: - val = s->spurious_vec; - break; - case 0x10 ... 0x17: - val = s->isr[index & 7]; - break; - case 0x18 ... 0x1f: - val = s->tmr[index & 7]; - break; - case 0x20 ... 0x27: - val = s->irr[index & 7]; - break; - case 0x28: - val = s->esr; - break; - case 0x30: - case 0x31: - val = s->icr[index & 1]; - break; - case 0x32 ... 0x37: - val = s->lvt[index - 0x32]; - break; - case 0x38: - val = s->initial_count; - break; - case 0x39: - val = apic_get_current_count(s); - break; - case 0x3e: - val = s->divide_conf; - break; - default: - s->esr |= ESR_ILLEGAL_ADDRESS; - val = 0; - break; - } -#ifdef DEBUG_APIC - printf("APIC read: %08x = %08x\n", (uint32_t)addr, val); -#endif - return val; -} - -static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - CPUState *env; - APICState *s; - int index; - - env = cpu_single_env; - if (!env) - return; - s = env->apic_state; - -#ifdef DEBUG_APIC - printf("APIC write: %08x = %08x\n", (uint32_t)addr, val); -#endif - - index = (addr >> 4) & 0xff; - switch(index) { - case 0x02: - s->id = (val >> 24); - break; - case 0x03: - break; - case 0x08: - s->tpr = val; - apic_update_irq(s); - break; - case 0x09: - case 0x0a: - break; - case 0x0b: /* EOI */ - apic_eoi(s); - break; - case 0x0d: - s->log_dest = val >> 24; - break; - case 0x0e: - s->dest_mode = val >> 28; - break; - case 0x0f: - s->spurious_vec = val & 0x1ff; - apic_update_irq(s); - break; - case 0x10 ... 0x17: - case 0x18 ... 0x1f: - case 0x20 ... 0x27: - case 0x28: - break; - case 0x30: - s->icr[0] = val; - apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1, - (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff), - (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1); - break; - case 0x31: - s->icr[1] = val; - break; - case 0x32 ... 0x37: - { - int n = index - 0x32; - s->lvt[n] = val; - if (n == APIC_LVT_TIMER) - apic_timer_update(s, qemu_get_clock(vm_clock)); - } - break; - case 0x38: - s->initial_count = val; - s->initial_count_load_time = qemu_get_clock(vm_clock); - apic_timer_update(s, s->initial_count_load_time); - break; - case 0x39: - break; - case 0x3e: - { - int v; - s->divide_conf = val & 0xb; - v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); - s->count_shift = (v + 1) & 7; - } - break; - default: - s->esr |= ESR_ILLEGAL_ADDRESS; - break; - } -} - -static void apic_save(QEMUFile *f, void *opaque) -{ - APICState *s = opaque; - int i; - - qemu_put_be32s(f, &s->apicbase); - qemu_put_8s(f, &s->id); - qemu_put_8s(f, &s->arb_id); - qemu_put_8s(f, &s->tpr); - qemu_put_be32s(f, &s->spurious_vec); - qemu_put_8s(f, &s->log_dest); - qemu_put_8s(f, &s->dest_mode); - for (i = 0; i < 8; i++) { - qemu_put_be32s(f, &s->isr[i]); - qemu_put_be32s(f, &s->tmr[i]); - qemu_put_be32s(f, &s->irr[i]); - } - for (i = 0; i < APIC_LVT_NB; i++) { - qemu_put_be32s(f, &s->lvt[i]); - } - qemu_put_be32s(f, &s->esr); - qemu_put_be32s(f, &s->icr[0]); - qemu_put_be32s(f, &s->icr[1]); - qemu_put_be32s(f, &s->divide_conf); - qemu_put_be32s(f, &s->count_shift); - qemu_put_be32s(f, &s->initial_count); - qemu_put_be64s(f, &s->initial_count_load_time); - qemu_put_be64s(f, &s->next_time); -} - -static int apic_load(QEMUFile *f, void *opaque, int version_id) -{ - APICState *s = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - /* XXX: what if the base changes? (registered memory regions) */ - qemu_get_be32s(f, &s->apicbase); - qemu_get_8s(f, &s->id); - qemu_get_8s(f, &s->arb_id); - qemu_get_8s(f, &s->tpr); - qemu_get_be32s(f, &s->spurious_vec); - qemu_get_8s(f, &s->log_dest); - qemu_get_8s(f, &s->dest_mode); - for (i = 0; i < 8; i++) { - qemu_get_be32s(f, &s->isr[i]); - qemu_get_be32s(f, &s->tmr[i]); - qemu_get_be32s(f, &s->irr[i]); - } - for (i = 0; i < APIC_LVT_NB; i++) { - qemu_get_be32s(f, &s->lvt[i]); - } - qemu_get_be32s(f, &s->esr); - qemu_get_be32s(f, &s->icr[0]); - qemu_get_be32s(f, &s->icr[1]); - qemu_get_be32s(f, &s->divide_conf); - qemu_get_be32s(f, &s->count_shift); - qemu_get_be32s(f, &s->initial_count); - qemu_get_be64s(f, &s->initial_count_load_time); - qemu_get_be64s(f, &s->next_time); - return 0; -} - -static void apic_reset(void *opaque) -{ - APICState *s = opaque; - apic_init_ipi(s); -} - -static CPUReadMemoryFunc *apic_mem_read[3] = { - apic_mem_readb, - apic_mem_readw, - apic_mem_readl, -}; - -static CPUWriteMemoryFunc *apic_mem_write[3] = { - apic_mem_writeb, - apic_mem_writew, - apic_mem_writel, -}; - -int apic_init(CPUState *env) -{ - APICState *s; - - if (last_apic_id >= MAX_APICS) - return -1; - s = qemu_mallocz(sizeof(APICState)); - if (!s) - return -1; - env->apic_state = s; - apic_init_ipi(s); - s->id = last_apic_id++; - s->cpu_env = env; - s->apicbase = 0xfee00000 | - (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE; - - /* XXX: mapping more APICs at the same memory location */ - if (apic_io_memory == 0) { - /* NOTE: the APIC is directly connected to the CPU - it is not - on the global memory bus. */ - apic_io_memory = cpu_register_io_memory(0, apic_mem_read, - apic_mem_write, NULL); - cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, - apic_io_memory); - } - s->timer = qemu_new_timer(vm_clock, apic_timer, s); - - register_savevm("apic", 0, 1, apic_save, apic_load, s); - qemu_register_reset(apic_reset, s); - - local_apics[s->id] = s; - return 0; -} - -static void ioapic_service(IOAPICState *s) -{ - uint8_t i; - uint8_t trig_mode; - uint8_t vector; - uint8_t delivery_mode; - uint32_t mask; - uint64_t entry; - uint8_t dest; - uint8_t dest_mode; - uint8_t polarity; - uint32_t deliver_bitmask[MAX_APIC_WORDS]; - - for (i = 0; i < IOAPIC_NUM_PINS; i++) { - mask = 1 << i; - if (s->irr & mask) { - entry = s->ioredtbl[i]; - if (!(entry & APIC_LVT_MASKED)) { - trig_mode = ((entry >> 15) & 1); - dest = entry >> 56; - dest_mode = (entry >> 11) & 1; - delivery_mode = (entry >> 8) & 7; - polarity = (entry >> 13) & 1; - if (trig_mode == APIC_TRIGGER_EDGE) - s->irr &= ~mask; - if (delivery_mode == APIC_DM_EXTINT) - vector = pic_read_irq(isa_pic); - else - vector = entry & 0xff; - - apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); - apic_bus_deliver(deliver_bitmask, delivery_mode, - vector, polarity, trig_mode); - } - } - } -} - -void ioapic_set_irq(void *opaque, int vector, int level) -{ - IOAPICState *s = opaque; - - if (vector >= 0 && vector < IOAPIC_NUM_PINS) { - uint32_t mask = 1 << vector; - uint64_t entry = s->ioredtbl[vector]; - - if ((entry >> 15) & 1) { - /* level triggered */ - if (level) { - s->irr |= mask; - ioapic_service(s); - } else { - s->irr &= ~mask; - } - } else { - /* edge triggered */ - if (level) { - s->irr |= mask; - ioapic_service(s); - } - } - } -} - -static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr) -{ - IOAPICState *s = opaque; - int index; - uint32_t val = 0; - - addr &= 0xff; - if (addr == 0x00) { - val = s->ioregsel; - } else if (addr == 0x10) { - switch (s->ioregsel) { - case 0x00: - val = s->id << 24; - break; - case 0x01: - val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */ - break; - case 0x02: - val = 0; - break; - default: - index = (s->ioregsel - 0x10) >> 1; - if (index >= 0 && index < IOAPIC_NUM_PINS) { - if (s->ioregsel & 1) - val = s->ioredtbl[index] >> 32; - else - val = s->ioredtbl[index] & 0xffffffff; - } - } -#ifdef DEBUG_IOAPIC - printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val); -#endif - } - return val; -} - -static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - IOAPICState *s = opaque; - int index; - - addr &= 0xff; - if (addr == 0x00) { - s->ioregsel = val; - return; - } else if (addr == 0x10) { -#ifdef DEBUG_IOAPIC - printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val); -#endif - switch (s->ioregsel) { - case 0x00: - s->id = (val >> 24) & 0xff; - return; - case 0x01: - case 0x02: - return; - default: - index = (s->ioregsel - 0x10) >> 1; - if (index >= 0 && index < IOAPIC_NUM_PINS) { - if (s->ioregsel & 1) { - s->ioredtbl[index] &= 0xffffffff; - s->ioredtbl[index] |= (uint64_t)val << 32; - } else { - s->ioredtbl[index] &= ~0xffffffffULL; - s->ioredtbl[index] |= val; - } - ioapic_service(s); - } - } - } -} - -static void ioapic_save(QEMUFile *f, void *opaque) -{ - IOAPICState *s = opaque; - int i; - - qemu_put_8s(f, &s->id); - qemu_put_8s(f, &s->ioregsel); - for (i = 0; i < IOAPIC_NUM_PINS; i++) { - qemu_put_be64s(f, &s->ioredtbl[i]); - } -} - -static int ioapic_load(QEMUFile *f, void *opaque, int version_id) -{ - IOAPICState *s = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - qemu_get_8s(f, &s->id); - qemu_get_8s(f, &s->ioregsel); - for (i = 0; i < IOAPIC_NUM_PINS; i++) { - qemu_get_be64s(f, &s->ioredtbl[i]); - } - return 0; -} - -static void ioapic_reset(void *opaque) -{ - IOAPICState *s = opaque; - int i; - - memset(s, 0, sizeof(*s)); - for(i = 0; i < IOAPIC_NUM_PINS; i++) - s->ioredtbl[i] = 1 << 16; /* mask LVT */ -} - -static CPUReadMemoryFunc *ioapic_mem_read[3] = { - ioapic_mem_readl, - ioapic_mem_readl, - ioapic_mem_readl, -}; - -static CPUWriteMemoryFunc *ioapic_mem_write[3] = { - ioapic_mem_writel, - ioapic_mem_writel, - ioapic_mem_writel, -}; - -IOAPICState *ioapic_init(void) -{ - IOAPICState *s; - int io_memory; - - s = qemu_mallocz(sizeof(IOAPICState)); - if (!s) - return NULL; - ioapic_reset(s); - s->id = last_apic_id++; - - io_memory = cpu_register_io_memory(0, ioapic_mem_read, - ioapic_mem_write, s); - cpu_register_physical_memory(0xfec00000, 0x1000, io_memory); - - register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s); - qemu_register_reset(ioapic_reset, s); - - return s; -} diff --git a/hw/arm_pic.c b/hw/arm_pic.c index fbc2d67..c228c04 100644 --- a/hw/arm_pic.c +++ b/hw/arm_pic.c @@ -11,11 +11,6 @@ #include "arm_pic.h" /* Stub functions for hardware that doesn't exist. */ -void pic_set_irq(int irq, int level) -{ - cpu_abort(cpu_single_env, "pic_set_irq"); -} - void pic_info(void) { } @@ -24,50 +19,30 @@ void irq_info(void) { } - -void pic_set_irq_new(void *opaque, int irq, int level) -{ - arm_pic_handler *p = (arm_pic_handler *)opaque; - /* Call the real handler. */ - (*p)(opaque, irq, level); -} - -/* Model the IRQ/FIQ CPU interrupt lines as a two input interrupt controller. - Input 0 is IRQ and input 1 is FIQ. */ -typedef struct -{ - arm_pic_handler handler; - CPUState *cpu_env; -} arm_pic_cpu_state; - +/* Input 0 is IRQ and input 1 is FIQ */ static void arm_pic_cpu_handler(void *opaque, int irq, int level) { - arm_pic_cpu_state *s = (arm_pic_cpu_state *)opaque; + CPUState *env = (CPUState *)opaque; switch (irq) { case ARM_PIC_CPU_IRQ: if (level) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + cpu_interrupt(env, CPU_INTERRUPT_HARD); else - cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); break; case ARM_PIC_CPU_FIQ: if (level) - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + cpu_interrupt(env, CPU_INTERRUPT_FIQ); else - cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ); + cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ); break; default: - cpu_abort(s->cpu_env, "arm_pic_cpu_handler: Bad interrput line %d\n", + cpu_abort(env, "arm_pic_cpu_handler: Bad interrput line %d\n", irq); } } -void *arm_pic_init_cpu(CPUState *env) +qemu_irq *arm_pic_init_cpu(CPUState *env) { - arm_pic_cpu_state *s; - - s = (arm_pic_cpu_state *)malloc(sizeof(arm_pic_cpu_state)); - s->handler = arm_pic_cpu_handler; - s->cpu_env = env; - return s; + return qemu_allocate_irqs(arm_pic_cpu_handler, env, 2); } diff --git a/hw/arm_pic.h b/hw/arm_pic.h index b299149..7886bcf 100644 --- a/hw/arm_pic.h +++ b/hw/arm_pic.h @@ -14,14 +14,12 @@ #ifndef ARM_INTERRUPT_H #define ARM_INTERRUPT_H 1 -/* The first element of an individual PIC state structures should - be a pointer to the handler routine. */ -typedef void (*arm_pic_handler)(void *opaque, int irq, int level); +#include "irq.h" /* The CPU is also modeled as an interrupt controller. */ #define ARM_PIC_CPU_IRQ 0 #define ARM_PIC_CPU_FIQ 1 -void *arm_pic_init_cpu(CPUState *env); +qemu_irq *arm_pic_init_cpu(CPUState *env); #endif /* !ARM_INTERRUPT_H */ diff --git a/hw/arm_timer.c b/hw/arm_timer.c deleted file mode 100644 index a97d73e..0000000 --- a/hw/arm_timer.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * ARM PrimeCell Timer modules. - * - * Copyright (c) 2005-2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the GPL. - */ - -#include "vl.h" -#include "arm_pic.h" - -/* Common timer implementation. */ - -#define TIMER_CTRL_ONESHOT (1 << 0) -#define TIMER_CTRL_32BIT (1 << 1) -#define TIMER_CTRL_DIV1 (0 << 2) -#define TIMER_CTRL_DIV16 (1 << 2) -#define TIMER_CTRL_DIV256 (2 << 2) -#define TIMER_CTRL_IE (1 << 5) -#define TIMER_CTRL_PERIODIC (1 << 6) -#define TIMER_CTRL_ENABLE (1 << 7) - -typedef struct { - int64_t next_time; - int64_t expires; - int64_t loaded; - QEMUTimer *timer; - uint32_t control; - uint32_t count; - uint32_t limit; - int raw_freq; - int freq; - int int_level; - void *pic; - int irq; -} arm_timer_state; - -/* Calculate the new expiry time of the given timer. */ - -static void arm_timer_reload(arm_timer_state *s) -{ - int64_t delay; - - s->loaded = s->expires; - delay = muldiv64(s->count, ticks_per_sec, s->freq); - if (delay == 0) - delay = 1; - s->expires += delay; -} - -/* Check all active timers, and schedule the next timer interrupt. */ - -static void arm_timer_update(arm_timer_state *s, int64_t now) -{ - int64_t next; - - /* Ignore disabled timers. */ - if ((s->control & TIMER_CTRL_ENABLE) == 0) - return; - /* Ignore expired one-shot timers. */ - if (s->count == 0 && (s->control & TIMER_CTRL_ONESHOT)) - return; - if (s->expires - now <= 0) { - /* Timer has expired. */ - s->int_level = 1; - if (s->control & TIMER_CTRL_ONESHOT) { - /* One-shot. */ - s->count = 0; - } else { - if ((s->control & TIMER_CTRL_PERIODIC) == 0) { - /* Free running. */ - if (s->control & TIMER_CTRL_32BIT) - s->count = 0xffffffff; - else - s->count = 0xffff; - } else { - /* Periodic. */ - s->count = s->limit; - } - } - } - while (s->expires - now <= 0) { - arm_timer_reload(s); - } - /* Update interrupts. */ - if (s->int_level && (s->control & TIMER_CTRL_IE)) { - pic_set_irq_new(s->pic, s->irq, 1); - } else { - pic_set_irq_new(s->pic, s->irq, 0); - } - - next = now; - if (next - s->expires < 0) - next = s->expires; - - /* Schedule the next timer interrupt. */ - if (next == now) { - qemu_del_timer(s->timer); - s->next_time = 0; - } else if (next != s->next_time) { - qemu_mod_timer(s->timer, next); - s->next_time = next; - } -} - -/* Return the current value of the timer. */ -static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now) -{ - int64_t elapsed; - int64_t period; - - if (s->count == 0) - return 0; - if ((s->control & TIMER_CTRL_ENABLE) == 0) - return s->count; - elapsed = now - s->loaded; - period = s->expires - s->loaded; - /* If the timer should have expired then return 0. This can happen - when the host timer signal doesnt occur immediately. It's better to - have a timer appear to sit at zero for a while than have it wrap - around before the guest interrupt is raised. */ - /* ??? Could we trigger the interrupt here? */ - if (elapsed > period) - return 0; - /* We need to calculate count * elapsed / period without overfowing. - Scale both elapsed and period so they fit in a 32-bit int. */ - while (period != (int32_t)period) { - period >>= 1; - elapsed >>= 1; - } - return ((uint64_t)s->count * (uint64_t)(int32_t)elapsed) - / (int32_t)period; -} - -uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset) -{ - arm_timer_state *s = (arm_timer_state *)opaque; - - switch (offset >> 2) { - case 0: /* TimerLoad */ - case 6: /* TimerBGLoad */ - return s->limit; - case 1: /* TimerValue */ - return arm_timer_getcount(s, qemu_get_clock(vm_clock)); - case 2: /* TimerControl */ - return s->control; - case 4: /* TimerRIS */ - return s->int_level; - case 5: /* TimerMIS */ - if ((s->control & TIMER_CTRL_IE) == 0) - return 0; - return s->int_level; - default: - cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", offset); - return 0; - } -} - -static void arm_timer_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - arm_timer_state *s = (arm_timer_state *)opaque; - int64_t now; - - now = qemu_get_clock(vm_clock); - switch (offset >> 2) { - case 0: /* TimerLoad */ - s->limit = value; - s->count = value; - s->expires = now; - arm_timer_reload(s); - break; - case 1: /* TimerValue */ - /* ??? Linux seems to want to write to this readonly register. - Ignore it. */ - break; - case 2: /* TimerControl */ - if (s->control & TIMER_CTRL_ENABLE) { - /* Pause the timer if it is running. This may cause some - inaccuracy dure to rounding, but avoids a whole lot of other - messyness. */ - s->count = arm_timer_getcount(s, now); - } - s->control = value; - s->freq = s->raw_freq; - /* ??? Need to recalculate expiry time after changing divisor. */ - switch ((value >> 2) & 3) { - case 1: s->freq >>= 4; break; - case 2: s->freq >>= 8; break; - } - if (s->control & TIMER_CTRL_ENABLE) { - /* Restart the timer if still enabled. */ - s->expires = now; - arm_timer_reload(s); - } - break; - case 3: /* TimerIntClr */ - s->int_level = 0; - break; - case 6: /* TimerBGLoad */ - s->limit = value; - break; - default: - cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", offset); - } - arm_timer_update(s, now); -} - -static void arm_timer_tick(void *opaque) -{ - int64_t now; - - now = qemu_get_clock(vm_clock); - arm_timer_update((arm_timer_state *)opaque, now); -} - -static void *arm_timer_init(uint32_t freq, void *pic, int irq) -{ - arm_timer_state *s; - - s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state)); - s->pic = pic; - s->irq = irq; - s->raw_freq = s->freq = 1000000; - s->control = TIMER_CTRL_IE; - s->count = 0xffffffff; - - s->timer = qemu_new_timer(vm_clock, arm_timer_tick, s); - /* ??? Save/restore. */ - return s; -} - -/* ARM PrimeCell SP804 dual timer module. - Docs for this device don't seem to be publicly available. This - implementation is based on gueswork, the linux kernel sources and the - Integrator/CP timer modules. */ - -typedef struct { - /* Include a pseudo-PIC device to merge the two interrupt sources. */ - arm_pic_handler handler; - void *timer[2]; - int level[2]; - uint32_t base; - /* The output PIC device. */ - void *pic; - int irq; -} sp804_state; - -static void sp804_set_irq(void *opaque, int irq, int level) -{ - sp804_state *s = (sp804_state *)opaque; - - s->level[irq] = level; - pic_set_irq_new(s->pic, s->irq, s->level[0] || s->level[1]); -} - -static uint32_t sp804_read(void *opaque, target_phys_addr_t offset) -{ - sp804_state *s = (sp804_state *)opaque; - - /* ??? Don't know the PrimeCell ID for this device. */ - offset -= s->base; - if (offset < 0x20) { - return arm_timer_read(s->timer[0], offset); - } else { - return arm_timer_read(s->timer[1], offset - 0x20); - } -} - -static void sp804_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - sp804_state *s = (sp804_state *)opaque; - - offset -= s->base; - if (offset < 0x20) { - arm_timer_write(s->timer[0], offset, value); - } else { - arm_timer_write(s->timer[1], offset - 0x20, value); - } -} - -static CPUReadMemoryFunc *sp804_readfn[] = { - sp804_read, - sp804_read, - sp804_read -}; - -static CPUWriteMemoryFunc *sp804_writefn[] = { - sp804_write, - sp804_write, - sp804_write -}; - -void sp804_init(uint32_t base, void *pic, int irq) -{ - int iomemtype; - sp804_state *s; - - s = (sp804_state *)qemu_mallocz(sizeof(sp804_state)); - s->handler = sp804_set_irq; - s->base = base; - s->pic = pic; - s->irq = irq; - /* ??? The timers are actually configurable between 32kHz and 1MHz, but - we don't implement that. */ - s->timer[0] = arm_timer_init(1000000, s, 0); - s->timer[1] = arm_timer_init(1000000, s, 1); - iomemtype = cpu_register_io_memory(0, sp804_readfn, - sp804_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - /* ??? Save/restore. */ -} - - -/* Integrator/CP timer module. */ - -typedef struct { - void *timer[3]; - uint32_t base; -} icp_pit_state; - -static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset) -{ - icp_pit_state *s = (icp_pit_state *)opaque; - int n; - - /* ??? Don't know the PrimeCell ID for this device. */ - offset -= s->base; - n = offset >> 8; - if (n > 3) - cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n); - - return arm_timer_read(s->timer[n], offset & 0xff); -} - -static void icp_pit_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - icp_pit_state *s = (icp_pit_state *)opaque; - int n; - - offset -= s->base; - n = offset >> 8; - if (n > 3) - cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n); - - arm_timer_write(s->timer[n], offset & 0xff, value); -} - - -static CPUReadMemoryFunc *icp_pit_readfn[] = { - icp_pit_read, - icp_pit_read, - icp_pit_read -}; - -static CPUWriteMemoryFunc *icp_pit_writefn[] = { - icp_pit_write, - icp_pit_write, - icp_pit_write -}; - -void icp_pit_init(uint32_t base, void *pic, int irq) -{ - int iomemtype; - icp_pit_state *s; - - s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state)); - s->base = base; - /* Timer 0 runs at the system clock speed (40MHz). */ - s->timer[0] = arm_timer_init(40000000, pic, irq); - /* The other two timers run at 1MHz. */ - s->timer[1] = arm_timer_init(1000000, pic, irq + 1); - s->timer[2] = arm_timer_init(1000000, pic, irq + 2); - - iomemtype = cpu_register_io_memory(0, icp_pit_readfn, - icp_pit_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - /* ??? Save/restore. */ -} - diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c deleted file mode 100644 index d186d79..0000000 --- a/hw/cirrus_vga.c +++ /dev/null @@ -1,3193 +0,0 @@ -/* - * QEMU Cirrus CLGD 54xx VGA Emulator. - * - * Copyright (c) 2004 Fabrice Bellard - * Copyright (c) 2004 Makoto Suzuki (suzu) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -/* - * Reference: Finn Thogersons' VGADOC4b - * available at http://home.worldonline.dk/~finth/ - */ -#include "vl.h" -#include "vga_int.h" - -/* - * TODO: - * - destination write mask support not complete (bits 5..7) - * - optimize linear mappings - * - optimize bitblt functions - */ - -//#define DEBUG_CIRRUS -//#define DEBUG_BITBLT - -/*************************************** - * - * definitions - * - ***************************************/ - -#define qemu_MIN(a,b) ((a) < (b) ? (a) : (b)) - -// ID -#define CIRRUS_ID_CLGD5422 (0x23<<2) -#define CIRRUS_ID_CLGD5426 (0x24<<2) -#define CIRRUS_ID_CLGD5424 (0x25<<2) -#define CIRRUS_ID_CLGD5428 (0x26<<2) -#define CIRRUS_ID_CLGD5430 (0x28<<2) -#define CIRRUS_ID_CLGD5434 (0x2A<<2) -#define CIRRUS_ID_CLGD5436 (0x2B<<2) -#define CIRRUS_ID_CLGD5446 (0x2E<<2) - -// sequencer 0x07 -#define CIRRUS_SR7_BPP_VGA 0x00 -#define CIRRUS_SR7_BPP_SVGA 0x01 -#define CIRRUS_SR7_BPP_MASK 0x0e -#define CIRRUS_SR7_BPP_8 0x00 -#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02 -#define CIRRUS_SR7_BPP_24 0x04 -#define CIRRUS_SR7_BPP_16 0x06 -#define CIRRUS_SR7_BPP_32 0x08 -#define CIRRUS_SR7_ISAADDR_MASK 0xe0 - -// sequencer 0x0f -#define CIRRUS_MEMSIZE_512k 0x08 -#define CIRRUS_MEMSIZE_1M 0x10 -#define CIRRUS_MEMSIZE_2M 0x18 -#define CIRRUS_MEMFLAGS_BANKSWITCH 0x80 // bank switching is enabled. - -// sequencer 0x12 -#define CIRRUS_CURSOR_SHOW 0x01 -#define CIRRUS_CURSOR_HIDDENPEL 0x02 -#define CIRRUS_CURSOR_LARGE 0x04 // 64x64 if set, 32x32 if clear - -// sequencer 0x17 -#define CIRRUS_BUSTYPE_VLBFAST 0x10 -#define CIRRUS_BUSTYPE_PCI 0x20 -#define CIRRUS_BUSTYPE_VLBSLOW 0x30 -#define CIRRUS_BUSTYPE_ISA 0x38 -#define CIRRUS_MMIO_ENABLE 0x04 -#define CIRRUS_MMIO_USE_PCIADDR 0x40 // 0xb8000 if cleared. -#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80 - -// control 0x0b -#define CIRRUS_BANKING_DUAL 0x01 -#define CIRRUS_BANKING_GRANULARITY_16K 0x20 // set:16k, clear:4k - -// control 0x30 -#define CIRRUS_BLTMODE_BACKWARDS 0x01 -#define CIRRUS_BLTMODE_MEMSYSDEST 0x02 -#define CIRRUS_BLTMODE_MEMSYSSRC 0x04 -#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08 -#define CIRRUS_BLTMODE_PATTERNCOPY 0x40 -#define CIRRUS_BLTMODE_COLOREXPAND 0x80 -#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30 -#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00 -#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10 -#define CIRRUS_BLTMODE_PIXELWIDTH24 0x20 -#define CIRRUS_BLTMODE_PIXELWIDTH32 0x30 - -// control 0x31 -#define CIRRUS_BLT_BUSY 0x01 -#define CIRRUS_BLT_START 0x02 -#define CIRRUS_BLT_RESET 0x04 -#define CIRRUS_BLT_FIFOUSED 0x10 -#define CIRRUS_BLT_AUTOSTART 0x80 - -// control 0x32 -#define CIRRUS_ROP_0 0x00 -#define CIRRUS_ROP_SRC_AND_DST 0x05 -#define CIRRUS_ROP_NOP 0x06 -#define CIRRUS_ROP_SRC_AND_NOTDST 0x09 -#define CIRRUS_ROP_NOTDST 0x0b -#define CIRRUS_ROP_SRC 0x0d -#define CIRRUS_ROP_1 0x0e -#define CIRRUS_ROP_NOTSRC_AND_DST 0x50 -#define CIRRUS_ROP_SRC_XOR_DST 0x59 -#define CIRRUS_ROP_SRC_OR_DST 0x6d -#define CIRRUS_ROP_NOTSRC_OR_NOTDST 0x90 -#define CIRRUS_ROP_SRC_NOTXOR_DST 0x95 -#define CIRRUS_ROP_SRC_OR_NOTDST 0xad -#define CIRRUS_ROP_NOTSRC 0xd0 -#define CIRRUS_ROP_NOTSRC_OR_DST 0xd6 -#define CIRRUS_ROP_NOTSRC_AND_NOTDST 0xda - -#define CIRRUS_ROP_NOP_INDEX 2 -#define CIRRUS_ROP_SRC_INDEX 5 - -// control 0x33 -#define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 -#define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02 -#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 - -// memory-mapped IO -#define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword -#define CIRRUS_MMIO_BLTFGCOLOR 0x04 // dword -#define CIRRUS_MMIO_BLTWIDTH 0x08 // word -#define CIRRUS_MMIO_BLTHEIGHT 0x0a // word -#define CIRRUS_MMIO_BLTDESTPITCH 0x0c // word -#define CIRRUS_MMIO_BLTSRCPITCH 0x0e // word -#define CIRRUS_MMIO_BLTDESTADDR 0x10 // dword -#define CIRRUS_MMIO_BLTSRCADDR 0x14 // dword -#define CIRRUS_MMIO_BLTWRITEMASK 0x17 // byte -#define CIRRUS_MMIO_BLTMODE 0x18 // byte -#define CIRRUS_MMIO_BLTROP 0x1a // byte -#define CIRRUS_MMIO_BLTMODEEXT 0x1b // byte -#define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c // word? -#define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20 // word? -#define CIRRUS_MMIO_LINEARDRAW_START_X 0x24 // word -#define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26 // word -#define CIRRUS_MMIO_LINEARDRAW_END_X 0x28 // word -#define CIRRUS_MMIO_LINEARDRAW_END_Y 0x2a // word -#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c // byte -#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d // byte -#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e // byte -#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f // byte -#define CIRRUS_MMIO_BRESENHAM_K1 0x30 // word -#define CIRRUS_MMIO_BRESENHAM_K3 0x32 // word -#define CIRRUS_MMIO_BRESENHAM_ERROR 0x34 // word -#define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36 // word -#define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38 // byte -#define CIRRUS_MMIO_LINEDRAW_MODE 0x39 // byte -#define CIRRUS_MMIO_BLTSTATUS 0x40 // byte - -// PCI 0x00: vendor, 0x02: device -#define PCI_VENDOR_CIRRUS 0x1013 -#define PCI_DEVICE_CLGD5462 0x00d0 -#define PCI_DEVICE_CLGD5465 0x00d6 - -// PCI 0x04: command(word), 0x06(word): status -#define PCI_COMMAND_IOACCESS 0x0001 -#define PCI_COMMAND_MEMACCESS 0x0002 -#define PCI_COMMAND_BUSMASTER 0x0004 -#define PCI_COMMAND_SPECIALCYCLE 0x0008 -#define PCI_COMMAND_MEMWRITEINVALID 0x0010 -#define PCI_COMMAND_PALETTESNOOPING 0x0020 -#define PCI_COMMAND_PARITYDETECTION 0x0040 -#define PCI_COMMAND_ADDRESSDATASTEPPING 0x0080 -#define PCI_COMMAND_SERR 0x0100 -#define PCI_COMMAND_BACKTOBACKTRANS 0x0200 -// PCI 0x08, 0xff000000 (0x09-0x0b:class,0x08:rev) -#define PCI_CLASS_BASE_DISPLAY 0x03 -// PCI 0x08, 0x00ff0000 -#define PCI_CLASS_SUB_VGA 0x00 -// PCI 0x0c, 0x00ff0000 (0x0c:cacheline,0x0d:latency,0x0e:headertype,0x0f:Built-in self test) -#define PCI_CLASS_HEADERTYPE_00h 0x00 -// 0x10-0x3f (headertype 00h) -// PCI 0x10,0x14,0x18,0x1c,0x20,0x24: base address mapping registers -// 0x10: MEMBASE, 0x14: IOBASE(hard-coded in XFree86 3.x) -#define PCI_MAP_MEM 0x0 -#define PCI_MAP_IO 0x1 -#define PCI_MAP_MEM_ADDR_MASK (~0xf) -#define PCI_MAP_IO_ADDR_MASK (~0x3) -#define PCI_MAP_MEMFLAGS_32BIT 0x0 -#define PCI_MAP_MEMFLAGS_32BIT_1M 0x1 -#define PCI_MAP_MEMFLAGS_64BIT 0x4 -#define PCI_MAP_MEMFLAGS_CACHEABLE 0x8 -// PCI 0x28: cardbus CIS pointer -// PCI 0x2c: subsystem vendor id, 0x2e: subsystem id -// PCI 0x30: expansion ROM base address -#define PCI_ROMBIOS_ENABLED 0x1 -// PCI 0x34: 0xffffff00=reserved, 0x000000ff=capabilities pointer -// PCI 0x38: reserved -// PCI 0x3c: 0x3c=int-line, 0x3d=int-pin, 0x3e=min-gnt, 0x3f=maax-lat - -#define CIRRUS_PNPMMIO_SIZE 0x1000 - - -/* I/O and memory hook */ -#define CIRRUS_HOOK_NOT_HANDLED 0 -#define CIRRUS_HOOK_HANDLED 1 - -struct CirrusVGAState; -typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s, - uint8_t * dst, const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight); -typedef void (*cirrus_fill_t)(struct CirrusVGAState *s, - uint8_t *dst, int dst_pitch, int width, int height); - -typedef struct CirrusVGAState { - VGA_STATE_COMMON - - int cirrus_linear_io_addr; - int cirrus_linear_bitblt_io_addr; - int cirrus_mmio_io_addr; - uint32_t cirrus_addr_mask; - uint32_t linear_mmio_mask; - uint8_t cirrus_shadow_gr0; - uint8_t cirrus_shadow_gr1; - uint8_t cirrus_hidden_dac_lockindex; - uint8_t cirrus_hidden_dac_data; - uint32_t cirrus_bank_base[2]; - uint32_t cirrus_bank_limit[2]; - uint8_t cirrus_hidden_palette[48]; - uint32_t hw_cursor_x; - uint32_t hw_cursor_y; - int cirrus_blt_pixelwidth; - int cirrus_blt_width; - int cirrus_blt_height; - int cirrus_blt_dstpitch; - int cirrus_blt_srcpitch; - uint32_t cirrus_blt_fgcol; - uint32_t cirrus_blt_bgcol; - uint32_t cirrus_blt_dstaddr; - uint32_t cirrus_blt_srcaddr; - uint8_t cirrus_blt_mode; - uint8_t cirrus_blt_modeext; - cirrus_bitblt_rop_t cirrus_rop; -#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */ - uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE]; - uint8_t *cirrus_srcptr; - uint8_t *cirrus_srcptr_end; - uint32_t cirrus_srccounter; - /* hwcursor display state */ - int last_hw_cursor_size; - int last_hw_cursor_x; - int last_hw_cursor_y; - int last_hw_cursor_y_start; - int last_hw_cursor_y_end; - int real_vram_size; /* XXX: suppress that */ - CPUWriteMemoryFunc **cirrus_linear_write; -} CirrusVGAState; - -typedef struct PCICirrusVGAState { - PCIDevice dev; - CirrusVGAState cirrus_vga; -} PCICirrusVGAState; - -static uint8_t rop_to_index[256]; - -/*************************************** - * - * prototypes. - * - ***************************************/ - - -static void cirrus_bitblt_reset(CirrusVGAState *s); -static void cirrus_update_memory_access(CirrusVGAState *s); - -/*************************************** - * - * raster operations - * - ***************************************/ - -static void cirrus_bitblt_rop_nop(CirrusVGAState *s, - uint8_t *dst,const uint8_t *src, - int dstpitch,int srcpitch, - int bltwidth,int bltheight) -{ -} - -static void cirrus_bitblt_fill_nop(CirrusVGAState *s, - uint8_t *dst, - int dstpitch, int bltwidth,int bltheight) -{ -} - -#define ROP_NAME 0 -#define ROP_OP(d, s) d = 0 -#include "cirrus_vga_rop.h" - -#define ROP_NAME src_and_dst -#define ROP_OP(d, s) d = (s) & (d) -#include "cirrus_vga_rop.h" - -#define ROP_NAME src_and_notdst -#define ROP_OP(d, s) d = (s) & (~(d)) -#include "cirrus_vga_rop.h" - -#define ROP_NAME notdst -#define ROP_OP(d, s) d = ~(d) -#include "cirrus_vga_rop.h" - -#define ROP_NAME src -#define ROP_OP(d, s) d = s -#include "cirrus_vga_rop.h" - -#define ROP_NAME 1 -#define ROP_OP(d, s) d = ~0 -#include "cirrus_vga_rop.h" - -#define ROP_NAME notsrc_and_dst -#define ROP_OP(d, s) d = (~(s)) & (d) -#include "cirrus_vga_rop.h" - -#define ROP_NAME src_xor_dst -#define ROP_OP(d, s) d = (s) ^ (d) -#include "cirrus_vga_rop.h" - -#define ROP_NAME src_or_dst -#define ROP_OP(d, s) d = (s) | (d) -#include "cirrus_vga_rop.h" - -#define ROP_NAME notsrc_or_notdst -#define ROP_OP(d, s) d = (~(s)) | (~(d)) -#include "cirrus_vga_rop.h" - -#define ROP_NAME src_notxor_dst -#define ROP_OP(d, s) d = ~((s) ^ (d)) -#include "cirrus_vga_rop.h" - -#define ROP_NAME src_or_notdst -#define ROP_OP(d, s) d = (s) | (~(d)) -#include "cirrus_vga_rop.h" - -#define ROP_NAME notsrc -#define ROP_OP(d, s) d = (~(s)) -#include "cirrus_vga_rop.h" - -#define ROP_NAME notsrc_or_dst -#define ROP_OP(d, s) d = (~(s)) | (d) -#include "cirrus_vga_rop.h" - -#define ROP_NAME notsrc_and_notdst -#define ROP_OP(d, s) d = (~(s)) & (~(d)) -#include "cirrus_vga_rop.h" - -static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = { - cirrus_bitblt_rop_fwd_0, - cirrus_bitblt_rop_fwd_src_and_dst, - cirrus_bitblt_rop_nop, - cirrus_bitblt_rop_fwd_src_and_notdst, - cirrus_bitblt_rop_fwd_notdst, - cirrus_bitblt_rop_fwd_src, - cirrus_bitblt_rop_fwd_1, - cirrus_bitblt_rop_fwd_notsrc_and_dst, - cirrus_bitblt_rop_fwd_src_xor_dst, - cirrus_bitblt_rop_fwd_src_or_dst, - cirrus_bitblt_rop_fwd_notsrc_or_notdst, - cirrus_bitblt_rop_fwd_src_notxor_dst, - cirrus_bitblt_rop_fwd_src_or_notdst, - cirrus_bitblt_rop_fwd_notsrc, - cirrus_bitblt_rop_fwd_notsrc_or_dst, - cirrus_bitblt_rop_fwd_notsrc_and_notdst, -}; - -static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = { - cirrus_bitblt_rop_bkwd_0, - cirrus_bitblt_rop_bkwd_src_and_dst, - cirrus_bitblt_rop_nop, - cirrus_bitblt_rop_bkwd_src_and_notdst, - cirrus_bitblt_rop_bkwd_notdst, - cirrus_bitblt_rop_bkwd_src, - cirrus_bitblt_rop_bkwd_1, - cirrus_bitblt_rop_bkwd_notsrc_and_dst, - cirrus_bitblt_rop_bkwd_src_xor_dst, - cirrus_bitblt_rop_bkwd_src_or_dst, - cirrus_bitblt_rop_bkwd_notsrc_or_notdst, - cirrus_bitblt_rop_bkwd_src_notxor_dst, - cirrus_bitblt_rop_bkwd_src_or_notdst, - cirrus_bitblt_rop_bkwd_notsrc, - cirrus_bitblt_rop_bkwd_notsrc_or_dst, - cirrus_bitblt_rop_bkwd_notsrc_and_notdst, -}; - -#define ROP2(name) {\ - name ## _8,\ - name ## _16,\ - name ## _24,\ - name ## _32,\ - } - -#define ROP_NOP2(func) {\ - func,\ - func,\ - func,\ - func,\ - } - -static const cirrus_bitblt_rop_t cirrus_patternfill[16][4] = { - ROP2(cirrus_patternfill_0), - ROP2(cirrus_patternfill_src_and_dst), - ROP_NOP2(cirrus_bitblt_rop_nop), - ROP2(cirrus_patternfill_src_and_notdst), - ROP2(cirrus_patternfill_notdst), - ROP2(cirrus_patternfill_src), - ROP2(cirrus_patternfill_1), - ROP2(cirrus_patternfill_notsrc_and_dst), - ROP2(cirrus_patternfill_src_xor_dst), - ROP2(cirrus_patternfill_src_or_dst), - ROP2(cirrus_patternfill_notsrc_or_notdst), - ROP2(cirrus_patternfill_src_notxor_dst), - ROP2(cirrus_patternfill_src_or_notdst), - ROP2(cirrus_patternfill_notsrc), - ROP2(cirrus_patternfill_notsrc_or_dst), - ROP2(cirrus_patternfill_notsrc_and_notdst), -}; - -static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = { - ROP2(cirrus_colorexpand_transp_0), - ROP2(cirrus_colorexpand_transp_src_and_dst), - ROP_NOP2(cirrus_bitblt_rop_nop), - ROP2(cirrus_colorexpand_transp_src_and_notdst), - ROP2(cirrus_colorexpand_transp_notdst), - ROP2(cirrus_colorexpand_transp_src), - ROP2(cirrus_colorexpand_transp_1), - ROP2(cirrus_colorexpand_transp_notsrc_and_dst), - ROP2(cirrus_colorexpand_transp_src_xor_dst), - ROP2(cirrus_colorexpand_transp_src_or_dst), - ROP2(cirrus_colorexpand_transp_notsrc_or_notdst), - ROP2(cirrus_colorexpand_transp_src_notxor_dst), - ROP2(cirrus_colorexpand_transp_src_or_notdst), - ROP2(cirrus_colorexpand_transp_notsrc), - ROP2(cirrus_colorexpand_transp_notsrc_or_dst), - ROP2(cirrus_colorexpand_transp_notsrc_and_notdst), -}; - -static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = { - ROP2(cirrus_colorexpand_0), - ROP2(cirrus_colorexpand_src_and_dst), - ROP_NOP2(cirrus_bitblt_rop_nop), - ROP2(cirrus_colorexpand_src_and_notdst), - ROP2(cirrus_colorexpand_notdst), - ROP2(cirrus_colorexpand_src), - ROP2(cirrus_colorexpand_1), - ROP2(cirrus_colorexpand_notsrc_and_dst), - ROP2(cirrus_colorexpand_src_xor_dst), - ROP2(cirrus_colorexpand_src_or_dst), - ROP2(cirrus_colorexpand_notsrc_or_notdst), - ROP2(cirrus_colorexpand_src_notxor_dst), - ROP2(cirrus_colorexpand_src_or_notdst), - ROP2(cirrus_colorexpand_notsrc), - ROP2(cirrus_colorexpand_notsrc_or_dst), - ROP2(cirrus_colorexpand_notsrc_and_notdst), -}; - -static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern_transp[16][4] = { - ROP2(cirrus_colorexpand_pattern_transp_0), - ROP2(cirrus_colorexpand_pattern_transp_src_and_dst), - ROP_NOP2(cirrus_bitblt_rop_nop), - ROP2(cirrus_colorexpand_pattern_transp_src_and_notdst), - ROP2(cirrus_colorexpand_pattern_transp_notdst), - ROP2(cirrus_colorexpand_pattern_transp_src), - ROP2(cirrus_colorexpand_pattern_transp_1), - ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_dst), - ROP2(cirrus_colorexpand_pattern_transp_src_xor_dst), - ROP2(cirrus_colorexpand_pattern_transp_src_or_dst), - ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_notdst), - ROP2(cirrus_colorexpand_pattern_transp_src_notxor_dst), - ROP2(cirrus_colorexpand_pattern_transp_src_or_notdst), - ROP2(cirrus_colorexpand_pattern_transp_notsrc), - ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_dst), - ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_notdst), -}; - -static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern[16][4] = { - ROP2(cirrus_colorexpand_pattern_0), - ROP2(cirrus_colorexpand_pattern_src_and_dst), - ROP_NOP2(cirrus_bitblt_rop_nop), - ROP2(cirrus_colorexpand_pattern_src_and_notdst), - ROP2(cirrus_colorexpand_pattern_notdst), - ROP2(cirrus_colorexpand_pattern_src), - ROP2(cirrus_colorexpand_pattern_1), - ROP2(cirrus_colorexpand_pattern_notsrc_and_dst), - ROP2(cirrus_colorexpand_pattern_src_xor_dst), - ROP2(cirrus_colorexpand_pattern_src_or_dst), - ROP2(cirrus_colorexpand_pattern_notsrc_or_notdst), - ROP2(cirrus_colorexpand_pattern_src_notxor_dst), - ROP2(cirrus_colorexpand_pattern_src_or_notdst), - ROP2(cirrus_colorexpand_pattern_notsrc), - ROP2(cirrus_colorexpand_pattern_notsrc_or_dst), - ROP2(cirrus_colorexpand_pattern_notsrc_and_notdst), -}; - -static const cirrus_fill_t cirrus_fill[16][4] = { - ROP2(cirrus_fill_0), - ROP2(cirrus_fill_src_and_dst), - ROP_NOP2(cirrus_bitblt_fill_nop), - ROP2(cirrus_fill_src_and_notdst), - ROP2(cirrus_fill_notdst), - ROP2(cirrus_fill_src), - ROP2(cirrus_fill_1), - ROP2(cirrus_fill_notsrc_and_dst), - ROP2(cirrus_fill_src_xor_dst), - ROP2(cirrus_fill_src_or_dst), - ROP2(cirrus_fill_notsrc_or_notdst), - ROP2(cirrus_fill_src_notxor_dst), - ROP2(cirrus_fill_src_or_notdst), - ROP2(cirrus_fill_notsrc), - ROP2(cirrus_fill_notsrc_or_dst), - ROP2(cirrus_fill_notsrc_and_notdst), -}; - -static inline void cirrus_bitblt_fgcol(CirrusVGAState *s) -{ - unsigned int color; - switch (s->cirrus_blt_pixelwidth) { - case 1: - s->cirrus_blt_fgcol = s->cirrus_shadow_gr1; - break; - case 2: - color = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8); - s->cirrus_blt_fgcol = le16_to_cpu(color); - break; - case 3: - s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 | - (s->gr[0x11] << 8) | (s->gr[0x13] << 16); - break; - default: - case 4: - color = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8) | - (s->gr[0x13] << 16) | (s->gr[0x15] << 24); - s->cirrus_blt_fgcol = le32_to_cpu(color); - break; - } -} - -static inline void cirrus_bitblt_bgcol(CirrusVGAState *s) -{ - unsigned int color; - switch (s->cirrus_blt_pixelwidth) { - case 1: - s->cirrus_blt_bgcol = s->cirrus_shadow_gr0; - break; - case 2: - color = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8); - s->cirrus_blt_bgcol = le16_to_cpu(color); - break; - case 3: - s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 | - (s->gr[0x10] << 8) | (s->gr[0x12] << 16); - break; - default: - case 4: - color = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8) | - (s->gr[0x12] << 16) | (s->gr[0x14] << 24); - s->cirrus_blt_bgcol = le32_to_cpu(color); - break; - } -} - -static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin, - int off_pitch, int bytesperline, - int lines) -{ - int y; - int off_cur; - int off_cur_end; - - for (y = 0; y < lines; y++) { - off_cur = off_begin; - off_cur_end = off_cur + bytesperline; - off_cur &= TARGET_PAGE_MASK; - while (off_cur < off_cur_end) { - cpu_physical_memory_set_dirty(s->vram_offset + off_cur); - off_cur += TARGET_PAGE_SIZE; - } - off_begin += off_pitch; - } -} - -static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s, - const uint8_t * src) -{ - uint8_t *dst; - - dst = s->vram_ptr + s->cirrus_blt_dstaddr; - (*s->cirrus_rop) (s, dst, src, - s->cirrus_blt_dstpitch, 0, - s->cirrus_blt_width, s->cirrus_blt_height); - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); - return 1; -} - -/* fill */ - -static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop) -{ - cirrus_fill_t rop_func; - - rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); - cirrus_bitblt_reset(s); - return 1; -} - -/*************************************** - * - * bitblt (video-to-video) - * - ***************************************/ - -static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s) -{ - return cirrus_bitblt_common_patterncopy(s, - s->vram_ptr + - (s->cirrus_blt_srcaddr & ~7)); -} - -static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h) -{ - int sx, sy; - int dx, dy; - int width, height; - int depth; - int notify = 0; - - depth = s->get_bpp((VGAState *)s) / 8; - s->get_resolution((VGAState *)s, &width, &height); - - /* extra x, y */ - sx = (src % (width * depth)) / depth; - sy = (src / (width * depth)); - dx = (dst % (width *depth)) / depth; - dy = (dst / (width * depth)); - - /* normalize width */ - w /= depth; - - /* if we're doing a backward copy, we have to adjust - our x/y to be the upper left corner (instead of the lower - right corner) */ - if (s->cirrus_blt_dstpitch < 0) { - sx -= (s->cirrus_blt_width / depth) - 1; - dx -= (s->cirrus_blt_width / depth) - 1; - sy -= s->cirrus_blt_height - 1; - dy -= s->cirrus_blt_height - 1; - } - - /* are we in the visible portion of memory? */ - if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 && - (sx + w) <= width && (sy + h) <= height && - (dx + w) <= width && (dy + h) <= height) { - notify = 1; - } - - /* make to sure only copy if it's a plain copy ROP */ - if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src && - *s->cirrus_rop != cirrus_bitblt_rop_bkwd_src) - notify = 0; - - /* we have to flush all pending changes so that the copy - is generated at the appropriate moment in time */ - if (notify) - vga_hw_update(); - - (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, - s->vram_ptr + s->cirrus_blt_srcaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - - if (notify) - s->ds->dpy_copy(s->ds, - sx, sy, dx, dy, - s->cirrus_blt_width / depth, - s->cirrus_blt_height); - - /* we don't have to notify the display that this portion has - changed since dpy_copy implies this */ - - if (!notify) - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); -} - -static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s) -{ - if (s->ds->dpy_copy) { - cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr, - s->cirrus_blt_srcaddr - s->start_addr, - s->cirrus_blt_width, s->cirrus_blt_height); - } else { - (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr, - s->vram_ptr + s->cirrus_blt_srcaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch, - s->cirrus_blt_width, s->cirrus_blt_height); - - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, - s->cirrus_blt_dstpitch, s->cirrus_blt_width, - s->cirrus_blt_height); - } - - return 1; -} - -/*************************************** - * - * bitblt (cpu-to-video) - * - ***************************************/ - -static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s) -{ - int copy_count; - uint8_t *end_ptr; - - if (s->cirrus_srccounter > 0) { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { - cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf); - the_end: - s->cirrus_srccounter = 0; - cirrus_bitblt_reset(s); - } else { - /* at least one scan line */ - do { - (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr, - s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1); - cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0, - s->cirrus_blt_width, 1); - s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch; - s->cirrus_srccounter -= s->cirrus_blt_srcpitch; - if (s->cirrus_srccounter <= 0) - goto the_end; - /* more bytes than needed can be transfered because of - word alignment, so we keep them for the next line */ - /* XXX: keep alignment to speed up transfer */ - end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; - copy_count = s->cirrus_srcptr_end - end_ptr; - memmove(s->cirrus_bltbuf, end_ptr, copy_count); - s->cirrus_srcptr = s->cirrus_bltbuf + copy_count; - s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; - } while (s->cirrus_srcptr >= s->cirrus_srcptr_end); - } - } -} - -/*************************************** - * - * bitblt wrapper - * - ***************************************/ - -static void cirrus_bitblt_reset(CirrusVGAState * s) -{ - s->gr[0x31] &= - ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED); - s->cirrus_srcptr = &s->cirrus_bltbuf[0]; - s->cirrus_srcptr_end = &s->cirrus_bltbuf[0]; - s->cirrus_srccounter = 0; - cirrus_update_memory_access(s); -} - -static int cirrus_bitblt_cputovideo(CirrusVGAState * s) -{ - int w; - - s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC; - s->cirrus_srcptr = &s->cirrus_bltbuf[0]; - s->cirrus_srcptr_end = &s->cirrus_bltbuf[0]; - - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { - s->cirrus_blt_srcpitch = 8; - } else { - /* XXX: check for 24 bpp */ - s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth; - } - s->cirrus_srccounter = s->cirrus_blt_srcpitch; - } else { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { - w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth; - if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) - s->cirrus_blt_srcpitch = ((w + 31) >> 5); - else - s->cirrus_blt_srcpitch = ((w + 7) >> 3); - } else { - /* always align input size to 32 bits */ - s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3; - } - s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height; - } - s->cirrus_srcptr = s->cirrus_bltbuf; - s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch; - cirrus_update_memory_access(s); - return 1; -} - -static int cirrus_bitblt_videotocpu(CirrusVGAState * s) -{ - /* XXX */ -#ifdef DEBUG_BITBLT - printf("cirrus: bitblt (video to cpu) is not implemented yet\n"); -#endif - return 0; -} - -static int cirrus_bitblt_videotovideo(CirrusVGAState * s) -{ - int ret; - - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { - ret = cirrus_bitblt_videotovideo_patterncopy(s); - } else { - ret = cirrus_bitblt_videotovideo_copy(s); - } - if (ret) - cirrus_bitblt_reset(s); - return ret; -} - -static void cirrus_bitblt_start(CirrusVGAState * s) -{ - uint8_t blt_rop; - - s->gr[0x31] |= CIRRUS_BLT_BUSY; - - s->cirrus_blt_width = (s->gr[0x20] | (s->gr[0x21] << 8)) + 1; - s->cirrus_blt_height = (s->gr[0x22] | (s->gr[0x23] << 8)) + 1; - s->cirrus_blt_dstpitch = (s->gr[0x24] | (s->gr[0x25] << 8)); - s->cirrus_blt_srcpitch = (s->gr[0x26] | (s->gr[0x27] << 8)); - s->cirrus_blt_dstaddr = - (s->gr[0x28] | (s->gr[0x29] << 8) | (s->gr[0x2a] << 16)); - s->cirrus_blt_srcaddr = - (s->gr[0x2c] | (s->gr[0x2d] << 8) | (s->gr[0x2e] << 16)); - s->cirrus_blt_mode = s->gr[0x30]; - s->cirrus_blt_modeext = s->gr[0x33]; - blt_rop = s->gr[0x32]; - -#ifdef DEBUG_BITBLT - printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n", - blt_rop, - s->cirrus_blt_mode, - s->cirrus_blt_modeext, - s->cirrus_blt_width, - s->cirrus_blt_height, - s->cirrus_blt_dstpitch, - s->cirrus_blt_srcpitch, - s->cirrus_blt_dstaddr, - s->cirrus_blt_srcaddr, - s->gr[0x2f]); -#endif - - switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - s->cirrus_blt_pixelwidth = 1; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - s->cirrus_blt_pixelwidth = 2; - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - s->cirrus_blt_pixelwidth = 3; - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - s->cirrus_blt_pixelwidth = 4; - break; - default: -#ifdef DEBUG_BITBLT - printf("cirrus: bitblt - pixel width is unknown\n"); -#endif - goto bitblt_ignore; - } - s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK; - - if ((s-> - cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC | - CIRRUS_BLTMODE_MEMSYSDEST)) - == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) { -#ifdef DEBUG_BITBLT - printf("cirrus: bitblt - memory-to-memory copy is requested\n"); -#endif - goto bitblt_ignore; - } - - if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) && - (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST | - CIRRUS_BLTMODE_TRANSPARENTCOMP | - CIRRUS_BLTMODE_PATTERNCOPY | - CIRRUS_BLTMODE_COLOREXPAND)) == - (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) { - cirrus_bitblt_fgcol(s); - cirrus_bitblt_solidfill(s, blt_rop); - } else { - if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND | - CIRRUS_BLTMODE_PATTERNCOPY)) == - CIRRUS_BLTMODE_COLOREXPAND) { - - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { - if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) - cirrus_bitblt_bgcol(s); - else - cirrus_bitblt_fgcol(s); - s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - } else { - cirrus_bitblt_fgcol(s); - cirrus_bitblt_bgcol(s); - s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - } - } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { - if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) - cirrus_bitblt_bgcol(s); - else - cirrus_bitblt_fgcol(s); - s->cirrus_rop = cirrus_colorexpand_pattern_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - } else { - cirrus_bitblt_fgcol(s); - cirrus_bitblt_bgcol(s); - s->cirrus_rop = cirrus_colorexpand_pattern[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - } - } else { - s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1]; - } - } else { - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) { - s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch; - s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch; - s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]]; - } else { - s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]]; - } - } - - // setup bitblt engine. - if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) { - if (!cirrus_bitblt_cputovideo(s)) - goto bitblt_ignore; - } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) { - if (!cirrus_bitblt_videotocpu(s)) - goto bitblt_ignore; - } else { - if (!cirrus_bitblt_videotovideo(s)) - goto bitblt_ignore; - } - } - return; - bitblt_ignore:; - cirrus_bitblt_reset(s); -} - -static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value) -{ - unsigned old_value; - - old_value = s->gr[0x31]; - s->gr[0x31] = reg_value; - - if (((old_value & CIRRUS_BLT_RESET) != 0) && - ((reg_value & CIRRUS_BLT_RESET) == 0)) { - cirrus_bitblt_reset(s); - } else if (((old_value & CIRRUS_BLT_START) == 0) && - ((reg_value & CIRRUS_BLT_START) != 0)) { - cirrus_bitblt_start(s); - } -} - - -/*************************************** - * - * basic parameters - * - ***************************************/ - -static void cirrus_get_offsets(VGAState *s1, - uint32_t *pline_offset, - uint32_t *pstart_addr) -{ - CirrusVGAState * s = (CirrusVGAState *)s1; - uint32_t start_addr; - uint32_t line_offset; - - line_offset = s->cr[0x13] - | ((s->cr[0x1b] & 0x10) << 4); - line_offset <<= 3; - *pline_offset = line_offset; - - start_addr = (s->cr[0x0c] << 8) - | s->cr[0x0d] - | ((s->cr[0x1b] & 0x01) << 16) - | ((s->cr[0x1b] & 0x0c) << 15) - | ((s->cr[0x1d] & 0x80) << 12); - *pstart_addr = start_addr; -} - -static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s) -{ - uint32_t ret = 16; - - switch (s->cirrus_hidden_dac_data & 0xf) { - case 0: - ret = 15; - break; /* Sierra HiColor */ - case 1: - ret = 16; - break; /* XGA HiColor */ - default: -#ifdef DEBUG_CIRRUS - printf("cirrus: invalid DAC value %x in 16bpp\n", - (s->cirrus_hidden_dac_data & 0xf)); -#endif - ret = 15; /* XXX */ - break; - } - return ret; -} - -static int cirrus_get_bpp(VGAState *s1) -{ - CirrusVGAState * s = (CirrusVGAState *)s1; - uint32_t ret = 8; - - if ((s->sr[0x07] & 0x01) != 0) { - /* Cirrus SVGA */ - switch (s->sr[0x07] & CIRRUS_SR7_BPP_MASK) { - case CIRRUS_SR7_BPP_8: - ret = 8; - break; - case CIRRUS_SR7_BPP_16_DOUBLEVCLK: - ret = cirrus_get_bpp16_depth(s); - break; - case CIRRUS_SR7_BPP_24: - ret = 24; - break; - case CIRRUS_SR7_BPP_16: - ret = cirrus_get_bpp16_depth(s); - break; - case CIRRUS_SR7_BPP_32: - ret = 32; - break; - default: -#ifdef DEBUG_CIRRUS - printf("cirrus: unknown bpp - sr7=%x\n", s->sr[0x7]); -#endif - ret = 8; - break; - } - } else { - /* VGA */ - ret = 0; - } - - return ret; -} - -static void cirrus_get_resolution(VGAState *s, int *pwidth, int *pheight) -{ - int width, height; - - width = (s->cr[0x01] + 1) * 8; - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); - height = (height + 1); - /* interlace support */ - if (s->cr[0x1a] & 0x01) - height = height * 2; - *pwidth = width; - *pheight = height; -} - -/*************************************** - * - * bank memory - * - ***************************************/ - -static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index) -{ - unsigned offset; - unsigned limit; - - if ((s->gr[0x0b] & 0x01) != 0) /* dual bank */ - offset = s->gr[0x09 + bank_index]; - else /* single bank */ - offset = s->gr[0x09]; - - if ((s->gr[0x0b] & 0x20) != 0) - offset <<= 14; - else - offset <<= 12; - - if (s->real_vram_size <= offset) - limit = 0; - else - limit = s->real_vram_size - offset; - - if (((s->gr[0x0b] & 0x01) == 0) && (bank_index != 0)) { - if (limit > 0x8000) { - offset += 0x8000; - limit -= 0x8000; - } else { - limit = 0; - } - } - - if (limit > 0) { - s->cirrus_bank_base[bank_index] = offset; - s->cirrus_bank_limit[bank_index] = limit; - } else { - s->cirrus_bank_base[bank_index] = 0; - s->cirrus_bank_limit[bank_index] = 0; - } -} - -/*************************************** - * - * I/O access between 0x3c4-0x3c5 - * - ***************************************/ - -static int -cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value) -{ - switch (reg_index) { - case 0x00: // Standard VGA - case 0x01: // Standard VGA - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - return CIRRUS_HOOK_NOT_HANDLED; - case 0x06: // Unlock Cirrus extensions - *reg_value = s->sr[reg_index]; - break; - case 0x10: - case 0x30: - case 0x50: - case 0x70: // Graphics Cursor X - case 0x90: - case 0xb0: - case 0xd0: - case 0xf0: // Graphics Cursor X - *reg_value = s->sr[0x10]; - break; - case 0x11: - case 0x31: - case 0x51: - case 0x71: // Graphics Cursor Y - case 0x91: - case 0xb1: - case 0xd1: - case 0xf1: // Graphics Cursor Y - *reg_value = s->sr[0x11]; - break; - case 0x05: // ??? - case 0x07: // Extended Sequencer Mode - case 0x08: // EEPROM Control - case 0x09: // Scratch Register 0 - case 0x0a: // Scratch Register 1 - case 0x0b: // VCLK 0 - case 0x0c: // VCLK 1 - case 0x0d: // VCLK 2 - case 0x0e: // VCLK 3 - case 0x0f: // DRAM Control - case 0x12: // Graphics Cursor Attribute - case 0x13: // Graphics Cursor Pattern Address - case 0x14: // Scratch Register 2 - case 0x15: // Scratch Register 3 - case 0x16: // Performance Tuning Register - case 0x17: // Configuration Readback and Extended Control - case 0x18: // Signature Generator Control - case 0x19: // Signal Generator Result - case 0x1a: // Signal Generator Result - case 0x1b: // VCLK 0 Denominator & Post - case 0x1c: // VCLK 1 Denominator & Post - case 0x1d: // VCLK 2 Denominator & Post - case 0x1e: // VCLK 3 Denominator & Post - case 0x1f: // BIOS Write Enable and MCLK select -#ifdef DEBUG_CIRRUS - printf("cirrus: handled inport sr_index %02x\n", reg_index); -#endif - *reg_value = s->sr[reg_index]; - break; - default: -#ifdef DEBUG_CIRRUS - printf("cirrus: inport sr_index %02x\n", reg_index); -#endif - *reg_value = 0xff; - break; - } - - return CIRRUS_HOOK_HANDLED; -} - -static int -cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value) -{ - switch (reg_index) { - case 0x00: // Standard VGA - case 0x01: // Standard VGA - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - return CIRRUS_HOOK_NOT_HANDLED; - case 0x06: // Unlock Cirrus extensions - reg_value &= 0x17; - if (reg_value == 0x12) { - s->sr[reg_index] = 0x12; - } else { - s->sr[reg_index] = 0x0f; - } - break; - case 0x10: - case 0x30: - case 0x50: - case 0x70: // Graphics Cursor X - case 0x90: - case 0xb0: - case 0xd0: - case 0xf0: // Graphics Cursor X - s->sr[0x10] = reg_value; - s->hw_cursor_x = (reg_value << 3) | (reg_index >> 5); - break; - case 0x11: - case 0x31: - case 0x51: - case 0x71: // Graphics Cursor Y - case 0x91: - case 0xb1: - case 0xd1: - case 0xf1: // Graphics Cursor Y - s->sr[0x11] = reg_value; - s->hw_cursor_y = (reg_value << 3) | (reg_index >> 5); - break; - case 0x07: // Extended Sequencer Mode - case 0x08: // EEPROM Control - case 0x09: // Scratch Register 0 - case 0x0a: // Scratch Register 1 - case 0x0b: // VCLK 0 - case 0x0c: // VCLK 1 - case 0x0d: // VCLK 2 - case 0x0e: // VCLK 3 - case 0x0f: // DRAM Control - case 0x12: // Graphics Cursor Attribute - case 0x13: // Graphics Cursor Pattern Address - case 0x14: // Scratch Register 2 - case 0x15: // Scratch Register 3 - case 0x16: // Performance Tuning Register - case 0x18: // Signature Generator Control - case 0x19: // Signature Generator Result - case 0x1a: // Signature Generator Result - case 0x1b: // VCLK 0 Denominator & Post - case 0x1c: // VCLK 1 Denominator & Post - case 0x1d: // VCLK 2 Denominator & Post - case 0x1e: // VCLK 3 Denominator & Post - case 0x1f: // BIOS Write Enable and MCLK select - s->sr[reg_index] = reg_value; -#ifdef DEBUG_CIRRUS - printf("cirrus: handled outport sr_index %02x, sr_value %02x\n", - reg_index, reg_value); -#endif - break; - case 0x17: // Configuration Readback and Extended Control - s->sr[reg_index] = (s->sr[reg_index] & 0x38) | (reg_value & 0xc7); - cirrus_update_memory_access(s); - break; - default: -#ifdef DEBUG_CIRRUS - printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index, - reg_value); -#endif - break; - } - - return CIRRUS_HOOK_HANDLED; -} - -/*************************************** - * - * I/O access at 0x3c6 - * - ***************************************/ - -static void cirrus_read_hidden_dac(CirrusVGAState * s, int *reg_value) -{ - *reg_value = 0xff; - if (++s->cirrus_hidden_dac_lockindex == 5) { - *reg_value = s->cirrus_hidden_dac_data; - s->cirrus_hidden_dac_lockindex = 0; - } -} - -static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value) -{ - if (s->cirrus_hidden_dac_lockindex == 4) { - s->cirrus_hidden_dac_data = reg_value; -#if defined(DEBUG_CIRRUS) - printf("cirrus: outport hidden DAC, value %02x\n", reg_value); -#endif - } - s->cirrus_hidden_dac_lockindex = 0; -} - -/*************************************** - * - * I/O access at 0x3c9 - * - ***************************************/ - -static int cirrus_hook_read_palette(CirrusVGAState * s, int *reg_value) -{ - if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) - return CIRRUS_HOOK_NOT_HANDLED; - *reg_value = - s->cirrus_hidden_palette[(s->dac_read_index & 0x0f) * 3 + - s->dac_sub_index]; - if (++s->dac_sub_index == 3) { - s->dac_sub_index = 0; - s->dac_read_index++; - } - return CIRRUS_HOOK_HANDLED; -} - -static int cirrus_hook_write_palette(CirrusVGAState * s, int reg_value) -{ - if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL)) - return CIRRUS_HOOK_NOT_HANDLED; - s->dac_cache[s->dac_sub_index] = reg_value; - if (++s->dac_sub_index == 3) { - memcpy(&s->cirrus_hidden_palette[(s->dac_write_index & 0x0f) * 3], - s->dac_cache, 3); - /* XXX update cursor */ - s->dac_sub_index = 0; - s->dac_write_index++; - } - return CIRRUS_HOOK_HANDLED; -} - -/*************************************** - * - * I/O access between 0x3ce-0x3cf - * - ***************************************/ - -static int -cirrus_hook_read_gr(CirrusVGAState * s, unsigned reg_index, int *reg_value) -{ - switch (reg_index) { - case 0x00: // Standard VGA, BGCOLOR 0x000000ff - *reg_value = s->cirrus_shadow_gr0; - return CIRRUS_HOOK_HANDLED; - case 0x01: // Standard VGA, FGCOLOR 0x000000ff - *reg_value = s->cirrus_shadow_gr1; - return CIRRUS_HOOK_HANDLED; - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - case 0x06: // Standard VGA - case 0x07: // Standard VGA - case 0x08: // Standard VGA - return CIRRUS_HOOK_NOT_HANDLED; - case 0x05: // Standard VGA, Cirrus extended mode - default: - break; - } - - if (reg_index < 0x3a) { - *reg_value = s->gr[reg_index]; - } else { -#ifdef DEBUG_CIRRUS - printf("cirrus: inport gr_index %02x\n", reg_index); -#endif - *reg_value = 0xff; - } - - return CIRRUS_HOOK_HANDLED; -} - -static int -cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value) -{ -#if defined(DEBUG_BITBLT) && 0 - printf("gr%02x: %02x\n", reg_index, reg_value); -#endif - switch (reg_index) { - case 0x00: // Standard VGA, BGCOLOR 0x000000ff - s->cirrus_shadow_gr0 = reg_value; - return CIRRUS_HOOK_NOT_HANDLED; - case 0x01: // Standard VGA, FGCOLOR 0x000000ff - s->cirrus_shadow_gr1 = reg_value; - return CIRRUS_HOOK_NOT_HANDLED; - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - case 0x06: // Standard VGA - case 0x07: // Standard VGA - case 0x08: // Standard VGA - return CIRRUS_HOOK_NOT_HANDLED; - case 0x05: // Standard VGA, Cirrus extended mode - s->gr[reg_index] = reg_value & 0x7f; - cirrus_update_memory_access(s); - break; - case 0x09: // bank offset #0 - case 0x0A: // bank offset #1 - s->gr[reg_index] = reg_value; - cirrus_update_bank_ptr(s, 0); - cirrus_update_bank_ptr(s, 1); - break; - case 0x0B: - s->gr[reg_index] = reg_value; - cirrus_update_bank_ptr(s, 0); - cirrus_update_bank_ptr(s, 1); - cirrus_update_memory_access(s); - break; - case 0x10: // BGCOLOR 0x0000ff00 - case 0x11: // FGCOLOR 0x0000ff00 - case 0x12: // BGCOLOR 0x00ff0000 - case 0x13: // FGCOLOR 0x00ff0000 - case 0x14: // BGCOLOR 0xff000000 - case 0x15: // FGCOLOR 0xff000000 - case 0x20: // BLT WIDTH 0x0000ff - case 0x22: // BLT HEIGHT 0x0000ff - case 0x24: // BLT DEST PITCH 0x0000ff - case 0x26: // BLT SRC PITCH 0x0000ff - case 0x28: // BLT DEST ADDR 0x0000ff - case 0x29: // BLT DEST ADDR 0x00ff00 - case 0x2c: // BLT SRC ADDR 0x0000ff - case 0x2d: // BLT SRC ADDR 0x00ff00 - case 0x2f: // BLT WRITEMASK - case 0x30: // BLT MODE - case 0x32: // RASTER OP - case 0x33: // BLT MODEEXT - case 0x34: // BLT TRANSPARENT COLOR 0x00ff - case 0x35: // BLT TRANSPARENT COLOR 0xff00 - case 0x38: // BLT TRANSPARENT COLOR MASK 0x00ff - case 0x39: // BLT TRANSPARENT COLOR MASK 0xff00 - s->gr[reg_index] = reg_value; - break; - case 0x21: // BLT WIDTH 0x001f00 - case 0x23: // BLT HEIGHT 0x001f00 - case 0x25: // BLT DEST PITCH 0x001f00 - case 0x27: // BLT SRC PITCH 0x001f00 - s->gr[reg_index] = reg_value & 0x1f; - break; - case 0x2a: // BLT DEST ADDR 0x3f0000 - s->gr[reg_index] = reg_value & 0x3f; - /* if auto start mode, starts bit blt now */ - if (s->gr[0x31] & CIRRUS_BLT_AUTOSTART) { - cirrus_bitblt_start(s); - } - break; - case 0x2e: // BLT SRC ADDR 0x3f0000 - s->gr[reg_index] = reg_value & 0x3f; - break; - case 0x31: // BLT STATUS/START - cirrus_write_bitblt(s, reg_value); - break; - default: -#ifdef DEBUG_CIRRUS - printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index, - reg_value); -#endif - break; - } - - return CIRRUS_HOOK_HANDLED; -} - -/*************************************** - * - * I/O access between 0x3d4-0x3d5 - * - ***************************************/ - -static int -cirrus_hook_read_cr(CirrusVGAState * s, unsigned reg_index, int *reg_value) -{ - switch (reg_index) { - case 0x00: // Standard VGA - case 0x01: // Standard VGA - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - case 0x05: // Standard VGA - case 0x06: // Standard VGA - case 0x07: // Standard VGA - case 0x08: // Standard VGA - case 0x09: // Standard VGA - case 0x0a: // Standard VGA - case 0x0b: // Standard VGA - case 0x0c: // Standard VGA - case 0x0d: // Standard VGA - case 0x0e: // Standard VGA - case 0x0f: // Standard VGA - case 0x10: // Standard VGA - case 0x11: // Standard VGA - case 0x12: // Standard VGA - case 0x13: // Standard VGA - case 0x14: // Standard VGA - case 0x15: // Standard VGA - case 0x16: // Standard VGA - case 0x17: // Standard VGA - case 0x18: // Standard VGA - return CIRRUS_HOOK_NOT_HANDLED; - case 0x19: // Interlace End - case 0x1a: // Miscellaneous Control - case 0x1b: // Extended Display Control - case 0x1c: // Sync Adjust and Genlock - case 0x1d: // Overlay Extended Control - case 0x22: // Graphics Data Latches Readback (R) - case 0x24: // Attribute Controller Toggle Readback (R) - case 0x25: // Part Status - case 0x27: // Part ID (R) - *reg_value = s->cr[reg_index]; - break; - case 0x26: // Attribute Controller Index Readback (R) - *reg_value = s->ar_index & 0x3f; - break; - default: -#ifdef DEBUG_CIRRUS - printf("cirrus: inport cr_index %02x\n", reg_index); - *reg_value = 0xff; -#endif - break; - } - - return CIRRUS_HOOK_HANDLED; -} - -static int -cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value) -{ - switch (reg_index) { - case 0x00: // Standard VGA - case 0x01: // Standard VGA - case 0x02: // Standard VGA - case 0x03: // Standard VGA - case 0x04: // Standard VGA - case 0x05: // Standard VGA - case 0x06: // Standard VGA - case 0x07: // Standard VGA - case 0x08: // Standard VGA - case 0x09: // Standard VGA - case 0x0a: // Standard VGA - case 0x0b: // Standard VGA - case 0x0c: // Standard VGA - case 0x0d: // Standard VGA - case 0x0e: // Standard VGA - case 0x0f: // Standard VGA - case 0x10: // Standard VGA - case 0x11: // Standard VGA - case 0x12: // Standard VGA - case 0x13: // Standard VGA - case 0x14: // Standard VGA - case 0x15: // Standard VGA - case 0x16: // Standard VGA - case 0x17: // Standard VGA - case 0x18: // Standard VGA - return CIRRUS_HOOK_NOT_HANDLED; - case 0x19: // Interlace End - case 0x1a: // Miscellaneous Control - case 0x1b: // Extended Display Control - case 0x1c: // Sync Adjust and Genlock - case 0x1d: // Overlay Extended Control - s->cr[reg_index] = reg_value; -#ifdef DEBUG_CIRRUS - printf("cirrus: handled outport cr_index %02x, cr_value %02x\n", - reg_index, reg_value); -#endif - break; - case 0x22: // Graphics Data Latches Readback (R) - case 0x24: // Attribute Controller Toggle Readback (R) - case 0x26: // Attribute Controller Index Readback (R) - case 0x27: // Part ID (R) - break; - case 0x25: // Part Status - default: -#ifdef DEBUG_CIRRUS - printf("cirrus: outport cr_index %02x, cr_value %02x\n", reg_index, - reg_value); -#endif - break; - } - - return CIRRUS_HOOK_HANDLED; -} - -/*************************************** - * - * memory-mapped I/O (bitblt) - * - ***************************************/ - -static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address) -{ - int value = 0xff; - - switch (address) { - case (CIRRUS_MMIO_BLTBGCOLOR + 0): - cirrus_hook_read_gr(s, 0x00, &value); - break; - case (CIRRUS_MMIO_BLTBGCOLOR + 1): - cirrus_hook_read_gr(s, 0x10, &value); - break; - case (CIRRUS_MMIO_BLTBGCOLOR + 2): - cirrus_hook_read_gr(s, 0x12, &value); - break; - case (CIRRUS_MMIO_BLTBGCOLOR + 3): - cirrus_hook_read_gr(s, 0x14, &value); - break; - case (CIRRUS_MMIO_BLTFGCOLOR + 0): - cirrus_hook_read_gr(s, 0x01, &value); - break; - case (CIRRUS_MMIO_BLTFGCOLOR + 1): - cirrus_hook_read_gr(s, 0x11, &value); - break; - case (CIRRUS_MMIO_BLTFGCOLOR + 2): - cirrus_hook_read_gr(s, 0x13, &value); - break; - case (CIRRUS_MMIO_BLTFGCOLOR + 3): - cirrus_hook_read_gr(s, 0x15, &value); - break; - case (CIRRUS_MMIO_BLTWIDTH + 0): - cirrus_hook_read_gr(s, 0x20, &value); - break; - case (CIRRUS_MMIO_BLTWIDTH + 1): - cirrus_hook_read_gr(s, 0x21, &value); - break; - case (CIRRUS_MMIO_BLTHEIGHT + 0): - cirrus_hook_read_gr(s, 0x22, &value); - break; - case (CIRRUS_MMIO_BLTHEIGHT + 1): - cirrus_hook_read_gr(s, 0x23, &value); - break; - case (CIRRUS_MMIO_BLTDESTPITCH + 0): - cirrus_hook_read_gr(s, 0x24, &value); - break; - case (CIRRUS_MMIO_BLTDESTPITCH + 1): - cirrus_hook_read_gr(s, 0x25, &value); - break; - case (CIRRUS_MMIO_BLTSRCPITCH + 0): - cirrus_hook_read_gr(s, 0x26, &value); - break; - case (CIRRUS_MMIO_BLTSRCPITCH + 1): - cirrus_hook_read_gr(s, 0x27, &value); - break; - case (CIRRUS_MMIO_BLTDESTADDR + 0): - cirrus_hook_read_gr(s, 0x28, &value); - break; - case (CIRRUS_MMIO_BLTDESTADDR + 1): - cirrus_hook_read_gr(s, 0x29, &value); - break; - case (CIRRUS_MMIO_BLTDESTADDR + 2): - cirrus_hook_read_gr(s, 0x2a, &value); - break; - case (CIRRUS_MMIO_BLTSRCADDR + 0): - cirrus_hook_read_gr(s, 0x2c, &value); - break; - case (CIRRUS_MMIO_BLTSRCADDR + 1): - cirrus_hook_read_gr(s, 0x2d, &value); - break; - case (CIRRUS_MMIO_BLTSRCADDR + 2): - cirrus_hook_read_gr(s, 0x2e, &value); - break; - case CIRRUS_MMIO_BLTWRITEMASK: - cirrus_hook_read_gr(s, 0x2f, &value); - break; - case CIRRUS_MMIO_BLTMODE: - cirrus_hook_read_gr(s, 0x30, &value); - break; - case CIRRUS_MMIO_BLTROP: - cirrus_hook_read_gr(s, 0x32, &value); - break; - case CIRRUS_MMIO_BLTMODEEXT: - cirrus_hook_read_gr(s, 0x33, &value); - break; - case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0): - cirrus_hook_read_gr(s, 0x34, &value); - break; - case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1): - cirrus_hook_read_gr(s, 0x35, &value); - break; - case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0): - cirrus_hook_read_gr(s, 0x38, &value); - break; - case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1): - cirrus_hook_read_gr(s, 0x39, &value); - break; - case CIRRUS_MMIO_BLTSTATUS: - cirrus_hook_read_gr(s, 0x31, &value); - break; - default: -#ifdef DEBUG_CIRRUS - printf("cirrus: mmio read - address 0x%04x\n", address); -#endif - break; - } - - return (uint8_t) value; -} - -static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address, - uint8_t value) -{ - switch (address) { - case (CIRRUS_MMIO_BLTBGCOLOR + 0): - cirrus_hook_write_gr(s, 0x00, value); - break; - case (CIRRUS_MMIO_BLTBGCOLOR + 1): - cirrus_hook_write_gr(s, 0x10, value); - break; - case (CIRRUS_MMIO_BLTBGCOLOR + 2): - cirrus_hook_write_gr(s, 0x12, value); - break; - case (CIRRUS_MMIO_BLTBGCOLOR + 3): - cirrus_hook_write_gr(s, 0x14, value); - break; - case (CIRRUS_MMIO_BLTFGCOLOR + 0): - cirrus_hook_write_gr(s, 0x01, value); - break; - case (CIRRUS_MMIO_BLTFGCOLOR + 1): - cirrus_hook_write_gr(s, 0x11, value); - break; - case (CIRRUS_MMIO_BLTFGCOLOR + 2): - cirrus_hook_write_gr(s, 0x13, value); - break; - case (CIRRUS_MMIO_BLTFGCOLOR + 3): - cirrus_hook_write_gr(s, 0x15, value); - break; - case (CIRRUS_MMIO_BLTWIDTH + 0): - cirrus_hook_write_gr(s, 0x20, value); - break; - case (CIRRUS_MMIO_BLTWIDTH + 1): - cirrus_hook_write_gr(s, 0x21, value); - break; - case (CIRRUS_MMIO_BLTHEIGHT + 0): - cirrus_hook_write_gr(s, 0x22, value); - break; - case (CIRRUS_MMIO_BLTHEIGHT + 1): - cirrus_hook_write_gr(s, 0x23, value); - break; - case (CIRRUS_MMIO_BLTDESTPITCH + 0): - cirrus_hook_write_gr(s, 0x24, value); - break; - case (CIRRUS_MMIO_BLTDESTPITCH + 1): - cirrus_hook_write_gr(s, 0x25, value); - break; - case (CIRRUS_MMIO_BLTSRCPITCH + 0): - cirrus_hook_write_gr(s, 0x26, value); - break; - case (CIRRUS_MMIO_BLTSRCPITCH + 1): - cirrus_hook_write_gr(s, 0x27, value); - break; - case (CIRRUS_MMIO_BLTDESTADDR + 0): - cirrus_hook_write_gr(s, 0x28, value); - break; - case (CIRRUS_MMIO_BLTDESTADDR + 1): - cirrus_hook_write_gr(s, 0x29, value); - break; - case (CIRRUS_MMIO_BLTDESTADDR + 2): - cirrus_hook_write_gr(s, 0x2a, value); - break; - case (CIRRUS_MMIO_BLTDESTADDR + 3): - /* ignored */ - break; - case (CIRRUS_MMIO_BLTSRCADDR + 0): - cirrus_hook_write_gr(s, 0x2c, value); - break; - case (CIRRUS_MMIO_BLTSRCADDR + 1): - cirrus_hook_write_gr(s, 0x2d, value); - break; - case (CIRRUS_MMIO_BLTSRCADDR + 2): - cirrus_hook_write_gr(s, 0x2e, value); - break; - case CIRRUS_MMIO_BLTWRITEMASK: - cirrus_hook_write_gr(s, 0x2f, value); - break; - case CIRRUS_MMIO_BLTMODE: - cirrus_hook_write_gr(s, 0x30, value); - break; - case CIRRUS_MMIO_BLTROP: - cirrus_hook_write_gr(s, 0x32, value); - break; - case CIRRUS_MMIO_BLTMODEEXT: - cirrus_hook_write_gr(s, 0x33, value); - break; - case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0): - cirrus_hook_write_gr(s, 0x34, value); - break; - case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1): - cirrus_hook_write_gr(s, 0x35, value); - break; - case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0): - cirrus_hook_write_gr(s, 0x38, value); - break; - case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1): - cirrus_hook_write_gr(s, 0x39, value); - break; - case CIRRUS_MMIO_BLTSTATUS: - cirrus_hook_write_gr(s, 0x31, value); - break; - default: -#ifdef DEBUG_CIRRUS - printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n", - address, value); -#endif - break; - } -} - -/*************************************** - * - * write mode 4/5 - * - * assume TARGET_PAGE_SIZE >= 16 - * - ***************************************/ - -static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s, - unsigned mode, - unsigned offset, - uint32_t mem_value) -{ - int x; - unsigned val = mem_value; - uint8_t *dst; - - dst = s->vram_ptr + offset; - for (x = 0; x < 8; x++) { - if (val & 0x80) { - *dst = s->cirrus_shadow_gr1; - } else if (mode == 5) { - *dst = s->cirrus_shadow_gr0; - } - val <<= 1; - dst++; - } - cpu_physical_memory_set_dirty(s->vram_offset + offset); - cpu_physical_memory_set_dirty(s->vram_offset + offset + 7); -} - -static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s, - unsigned mode, - unsigned offset, - uint32_t mem_value) -{ - int x; - unsigned val = mem_value; - uint8_t *dst; - - dst = s->vram_ptr + offset; - for (x = 0; x < 8; x++) { - if (val & 0x80) { - *dst = s->cirrus_shadow_gr1; - *(dst + 1) = s->gr[0x11]; - } else if (mode == 5) { - *dst = s->cirrus_shadow_gr0; - *(dst + 1) = s->gr[0x10]; - } - val <<= 1; - dst += 2; - } - cpu_physical_memory_set_dirty(s->vram_offset + offset); - cpu_physical_memory_set_dirty(s->vram_offset + offset + 15); -} - -/*************************************** - * - * memory access between 0xa0000-0xbffff - * - ***************************************/ - -static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr) -{ - CirrusVGAState *s = opaque; - unsigned bank_index; - unsigned bank_offset; - uint32_t val; - - if ((s->sr[0x07] & 0x01) == 0) { - return vga_mem_readb(s, addr); - } - - addr &= 0x1ffff; - - if (addr < 0x10000) { - /* XXX handle bitblt */ - /* video memory */ - bank_index = addr >> 15; - bank_offset = addr & 0x7fff; - if (bank_offset < s->cirrus_bank_limit[bank_index]) { - bank_offset += s->cirrus_bank_base[bank_index]; - if ((s->gr[0x0B] & 0x14) == 0x14) { - bank_offset <<= 4; - } else if (s->gr[0x0B] & 0x02) { - bank_offset <<= 3; - } - bank_offset &= s->cirrus_addr_mask; - val = *(s->vram_ptr + bank_offset); - } else - val = 0xff; - } else if (addr >= 0x18000 && addr < 0x18100) { - /* memory-mapped I/O */ - val = 0xff; - if ((s->sr[0x17] & 0x44) == 0x04) { - val = cirrus_mmio_blt_read(s, addr & 0xff); - } - } else { - val = 0xff; -#ifdef DEBUG_CIRRUS - printf("cirrus: mem_readb %06x\n", addr); -#endif - } - return val; -} - -static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_vga_mem_readb(opaque, addr) << 8; - v |= cirrus_vga_mem_readb(opaque, addr + 1); -#else - v = cirrus_vga_mem_readb(opaque, addr); - v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8; -#endif - return v; -} - -static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_vga_mem_readb(opaque, addr) << 24; - v |= cirrus_vga_mem_readb(opaque, addr + 1) << 16; - v |= cirrus_vga_mem_readb(opaque, addr + 2) << 8; - v |= cirrus_vga_mem_readb(opaque, addr + 3); -#else - v = cirrus_vga_mem_readb(opaque, addr); - v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8; - v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16; - v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24; -#endif - return v; -} - -static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr, - uint32_t mem_value) -{ - CirrusVGAState *s = opaque; - unsigned bank_index; - unsigned bank_offset; - unsigned mode; - - if ((s->sr[0x07] & 0x01) == 0) { - vga_mem_writeb(s, addr, mem_value); - return; - } - - addr &= 0x1ffff; - - if (addr < 0x10000) { - if (s->cirrus_srcptr != s->cirrus_srcptr_end) { - /* bitblt */ - *s->cirrus_srcptr++ = (uint8_t) mem_value; - if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { - cirrus_bitblt_cputovideo_next(s); - } - } else { - /* video memory */ - bank_index = addr >> 15; - bank_offset = addr & 0x7fff; - if (bank_offset < s->cirrus_bank_limit[bank_index]) { - bank_offset += s->cirrus_bank_base[bank_index]; - if ((s->gr[0x0B] & 0x14) == 0x14) { - bank_offset <<= 4; - } else if (s->gr[0x0B] & 0x02) { - bank_offset <<= 3; - } - bank_offset &= s->cirrus_addr_mask; - mode = s->gr[0x05] & 0x7; - if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { - *(s->vram_ptr + bank_offset) = mem_value; - cpu_physical_memory_set_dirty(s->vram_offset + - bank_offset); - } else { - if ((s->gr[0x0B] & 0x14) != 0x14) { - cirrus_mem_writeb_mode4and5_8bpp(s, mode, - bank_offset, - mem_value); - } else { - cirrus_mem_writeb_mode4and5_16bpp(s, mode, - bank_offset, - mem_value); - } - } - } - } - } else if (addr >= 0x18000 && addr < 0x18100) { - /* memory-mapped I/O */ - if ((s->sr[0x17] & 0x44) == 0x04) { - cirrus_mmio_blt_write(s, addr & 0xff, mem_value); - } - } else { -#ifdef DEBUG_CIRRUS - printf("cirrus: mem_writeb %06x value %02x\n", addr, mem_value); -#endif - } -} - -static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_vga_mem_writeb(opaque, addr, (val >> 8) & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 1, val & 0xff); -#else - cirrus_vga_mem_writeb(opaque, addr, val & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif -} - -static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 3, val & 0xff); -#else - cirrus_vga_mem_writeb(opaque, addr, val & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); - cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif -} - -static CPUReadMemoryFunc *cirrus_vga_mem_read[3] = { - cirrus_vga_mem_readb, - cirrus_vga_mem_readw, - cirrus_vga_mem_readl, -}; - -static CPUWriteMemoryFunc *cirrus_vga_mem_write[3] = { - cirrus_vga_mem_writeb, - cirrus_vga_mem_writew, - cirrus_vga_mem_writel, -}; - -/*************************************** - * - * hardware cursor - * - ***************************************/ - -static inline void invalidate_cursor1(CirrusVGAState *s) -{ - if (s->last_hw_cursor_size) { - vga_invalidate_scanlines((VGAState *)s, - s->last_hw_cursor_y + s->last_hw_cursor_y_start, - s->last_hw_cursor_y + s->last_hw_cursor_y_end); - } -} - -static inline void cirrus_cursor_compute_yrange(CirrusVGAState *s) -{ - const uint8_t *src; - uint32_t content; - int y, y_min, y_max; - - src = s->vram_ptr + s->real_vram_size - 16 * 1024; - if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { - src += (s->sr[0x13] & 0x3c) * 256; - y_min = 64; - y_max = -1; - for(y = 0; y < 64; y++) { - content = ((uint32_t *)src)[0] | - ((uint32_t *)src)[1] | - ((uint32_t *)src)[2] | - ((uint32_t *)src)[3]; - if (content) { - if (y < y_min) - y_min = y; - if (y > y_max) - y_max = y; - } - src += 16; - } - } else { - src += (s->sr[0x13] & 0x3f) * 256; - y_min = 32; - y_max = -1; - for(y = 0; y < 32; y++) { - content = ((uint32_t *)src)[0] | - ((uint32_t *)(src + 128))[0]; - if (content) { - if (y < y_min) - y_min = y; - if (y > y_max) - y_max = y; - } - src += 4; - } - } - if (y_min > y_max) { - s->last_hw_cursor_y_start = 0; - s->last_hw_cursor_y_end = 0; - } else { - s->last_hw_cursor_y_start = y_min; - s->last_hw_cursor_y_end = y_max + 1; - } -} - -/* NOTE: we do not currently handle the cursor bitmap change, so we - update the cursor only if it moves. */ -static void cirrus_cursor_invalidate(VGAState *s1) -{ - CirrusVGAState *s = (CirrusVGAState *)s1; - int size; - - if (!s->sr[0x12] & CIRRUS_CURSOR_SHOW) { - size = 0; - } else { - if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) - size = 64; - else - size = 32; - } - /* invalidate last cursor and new cursor if any change */ - if (s->last_hw_cursor_size != size || - s->last_hw_cursor_x != s->hw_cursor_x || - s->last_hw_cursor_y != s->hw_cursor_y) { - - invalidate_cursor1(s); - - s->last_hw_cursor_size = size; - s->last_hw_cursor_x = s->hw_cursor_x; - s->last_hw_cursor_y = s->hw_cursor_y; - /* compute the real cursor min and max y */ - cirrus_cursor_compute_yrange(s); - invalidate_cursor1(s); - } -} - -static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y) -{ - CirrusVGAState *s = (CirrusVGAState *)s1; - int w, h, bpp, x1, x2, poffset; - unsigned int color0, color1; - const uint8_t *palette, *src; - uint32_t content; - - if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW)) - return; - /* fast test to see if the cursor intersects with the scan line */ - if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { - h = 64; - } else { - h = 32; - } - if (scr_y < s->hw_cursor_y || - scr_y >= (s->hw_cursor_y + h)) - return; - - src = s->vram_ptr + s->real_vram_size - 16 * 1024; - if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) { - src += (s->sr[0x13] & 0x3c) * 256; - src += (scr_y - s->hw_cursor_y) * 16; - poffset = 8; - content = ((uint32_t *)src)[0] | - ((uint32_t *)src)[1] | - ((uint32_t *)src)[2] | - ((uint32_t *)src)[3]; - } else { - src += (s->sr[0x13] & 0x3f) * 256; - src += (scr_y - s->hw_cursor_y) * 4; - poffset = 128; - content = ((uint32_t *)src)[0] | - ((uint32_t *)(src + 128))[0]; - } - /* if nothing to draw, no need to continue */ - if (!content) - return; - w = h; - - x1 = s->hw_cursor_x; - if (x1 >= s->last_scr_width) - return; - x2 = s->hw_cursor_x + w; - if (x2 > s->last_scr_width) - x2 = s->last_scr_width; - w = x2 - x1; - palette = s->cirrus_hidden_palette; - color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]), - c6_to_8(palette[0x0 * 3 + 1]), - c6_to_8(palette[0x0 * 3 + 2])); - color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]), - c6_to_8(palette[0xf * 3 + 1]), - c6_to_8(palette[0xf * 3 + 2])); - bpp = ((s->ds->depth + 7) >> 3); - d1 += x1 * bpp; - switch(s->ds->depth) { - default: - break; - case 8: - vga_draw_cursor_line_8(d1, src, poffset, w, color0, color1, 0xff); - break; - case 15: - vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0x7fff); - break; - case 16: - vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0xffff); - break; - case 32: - vga_draw_cursor_line_32(d1, src, poffset, w, color0, color1, 0xffffff); - break; - } -} - -/*************************************** - * - * LFB memory access - * - ***************************************/ - -static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - uint32_t ret; - - addr &= s->cirrus_addr_mask; - - if (((s->sr[0x17] & 0x44) == 0x44) && - ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { - /* memory-mapped I/O */ - ret = cirrus_mmio_blt_read(s, addr & 0xff); - } else if (0) { - /* XXX handle bitblt */ - ret = 0xff; - } else { - /* video memory */ - if ((s->gr[0x0B] & 0x14) == 0x14) { - addr <<= 4; - } else if (s->gr[0x0B] & 0x02) { - addr <<= 3; - } - addr &= s->cirrus_addr_mask; - ret = *(s->vram_ptr + addr); - } - - return ret; -} - -static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_linear_readb(opaque, addr) << 8; - v |= cirrus_linear_readb(opaque, addr + 1); -#else - v = cirrus_linear_readb(opaque, addr); - v |= cirrus_linear_readb(opaque, addr + 1) << 8; -#endif - return v; -} - -static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_linear_readb(opaque, addr) << 24; - v |= cirrus_linear_readb(opaque, addr + 1) << 16; - v |= cirrus_linear_readb(opaque, addr + 2) << 8; - v |= cirrus_linear_readb(opaque, addr + 3); -#else - v = cirrus_linear_readb(opaque, addr); - v |= cirrus_linear_readb(opaque, addr + 1) << 8; - v |= cirrus_linear_readb(opaque, addr + 2) << 16; - v |= cirrus_linear_readb(opaque, addr + 3) << 24; -#endif - return v; -} - -static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - unsigned mode; - - addr &= s->cirrus_addr_mask; - - if (((s->sr[0x17] & 0x44) == 0x44) && - ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) { - /* memory-mapped I/O */ - cirrus_mmio_blt_write(s, addr & 0xff, val); - } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) { - /* bitblt */ - *s->cirrus_srcptr++ = (uint8_t) val; - if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { - cirrus_bitblt_cputovideo_next(s); - } - } else { - /* video memory */ - if ((s->gr[0x0B] & 0x14) == 0x14) { - addr <<= 4; - } else if (s->gr[0x0B] & 0x02) { - addr <<= 3; - } - addr &= s->cirrus_addr_mask; - - mode = s->gr[0x05] & 0x7; - if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { - *(s->vram_ptr + addr) = (uint8_t) val; - cpu_physical_memory_set_dirty(s->vram_offset + addr); - } else { - if ((s->gr[0x0B] & 0x14) != 0x14) { - cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val); - } else { - cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val); - } - } - } -} - -static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_linear_writeb(opaque, addr, (val >> 8) & 0xff); - cirrus_linear_writeb(opaque, addr + 1, val & 0xff); -#else - cirrus_linear_writeb(opaque, addr, val & 0xff); - cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif -} - -static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_linear_writeb(opaque, addr, (val >> 24) & 0xff); - cirrus_linear_writeb(opaque, addr + 1, (val >> 16) & 0xff); - cirrus_linear_writeb(opaque, addr + 2, (val >> 8) & 0xff); - cirrus_linear_writeb(opaque, addr + 3, val & 0xff); -#else - cirrus_linear_writeb(opaque, addr, val & 0xff); - cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff); - cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff); - cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif -} - - -static CPUReadMemoryFunc *cirrus_linear_read[3] = { - cirrus_linear_readb, - cirrus_linear_readw, - cirrus_linear_readl, -}; - -static CPUWriteMemoryFunc *cirrus_linear_write[3] = { - cirrus_linear_writeb, - cirrus_linear_writew, - cirrus_linear_writel, -}; - -static void cirrus_linear_mem_writeb(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - - addr &= s->cirrus_addr_mask; - *(s->vram_ptr + addr) = val; - cpu_physical_memory_set_dirty(s->vram_offset + addr); -} - -static void cirrus_linear_mem_writew(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - - addr &= s->cirrus_addr_mask; - cpu_to_le16w((uint16_t *)(s->vram_ptr + addr), val); - cpu_physical_memory_set_dirty(s->vram_offset + addr); -} - -static void cirrus_linear_mem_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - - addr &= s->cirrus_addr_mask; - cpu_to_le32w((uint32_t *)(s->vram_ptr + addr), val); - cpu_physical_memory_set_dirty(s->vram_offset + addr); -} - -/*************************************** - * - * system to screen memory access - * - ***************************************/ - - -static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr) -{ - uint32_t ret; - - /* XXX handle bitblt */ - ret = 0xff; - return ret; -} - -static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_linear_bitblt_readb(opaque, addr) << 8; - v |= cirrus_linear_bitblt_readb(opaque, addr + 1); -#else - v = cirrus_linear_bitblt_readb(opaque, addr); - v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8; -#endif - return v; -} - -static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_linear_bitblt_readb(opaque, addr) << 24; - v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 16; - v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 8; - v |= cirrus_linear_bitblt_readb(opaque, addr + 3); -#else - v = cirrus_linear_bitblt_readb(opaque, addr); - v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8; - v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 16; - v |= cirrus_linear_bitblt_readb(opaque, addr + 3) << 24; -#endif - return v; -} - -static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - - if (s->cirrus_srcptr != s->cirrus_srcptr_end) { - /* bitblt */ - *s->cirrus_srcptr++ = (uint8_t) val; - if (s->cirrus_srcptr >= s->cirrus_srcptr_end) { - cirrus_bitblt_cputovideo_next(s); - } - } -} - -static void cirrus_linear_bitblt_writew(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_linear_bitblt_writeb(opaque, addr, (val >> 8) & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 1, val & 0xff); -#else - cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif -} - -static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_linear_bitblt_writeb(opaque, addr, (val >> 24) & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 16) & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 8) & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 3, val & 0xff); -#else - cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 16) & 0xff); - cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif -} - - -static CPUReadMemoryFunc *cirrus_linear_bitblt_read[3] = { - cirrus_linear_bitblt_readb, - cirrus_linear_bitblt_readw, - cirrus_linear_bitblt_readl, -}; - -static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = { - cirrus_linear_bitblt_writeb, - cirrus_linear_bitblt_writew, - cirrus_linear_bitblt_writel, -}; - -/* Compute the memory access functions */ -static void cirrus_update_memory_access(CirrusVGAState *s) -{ - unsigned mode; - - if ((s->sr[0x17] & 0x44) == 0x44) { - goto generic_io; - } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) { - goto generic_io; - } else { - if ((s->gr[0x0B] & 0x14) == 0x14) { - goto generic_io; - } else if (s->gr[0x0B] & 0x02) { - goto generic_io; - } - - mode = s->gr[0x05] & 0x7; - if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) { - s->cirrus_linear_write[0] = cirrus_linear_mem_writeb; - s->cirrus_linear_write[1] = cirrus_linear_mem_writew; - s->cirrus_linear_write[2] = cirrus_linear_mem_writel; - } else { - generic_io: - s->cirrus_linear_write[0] = cirrus_linear_writeb; - s->cirrus_linear_write[1] = cirrus_linear_writew; - s->cirrus_linear_write[2] = cirrus_linear_writel; - } - } -} - - -/* I/O ports */ - -static uint32_t vga_ioport_read(void *opaque, uint32_t addr) -{ - CirrusVGAState *s = opaque; - int val, index; - - /* check port range access depending on color/monochrome mode */ - if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) - || (addr >= 0x3d0 && addr <= 0x3df - && !(s->msr & MSR_COLOR_EMULATION))) { - val = 0xff; - } else { - switch (addr) { - case 0x3c0: - if (s->ar_flip_flop == 0) { - val = s->ar_index; - } else { - val = 0; - } - break; - case 0x3c1: - index = s->ar_index & 0x1f; - if (index < 21) - val = s->ar[index]; - else - val = 0; - break; - case 0x3c2: - val = s->st00; - break; - case 0x3c4: - val = s->sr_index; - break; - case 0x3c5: - if (cirrus_hook_read_sr(s, s->sr_index, &val)) - break; - val = s->sr[s->sr_index]; -#ifdef DEBUG_VGA_REG - printf("vga: read SR%x = 0x%02x\n", s->sr_index, val); -#endif - break; - case 0x3c6: - cirrus_read_hidden_dac(s, &val); - break; - case 0x3c7: - val = s->dac_state; - break; - case 0x3c8: - val = s->dac_write_index; - s->cirrus_hidden_dac_lockindex = 0; - break; - case 0x3c9: - if (cirrus_hook_read_palette(s, &val)) - break; - val = s->palette[s->dac_read_index * 3 + s->dac_sub_index]; - if (++s->dac_sub_index == 3) { - s->dac_sub_index = 0; - s->dac_read_index++; - } - break; - case 0x3ca: - val = s->fcr; - break; - case 0x3cc: - val = s->msr; - break; - case 0x3ce: - val = s->gr_index; - break; - case 0x3cf: - if (cirrus_hook_read_gr(s, s->gr_index, &val)) - break; - val = s->gr[s->gr_index]; -#ifdef DEBUG_VGA_REG - printf("vga: read GR%x = 0x%02x\n", s->gr_index, val); -#endif - break; - case 0x3b4: - case 0x3d4: - val = s->cr_index; - break; - case 0x3b5: - case 0x3d5: - if (cirrus_hook_read_cr(s, s->cr_index, &val)) - break; - val = s->cr[s->cr_index]; -#ifdef DEBUG_VGA_REG - printf("vga: read CR%x = 0x%02x\n", s->cr_index, val); -#endif - break; - case 0x3ba: - case 0x3da: - /* just toggle to fool polling */ - s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE; - val = s->st01; - s->ar_flip_flop = 0; - break; - default: - val = 0x00; - break; - } - } -#if defined(DEBUG_VGA) - printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val); -#endif - return val; -} - -static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - CirrusVGAState *s = opaque; - int index; - - /* check port range access depending on color/monochrome mode */ - if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) - || (addr >= 0x3d0 && addr <= 0x3df - && !(s->msr & MSR_COLOR_EMULATION))) - return; - -#ifdef DEBUG_VGA - printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val); -#endif - - switch (addr) { - case 0x3c0: - if (s->ar_flip_flop == 0) { - val &= 0x3f; - s->ar_index = val; - } else { - index = s->ar_index & 0x1f; - switch (index) { - case 0x00 ... 0x0f: - s->ar[index] = val & 0x3f; - break; - case 0x10: - s->ar[index] = val & ~0x10; - break; - case 0x11: - s->ar[index] = val; - break; - case 0x12: - s->ar[index] = val & ~0xc0; - break; - case 0x13: - s->ar[index] = val & ~0xf0; - break; - case 0x14: - s->ar[index] = val & ~0xf0; - break; - default: - break; - } - } - s->ar_flip_flop ^= 1; - break; - case 0x3c2: - s->msr = val & ~0x10; - break; - case 0x3c4: - s->sr_index = val; - break; - case 0x3c5: - if (cirrus_hook_write_sr(s, s->sr_index, val)) - break; -#ifdef DEBUG_VGA_REG - printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); -#endif - s->sr[s->sr_index] = val & sr_mask[s->sr_index]; - break; - case 0x3c6: - cirrus_write_hidden_dac(s, val); - break; - case 0x3c7: - s->dac_read_index = val; - s->dac_sub_index = 0; - s->dac_state = 3; - break; - case 0x3c8: - s->dac_write_index = val; - s->dac_sub_index = 0; - s->dac_state = 0; - break; - case 0x3c9: - if (cirrus_hook_write_palette(s, val)) - break; - s->dac_cache[s->dac_sub_index] = val; - if (++s->dac_sub_index == 3) { - memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3); - s->dac_sub_index = 0; - s->dac_write_index++; - } - break; - case 0x3ce: - s->gr_index = val; - break; - case 0x3cf: - if (cirrus_hook_write_gr(s, s->gr_index, val)) - break; -#ifdef DEBUG_VGA_REG - printf("vga: write GR%x = 0x%02x\n", s->gr_index, val); -#endif - s->gr[s->gr_index] = val & gr_mask[s->gr_index]; - break; - case 0x3b4: - case 0x3d4: - s->cr_index = val; - break; - case 0x3b5: - case 0x3d5: - if (cirrus_hook_write_cr(s, s->cr_index, val)) - break; -#ifdef DEBUG_VGA_REG - printf("vga: write CR%x = 0x%02x\n", s->cr_index, val); -#endif - /* handle CR0-7 protection */ - if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) { - /* can always write bit 4 of CR7 */ - if (s->cr_index == 7) - s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); - return; - } - switch (s->cr_index) { - case 0x01: /* horizontal display end */ - case 0x07: - case 0x09: - case 0x0c: - case 0x0d: - case 0x12: /* veritcal display end */ - s->cr[s->cr_index] = val; - break; - - default: - s->cr[s->cr_index] = val; - break; - } - break; - case 0x3ba: - case 0x3da: - s->fcr = val & 0x10; - break; - } -} - -/*************************************** - * - * memory-mapped I/O access - * - ***************************************/ - -static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - - addr &= CIRRUS_PNPMMIO_SIZE - 1; - - if (addr >= 0x100) { - return cirrus_mmio_blt_read(s, addr - 0x100); - } else { - return vga_ioport_read(s, addr + 0x3c0); - } -} - -static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_mmio_readb(opaque, addr) << 8; - v |= cirrus_mmio_readb(opaque, addr + 1); -#else - v = cirrus_mmio_readb(opaque, addr); - v |= cirrus_mmio_readb(opaque, addr + 1) << 8; -#endif - return v; -} - -static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = cirrus_mmio_readb(opaque, addr) << 24; - v |= cirrus_mmio_readb(opaque, addr + 1) << 16; - v |= cirrus_mmio_readb(opaque, addr + 2) << 8; - v |= cirrus_mmio_readb(opaque, addr + 3); -#else - v = cirrus_mmio_readb(opaque, addr); - v |= cirrus_mmio_readb(opaque, addr + 1) << 8; - v |= cirrus_mmio_readb(opaque, addr + 2) << 16; - v |= cirrus_mmio_readb(opaque, addr + 3) << 24; -#endif - return v; -} - -static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - CirrusVGAState *s = (CirrusVGAState *) opaque; - - addr &= CIRRUS_PNPMMIO_SIZE - 1; - - if (addr >= 0x100) { - cirrus_mmio_blt_write(s, addr - 0x100, val); - } else { - vga_ioport_write(s, addr + 0x3c0, val); - } -} - -static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff); - cirrus_mmio_writeb(opaque, addr + 1, val & 0xff); -#else - cirrus_mmio_writeb(opaque, addr, val & 0xff); - cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif -} - -static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff); - cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff); - cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff); - cirrus_mmio_writeb(opaque, addr + 3, val & 0xff); -#else - cirrus_mmio_writeb(opaque, addr, val & 0xff); - cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff); - cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff); - cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif -} - - -static CPUReadMemoryFunc *cirrus_mmio_read[3] = { - cirrus_mmio_readb, - cirrus_mmio_readw, - cirrus_mmio_readl, -}; - -static CPUWriteMemoryFunc *cirrus_mmio_write[3] = { - cirrus_mmio_writeb, - cirrus_mmio_writew, - cirrus_mmio_writel, -}; - -/* load/save state */ - -static void cirrus_vga_save(QEMUFile *f, void *opaque) -{ - CirrusVGAState *s = opaque; - - qemu_put_be32s(f, &s->latch); - qemu_put_8s(f, &s->sr_index); - qemu_put_buffer(f, s->sr, 256); - qemu_put_8s(f, &s->gr_index); - qemu_put_8s(f, &s->cirrus_shadow_gr0); - qemu_put_8s(f, &s->cirrus_shadow_gr1); - qemu_put_buffer(f, s->gr + 2, 254); - qemu_put_8s(f, &s->ar_index); - qemu_put_buffer(f, s->ar, 21); - qemu_put_be32s(f, &s->ar_flip_flop); - qemu_put_8s(f, &s->cr_index); - qemu_put_buffer(f, s->cr, 256); - qemu_put_8s(f, &s->msr); - qemu_put_8s(f, &s->fcr); - qemu_put_8s(f, &s->st00); - qemu_put_8s(f, &s->st01); - - qemu_put_8s(f, &s->dac_state); - qemu_put_8s(f, &s->dac_sub_index); - qemu_put_8s(f, &s->dac_read_index); - qemu_put_8s(f, &s->dac_write_index); - qemu_put_buffer(f, s->dac_cache, 3); - qemu_put_buffer(f, s->palette, 768); - - qemu_put_be32s(f, &s->bank_offset); - - qemu_put_8s(f, &s->cirrus_hidden_dac_lockindex); - qemu_put_8s(f, &s->cirrus_hidden_dac_data); - - qemu_put_be32s(f, &s->hw_cursor_x); - qemu_put_be32s(f, &s->hw_cursor_y); - /* XXX: we do not save the bitblt state - we assume we do not save - the state when the blitter is active */ -} - -static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id) -{ - CirrusVGAState *s = opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_be32s(f, &s->latch); - qemu_get_8s(f, &s->sr_index); - qemu_get_buffer(f, s->sr, 256); - qemu_get_8s(f, &s->gr_index); - qemu_get_8s(f, &s->cirrus_shadow_gr0); - qemu_get_8s(f, &s->cirrus_shadow_gr1); - s->gr[0x00] = s->cirrus_shadow_gr0 & 0x0f; - s->gr[0x01] = s->cirrus_shadow_gr1 & 0x0f; - qemu_get_buffer(f, s->gr + 2, 254); - qemu_get_8s(f, &s->ar_index); - qemu_get_buffer(f, s->ar, 21); - qemu_get_be32s(f, &s->ar_flip_flop); - qemu_get_8s(f, &s->cr_index); - qemu_get_buffer(f, s->cr, 256); - qemu_get_8s(f, &s->msr); - qemu_get_8s(f, &s->fcr); - qemu_get_8s(f, &s->st00); - qemu_get_8s(f, &s->st01); - - qemu_get_8s(f, &s->dac_state); - qemu_get_8s(f, &s->dac_sub_index); - qemu_get_8s(f, &s->dac_read_index); - qemu_get_8s(f, &s->dac_write_index); - qemu_get_buffer(f, s->dac_cache, 3); - qemu_get_buffer(f, s->palette, 768); - - qemu_get_be32s(f, &s->bank_offset); - - qemu_get_8s(f, &s->cirrus_hidden_dac_lockindex); - qemu_get_8s(f, &s->cirrus_hidden_dac_data); - - qemu_get_be32s(f, &s->hw_cursor_x); - qemu_get_be32s(f, &s->hw_cursor_y); - - /* force refresh */ - s->graphic_mode = -1; - cirrus_update_bank_ptr(s, 0); - cirrus_update_bank_ptr(s, 1); - return 0; -} - -/*************************************** - * - * initialize - * - ***************************************/ - -static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci) -{ - int vga_io_memory, i; - static int inited; - - if (!inited) { - inited = 1; - for(i = 0;i < 256; i++) - rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */ - rop_to_index[CIRRUS_ROP_0] = 0; - rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1; - rop_to_index[CIRRUS_ROP_NOP] = 2; - rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3; - rop_to_index[CIRRUS_ROP_NOTDST] = 4; - rop_to_index[CIRRUS_ROP_SRC] = 5; - rop_to_index[CIRRUS_ROP_1] = 6; - rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7; - rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8; - rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9; - rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10; - rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11; - rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12; - rop_to_index[CIRRUS_ROP_NOTSRC] = 13; - rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14; - rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15; - } - - register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s); - - register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s); - register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s); - register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s); - register_ioport_write(0x3da, 1, 1, vga_ioport_write, s); - - register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s); - - register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s); - register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s); - register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s); - register_ioport_read(0x3da, 1, 1, vga_ioport_read, s); - - vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read, - cirrus_vga_mem_write, s); - cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, - vga_io_memory); - - s->sr[0x06] = 0x0f; - if (device_id == CIRRUS_ID_CLGD5446) { - /* 4MB 64 bit memory config, always PCI */ - s->sr[0x1F] = 0x2d; // MemClock - s->gr[0x18] = 0x0f; // fastest memory configuration -#if 1 - s->sr[0x0f] = 0x98; - s->sr[0x17] = 0x20; - s->sr[0x15] = 0x04; /* memory size, 3=2MB, 4=4MB */ - s->real_vram_size = 4096 * 1024; -#else - s->sr[0x0f] = 0x18; - s->sr[0x17] = 0x20; - s->sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */ - s->real_vram_size = 2048 * 1024; -#endif - } else { - s->sr[0x1F] = 0x22; // MemClock - s->sr[0x0F] = CIRRUS_MEMSIZE_2M; - if (is_pci) - s->sr[0x17] = CIRRUS_BUSTYPE_PCI; - else - s->sr[0x17] = CIRRUS_BUSTYPE_ISA; - s->real_vram_size = 2048 * 1024; - s->sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */ - } - s->cr[0x27] = device_id; - - /* Win2K seems to assume that the pattern buffer is at 0xff - initially ! */ - memset(s->vram_ptr, 0xff, s->real_vram_size); - - s->cirrus_hidden_dac_lockindex = 5; - s->cirrus_hidden_dac_data = 0; - - /* I/O handler for LFB */ - s->cirrus_linear_io_addr = - cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write, - s); - s->cirrus_linear_write = cpu_get_io_memory_write(s->cirrus_linear_io_addr); - - /* I/O handler for LFB */ - s->cirrus_linear_bitblt_io_addr = - cpu_register_io_memory(0, cirrus_linear_bitblt_read, cirrus_linear_bitblt_write, - s); - - /* I/O handler for memory-mapped I/O */ - s->cirrus_mmio_io_addr = - cpu_register_io_memory(0, cirrus_mmio_read, cirrus_mmio_write, s); - - /* XXX: s->vram_size must be a power of two */ - s->cirrus_addr_mask = s->real_vram_size - 1; - s->linear_mmio_mask = s->real_vram_size - 256; - - s->get_bpp = cirrus_get_bpp; - s->get_offsets = cirrus_get_offsets; - s->get_resolution = cirrus_get_resolution; - s->cursor_invalidate = cirrus_cursor_invalidate; - s->cursor_draw_line = cirrus_cursor_draw_line; - - register_savevm("cirrus_vga", 0, 1, cirrus_vga_save, cirrus_vga_load, s); -} - -/*************************************** - * - * ISA bus support - * - ***************************************/ - -void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size) -{ - CirrusVGAState *s; - - s = qemu_mallocz(sizeof(CirrusVGAState)); - - vga_common_init((VGAState *)s, - ds, vga_ram_base, vga_ram_offset, vga_ram_size); - cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0); - /* XXX ISA-LFB support */ -} - -/*************************************** - * - * PCI bus support - * - ***************************************/ - -static void cirrus_pci_lfb_map(PCIDevice *d, int region_num, - uint32_t addr, uint32_t size, int type) -{ - CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga; - - /* XXX: add byte swapping apertures */ - cpu_register_physical_memory(addr, s->vram_size, - s->cirrus_linear_io_addr); - cpu_register_physical_memory(addr + 0x1000000, 0x400000, - s->cirrus_linear_bitblt_io_addr); -} - -static void cirrus_pci_mmio_map(PCIDevice *d, int region_num, - uint32_t addr, uint32_t size, int type) -{ - CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga; - - cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE, - s->cirrus_mmio_io_addr); -} - -void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size) -{ - PCICirrusVGAState *d; - uint8_t *pci_conf; - CirrusVGAState *s; - int device_id; - - device_id = CIRRUS_ID_CLGD5446; - - /* setup PCI configuration registers */ - d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA", - sizeof(PCICirrusVGAState), - -1, NULL, NULL); - pci_conf = d->dev.config; - pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff); - pci_conf[0x01] = (uint8_t) (PCI_VENDOR_CIRRUS >> 8); - pci_conf[0x02] = (uint8_t) (device_id & 0xff); - pci_conf[0x03] = (uint8_t) (device_id >> 8); - pci_conf[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS; - pci_conf[0x0a] = PCI_CLASS_SUB_VGA; - pci_conf[0x0b] = PCI_CLASS_BASE_DISPLAY; - pci_conf[0x0e] = PCI_CLASS_HEADERTYPE_00h; - - /* setup VGA */ - s = &d->cirrus_vga; - vga_common_init((VGAState *)s, - ds, vga_ram_base, vga_ram_offset, vga_ram_size); - cirrus_init_common(s, device_id, 1); - - /* setup memory space */ - /* memory #0 LFB */ - /* memory #1 memory-mapped I/O */ - /* XXX: s->vram_size must be a power of two */ - pci_register_io_region((PCIDevice *)d, 0, 0x2000000, - PCI_ADDRESS_SPACE_MEM_PREFETCH, cirrus_pci_lfb_map); - if (device_id == CIRRUS_ID_CLGD5446) { - pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE, - PCI_ADDRESS_SPACE_MEM, cirrus_pci_mmio_map); - } - /* XXX: ROM BIOS */ -} diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h deleted file mode 100644 index c54f125..0000000 --- a/hw/cirrus_vga_rop.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * QEMU Cirrus CLGD 54xx VGA Emulator. - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -static void -glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s, - uint8_t *dst,const uint8_t *src, - int dstpitch,int srcpitch, - int bltwidth,int bltheight) -{ - int x,y; - dstpitch -= bltwidth; - srcpitch -= bltwidth; - for (y = 0; y < bltheight; y++) { - for (x = 0; x < bltwidth; x++) { - ROP_OP(*dst, *src); - dst++; - src++; - } - dst += dstpitch; - src += srcpitch; - } -} - -static void -glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s, - uint8_t *dst,const uint8_t *src, - int dstpitch,int srcpitch, - int bltwidth,int bltheight) -{ - int x,y; - dstpitch += bltwidth; - srcpitch += bltwidth; - for (y = 0; y < bltheight; y++) { - for (x = 0; x < bltwidth; x++) { - ROP_OP(*dst, *src); - dst--; - src--; - } - dst += dstpitch; - src += srcpitch; - } -} - -#define DEPTH 8 -#include "cirrus_vga_rop2.h" - -#define DEPTH 16 -#include "cirrus_vga_rop2.h" - -#define DEPTH 24 -#include "cirrus_vga_rop2.h" - -#define DEPTH 32 -#include "cirrus_vga_rop2.h" - -#undef ROP_NAME -#undef ROP_OP diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h deleted file mode 100644 index da11d0f..0000000 --- a/hw/cirrus_vga_rop2.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * QEMU Cirrus CLGD 54xx VGA Emulator. - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#if DEPTH == 8 -#define PUTPIXEL() ROP_OP(d[0], col) -#elif DEPTH == 16 -#define PUTPIXEL() ROP_OP(((uint16_t *)d)[0], col); -#elif DEPTH == 24 -#define PUTPIXEL() ROP_OP(d[0], col); \ - ROP_OP(d[1], (col >> 8)); \ - ROP_OP(d[2], (col >> 16)) -#elif DEPTH == 32 -#define PUTPIXEL() ROP_OP(((uint32_t *)d)[0], col) -#else -#error unsupported DEPTH -#endif - -static void -glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH) - (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight) -{ - uint8_t *d; - int x, y, pattern_y, pattern_pitch, pattern_x; - unsigned int col; - const uint8_t *src1; -#if DEPTH == 24 - int skipleft = s->gr[0x2f] & 0x1f; -#else - int skipleft = (s->gr[0x2f] & 0x07) * (DEPTH / 8); -#endif - -#if DEPTH == 8 - pattern_pitch = 8; -#elif DEPTH == 16 - pattern_pitch = 16; -#else - pattern_pitch = 32; -#endif - pattern_y = s->cirrus_blt_srcaddr & 7; - for(y = 0; y < bltheight; y++) { - pattern_x = skipleft; - d = dst + skipleft; - src1 = src + pattern_y * pattern_pitch; - for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) { -#if DEPTH == 8 - col = src1[pattern_x]; - pattern_x = (pattern_x + 1) & 7; -#elif DEPTH == 16 - col = ((uint16_t *)(src1 + pattern_x))[0]; - pattern_x = (pattern_x + 2) & 15; -#elif DEPTH == 24 - { - const uint8_t *src2 = src1 + pattern_x * 3; - col = src2[0] | (src2[1] << 8) | (src2[2] << 16); - pattern_x = (pattern_x + 1) & 7; - } -#else - col = ((uint32_t *)(src1 + pattern_x))[0]; - pattern_x = (pattern_x + 4) & 31; -#endif - PUTPIXEL(); - d += (DEPTH / 8); - } - pattern_y = (pattern_y + 1) & 7; - dst += dstpitch; - } -} - -/* NOTE: srcpitch is ignored */ -static void -glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH) - (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight) -{ - uint8_t *d; - int x, y; - unsigned bits, bits_xor; - unsigned int col; - unsigned bitmask; - unsigned index; -#if DEPTH == 24 - int dstskipleft = s->gr[0x2f] & 0x1f; - int srcskipleft = dstskipleft / 3; -#else - int srcskipleft = s->gr[0x2f] & 0x07; - int dstskipleft = srcskipleft * (DEPTH / 8); -#endif - - if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { - bits_xor = 0xff; - col = s->cirrus_blt_bgcol; - } else { - bits_xor = 0x00; - col = s->cirrus_blt_fgcol; - } - - for(y = 0; y < bltheight; y++) { - bitmask = 0x80 >> srcskipleft; - bits = *src++ ^ bits_xor; - d = dst + dstskipleft; - for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) { - if ((bitmask & 0xff) == 0) { - bitmask = 0x80; - bits = *src++ ^ bits_xor; - } - index = (bits & bitmask); - if (index) { - PUTPIXEL(); - } - d += (DEPTH / 8); - bitmask >>= 1; - } - dst += dstpitch; - } -} - -static void -glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH) - (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight) -{ - uint32_t colors[2]; - uint8_t *d; - int x, y; - unsigned bits; - unsigned int col; - unsigned bitmask; - int srcskipleft = s->gr[0x2f] & 0x07; - int dstskipleft = srcskipleft * (DEPTH / 8); - - colors[0] = s->cirrus_blt_bgcol; - colors[1] = s->cirrus_blt_fgcol; - for(y = 0; y < bltheight; y++) { - bitmask = 0x80 >> srcskipleft; - bits = *src++; - d = dst + dstskipleft; - for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) { - if ((bitmask & 0xff) == 0) { - bitmask = 0x80; - bits = *src++; - } - col = colors[!!(bits & bitmask)]; - PUTPIXEL(); - d += (DEPTH / 8); - bitmask >>= 1; - } - dst += dstpitch; - } -} - -static void -glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH) - (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight) -{ - uint8_t *d; - int x, y, bitpos, pattern_y; - unsigned int bits, bits_xor; - unsigned int col; -#if DEPTH == 24 - int dstskipleft = s->gr[0x2f] & 0x1f; - int srcskipleft = dstskipleft / 3; -#else - int srcskipleft = s->gr[0x2f] & 0x07; - int dstskipleft = srcskipleft * (DEPTH / 8); -#endif - - if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { - bits_xor = 0xff; - col = s->cirrus_blt_bgcol; - } else { - bits_xor = 0x00; - col = s->cirrus_blt_fgcol; - } - pattern_y = s->cirrus_blt_srcaddr & 7; - - for(y = 0; y < bltheight; y++) { - bits = src[pattern_y] ^ bits_xor; - bitpos = 7 - srcskipleft; - d = dst + dstskipleft; - for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) { - if ((bits >> bitpos) & 1) { - PUTPIXEL(); - } - d += (DEPTH / 8); - bitpos = (bitpos - 1) & 7; - } - pattern_y = (pattern_y + 1) & 7; - dst += dstpitch; - } -} - -static void -glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH) - (CirrusVGAState * s, uint8_t * dst, - const uint8_t * src, - int dstpitch, int srcpitch, - int bltwidth, int bltheight) -{ - uint32_t colors[2]; - uint8_t *d; - int x, y, bitpos, pattern_y; - unsigned int bits; - unsigned int col; - int srcskipleft = s->gr[0x2f] & 0x07; - int dstskipleft = srcskipleft * (DEPTH / 8); - - colors[0] = s->cirrus_blt_bgcol; - colors[1] = s->cirrus_blt_fgcol; - pattern_y = s->cirrus_blt_srcaddr & 7; - - for(y = 0; y < bltheight; y++) { - bits = src[pattern_y]; - bitpos = 7 - srcskipleft; - d = dst + dstskipleft; - for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) { - col = colors[(bits >> bitpos) & 1]; - PUTPIXEL(); - d += (DEPTH / 8); - bitpos = (bitpos - 1) & 7; - } - pattern_y = (pattern_y + 1) & 7; - dst += dstpitch; - } -} - -static void -glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH) - (CirrusVGAState *s, - uint8_t *dst, int dst_pitch, - int width, int height) -{ - uint8_t *d, *d1; - uint32_t col; - int x, y; - - col = s->cirrus_blt_fgcol; - - d1 = dst; - for(y = 0; y < height; y++) { - d = d1; - for(x = 0; x < width; x += (DEPTH / 8)) { - PUTPIXEL(); - d += (DEPTH / 8); - } - d1 += dst_pitch; - } -} - -#undef DEPTH -#undef PUTPIXEL diff --git a/hw/cuda.c b/hw/cuda.c deleted file mode 100644 index f3c2b56..0000000 --- a/hw/cuda.c +++ /dev/null @@ -1,656 +0,0 @@ -/* - * QEMU CUDA support - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* XXX: implement all timer modes */ - -//#define DEBUG_CUDA -//#define DEBUG_CUDA_PACKET - -/* Bits in B data register: all active low */ -#define TREQ 0x08 /* Transfer request (input) */ -#define TACK 0x10 /* Transfer acknowledge (output) */ -#define TIP 0x20 /* Transfer in progress (output) */ - -/* Bits in ACR */ -#define SR_CTRL 0x1c /* Shift register control bits */ -#define SR_EXT 0x0c /* Shift on external clock */ -#define SR_OUT 0x10 /* Shift out if 1 */ - -/* Bits in IFR and IER */ -#define IER_SET 0x80 /* set bits in IER */ -#define IER_CLR 0 /* clear bits in IER */ -#define SR_INT 0x04 /* Shift register full/empty */ -#define T1_INT 0x40 /* Timer 1 interrupt */ -#define T2_INT 0x20 /* Timer 2 interrupt */ - -/* Bits in ACR */ -#define T1MODE 0xc0 /* Timer 1 mode */ -#define T1MODE_CONT 0x40 /* continuous interrupts */ - -/* commands (1st byte) */ -#define ADB_PACKET 0 -#define CUDA_PACKET 1 -#define ERROR_PACKET 2 -#define TIMER_PACKET 3 -#define POWER_PACKET 4 -#define MACIIC_PACKET 5 -#define PMU_PACKET 6 - - -/* CUDA commands (2nd byte) */ -#define CUDA_WARM_START 0x0 -#define CUDA_AUTOPOLL 0x1 -#define CUDA_GET_6805_ADDR 0x2 -#define CUDA_GET_TIME 0x3 -#define CUDA_GET_PRAM 0x7 -#define CUDA_SET_6805_ADDR 0x8 -#define CUDA_SET_TIME 0x9 -#define CUDA_POWERDOWN 0xa -#define CUDA_POWERUP_TIME 0xb -#define CUDA_SET_PRAM 0xc -#define CUDA_MS_RESET 0xd -#define CUDA_SEND_DFAC 0xe -#define CUDA_BATTERY_SWAP_SENSE 0x10 -#define CUDA_RESET_SYSTEM 0x11 -#define CUDA_SET_IPL 0x12 -#define CUDA_FILE_SERVER_FLAG 0x13 -#define CUDA_SET_AUTO_RATE 0x14 -#define CUDA_GET_AUTO_RATE 0x16 -#define CUDA_SET_DEVICE_LIST 0x19 -#define CUDA_GET_DEVICE_LIST 0x1a -#define CUDA_SET_ONE_SECOND_MODE 0x1b -#define CUDA_SET_POWER_MESSAGES 0x21 -#define CUDA_GET_SET_IIC 0x22 -#define CUDA_WAKEUP 0x23 -#define CUDA_TIMER_TICKLE 0x24 -#define CUDA_COMBINED_FORMAT_IIC 0x25 - -#define CUDA_TIMER_FREQ (4700000 / 6) -#define CUDA_ADB_POLL_FREQ 50 - -/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */ -#define RTC_OFFSET 2082844800 - -typedef struct CUDATimer { - int index; - uint16_t latch; - uint16_t counter_value; /* counter value at load time */ - int64_t load_time; - int64_t next_irq_time; - QEMUTimer *timer; -} CUDATimer; - -typedef struct CUDAState { - /* cuda registers */ - uint8_t b; /* B-side data */ - uint8_t a; /* A-side data */ - uint8_t dirb; /* B-side direction (1=output) */ - uint8_t dira; /* A-side direction (1=output) */ - uint8_t sr; /* Shift register */ - uint8_t acr; /* Auxiliary control register */ - uint8_t pcr; /* Peripheral control register */ - uint8_t ifr; /* Interrupt flag register */ - uint8_t ier; /* Interrupt enable register */ - uint8_t anh; /* A-side data, no handshake */ - - CUDATimer timers[2]; - - uint8_t last_b; /* last value of B register */ - uint8_t last_acr; /* last value of B register */ - - int data_in_size; - int data_in_index; - int data_out_index; - - SetIRQFunc *set_irq; - int irq; - void *irq_opaque; - uint8_t autopoll; - uint8_t data_in[128]; - uint8_t data_out[16]; - QEMUTimer *adb_poll_timer; -} CUDAState; - -static CUDAState cuda_state; -ADBBusState adb_bus; - -static void cuda_update(CUDAState *s); -static void cuda_receive_packet_from_host(CUDAState *s, - const uint8_t *data, int len); -static void cuda_timer_update(CUDAState *s, CUDATimer *ti, - int64_t current_time); - -static void cuda_update_irq(CUDAState *s) -{ - if (s->ifr & s->ier & (SR_INT | T1_INT)) { - s->set_irq(s->irq_opaque, s->irq, 1); - } else { - s->set_irq(s->irq_opaque, s->irq, 0); - } -} - -static unsigned int get_counter(CUDATimer *s) -{ - int64_t d; - unsigned int counter; - - d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, - CUDA_TIMER_FREQ, ticks_per_sec); - if (s->index == 0) { - /* the timer goes down from latch to -1 (period of latch + 2) */ - if (d <= (s->counter_value + 1)) { - counter = (s->counter_value - d) & 0xffff; - } else { - counter = (d - (s->counter_value + 1)) % (s->latch + 2); - counter = (s->latch - counter) & 0xffff; - } - } else { - counter = (s->counter_value - d) & 0xffff; - } - return counter; -} - -static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) -{ -#ifdef DEBUG_CUDA - printf("cuda: T%d.counter=%d\n", - 1 + (ti->timer == NULL), val); -#endif - ti->load_time = qemu_get_clock(vm_clock); - ti->counter_value = val; - cuda_timer_update(s, ti, ti->load_time); -} - -static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) -{ - int64_t d, next_time; - unsigned int counter; - - /* current counter value */ - d = muldiv64(current_time - s->load_time, - CUDA_TIMER_FREQ, ticks_per_sec); - /* the timer goes down from latch to -1 (period of latch + 2) */ - if (d <= (s->counter_value + 1)) { - counter = (s->counter_value - d) & 0xffff; - } else { - counter = (d - (s->counter_value + 1)) % (s->latch + 2); - counter = (s->latch - counter) & 0xffff; - } - - /* Note: we consider the irq is raised on 0 */ - if (counter == 0xffff) { - next_time = d + s->latch + 1; - } else if (counter == 0) { - next_time = d + s->latch + 2; - } else { - next_time = d + counter; - } -#if 0 -#ifdef DEBUG_CUDA - printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", - s->latch, d, next_time - d); -#endif -#endif - next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + - s->load_time; - if (next_time <= current_time) - next_time = current_time + 1; - return next_time; -} - -static void cuda_timer_update(CUDAState *s, CUDATimer *ti, - int64_t current_time) -{ - if (!ti->timer) - return; - if ((s->acr & T1MODE) != T1MODE_CONT) { - qemu_del_timer(ti->timer); - } else { - ti->next_irq_time = get_next_irq_time(ti, current_time); - qemu_mod_timer(ti->timer, ti->next_irq_time); - } -} - -static void cuda_timer1(void *opaque) -{ - CUDAState *s = opaque; - CUDATimer *ti = &s->timers[0]; - - cuda_timer_update(s, ti, ti->next_irq_time); - s->ifr |= T1_INT; - cuda_update_irq(s); -} - -static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) -{ - CUDAState *s = opaque; - uint32_t val; - - addr = (addr >> 9) & 0xf; - switch(addr) { - case 0: - val = s->b; - break; - case 1: - val = s->a; - break; - case 2: - val = s->dirb; - break; - case 3: - val = s->dira; - break; - case 4: - val = get_counter(&s->timers[0]) & 0xff; - s->ifr &= ~T1_INT; - cuda_update_irq(s); - break; - case 5: - val = get_counter(&s->timers[0]) >> 8; - cuda_update_irq(s); - break; - case 6: - val = s->timers[0].latch & 0xff; - break; - case 7: - /* XXX: check this */ - val = (s->timers[0].latch >> 8) & 0xff; - break; - case 8: - val = get_counter(&s->timers[1]) & 0xff; - s->ifr &= ~T2_INT; - break; - case 9: - val = get_counter(&s->timers[1]) >> 8; - break; - case 10: - val = s->sr; - s->ifr &= ~SR_INT; - cuda_update_irq(s); - break; - case 11: - val = s->acr; - break; - case 12: - val = s->pcr; - break; - case 13: - val = s->ifr; - if (s->ifr & s->ier) - val |= 0x80; - break; - case 14: - val = s->ier | 0x80; - break; - default: - case 15: - val = s->anh; - break; - } -#ifdef DEBUG_CUDA - if (addr != 13 || val != 0) - printf("cuda: read: reg=0x%x val=%02x\n", addr, val); -#endif - return val; -} - -static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - CUDAState *s = opaque; - - addr = (addr >> 9) & 0xf; -#ifdef DEBUG_CUDA - printf("cuda: write: reg=0x%x val=%02x\n", addr, val); -#endif - - switch(addr) { - case 0: - s->b = val; - cuda_update(s); - break; - case 1: - s->a = val; - break; - case 2: - s->dirb = val; - break; - case 3: - s->dira = val; - break; - case 4: - s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; - cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); - break; - case 5: - s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); - s->ifr &= ~T1_INT; - set_counter(s, &s->timers[0], s->timers[0].latch); - break; - case 6: - s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; - cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); - break; - case 7: - s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); - s->ifr &= ~T1_INT; - cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); - break; - case 8: - s->timers[1].latch = val; - set_counter(s, &s->timers[1], val); - break; - case 9: - set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch); - break; - case 10: - s->sr = val; - break; - case 11: - s->acr = val; - cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); - cuda_update(s); - break; - case 12: - s->pcr = val; - break; - case 13: - /* reset bits */ - s->ifr &= ~val; - cuda_update_irq(s); - break; - case 14: - if (val & IER_SET) { - /* set bits */ - s->ier |= val & 0x7f; - } else { - /* reset bits */ - s->ier &= ~val; - } - cuda_update_irq(s); - break; - default: - case 15: - s->anh = val; - break; - } -} - -/* NOTE: TIP and TREQ are negated */ -static void cuda_update(CUDAState *s) -{ - int packet_received, len; - - packet_received = 0; - if (!(s->b & TIP)) { - /* transfer requested from host */ - - if (s->acr & SR_OUT) { - /* data output */ - if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { - if (s->data_out_index < sizeof(s->data_out)) { -#ifdef DEBUG_CUDA - printf("cuda: send: %02x\n", s->sr); -#endif - s->data_out[s->data_out_index++] = s->sr; - s->ifr |= SR_INT; - cuda_update_irq(s); - } - } - } else { - if (s->data_in_index < s->data_in_size) { - /* data input */ - if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { - s->sr = s->data_in[s->data_in_index++]; -#ifdef DEBUG_CUDA - printf("cuda: recv: %02x\n", s->sr); -#endif - /* indicate end of transfer */ - if (s->data_in_index >= s->data_in_size) { - s->b = (s->b | TREQ); - } - s->ifr |= SR_INT; - cuda_update_irq(s); - } - } - } - } else { - /* no transfer requested: handle sync case */ - if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) { - /* update TREQ state each time TACK change state */ - if (s->b & TACK) - s->b = (s->b | TREQ); - else - s->b = (s->b & ~TREQ); - s->ifr |= SR_INT; - cuda_update_irq(s); - } else { - if (!(s->last_b & TIP)) { - /* handle end of host to cuda transfert */ - packet_received = (s->data_out_index > 0); - /* always an IRQ at the end of transfert */ - s->ifr |= SR_INT; - cuda_update_irq(s); - } - /* signal if there is data to read */ - if (s->data_in_index < s->data_in_size) { - s->b = (s->b & ~TREQ); - } - } - } - - s->last_acr = s->acr; - s->last_b = s->b; - - /* NOTE: cuda_receive_packet_from_host() can call cuda_update() - recursively */ - if (packet_received) { - len = s->data_out_index; - s->data_out_index = 0; - cuda_receive_packet_from_host(s, s->data_out, len); - } -} - -static void cuda_send_packet_to_host(CUDAState *s, - const uint8_t *data, int len) -{ -#ifdef DEBUG_CUDA_PACKET - { - int i; - printf("cuda_send_packet_to_host:\n"); - for(i = 0; i < len; i++) - printf(" %02x", data[i]); - printf("\n"); - } -#endif - memcpy(s->data_in, data, len); - s->data_in_size = len; - s->data_in_index = 0; - cuda_update(s); - s->ifr |= SR_INT; - cuda_update_irq(s); -} - -static void cuda_adb_poll(void *opaque) -{ - CUDAState *s = opaque; - uint8_t obuf[ADB_MAX_OUT_LEN + 2]; - int olen; - - olen = adb_poll(&adb_bus, obuf + 2); - if (olen > 0) { - obuf[0] = ADB_PACKET; - obuf[1] = 0x40; /* polled data */ - cuda_send_packet_to_host(s, obuf, olen + 2); - } - qemu_mod_timer(s->adb_poll_timer, - qemu_get_clock(vm_clock) + - (ticks_per_sec / CUDA_ADB_POLL_FREQ)); -} - -static void cuda_receive_packet(CUDAState *s, - const uint8_t *data, int len) -{ - uint8_t obuf[16]; - int ti, autopoll; - - switch(data[0]) { - case CUDA_AUTOPOLL: - autopoll = (data[1] != 0); - if (autopoll != s->autopoll) { - s->autopoll = autopoll; - if (autopoll) { - qemu_mod_timer(s->adb_poll_timer, - qemu_get_clock(vm_clock) + - (ticks_per_sec / CUDA_ADB_POLL_FREQ)); - } else { - qemu_del_timer(s->adb_poll_timer); - } - } - obuf[0] = CUDA_PACKET; - obuf[1] = data[1]; - cuda_send_packet_to_host(s, obuf, 2); - break; - case CUDA_GET_TIME: - case CUDA_SET_TIME: - /* XXX: add time support ? */ - ti = time(NULL) + RTC_OFFSET; - obuf[0] = CUDA_PACKET; - obuf[1] = 0; - obuf[2] = 0; - obuf[3] = ti >> 24; - obuf[4] = ti >> 16; - obuf[5] = ti >> 8; - obuf[6] = ti; - cuda_send_packet_to_host(s, obuf, 7); - break; - case CUDA_FILE_SERVER_FLAG: - case CUDA_SET_DEVICE_LIST: - case CUDA_SET_AUTO_RATE: - case CUDA_SET_POWER_MESSAGES: - obuf[0] = CUDA_PACKET; - obuf[1] = 0; - cuda_send_packet_to_host(s, obuf, 2); - break; - case CUDA_POWERDOWN: - obuf[0] = CUDA_PACKET; - obuf[1] = 0; - cuda_send_packet_to_host(s, obuf, 2); - qemu_system_shutdown_request(); - break; - default: - break; - } -} - -static void cuda_receive_packet_from_host(CUDAState *s, - const uint8_t *data, int len) -{ -#ifdef DEBUG_CUDA_PACKET - { - int i; - printf("cuda_receive_packet_from_host:\n"); - for(i = 0; i < len; i++) - printf(" %02x", data[i]); - printf("\n"); - } -#endif - switch(data[0]) { - case ADB_PACKET: - { - uint8_t obuf[ADB_MAX_OUT_LEN + 2]; - int olen; - olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1); - if (olen > 0) { - obuf[0] = ADB_PACKET; - obuf[1] = 0x00; - } else { - /* error */ - obuf[0] = ADB_PACKET; - obuf[1] = -olen; - olen = 0; - } - cuda_send_packet_to_host(s, obuf, olen + 2); - } - break; - case CUDA_PACKET: - cuda_receive_packet(s, data + 1, len - 1); - break; - } -} - -static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -} - -static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -} - -static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr) -{ - return 0; -} - -static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr) -{ - return 0; -} - -static CPUWriteMemoryFunc *cuda_write[] = { - &cuda_writeb, - &cuda_writew, - &cuda_writel, -}; - -static CPUReadMemoryFunc *cuda_read[] = { - &cuda_readb, - &cuda_readw, - &cuda_readl, -}; - -int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq) -{ - CUDAState *s = &cuda_state; - int cuda_mem_index; - - s->set_irq = set_irq; - s->irq_opaque = irq_opaque; - s->irq = irq; - - s->timers[0].index = 0; - s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); - s->timers[0].latch = 0xffff; - set_counter(s, &s->timers[0], 0xffff); - - s->timers[1].index = 1; - s->timers[1].latch = 0; - // s->ier = T1_INT | SR_INT; - s->ier = 0; - set_counter(s, &s->timers[1], 0xffff); - - s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s); - cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s); - return cuda_mem_index; -} diff --git a/hw/es1370.c b/hw/es1370.c deleted file mode 100644 index 0d2d861..0000000 --- a/hw/es1370.c +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * QEMU ES1370 emulation - * - * Copyright (c) 2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* #define DEBUG_ES1370 */ -/* #define VERBOSE_ES1370 */ -#define SILENT_ES1370 - -#include "vl.h" - -/* Missing stuff: - SCTRL_P[12](END|ST)INC - SCTRL_P1SCTRLD - SCTRL_P2DACSEN - CTRL_DAC_SYNC - MIDI - non looped mode - surely more -*/ - -/* - Following macros and samplerate array were copied verbatim from - Linux kernel 2.4.30: drivers/sound/es1370.c - - Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch) -*/ - -/* Start blatant GPL violation */ - -#define ES1370_REG_CONTROL 0x00 -#define ES1370_REG_STATUS 0x04 -#define ES1370_REG_UART_DATA 0x08 -#define ES1370_REG_UART_STATUS 0x09 -#define ES1370_REG_UART_CONTROL 0x09 -#define ES1370_REG_UART_TEST 0x0a -#define ES1370_REG_MEMPAGE 0x0c -#define ES1370_REG_CODEC 0x10 -#define ES1370_REG_SERIAL_CONTROL 0x20 -#define ES1370_REG_DAC1_SCOUNT 0x24 -#define ES1370_REG_DAC2_SCOUNT 0x28 -#define ES1370_REG_ADC_SCOUNT 0x2c - -#define ES1370_REG_DAC1_FRAMEADR 0xc30 -#define ES1370_REG_DAC1_FRAMECNT 0xc34 -#define ES1370_REG_DAC2_FRAMEADR 0xc38 -#define ES1370_REG_DAC2_FRAMECNT 0xc3c -#define ES1370_REG_ADC_FRAMEADR 0xd30 -#define ES1370_REG_ADC_FRAMECNT 0xd34 -#define ES1370_REG_PHANTOM_FRAMEADR 0xd38 -#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c - -static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 }; - -#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2) -#define DAC2_DIVTOSR(x) (1411200/((x)+2)) - -#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */ -#define CTRL_XCTL1 0x40000000 /* electret mic bias */ -#define CTRL_OPEN 0x20000000 /* no function, can be read and written */ -#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */ -#define CTRL_SH_PCLKDIV 16 -#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */ -#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */ -#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */ -#define CTRL_SH_WTSRSEL 12 -#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */ -#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */ -#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = MPEG */ -#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */ -#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */ -#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */ -#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */ -#define CTRL_ADC_EN 0x00000010 /* enable ADC */ -#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */ -#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably at address 0x200) */ -#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */ -#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */ - -#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */ -#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in progress */ -#define STAT_CBUSY 0x00000200 /* 1 = codec busy */ -#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */ -#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */ -#define STAT_SH_VC 5 -#define STAT_MCCB 0x00000010 /* CCB int pending */ -#define STAT_UART 0x00000008 /* UART int pending */ -#define STAT_DAC1 0x00000004 /* DAC1 int pending */ -#define STAT_DAC2 0x00000002 /* DAC2 int pending */ -#define STAT_ADC 0x00000001 /* ADC int pending */ - -#define USTAT_RXINT 0x80 /* UART rx int pending */ -#define USTAT_TXINT 0x04 /* UART tx int pending */ -#define USTAT_TXRDY 0x02 /* UART tx ready */ -#define USTAT_RXRDY 0x01 /* UART rx ready */ - -#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */ -#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */ -#define UCTRL_ENA_TXINT 0x20 /* enable TX int */ -#define UCTRL_CNTRL 0x03 /* control field */ -#define UCTRL_CNTRL_SWR 0x03 /* software reset command */ - -#define SCTRL_P2ENDINC 0x00380000 /* */ -#define SCTRL_SH_P2ENDINC 19 -#define SCTRL_P2STINC 0x00070000 /* */ -#define SCTRL_SH_P2STINC 16 -#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */ -#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */ -#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */ -#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */ -#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */ -#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */ -#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */ -#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */ -#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */ -#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */ -#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */ -#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */ -#define SCTRL_R1FMT 0x00000030 /* format mask */ -#define SCTRL_SH_R1FMT 4 -#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */ -#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */ -#define SCTRL_P2FMT 0x0000000c /* format mask */ -#define SCTRL_SH_P2FMT 2 -#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */ -#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */ -#define SCTRL_P1FMT 0x00000003 /* format mask */ -#define SCTRL_SH_P1FMT 0 - -/* End blatant GPL violation */ - -#define NB_CHANNELS 3 -#define DAC1_CHANNEL 0 -#define DAC2_CHANNEL 1 -#define ADC_CHANNEL 2 - -#define IO_READ_PROTO(n) \ -static uint32_t n (void *opaque, uint32_t addr) -#define IO_WRITE_PROTO(n) \ -static void n (void *opaque, uint32_t addr, uint32_t val) - -static void es1370_dac1_callback (void *opaque, int free); -static void es1370_dac2_callback (void *opaque, int free); -static void es1370_adc_callback (void *opaque, int avail); - -#ifdef DEBUG_ES1370 - -#define ldebug(...) AUD_log ("es1370", __VA_ARGS__) - -static void print_ctl (uint32_t val) -{ - char buf[1024]; - - buf[0] = '\0'; -#define a(n) if (val & CTRL_##n) strcat (buf, " "#n) - a (ADC_STOP); - a (XCTL1); - a (OPEN); - a (MSFMTSEL); - a (M_SBB); - a (DAC_SYNC); - a (CCB_INTRM); - a (M_CB); - a (XCTL0); - a (BREQ); - a (DAC1_EN); - a (DAC2_EN); - a (ADC_EN); - a (UART_EN); - a (JYSTK_EN); - a (CDC_EN); - a (SERR_DIS); -#undef a - AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n", - (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV, - DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), - dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], - buf); -} - -static void print_sctl (uint32_t val) -{ - static const char *fmt_names[] = {"8M", "8S", "16M", "16S"}; - char buf[1024]; - - buf[0] = '\0'; - -#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n) -#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n) - b (R1LOOPSEL); - b (P2LOOPSEL); - b (P1LOOPSEL); - a (P2PAUSE); - a (P1PAUSE); - a (R1INTEN); - a (P2INTEN); - a (P1INTEN); - a (P1SCTRLD); - a (P2DACSEN); - if (buf[0]) { - strcat (buf, "\n "); - } - else { - buf[0] = ' '; - buf[1] = '\0'; - } -#undef b -#undef a - AUD_log ("es1370", - "%s" - "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n", - buf, - (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC, - (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC, - fmt_names [(val >> SCTRL_SH_R1FMT) & 3], - fmt_names [(val >> SCTRL_SH_P2FMT) & 3], - fmt_names [(val >> SCTRL_SH_P1FMT) & 3] - ); -} -#else -#define ldebug(...) -#define print_ctl(...) -#define print_sctl(...) -#endif - -#ifdef VERBOSE_ES1370 -#define dolog(...) AUD_log ("es1370", __VA_ARGS__) -#else -#define dolog(...) -#endif - -#ifndef SILENT_ES1370 -#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__) -#else -#define lwarn(...) -#endif - -struct chan { - uint32_t shift; - uint32_t leftover; - uint32_t scount; - uint32_t frame_addr; - uint32_t frame_cnt; -}; - -typedef struct ES1370State { - PCIDevice *pci_dev; - - QEMUSoundCard card; - struct chan chan[NB_CHANNELS]; - SWVoiceOut *dac_voice[2]; - SWVoiceIn *adc_voice; - - uint32_t ctl; - uint32_t status; - uint32_t mempage; - uint32_t codec; - uint32_t sctl; -} ES1370State; - -typedef struct PCIES1370State { - PCIDevice dev; - ES1370State es1370; -} PCIES1370State; - -struct chan_bits { - uint32_t ctl_en; - uint32_t stat_int; - uint32_t sctl_pause; - uint32_t sctl_inten; - uint32_t sctl_fmt; - uint32_t sctl_sh_fmt; - uint32_t sctl_loopsel; - void (*calc_freq) (ES1370State *s, uint32_t ctl, - uint32_t *old_freq, uint32_t *new_freq); -}; - -static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl, - uint32_t *old_freq, uint32_t *new_freq); -static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl, - uint32_t *old_freq, - uint32_t *new_freq); - -static const struct chan_bits es1370_chan_bits[] = { - {CTRL_DAC1_EN, STAT_DAC1, SCTRL_P1PAUSE, SCTRL_P1INTEN, - SCTRL_P1FMT, SCTRL_SH_P1FMT, SCTRL_P1LOOPSEL, - es1370_dac1_calc_freq}, - - {CTRL_DAC2_EN, STAT_DAC2, SCTRL_P2PAUSE, SCTRL_P2INTEN, - SCTRL_P2FMT, SCTRL_SH_P2FMT, SCTRL_P2LOOPSEL, - es1370_dac2_and_adc_calc_freq}, - - {CTRL_ADC_EN, STAT_ADC, 0, SCTRL_R1INTEN, - SCTRL_R1FMT, SCTRL_SH_R1FMT, SCTRL_R1LOOPSEL, - es1370_dac2_and_adc_calc_freq} -}; - -static void es1370_update_status (ES1370State *s, uint32_t new_status) -{ - uint32_t level = new_status & (STAT_DAC1 | STAT_DAC2 | STAT_ADC); - - if (level) { - s->status = new_status | STAT_INTR; - } - else { - s->status = new_status & ~STAT_INTR; - } - pci_set_irq (s->pci_dev, 0, !!level); -} - -static void es1370_reset (ES1370State *s) -{ - size_t i; - - s->ctl = 1; - s->status = 0x60; - s->mempage = 0; - s->codec = 0; - s->sctl = 0; - - for (i = 0; i < NB_CHANNELS; ++i) { - struct chan *d = &s->chan[i]; - d->scount = 0; - d->leftover = 0; - if (i == ADC_CHANNEL) { - AUD_close_in (&s->card, s->adc_voice); - s->adc_voice = NULL; - } - else { - AUD_close_out (&s->card, s->dac_voice[i]); - s->dac_voice[i] = NULL; - } - } - pci_set_irq (s->pci_dev, 0, 0); -} - -static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl) -{ - uint32_t new_status = s->status; - - if (!(sctl & SCTRL_P1INTEN) && (s->sctl & SCTRL_P1INTEN)) { - new_status &= ~STAT_DAC1; - } - - if (!(sctl & SCTRL_P2INTEN) && (s->sctl & SCTRL_P2INTEN)) { - new_status &= ~STAT_DAC2; - } - - if (!(sctl & SCTRL_R1INTEN) && (s->sctl & SCTRL_R1INTEN)) { - new_status &= ~STAT_ADC; - } - - if (new_status != s->status) { - es1370_update_status (s, new_status); - } -} - -static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl, - uint32_t *old_freq, uint32_t *new_freq) - -{ - *old_freq = dac1_samplerate[(s->ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; - *new_freq = dac1_samplerate[(ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; -} - -static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl, - uint32_t *old_freq, - uint32_t *new_freq) - -{ - uint32_t old_pclkdiv, new_pclkdiv; - - new_pclkdiv = (ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV; - old_pclkdiv = (s->ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV; - *new_freq = DAC2_DIVTOSR (new_pclkdiv); - *old_freq = DAC2_DIVTOSR (old_pclkdiv); -} - -static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) -{ - size_t i; - uint32_t old_freq, new_freq, old_fmt, new_fmt; - - for (i = 0; i < NB_CHANNELS; ++i) { - struct chan *d = &s->chan[i]; - const struct chan_bits *b = &es1370_chan_bits[i]; - - new_fmt = (sctl & b->sctl_fmt) >> b->sctl_sh_fmt; - old_fmt = (s->sctl & b->sctl_fmt) >> b->sctl_sh_fmt; - - b->calc_freq (s, ctl, &old_freq, &new_freq); - - if ((old_fmt != new_fmt) || (old_freq != new_freq)) { - d->shift = (new_fmt & 1) + (new_fmt >> 1); - ldebug ("channel %d, freq = %d, nchannels %d, fmt %d, shift %d\n", - i, - new_freq, - 1 << (new_fmt & 1), - (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8, - d->shift); - if (new_freq) { - audsettings_t as; - - as.freq = new_freq; - as.nchannels = 1 << (new_fmt & 1); - as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8; - as.endianness = 0; - - if (i == ADC_CHANNEL) { - s->adc_voice = - AUD_open_in ( - &s->card, - s->adc_voice, - "es1370.adc", - s, - es1370_adc_callback, - &as - ); - } - else { - s->dac_voice[i] = - AUD_open_out ( - &s->card, - s->dac_voice[i], - i ? "es1370.dac2" : "es1370.dac1", - s, - i ? es1370_dac2_callback : es1370_dac1_callback, - &as - ); - } - } - } - - if (((ctl ^ s->ctl) & b->ctl_en) - || ((sctl ^ s->sctl) & b->sctl_pause)) { - int on = (ctl & b->ctl_en) && !(sctl & b->sctl_pause); - - if (i == ADC_CHANNEL) { - AUD_set_active_in (s->adc_voice, on); - } - else { - AUD_set_active_out (s->dac_voice[i], on); - } - } - } - - s->ctl = ctl; - s->sctl = sctl; -} - -static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr) -{ - addr &= 0xff; - if (addr >= 0x30 && addr <= 0x3f) - addr |= s->mempage << 8; - return addr; -} - -IO_WRITE_PROTO (es1370_writeb) -{ - ES1370State *s = opaque; - uint32_t shift, mask; - - addr = es1370_fixup (s, addr); - - switch (addr) { - case ES1370_REG_CONTROL: - case ES1370_REG_CONTROL + 1: - case ES1370_REG_CONTROL + 2: - case ES1370_REG_CONTROL + 3: - shift = (addr - ES1370_REG_CONTROL) << 3; - mask = 0xff << shift; - val = (s->ctl & ~mask) | ((val & 0xff) << shift); - es1370_update_voices (s, val, s->sctl); - print_ctl (val); - break; - case ES1370_REG_MEMPAGE: - s->mempage = val; - break; - case ES1370_REG_SERIAL_CONTROL: - case ES1370_REG_SERIAL_CONTROL + 1: - case ES1370_REG_SERIAL_CONTROL + 2: - case ES1370_REG_SERIAL_CONTROL + 3: - shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3; - mask = 0xff << shift; - val = (s->sctl & ~mask) | ((val & 0xff) << shift); - es1370_maybe_lower_irq (s, val); - es1370_update_voices (s, s->ctl, val); - print_sctl (val); - break; - default: - lwarn ("writeb %#x <- %#x\n", addr, val); - break; - } -} - -IO_WRITE_PROTO (es1370_writew) -{ - ES1370State *s = opaque; - addr = es1370_fixup (s, addr); - uint32_t shift, mask; - struct chan *d = &s->chan[0]; - - switch (addr) { - case ES1370_REG_CODEC: - dolog ("ignored codec write address %#x, data %#x\n", - (val >> 8) & 0xff, val & 0xff); - s->codec = val; - break; - - case ES1370_REG_CONTROL: - case ES1370_REG_CONTROL + 2: - shift = (addr != ES1370_REG_CONTROL) << 4; - mask = 0xffff << shift; - val = (s->ctl & ~mask) | ((val & 0xffff) << shift); - es1370_update_voices (s, val, s->sctl); - print_ctl (val); - break; - - case ES1370_REG_ADC_SCOUNT: - d++; - case ES1370_REG_DAC2_SCOUNT: - d++; - case ES1370_REG_DAC1_SCOUNT: - d->scount = (d->scount & ~0xffff) | (val & 0xffff); - break; - - default: - lwarn ("writew %#x <- %#x\n", addr, val); - break; - } -} - -IO_WRITE_PROTO (es1370_writel) -{ - ES1370State *s = opaque; - struct chan *d = &s->chan[0]; - - addr = es1370_fixup (s, addr); - - switch (addr) { - case ES1370_REG_CONTROL: - es1370_update_voices (s, val, s->sctl); - print_ctl (val); - break; - - case ES1370_REG_MEMPAGE: - s->mempage = val & 0xf; - break; - - case ES1370_REG_SERIAL_CONTROL: - es1370_maybe_lower_irq (s, val); - es1370_update_voices (s, s->ctl, val); - print_sctl (val); - break; - - case ES1370_REG_ADC_SCOUNT: - d++; - case ES1370_REG_DAC2_SCOUNT: - d++; - case ES1370_REG_DAC1_SCOUNT: - d->scount = (val & 0xffff) | (d->scount & ~0xffff); - ldebug ("chan %d CURR_SAMP_CT %d, SAMP_CT %d\n", - d - &s->chan[0], val >> 16, (val & 0xffff)); - break; - - case ES1370_REG_ADC_FRAMEADR: - d++; - case ES1370_REG_DAC2_FRAMEADR: - d++; - case ES1370_REG_DAC1_FRAMEADR: - d->frame_addr = val; - ldebug ("chan %d frame address %#x\n", d - &s->chan[0], val); - break; - - case ES1370_REG_PHANTOM_FRAMECNT: - lwarn ("writing to phantom frame count %#x\n", val); - break; - case ES1370_REG_PHANTOM_FRAMEADR: - lwarn ("writing to phantom frame address %#x\n", val); - break; - - case ES1370_REG_ADC_FRAMECNT: - d++; - case ES1370_REG_DAC2_FRAMECNT: - d++; - case ES1370_REG_DAC1_FRAMECNT: - d->frame_cnt = val; - d->leftover = 0; - ldebug ("chan %d frame count %d, buffer size %d\n", - d - &s->chan[0], val >> 16, val & 0xffff); - break; - - default: - lwarn ("writel %#x <- %#x\n", addr, val); - break; - } -} - -IO_READ_PROTO (es1370_readb) -{ - ES1370State *s = opaque; - uint32_t val; - - addr = es1370_fixup (s, addr); - - switch (addr) { - case 0x1b: /* Legacy */ - lwarn ("Attempt to read from legacy register\n"); - val = 5; - break; - case ES1370_REG_MEMPAGE: - val = s->mempage; - break; - case ES1370_REG_CONTROL + 0: - case ES1370_REG_CONTROL + 1: - case ES1370_REG_CONTROL + 2: - case ES1370_REG_CONTROL + 3: - val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3); - break; - case ES1370_REG_STATUS + 0: - case ES1370_REG_STATUS + 1: - case ES1370_REG_STATUS + 2: - case ES1370_REG_STATUS + 3: - val = s->status >> ((addr - ES1370_REG_STATUS) << 3); - break; - default: - val = ~0; - lwarn ("readb %#x -> %#x\n", addr, val); - break; - } - return val; -} - -IO_READ_PROTO (es1370_readw) -{ - ES1370State *s = opaque; - struct chan *d = &s->chan[0]; - uint32_t val; - - addr = es1370_fixup (s, addr); - - switch (addr) { - case ES1370_REG_ADC_SCOUNT + 2: - d++; - case ES1370_REG_DAC2_SCOUNT + 2: - d++; - case ES1370_REG_DAC1_SCOUNT + 2: - val = d->scount >> 16; - break; - - case ES1370_REG_ADC_FRAMECNT: - d++; - case ES1370_REG_DAC2_FRAMECNT: - d++; - case ES1370_REG_DAC1_FRAMECNT: - val = d->frame_cnt & 0xffff; - break; - - case ES1370_REG_ADC_FRAMECNT + 2: - d++; - case ES1370_REG_DAC2_FRAMECNT + 2: - d++; - case ES1370_REG_DAC1_FRAMECNT + 2: - val = d->frame_cnt >> 16; - break; - - default: - val = ~0; - lwarn ("readw %#x -> %#x\n", addr, val); - break; - } - - return val; -} - -IO_READ_PROTO (es1370_readl) -{ - ES1370State *s = opaque; - uint32_t val; - struct chan *d = &s->chan[0]; - - addr = es1370_fixup (s, addr); - - switch (addr) { - case ES1370_REG_CONTROL: - val = s->ctl; - break; - case ES1370_REG_STATUS: - val = s->status; - break; - case ES1370_REG_MEMPAGE: - val = s->mempage; - break; - case ES1370_REG_CODEC: - val = s->codec; - break; - case ES1370_REG_SERIAL_CONTROL: - val = s->sctl; - break; - - case ES1370_REG_ADC_SCOUNT: - d++; - case ES1370_REG_DAC2_SCOUNT: - d++; - case ES1370_REG_DAC1_SCOUNT: - val = d->scount; -#ifdef DEBUG_ES1370 - { - uint32_t curr_count = d->scount >> 16; - uint32_t count = d->scount & 0xffff; - - curr_count <<= d->shift; - count <<= d->shift; - dolog ("read scount curr %d, total %d\n", curr_count, count); - } -#endif - break; - - case ES1370_REG_ADC_FRAMECNT: - d++; - case ES1370_REG_DAC2_FRAMECNT: - d++; - case ES1370_REG_DAC1_FRAMECNT: - val = d->frame_cnt; -#ifdef DEBUG_ES1370 - { - uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2; - uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2; - if (curr > size) - dolog ("read framecnt curr %d, size %d %d\n", curr, size, - curr > size); - } -#endif - break; - - case ES1370_REG_ADC_FRAMEADR: - d++; - case ES1370_REG_DAC2_FRAMEADR: - d++; - case ES1370_REG_DAC1_FRAMEADR: - val = d->frame_addr; - break; - - case ES1370_REG_PHANTOM_FRAMECNT: - val = ~0U; - lwarn ("reading from phantom frame count\n"); - break; - case ES1370_REG_PHANTOM_FRAMEADR: - val = ~0U; - lwarn ("reading from phantom frame address\n"); - break; - - default: - val = ~0U; - lwarn ("readl %#x -> %#x\n", addr, val); - break; - } - return val; -} - - -static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel, - int max, int *irq) -{ - uint8_t tmpbuf[4096]; - uint32_t addr = d->frame_addr; - int sc = d->scount & 0xffff; - int csc = d->scount >> 16; - int csc_bytes = (csc + 1) << d->shift; - int cnt = d->frame_cnt >> 16; - int size = d->frame_cnt & 0xffff; - int left = ((size - cnt + 1) << 2) + d->leftover; - int transfered = 0; - int temp = audio_MIN (max, audio_MIN (left, csc_bytes)); - int index = d - &s->chan[0]; - - addr += (cnt << 2) + d->leftover; - - if (index == ADC_CHANNEL) { - while (temp) { - int acquired, to_copy; - - to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); - acquired = AUD_read (s->adc_voice, tmpbuf, to_copy); - if (!acquired) - break; - - cpu_physical_memory_write (addr, tmpbuf, acquired); - - temp -= acquired; - addr += acquired; - transfered += acquired; - } - } - else { - SWVoiceOut *voice = s->dac_voice[index]; - - while (temp) { - int copied, to_copy; - - to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf)); - cpu_physical_memory_read (addr, tmpbuf, to_copy); - copied = AUD_write (voice, tmpbuf, to_copy); - if (!copied) - break; - temp -= copied; - addr += copied; - transfered += copied; - } - } - - if (csc_bytes == transfered) { - *irq = 1; - d->scount = sc | (sc << 16); - ldebug ("sc = %d, rate = %f\n", - (sc + 1) << d->shift, - (sc + 1) / (double) 44100); - } - else { - *irq = 0; - d->scount = sc | (((csc_bytes - transfered - 1) >> d->shift) << 16); - } - - cnt += (transfered + d->leftover) >> 2; - - if (s->sctl & loop_sel) { - /* Bah, how stupid is that having a 0 represent true value? - i just spent few hours on this shit */ - AUD_log ("es1370: warning", "non looping mode\n"); - } - else { - d->frame_cnt = size; - - if ((uint32_t) cnt <= d->frame_cnt) - d->frame_cnt |= cnt << 16; - } - - d->leftover = (transfered + d->leftover) & 3; -} - -static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail) -{ - uint32_t new_status = s->status; - int max_bytes, irq; - struct chan *d = &s->chan[chan]; - const struct chan_bits *b = &es1370_chan_bits[chan]; - - if (!(s->ctl & b->ctl_en) || (s->sctl & b->sctl_pause)) { - return; - } - - max_bytes = free_or_avail; - max_bytes &= ~((1 << d->shift) - 1); - if (!max_bytes) { - return; - } - - es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq); - - if (irq) { - if (s->sctl & b->sctl_inten) { - new_status |= b->stat_int; - } - } - - if (new_status != s->status) { - es1370_update_status (s, new_status); - } -} - -static void es1370_dac1_callback (void *opaque, int free) -{ - ES1370State *s = opaque; - - es1370_run_channel (s, DAC1_CHANNEL, free); -} - -static void es1370_dac2_callback (void *opaque, int free) -{ - ES1370State *s = opaque; - - es1370_run_channel (s, DAC2_CHANNEL, free); -} - -static void es1370_adc_callback (void *opaque, int avail) -{ - ES1370State *s = opaque; - - es1370_run_channel (s, ADC_CHANNEL, avail); -} - -static void es1370_map (PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - PCIES1370State *d = (PCIES1370State *) pci_dev; - ES1370State *s = &d->es1370; - - (void) region_num; - (void) size; - (void) type; - - register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s); - register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s); - register_ioport_write (addr, 0x40, 4, es1370_writel, s); - - register_ioport_read (addr, 0x40 * 4, 1, es1370_readb, s); - register_ioport_read (addr, 0x40 * 2, 2, es1370_readw, s); - register_ioport_read (addr, 0x40, 4, es1370_readl, s); -} - -static void es1370_save (QEMUFile *f, void *opaque) -{ - ES1370State *s = opaque; - size_t i; - - for (i = 0; i < NB_CHANNELS; ++i) { - struct chan *d = &s->chan[i]; - qemu_put_be32s (f, &d->shift); - qemu_put_be32s (f, &d->leftover); - qemu_put_be32s (f, &d->scount); - qemu_put_be32s (f, &d->frame_addr); - qemu_put_be32s (f, &d->frame_cnt); - } - qemu_put_be32s (f, &s->ctl); - qemu_put_be32s (f, &s->status); - qemu_put_be32s (f, &s->mempage); - qemu_put_be32s (f, &s->codec); - qemu_put_be32s (f, &s->sctl); -} - -static int es1370_load (QEMUFile *f, void *opaque, int version_id) -{ - uint32_t ctl, sctl; - ES1370State *s = opaque; - size_t i; - - if (version_id != 1) - return -EINVAL; - - for (i = 0; i < NB_CHANNELS; ++i) { - struct chan *d = &s->chan[i]; - qemu_get_be32s (f, &d->shift); - qemu_get_be32s (f, &d->leftover); - qemu_get_be32s (f, &d->scount); - qemu_get_be32s (f, &d->frame_addr); - qemu_get_be32s (f, &d->frame_cnt); - if (i == ADC_CHANNEL) { - if (s->adc_voice) { - AUD_close_in (&s->card, s->adc_voice); - s->adc_voice = NULL; - } - } - else { - if (s->dac_voice[i]) { - AUD_close_out (&s->card, s->dac_voice[i]); - s->dac_voice[i] = NULL; - } - } - } - - qemu_get_be32s (f, &ctl); - qemu_get_be32s (f, &s->status); - qemu_get_be32s (f, &s->mempage); - qemu_get_be32s (f, &s->codec); - qemu_get_be32s (f, &sctl); - - s->ctl = 0; - s->sctl = 0; - es1370_update_voices (s, ctl, sctl); - return 0; -} - -static void es1370_on_reset (void *opaque) -{ - ES1370State *s = opaque; - es1370_reset (s); -} - -int es1370_init (PCIBus *bus, AudioState *audio) -{ - PCIES1370State *d; - ES1370State *s; - uint8_t *c; - - if (!bus) { - dolog ("No PCI bus\n"); - return -1; - } - - if (!audio) { - dolog ("No audio state\n"); - return -1; - } - - d = (PCIES1370State *) pci_register_device (bus, "ES1370", - sizeof (PCIES1370State), - -1, NULL, NULL); - - if (!d) { - AUD_log (NULL, "Failed to register PCI device for ES1370\n"); - return -1; - } - - c = d->dev.config; - c[0x00] = 0x74; - c[0x01] = 0x12; - c[0x02] = 0x00; - c[0x03] = 0x50; - c[0x07] = 2 << 1; - c[0x0a] = 0x01; - c[0x0b] = 0x04; - -#if 1 - c[0x2c] = 0x42; - c[0x2d] = 0x49; - c[0x2e] = 0x4c; - c[0x2f] = 0x4c; -#else - c[0x2c] = 0x74; - c[0x2d] = 0x12; - c[0x2e] = 0x71; - c[0x2f] = 0x13; - c[0x34] = 0xdc; - c[0x3c] = 10; - c[0xdc] = 0x00; -#endif - - c[0x3d] = 1; - c[0x3e] = 0x0c; - c[0x3f] = 0x80; - - s = &d->es1370; - s->pci_dev = &d->dev; - - pci_register_io_region (&d->dev, 0, 256, PCI_ADDRESS_SPACE_IO, es1370_map); - register_savevm ("es1370", 0, 1, es1370_save, es1370_load, s); - qemu_register_reset (es1370_on_reset, s); - - AUD_register_card (audio, "es1370", &s->card); - es1370_reset (s); - return 0; -} diff --git a/hw/esp.c b/hw/esp.c deleted file mode 100644 index cdd062f..0000000 --- a/hw/esp.c +++ /dev/null @@ -1,571 +0,0 @@ -/* - * QEMU ESP emulation - * - * Copyright (c) 2005-2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* debug ESP card */ -//#define DEBUG_ESP - -#ifdef DEBUG_ESP -#define DPRINTF(fmt, args...) \ -do { printf("ESP: " fmt , ##args); } while (0) -#define pic_set_irq(irq, level) \ -do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0) -#else -#define DPRINTF(fmt, args...) -#endif - -#define ESPDMA_REGS 4 -#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) -#define ESP_MAXREG 0x3f -#define TI_BUFSZ 32 -#define DMA_VER 0xa0000000 -#define DMA_INTR 1 -#define DMA_INTREN 0x10 -#define DMA_WRITE_MEM 0x100 -#define DMA_LOADED 0x04000000 -typedef struct ESPState ESPState; - -struct ESPState { - BlockDriverState **bd; - uint8_t rregs[ESP_MAXREG]; - uint8_t wregs[ESP_MAXREG]; - int irq; - uint32_t espdmaregs[ESPDMA_REGS]; - uint32_t ti_size; - uint32_t ti_rptr, ti_wptr; - uint8_t ti_buf[TI_BUFSZ]; - int sense; - int dma; - SCSIDevice *scsi_dev[MAX_DISKS]; - SCSIDevice *current_dev; - uint8_t cmdbuf[TI_BUFSZ]; - int cmdlen; - int do_cmd; -}; - -#define STAT_DO 0x00 -#define STAT_DI 0x01 -#define STAT_CD 0x02 -#define STAT_ST 0x03 -#define STAT_MI 0x06 -#define STAT_MO 0x07 - -#define STAT_TC 0x10 -#define STAT_IN 0x80 - -#define INTR_FC 0x08 -#define INTR_BS 0x10 -#define INTR_DC 0x20 -#define INTR_RST 0x80 - -#define SEQ_0 0x0 -#define SEQ_CD 0x4 - -static int get_cmd(ESPState *s, uint8_t *buf) -{ - uint32_t dmaptr, dmalen; - int target; - - dmalen = s->wregs[0] | (s->wregs[1] << 8); - target = s->wregs[4] & 7; - DPRINTF("get_cmd: len %d target %d\n", dmalen, target); - if (s->dma) { - dmaptr = iommu_translate(s->espdmaregs[1]); - DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", - s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr); - cpu_physical_memory_read(dmaptr, buf, dmalen); - } else { - buf[0] = 0; - memcpy(&buf[1], s->ti_buf, dmalen); - dmalen++; - } - - s->ti_size = 0; - s->ti_rptr = 0; - s->ti_wptr = 0; - - if (target >= 4 || !s->scsi_dev[target]) { - // No such drive - s->rregs[4] = STAT_IN; - s->rregs[5] = INTR_DC; - s->rregs[6] = SEQ_0; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); - return 0; - } - s->current_dev = s->scsi_dev[target]; - return dmalen; -} - -static void do_cmd(ESPState *s, uint8_t *buf) -{ - int32_t datalen; - int lun; - - DPRINTF("do_cmd: busid 0x%x\n", buf[0]); - lun = buf[0] & 7; - datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun); - if (datalen == 0) { - s->ti_size = 0; - } else { - s->rregs[4] = STAT_IN | STAT_TC; - if (datalen > 0) { - s->rregs[4] |= STAT_DI; - s->ti_size = datalen; - } else { - s->rregs[4] |= STAT_DO; - s->ti_size = -datalen; - } - } - s->rregs[5] = INTR_BS | INTR_FC; - s->rregs[6] = SEQ_CD; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); -} - -static void handle_satn(ESPState *s) -{ - uint8_t buf[32]; - int len; - - len = get_cmd(s, buf); - if (len) - do_cmd(s, buf); -} - -static void handle_satn_stop(ESPState *s) -{ - s->cmdlen = get_cmd(s, s->cmdbuf); - if (s->cmdlen) { - DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen); - s->do_cmd = 1; - s->espdmaregs[1] += s->cmdlen; - s->rregs[4] = STAT_IN | STAT_TC | STAT_CD; - s->rregs[5] = INTR_BS | INTR_FC; - s->rregs[6] = SEQ_CD; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); - } -} - -static void write_response(ESPState *s) -{ - uint32_t dmaptr; - - DPRINTF("Transfer status (sense=%d)\n", s->sense); - s->ti_buf[0] = s->sense; - s->ti_buf[1] = 0; - if (s->dma) { - dmaptr = iommu_translate(s->espdmaregs[1]); - DPRINTF("DMA Direction: %c\n", - s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); - cpu_physical_memory_write(dmaptr, s->ti_buf, 2); - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - s->rregs[5] = INTR_BS | INTR_FC; - s->rregs[6] = SEQ_CD; - } else { - s->ti_size = 2; - s->ti_rptr = 0; - s->ti_wptr = 0; - s->rregs[7] = 2; - } - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); - -} - -static void esp_command_complete(void *opaque, uint32_t tag, int sense) -{ - ESPState *s = (ESPState *)opaque; - - DPRINTF("SCSI Command complete\n"); - if (s->ti_size != 0) - DPRINTF("SCSI command completed unexpectedly\n"); - s->ti_size = 0; - if (sense) - DPRINTF("Command failed\n"); - s->sense = sense; - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; -} - -static void handle_ti(ESPState *s) -{ - uint32_t dmaptr, dmalen, minlen, len, from, to; - unsigned int i; - int to_device; - uint8_t buf[TARGET_PAGE_SIZE]; - - dmalen = s->wregs[0] | (s->wregs[1] << 8); - if (dmalen==0) { - dmalen=0x10000; - } - - if (s->do_cmd) - minlen = (dmalen < 32) ? dmalen : 32; - else - minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; - DPRINTF("Transfer Information len %d\n", minlen); - if (s->dma) { - dmaptr = iommu_translate(s->espdmaregs[1]); - /* Check if the transfer writes to to reads from the device. */ - to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; - DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n", - to_device ? 'r': 'w', dmaptr, s->ti_size); - from = s->espdmaregs[1]; - to = from + minlen; - for (i = 0; i < minlen; i += len, from += len) { - dmaptr = iommu_translate(s->espdmaregs[1] + i); - if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { - len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); - } else { - len = to - from; - } - DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to); - s->ti_size -= len; - if (s->do_cmd) { - DPRINTF("command len %d + %d\n", s->cmdlen, len); - cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len); - s->ti_size = 0; - s->cmdlen = 0; - s->do_cmd = 0; - do_cmd(s, s->cmdbuf); - return; - } else { - if (to_device) { - cpu_physical_memory_read(dmaptr, buf, len); - scsi_write_data(s->current_dev, buf, len); - } else { - scsi_read_data(s->current_dev, buf, len); - cpu_physical_memory_write(dmaptr, buf, len); - } - } - } - if (s->ti_size) { - s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI); - } - s->rregs[5] = INTR_BS; - s->rregs[6] = 0; - s->rregs[7] = 0; - s->espdmaregs[0] |= DMA_INTR; - } else if (s->do_cmd) { - DPRINTF("command len %d\n", s->cmdlen); - s->ti_size = 0; - s->cmdlen = 0; - s->do_cmd = 0; - do_cmd(s, s->cmdbuf); - return; - } - pic_set_irq(s->irq, 1); -} - -static void esp_reset(void *opaque) -{ - ESPState *s = opaque; - memset(s->rregs, 0, ESP_MAXREG); - memset(s->wregs, 0, ESP_MAXREG); - s->rregs[0x0e] = 0x4; // Indicate fas100a - memset(s->espdmaregs, 0, ESPDMA_REGS * 4); - s->ti_size = 0; - s->ti_rptr = 0; - s->ti_wptr = 0; - s->dma = 0; - s->do_cmd = 0; -} - -static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) -{ - ESPState *s = opaque; - uint32_t saddr; - - saddr = (addr & ESP_MAXREG) >> 2; - DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); - switch (saddr) { - case 2: - // FIFO - if (s->ti_size > 0) { - s->ti_size--; - if ((s->rregs[4] & 6) == 0) { - /* Data in/out. */ - scsi_read_data(s->current_dev, &s->rregs[2], 0); - } else { - s->rregs[2] = s->ti_buf[s->ti_rptr++]; - } - pic_set_irq(s->irq, 1); - } - if (s->ti_size == 0) { - s->ti_rptr = 0; - s->ti_wptr = 0; - } - break; - case 5: - // interrupt - // Clear status bits except TC - s->rregs[4] &= STAT_TC; - pic_set_irq(s->irq, 0); - s->espdmaregs[0] &= ~DMA_INTR; - break; - default: - break; - } - return s->rregs[saddr]; -} - -static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - ESPState *s = opaque; - uint32_t saddr; - - saddr = (addr & ESP_MAXREG) >> 2; - DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); - switch (saddr) { - case 0: - case 1: - s->rregs[saddr] = val; - break; - case 2: - // FIFO - if (s->do_cmd) { - s->cmdbuf[s->cmdlen++] = val & 0xff; - } else if ((s->rregs[4] & 6) == 0) { - uint8_t buf; - buf = val & 0xff; - s->ti_size--; - scsi_write_data(s->current_dev, &buf, 0); - } else { - s->ti_size++; - s->ti_buf[s->ti_wptr++] = val & 0xff; - } - break; - case 3: - s->rregs[saddr] = val; - // Command - if (val & 0x80) { - s->dma = 1; - } else { - s->dma = 0; - } - switch(val & 0x7f) { - case 0: - DPRINTF("NOP (%2.2x)\n", val); - break; - case 1: - DPRINTF("Flush FIFO (%2.2x)\n", val); - //s->ti_size = 0; - s->rregs[5] = INTR_FC; - s->rregs[6] = 0; - break; - case 2: - DPRINTF("Chip reset (%2.2x)\n", val); - esp_reset(s); - break; - case 3: - DPRINTF("Bus reset (%2.2x)\n", val); - s->rregs[5] = INTR_RST; - if (!(s->wregs[8] & 0x40)) { - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); - } - break; - case 0x10: - handle_ti(s); - break; - case 0x11: - DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); - write_response(s); - break; - case 0x12: - DPRINTF("Message Accepted (%2.2x)\n", val); - write_response(s); - s->rregs[5] = INTR_DC; - s->rregs[6] = 0; - break; - case 0x1a: - DPRINTF("Set ATN (%2.2x)\n", val); - break; - case 0x42: - DPRINTF("Set ATN (%2.2x)\n", val); - handle_satn(s); - break; - case 0x43: - DPRINTF("Set ATN & stop (%2.2x)\n", val); - handle_satn_stop(s); - break; - default: - DPRINTF("Unhandled ESP command (%2.2x)\n", val); - break; - } - break; - case 4 ... 7: - break; - case 8: - s->rregs[saddr] = val; - break; - case 9 ... 10: - break; - case 11: - s->rregs[saddr] = val & 0x15; - break; - case 12 ... 15: - s->rregs[saddr] = val; - break; - default: - break; - } - s->wregs[saddr] = val; -} - -static CPUReadMemoryFunc *esp_mem_read[3] = { - esp_mem_readb, - esp_mem_readb, - esp_mem_readb, -}; - -static CPUWriteMemoryFunc *esp_mem_write[3] = { - esp_mem_writeb, - esp_mem_writeb, - esp_mem_writeb, -}; - -static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr) -{ - ESPState *s = opaque; - uint32_t saddr; - - saddr = (addr & ESPDMA_MAXADDR) >> 2; - DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]); - - return s->espdmaregs[saddr]; -} - -static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - ESPState *s = opaque; - uint32_t saddr; - - saddr = (addr & ESPDMA_MAXADDR) >> 2; - DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val); - switch (saddr) { - case 0: - if (!(val & DMA_INTREN)) - pic_set_irq(s->irq, 0); - if (val & 0x80) { - esp_reset(s); - } else if (val & 0x40) { - val &= ~0x40; - } else if (val == 0) - val = 0x40; - val &= 0x0fffffff; - val |= DMA_VER; - break; - case 1: - s->espdmaregs[0] |= DMA_LOADED; - break; - default: - break; - } - s->espdmaregs[saddr] = val; -} - -static CPUReadMemoryFunc *espdma_mem_read[3] = { - espdma_mem_readl, - espdma_mem_readl, - espdma_mem_readl, -}; - -static CPUWriteMemoryFunc *espdma_mem_write[3] = { - espdma_mem_writel, - espdma_mem_writel, - espdma_mem_writel, -}; - -static void esp_save(QEMUFile *f, void *opaque) -{ - ESPState *s = opaque; - unsigned int i; - - qemu_put_buffer(f, s->rregs, ESP_MAXREG); - qemu_put_buffer(f, s->wregs, ESP_MAXREG); - qemu_put_be32s(f, &s->irq); - for (i = 0; i < ESPDMA_REGS; i++) - qemu_put_be32s(f, &s->espdmaregs[i]); - qemu_put_be32s(f, &s->ti_size); - qemu_put_be32s(f, &s->ti_rptr); - qemu_put_be32s(f, &s->ti_wptr); - qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); - qemu_put_be32s(f, &s->dma); -} - -static int esp_load(QEMUFile *f, void *opaque, int version_id) -{ - ESPState *s = opaque; - unsigned int i; - - if (version_id != 1) - return -EINVAL; - - qemu_get_buffer(f, s->rregs, ESP_MAXREG); - qemu_get_buffer(f, s->wregs, ESP_MAXREG); - qemu_get_be32s(f, &s->irq); - for (i = 0; i < ESPDMA_REGS; i++) - qemu_get_be32s(f, &s->espdmaregs[i]); - qemu_get_be32s(f, &s->ti_size); - qemu_get_be32s(f, &s->ti_rptr); - qemu_get_be32s(f, &s->ti_wptr); - qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); - qemu_get_be32s(f, &s->dma); - - return 0; -} - -void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr) -{ - ESPState *s; - int esp_io_memory, espdma_io_memory; - int i; - - s = qemu_mallocz(sizeof(ESPState)); - if (!s) - return; - - s->bd = bd; - s->irq = irq; - - esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s); - cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory); - - espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s); - cpu_register_physical_memory(espdaddr, 16, espdma_io_memory); - - esp_reset(s); - - register_savevm("esp", espaddr, 1, esp_save, esp_load, s); - qemu_register_reset(esp_reset, s); - for (i = 0; i < MAX_DISKS; i++) { - if (bs_table[i]) { - s->scsi_dev[i] = - scsi_disk_init(bs_table[i], esp_command_complete, s); - } - } -} - diff --git a/hw/fdc.c b/hw/fdc.c deleted file mode 100644 index 3890ace..0000000 --- a/hw/fdc.c +++ /dev/null @@ -1,1757 +0,0 @@ -/* - * QEMU Floppy disk emulator (Intel 82078) - * - * Copyright (c) 2003 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -/* - * The controller is used in Sun4m systems in a slightly different - * way. There are changes in DOR register and DMA is not available. - */ -#include "vl.h" - -/********************************************************/ -/* debug Floppy devices */ -//#define DEBUG_FLOPPY - -#ifdef DEBUG_FLOPPY -#define FLOPPY_DPRINTF(fmt, args...) \ -do { printf("FLOPPY: " fmt , ##args); } while (0) -#else -#define FLOPPY_DPRINTF(fmt, args...) -#endif - -#define FLOPPY_ERROR(fmt, args...) \ -do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0) - -/********************************************************/ -/* Floppy drive emulation */ - -/* Will always be a fixed parameter for us */ -#define FD_SECTOR_LEN 512 -#define FD_SECTOR_SC 2 /* Sector size code */ - -/* Floppy disk drive emulation */ -typedef enum fdisk_type_t { - FDRIVE_DISK_288 = 0x01, /* 2.88 MB disk */ - FDRIVE_DISK_144 = 0x02, /* 1.44 MB disk */ - FDRIVE_DISK_720 = 0x03, /* 720 kB disk */ - FDRIVE_DISK_USER = 0x04, /* User defined geometry */ - FDRIVE_DISK_NONE = 0x05, /* No disk */ -} fdisk_type_t; - -typedef enum fdrive_type_t { - FDRIVE_DRV_144 = 0x00, /* 1.44 MB 3"5 drive */ - FDRIVE_DRV_288 = 0x01, /* 2.88 MB 3"5 drive */ - FDRIVE_DRV_120 = 0x02, /* 1.2 MB 5"25 drive */ - FDRIVE_DRV_NONE = 0x03, /* No drive connected */ -} fdrive_type_t; - -typedef enum fdrive_flags_t { - FDRIVE_MOTOR_ON = 0x01, /* motor on/off */ - FDRIVE_REVALIDATE = 0x02, /* Revalidated */ -} fdrive_flags_t; - -typedef enum fdisk_flags_t { - FDISK_DBL_SIDES = 0x01, -} fdisk_flags_t; - -typedef struct fdrive_t { - BlockDriverState *bs; - /* Drive status */ - fdrive_type_t drive; - fdrive_flags_t drflags; - uint8_t perpendicular; /* 2.88 MB access mode */ - /* Position */ - uint8_t head; - uint8_t track; - uint8_t sect; - /* Last operation status */ - uint8_t dir; /* Direction */ - uint8_t rw; /* Read/write */ - /* Media */ - fdisk_flags_t flags; - uint8_t last_sect; /* Nb sector per track */ - uint8_t max_track; /* Nb of tracks */ - uint16_t bps; /* Bytes per sector */ - uint8_t ro; /* Is read-only */ -} fdrive_t; - -static void fd_init (fdrive_t *drv, BlockDriverState *bs) -{ - /* Drive */ - drv->bs = bs; - drv->drive = FDRIVE_DRV_NONE; - drv->drflags = 0; - drv->perpendicular = 0; - /* Disk */ - drv->last_sect = 0; - drv->max_track = 0; -} - -static int _fd_sector (uint8_t head, uint8_t track, - uint8_t sect, uint8_t last_sect) -{ - return (((track * 2) + head) * last_sect) + sect - 1; -} - -/* Returns current position, in sectors, for given drive */ -static int fd_sector (fdrive_t *drv) -{ - return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect); -} - -static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect, - int enable_seek) -{ - uint32_t sector; - int ret; - - if (track > drv->max_track || - (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) { - FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n", - head, track, sect, 1, - (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1, - drv->max_track, drv->last_sect); - return 2; - } - if (sect > drv->last_sect) { - FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n", - head, track, sect, 1, - (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1, - drv->max_track, drv->last_sect); - return 3; - } - sector = _fd_sector(head, track, sect, drv->last_sect); - ret = 0; - if (sector != fd_sector(drv)) { -#if 0 - if (!enable_seek) { - FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n", - head, track, sect, 1, drv->max_track, drv->last_sect); - return 4; - } -#endif - drv->head = head; - if (drv->track != track) - ret = 1; - drv->track = track; - drv->sect = sect; - } - - return ret; -} - -/* Set drive back to track 0 */ -static void fd_recalibrate (fdrive_t *drv) -{ - FLOPPY_DPRINTF("recalibrate\n"); - drv->head = 0; - drv->track = 0; - drv->sect = 1; - drv->dir = 1; - drv->rw = 0; -} - -/* Recognize floppy formats */ -typedef struct fd_format_t { - fdrive_type_t drive; - fdisk_type_t disk; - uint8_t last_sect; - uint8_t max_track; - uint8_t max_head; - const unsigned char *str; -} fd_format_t; - -static fd_format_t fd_formats[] = { - /* First entry is default format */ - /* 1.44 MB 3"1/2 floppy disks */ - { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1, "1.6 MB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", }, - /* 2.88 MB 3"1/2 floppy disks */ - { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", }, - { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", }, - { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1, "3.2 MB 3\"1/2", }, - { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", }, - { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", }, - /* 720 kB 3"1/2 floppy disks */ - { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 1, "720 kB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1, "800 kB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1, "820 kB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1, "830 kB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", }, - { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", }, - /* 1.2 MB 5"1/4 floppy disks */ - { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1, "1.2 kB 5\"1/4", }, - { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", }, - { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", }, - { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", }, - { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1, "1.6 MB 5\"1/4", }, - /* 720 kB 5"1/4 floppy disks */ - { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 80, 1, "720 kB 5\"1/4", }, - { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1, "880 kB 5\"1/4", }, - /* 360 kB 5"1/4 floppy disks */ - { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 1, "360 kB 5\"1/4", }, - { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", }, - { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", }, - { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", }, - /* 320 kB 5"1/4 floppy disks */ - { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", }, - { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", }, - /* 360 kB must match 5"1/4 better than 3"1/2... */ - { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 0, "360 kB 3\"1/2", }, - /* end */ - { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, }, -}; - -/* Revalidate a disk drive after a disk change */ -static void fd_revalidate (fdrive_t *drv) -{ - fd_format_t *parse; - int64_t nb_sectors, size; - int i, first_match, match; - int nb_heads, max_track, last_sect, ro; - - FLOPPY_DPRINTF("revalidate\n"); - drv->drflags &= ~FDRIVE_REVALIDATE; - if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) { - ro = bdrv_is_read_only(drv->bs); - bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect); - if (nb_heads != 0 && max_track != 0 && last_sect != 0) { - FLOPPY_DPRINTF("User defined disk (%d %d %d)", - nb_heads - 1, max_track, last_sect); - } else { - bdrv_get_geometry(drv->bs, &nb_sectors); - match = -1; - first_match = -1; - for (i = 0;; i++) { - parse = &fd_formats[i]; - if (parse->drive == FDRIVE_DRV_NONE) - break; - if (drv->drive == parse->drive || - drv->drive == FDRIVE_DRV_NONE) { - size = (parse->max_head + 1) * parse->max_track * - parse->last_sect; - if (nb_sectors == size) { - match = i; - break; - } - if (first_match == -1) - first_match = i; - } - } - if (match == -1) { - if (first_match == -1) - match = 1; - else - match = first_match; - parse = &fd_formats[match]; - } - nb_heads = parse->max_head + 1; - max_track = parse->max_track; - last_sect = parse->last_sect; - drv->drive = parse->drive; - FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str, - nb_heads, max_track, last_sect, ro ? "ro" : "rw"); - } - if (nb_heads == 1) { - drv->flags &= ~FDISK_DBL_SIDES; - } else { - drv->flags |= FDISK_DBL_SIDES; - } - drv->max_track = max_track; - drv->last_sect = last_sect; - drv->ro = ro; - } else { - FLOPPY_DPRINTF("No disk in drive\n"); - drv->last_sect = 0; - drv->max_track = 0; - drv->flags &= ~FDISK_DBL_SIDES; - } - drv->drflags |= FDRIVE_REVALIDATE; -} - -/* Motor control */ -static void fd_start (fdrive_t *drv) -{ - drv->drflags |= FDRIVE_MOTOR_ON; -} - -static void fd_stop (fdrive_t *drv) -{ - drv->drflags &= ~FDRIVE_MOTOR_ON; -} - -/* Re-initialise a drives (motor off, repositioned) */ -static void fd_reset (fdrive_t *drv) -{ - fd_stop(drv); - fd_recalibrate(drv); -} - -/********************************************************/ -/* Intel 82078 floppy disk controller emulation */ - -static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq); -static void fdctrl_reset_fifo (fdctrl_t *fdctrl); -static int fdctrl_transfer_handler (void *opaque, int nchan, - int dma_pos, int dma_len); -static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status); -static void fdctrl_result_timer(void *opaque); - -static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl); -static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl); -static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value); -static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl); -static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value); -static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl); -static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value); -static uint32_t fdctrl_read_data (fdctrl_t *fdctrl); -static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value); -static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl); - -enum { - FD_CTRL_ACTIVE = 0x01, /* XXX: suppress that */ - FD_CTRL_RESET = 0x02, - FD_CTRL_SLEEP = 0x04, /* XXX: suppress that */ - FD_CTRL_BUSY = 0x08, /* dma transfer in progress */ - FD_CTRL_INTR = 0x10, -}; - -enum { - FD_DIR_WRITE = 0, - FD_DIR_READ = 1, - FD_DIR_SCANE = 2, - FD_DIR_SCANL = 3, - FD_DIR_SCANH = 4, -}; - -enum { - FD_STATE_CMD = 0x00, - FD_STATE_STATUS = 0x01, - FD_STATE_DATA = 0x02, - FD_STATE_STATE = 0x03, - FD_STATE_MULTI = 0x10, - FD_STATE_SEEK = 0x20, - FD_STATE_FORMAT = 0x40, -}; - -#define FD_STATE(state) ((state) & FD_STATE_STATE) -#define FD_SET_STATE(state, new_state) \ -do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0) -#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI) -#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK) -#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT) - -struct fdctrl_t { - fdctrl_t *fdctrl; - /* Controller's identification */ - uint8_t version; - /* HW */ - int irq_lvl; - int dma_chann; - uint32_t io_base; - /* Controller state */ - QEMUTimer *result_timer; - uint8_t state; - uint8_t dma_en; - uint8_t cur_drv; - uint8_t bootsel; - /* Command FIFO */ - uint8_t fifo[FD_SECTOR_LEN]; - uint32_t data_pos; - uint32_t data_len; - uint8_t data_state; - uint8_t data_dir; - uint8_t int_status; - uint8_t eot; /* last wanted sector */ - /* States kept only to be returned back */ - /* Timers state */ - uint8_t timer0; - uint8_t timer1; - /* precompensation */ - uint8_t precomp_trk; - uint8_t config; - uint8_t lock; - /* Power down config (also with status regB access mode */ - uint8_t pwrd; - /* Floppy drives */ - fdrive_t drives[2]; -}; - -static uint32_t fdctrl_read (void *opaque, uint32_t reg) -{ - fdctrl_t *fdctrl = opaque; - uint32_t retval; - - switch (reg & 0x07) { -#ifdef TARGET_SPARC - case 0x00: - // Identify to Linux as S82078B - retval = fdctrl_read_statusB(fdctrl); - break; -#endif - case 0x01: - retval = fdctrl_read_statusB(fdctrl); - break; - case 0x02: - retval = fdctrl_read_dor(fdctrl); - break; - case 0x03: - retval = fdctrl_read_tape(fdctrl); - break; - case 0x04: - retval = fdctrl_read_main_status(fdctrl); - break; - case 0x05: - retval = fdctrl_read_data(fdctrl); - break; - case 0x07: - retval = fdctrl_read_dir(fdctrl); - break; - default: - retval = (uint32_t)(-1); - break; - } - FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval); - - return retval; -} - -static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value) -{ - fdctrl_t *fdctrl = opaque; - - FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value); - - switch (reg & 0x07) { - case 0x02: - fdctrl_write_dor(fdctrl, value); - break; - case 0x03: - fdctrl_write_tape(fdctrl, value); - break; - case 0x04: - fdctrl_write_rate(fdctrl, value); - break; - case 0x05: - fdctrl_write_data(fdctrl, value); - break; - default: - break; - } -} - -static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg) -{ - return fdctrl_read(opaque, reg); -} - -static void fdctrl_write_mem (void *opaque, - target_phys_addr_t reg, uint32_t value) -{ - fdctrl_write(opaque, reg, value); -} - -static CPUReadMemoryFunc *fdctrl_mem_read[3] = { - fdctrl_read_mem, - fdctrl_read_mem, - fdctrl_read_mem, -}; - -static CPUWriteMemoryFunc *fdctrl_mem_write[3] = { - fdctrl_write_mem, - fdctrl_write_mem, - fdctrl_write_mem, -}; - -static void fd_change_cb (void *opaque) -{ - fdrive_t *drv = opaque; - - FLOPPY_DPRINTF("disk change\n"); - fd_revalidate(drv); -#if 0 - fd_recalibrate(drv); - fdctrl_reset_fifo(drv->fdctrl); - fdctrl_raise_irq(drv->fdctrl, 0x20); -#endif -} - -fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, - uint32_t io_base, - BlockDriverState **fds) -{ - fdctrl_t *fdctrl; - int io_mem; - int i; - - FLOPPY_DPRINTF("init controller\n"); - fdctrl = qemu_mallocz(sizeof(fdctrl_t)); - if (!fdctrl) - return NULL; - fdctrl->result_timer = qemu_new_timer(vm_clock, - fdctrl_result_timer, fdctrl); - - fdctrl->version = 0x90; /* Intel 82078 controller */ - fdctrl->irq_lvl = irq_lvl; - fdctrl->dma_chann = dma_chann; - fdctrl->io_base = io_base; - fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */ - if (fdctrl->dma_chann != -1) { - fdctrl->dma_en = 1; - DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl); - } else { - fdctrl->dma_en = 0; - } - for (i = 0; i < 2; i++) { - fd_init(&fdctrl->drives[i], fds[i]); - if (fds[i]) { - bdrv_set_change_cb(fds[i], - &fd_change_cb, &fdctrl->drives[i]); - } - } - fdctrl_reset(fdctrl, 0); - fdctrl->state = FD_CTRL_ACTIVE; - if (mem_mapped) { - io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl); - cpu_register_physical_memory(io_base, 0x08, io_mem); - } else { - register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl); - register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl); - register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl); - register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl); - } - for (i = 0; i < 2; i++) { - fd_revalidate(&fdctrl->drives[i]); - } - - return fdctrl; -} - -/* XXX: may change if moved to bdrv */ -int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num) -{ - return fdctrl->drives[drive_num].drive; -} - -/* Change IRQ state */ -static void fdctrl_reset_irq (fdctrl_t *fdctrl) -{ - FLOPPY_DPRINTF("Reset interrupt\n"); - pic_set_irq(fdctrl->irq_lvl, 0); - fdctrl->state &= ~FD_CTRL_INTR; -} - -static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status) -{ -#ifdef TARGET_SPARC - // Sparc mutation - if (!fdctrl->dma_en) { - fdctrl->state &= ~FD_CTRL_BUSY; - fdctrl->int_status = status; - return; - } -#endif - if (~(fdctrl->state & FD_CTRL_INTR)) { - pic_set_irq(fdctrl->irq_lvl, 1); - fdctrl->state |= FD_CTRL_INTR; - } - FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status); - fdctrl->int_status = status; -} - -/* Reset controller */ -static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq) -{ - int i; - - FLOPPY_DPRINTF("reset controller\n"); - fdctrl_reset_irq(fdctrl); - /* Initialise controller */ - fdctrl->cur_drv = 0; - /* FIFO state */ - fdctrl->data_pos = 0; - fdctrl->data_len = 0; - fdctrl->data_state = FD_STATE_CMD; - fdctrl->data_dir = FD_DIR_WRITE; - for (i = 0; i < MAX_FD; i++) - fd_reset(&fdctrl->drives[i]); - fdctrl_reset_fifo(fdctrl); - if (do_irq) - fdctrl_raise_irq(fdctrl, 0xc0); -} - -static inline fdrive_t *drv0 (fdctrl_t *fdctrl) -{ - return &fdctrl->drives[fdctrl->bootsel]; -} - -static inline fdrive_t *drv1 (fdctrl_t *fdctrl) -{ - return &fdctrl->drives[1 - fdctrl->bootsel]; -} - -static fdrive_t *get_cur_drv (fdctrl_t *fdctrl) -{ - return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl); -} - -/* Status B register : 0x01 (read-only) */ -static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl) -{ - FLOPPY_DPRINTF("status register: 0x00\n"); - return 0; -} - -/* Digital output register : 0x02 */ -static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl) -{ - uint32_t retval = 0; - - /* Drive motors state indicators */ - if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON) - retval |= 1 << 5; - if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON) - retval |= 1 << 4; - /* DMA enable */ - retval |= fdctrl->dma_en << 3; - /* Reset indicator */ - retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0; - /* Selected drive */ - retval |= fdctrl->cur_drv; - FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval); - - return retval; -} - -static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value) -{ - /* Reset mode */ - if (fdctrl->state & FD_CTRL_RESET) { - if (!(value & 0x04)) { - FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); - return; - } - } - FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value); - /* Drive motors state indicators */ - if (value & 0x20) - fd_start(drv1(fdctrl)); - else - fd_stop(drv1(fdctrl)); - if (value & 0x10) - fd_start(drv0(fdctrl)); - else - fd_stop(drv0(fdctrl)); - /* DMA enable */ -#if 0 - if (fdctrl->dma_chann != -1) - fdctrl->dma_en = 1 - ((value >> 3) & 1); -#endif - /* Reset */ - if (!(value & 0x04)) { - if (!(fdctrl->state & FD_CTRL_RESET)) { - FLOPPY_DPRINTF("controller enter RESET state\n"); - fdctrl->state |= FD_CTRL_RESET; - } - } else { - if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("controller out of RESET state\n"); - fdctrl_reset(fdctrl, 1); - fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP); - } - } - /* Selected drive */ - fdctrl->cur_drv = value & 1; -} - -/* Tape drive register : 0x03 */ -static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl) -{ - uint32_t retval = 0; - - /* Disk boot selection indicator */ - retval |= fdctrl->bootsel << 2; - /* Tape indicators: never allowed */ - FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval); - - return retval; -} - -static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value) -{ - /* Reset mode */ - if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); - return; - } - FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value); - /* Disk boot selection indicator */ - fdctrl->bootsel = (value >> 2) & 1; - /* Tape indicators: never allow */ -} - -/* Main status register : 0x04 (read) */ -static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl) -{ - uint32_t retval = 0; - - fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET); - if (!(fdctrl->state & FD_CTRL_BUSY)) { - /* Data transfer allowed */ - retval |= 0x80; - /* Data transfer direction indicator */ - if (fdctrl->data_dir == FD_DIR_READ) - retval |= 0x40; - } - /* Should handle 0x20 for SPECIFY command */ - /* Command busy indicator */ - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA || - FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) - retval |= 0x10; - FLOPPY_DPRINTF("main status register: 0x%02x\n", retval); - - return retval; -} - -/* Data select rate register : 0x04 (write) */ -static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value) -{ - /* Reset mode */ - if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); - return; - } - FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value); - /* Reset: autoclear */ - if (value & 0x80) { - fdctrl->state |= FD_CTRL_RESET; - fdctrl_reset(fdctrl, 1); - fdctrl->state &= ~FD_CTRL_RESET; - } - if (value & 0x40) { - fdctrl->state |= FD_CTRL_SLEEP; - fdctrl_reset(fdctrl, 1); - } -// fdctrl.precomp = (value >> 2) & 0x07; -} - -/* Digital input register : 0x07 (read-only) */ -static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl) -{ - uint32_t retval = 0; - - if (drv0(fdctrl)->drflags & FDRIVE_REVALIDATE || - drv1(fdctrl)->drflags & FDRIVE_REVALIDATE) - retval |= 0x80; - if (retval != 0) - FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval); - drv0(fdctrl)->drflags &= ~FDRIVE_REVALIDATE; - drv1(fdctrl)->drflags &= ~FDRIVE_REVALIDATE; - - return retval; -} - -/* FIFO state control */ -static void fdctrl_reset_fifo (fdctrl_t *fdctrl) -{ - fdctrl->data_dir = FD_DIR_WRITE; - fdctrl->data_pos = 0; - FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD); -} - -/* Set FIFO status for the host to read */ -static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq) -{ - fdctrl->data_dir = FD_DIR_READ; - fdctrl->data_len = fifo_len; - fdctrl->data_pos = 0; - FD_SET_STATE(fdctrl->data_state, FD_STATE_STATUS); - if (do_irq) - fdctrl_raise_irq(fdctrl, 0x00); -} - -/* Set an error: unimplemented/unknown command */ -static void fdctrl_unimplemented (fdctrl_t *fdctrl) -{ -#if 0 - fdrive_t *cur_drv; - - cur_drv = get_cur_drv(fdctrl); - fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv; - fdctrl->fifo[1] = 0x00; - fdctrl->fifo[2] = 0x00; - fdctrl_set_fifo(fdctrl, 3, 1); -#else - // fdctrl_reset_fifo(fdctrl); - fdctrl->fifo[0] = 0x80; - fdctrl_set_fifo(fdctrl, 1, 0); -#endif -} - -/* Callback for transfer end (stop or abort) */ -static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0, - uint8_t status1, uint8_t status2) -{ - fdrive_t *cur_drv; - - cur_drv = get_cur_drv(fdctrl); - FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n", - status0, status1, status2, - status0 | (cur_drv->head << 2) | fdctrl->cur_drv); - fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv; - fdctrl->fifo[1] = status1; - fdctrl->fifo[2] = status2; - fdctrl->fifo[3] = cur_drv->track; - fdctrl->fifo[4] = cur_drv->head; - fdctrl->fifo[5] = cur_drv->sect; - fdctrl->fifo[6] = FD_SECTOR_SC; - fdctrl->data_dir = FD_DIR_READ; - if (fdctrl->state & FD_CTRL_BUSY) { - DMA_release_DREQ(fdctrl->dma_chann); - fdctrl->state &= ~FD_CTRL_BUSY; - } - fdctrl_set_fifo(fdctrl, 7, 1); -} - -/* Prepare a data transfer (either DMA or FIFO) */ -static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction) -{ - fdrive_t *cur_drv; - uint8_t kh, kt, ks; - int did_seek; - - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - kt = fdctrl->fifo[2]; - kh = fdctrl->fifo[3]; - ks = fdctrl->fifo[4]; - FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n", - fdctrl->cur_drv, kh, kt, ks, - _fd_sector(kh, kt, ks, cur_drv->last_sect)); - did_seek = 0; - switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) { - case 2: - /* sect too big */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); - fdctrl->fifo[3] = kt; - fdctrl->fifo[4] = kh; - fdctrl->fifo[5] = ks; - return; - case 3: - /* track too big */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00); - fdctrl->fifo[3] = kt; - fdctrl->fifo[4] = kh; - fdctrl->fifo[5] = ks; - return; - case 4: - /* No seek enabled */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); - fdctrl->fifo[3] = kt; - fdctrl->fifo[4] = kh; - fdctrl->fifo[5] = ks; - return; - case 1: - did_seek = 1; - break; - default: - break; - } - /* Set the FIFO state */ - fdctrl->data_dir = direction; - fdctrl->data_pos = 0; - FD_SET_STATE(fdctrl->data_state, FD_STATE_DATA); /* FIFO ready for data */ - if (fdctrl->fifo[0] & 0x80) - fdctrl->data_state |= FD_STATE_MULTI; - else - fdctrl->data_state &= ~FD_STATE_MULTI; - if (did_seek) - fdctrl->data_state |= FD_STATE_SEEK; - else - fdctrl->data_state &= ~FD_STATE_SEEK; - if (fdctrl->fifo[5] == 00) { - fdctrl->data_len = fdctrl->fifo[8]; - } else { - int tmp; - fdctrl->data_len = 128 << fdctrl->fifo[5]; - tmp = (cur_drv->last_sect - ks + 1); - if (fdctrl->fifo[0] & 0x80) - tmp += cur_drv->last_sect; - fdctrl->data_len *= tmp; - } - fdctrl->eot = fdctrl->fifo[6]; - if (fdctrl->dma_en) { - int dma_mode; - /* DMA transfer are enabled. Check if DMA channel is well programmed */ - dma_mode = DMA_get_channel_mode(fdctrl->dma_chann); - dma_mode = (dma_mode >> 2) & 3; - FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n", - dma_mode, direction, - (128 << fdctrl->fifo[5]) * - (cur_drv->last_sect - ks + 1), fdctrl->data_len); - if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL || - direction == FD_DIR_SCANH) && dma_mode == 0) || - (direction == FD_DIR_WRITE && dma_mode == 2) || - (direction == FD_DIR_READ && dma_mode == 1)) { - /* No access is allowed until DMA transfer has completed */ - fdctrl->state |= FD_CTRL_BUSY; - /* Now, we just have to wait for the DMA controller to - * recall us... - */ - DMA_hold_DREQ(fdctrl->dma_chann); - DMA_schedule(fdctrl->dma_chann); - return; - } else { - FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction); - } - } - FLOPPY_DPRINTF("start non-DMA transfer\n"); - /* IO based transfer: calculate len */ - fdctrl_raise_irq(fdctrl, 0x00); - - return; -} - -/* Prepare a transfer of deleted data */ -static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction) -{ - /* We don't handle deleted data, - * so we don't return *ANYTHING* - */ - fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); -} - -/* handlers for DMA transfers */ -static int fdctrl_transfer_handler (void *opaque, int nchan, - int dma_pos, int dma_len) -{ - fdctrl_t *fdctrl; - fdrive_t *cur_drv; - int len, start_pos, rel_pos; - uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00; - - fdctrl = opaque; - if (!(fdctrl->state & FD_CTRL_BUSY)) { - FLOPPY_DPRINTF("Not in DMA transfer mode !\n"); - return 0; - } - cur_drv = get_cur_drv(fdctrl); - if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL || - fdctrl->data_dir == FD_DIR_SCANH) - status2 = 0x04; - if (dma_len > fdctrl->data_len) - dma_len = fdctrl->data_len; - if (cur_drv->bs == NULL) { - if (fdctrl->data_dir == FD_DIR_WRITE) - fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); - else - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); - len = 0; - goto transfer_error; - } - rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; - for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) { - len = dma_len - fdctrl->data_pos; - if (len + rel_pos > FD_SECTOR_LEN) - len = FD_SECTOR_LEN - rel_pos; - FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x " - "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos, - fdctrl->data_len, fdctrl->cur_drv, cur_drv->head, - cur_drv->track, cur_drv->sect, fd_sector(cur_drv), - fd_sector(cur_drv) * 512); - if (fdctrl->data_dir != FD_DIR_WRITE || - len < FD_SECTOR_LEN || rel_pos != 0) { - /* READ & SCAN commands and realign to a sector for WRITE */ - if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), - fdctrl->fifo, 1) < 0) { - FLOPPY_DPRINTF("Floppy: error getting sector %d\n", - fd_sector(cur_drv)); - /* Sure, image size is too small... */ - memset(fdctrl->fifo, 0, FD_SECTOR_LEN); - } - } - switch (fdctrl->data_dir) { - case FD_DIR_READ: - /* READ commands */ - DMA_write_memory (nchan, fdctrl->fifo + rel_pos, - fdctrl->data_pos, len); -/* cpu_physical_memory_write(addr + fdctrl->data_pos, */ -/* fdctrl->fifo + rel_pos, len); */ - break; - case FD_DIR_WRITE: - /* WRITE commands */ - DMA_read_memory (nchan, fdctrl->fifo + rel_pos, - fdctrl->data_pos, len); -/* cpu_physical_memory_read(addr + fdctrl->data_pos, */ -/* fdctrl->fifo + rel_pos, len); */ - if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), - fdctrl->fifo, 1) < 0) { - FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv)); - fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); - goto transfer_error; - } - break; - default: - /* SCAN commands */ - { - uint8_t tmpbuf[FD_SECTOR_LEN]; - int ret; - DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len); -/* cpu_physical_memory_read(addr + fdctrl->data_pos, */ -/* tmpbuf, len); */ - ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len); - if (ret == 0) { - status2 = 0x08; - goto end_transfer; - } - if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) || - (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) { - status2 = 0x00; - goto end_transfer; - } - } - break; - } - fdctrl->data_pos += len; - rel_pos = fdctrl->data_pos % FD_SECTOR_LEN; - if (rel_pos == 0) { - /* Seek to next sector */ - FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n", - cur_drv->head, cur_drv->track, cur_drv->sect, - fd_sector(cur_drv), - fdctrl->data_pos - len); - /* XXX: cur_drv->sect >= cur_drv->last_sect should be an - error in fact */ - if (cur_drv->sect >= cur_drv->last_sect || - cur_drv->sect == fdctrl->eot) { - cur_drv->sect = 1; - if (FD_MULTI_TRACK(fdctrl->data_state)) { - if (cur_drv->head == 0 && - (cur_drv->flags & FDISK_DBL_SIDES) != 0) { - cur_drv->head = 1; - } else { - cur_drv->head = 0; - cur_drv->track++; - if ((cur_drv->flags & FDISK_DBL_SIDES) == 0) - break; - } - } else { - cur_drv->track++; - break; - } - FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n", - cur_drv->head, cur_drv->track, - cur_drv->sect, fd_sector(cur_drv)); - } else { - cur_drv->sect++; - } - } - } -end_transfer: - len = fdctrl->data_pos - start_pos; - FLOPPY_DPRINTF("end transfer %d %d %d\n", - fdctrl->data_pos, len, fdctrl->data_len); - if (fdctrl->data_dir == FD_DIR_SCANE || - fdctrl->data_dir == FD_DIR_SCANL || - fdctrl->data_dir == FD_DIR_SCANH) - status2 = 0x08; - if (FD_DID_SEEK(fdctrl->data_state)) - status0 |= 0x20; - fdctrl->data_len -= len; - // if (fdctrl->data_len == 0) - fdctrl_stop_transfer(fdctrl, status0, status1, status2); -transfer_error: - - return len; -} - -/* Data register : 0x05 */ -static uint32_t fdctrl_read_data (fdctrl_t *fdctrl) -{ - fdrive_t *cur_drv; - uint32_t retval = 0; - int pos, len; - - cur_drv = get_cur_drv(fdctrl); - fdctrl->state &= ~FD_CTRL_SLEEP; - if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) { - FLOPPY_ERROR("can't read data in CMD state\n"); - return 0; - } - pos = fdctrl->data_pos; - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { - pos %= FD_SECTOR_LEN; - if (pos == 0) { - len = fdctrl->data_len - fdctrl->data_pos; - if (len > FD_SECTOR_LEN) - len = FD_SECTOR_LEN; - bdrv_read(cur_drv->bs, fd_sector(cur_drv), - fdctrl->fifo, len); - } - } - retval = fdctrl->fifo[pos]; - if (++fdctrl->data_pos == fdctrl->data_len) { - fdctrl->data_pos = 0; - /* Switch from transfer mode to status mode - * then from status mode to command mode - */ - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { - fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); - } else { - fdctrl_reset_fifo(fdctrl); - fdctrl_reset_irq(fdctrl); - } - } - FLOPPY_DPRINTF("data register: 0x%02x\n", retval); - - return retval; -} - -static void fdctrl_format_sector (fdctrl_t *fdctrl) -{ - fdrive_t *cur_drv; - uint8_t kh, kt, ks; - int did_seek; - - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - kt = fdctrl->fifo[6]; - kh = fdctrl->fifo[7]; - ks = fdctrl->fifo[8]; - FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n", - fdctrl->cur_drv, kh, kt, ks, - _fd_sector(kh, kt, ks, cur_drv->last_sect)); - did_seek = 0; - switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) { - case 2: - /* sect too big */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); - fdctrl->fifo[3] = kt; - fdctrl->fifo[4] = kh; - fdctrl->fifo[5] = ks; - return; - case 3: - /* track too big */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00); - fdctrl->fifo[3] = kt; - fdctrl->fifo[4] = kh; - fdctrl->fifo[5] = ks; - return; - case 4: - /* No seek enabled */ - fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00); - fdctrl->fifo[3] = kt; - fdctrl->fifo[4] = kh; - fdctrl->fifo[5] = ks; - return; - case 1: - did_seek = 1; - fdctrl->data_state |= FD_STATE_SEEK; - break; - default: - break; - } - memset(fdctrl->fifo, 0, FD_SECTOR_LEN); - if (cur_drv->bs == NULL || - bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) { - FLOPPY_ERROR("formating sector %d\n", fd_sector(cur_drv)); - fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00); - } else { - if (cur_drv->sect == cur_drv->last_sect) { - fdctrl->data_state &= ~FD_STATE_FORMAT; - /* Last sector done */ - if (FD_DID_SEEK(fdctrl->data_state)) - fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); - else - fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); - } else { - /* More to do */ - fdctrl->data_pos = 0; - fdctrl->data_len = 4; - } - } -} - -static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value) -{ - fdrive_t *cur_drv; - - cur_drv = get_cur_drv(fdctrl); - /* Reset mode */ - if (fdctrl->state & FD_CTRL_RESET) { - FLOPPY_DPRINTF("Floppy controller in RESET state !\n"); - return; - } - fdctrl->state &= ~FD_CTRL_SLEEP; - if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) { - FLOPPY_ERROR("can't write data in status mode\n"); - return; - } - /* Is it write command time ? */ - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) { - /* FIFO data write */ - fdctrl->fifo[fdctrl->data_pos++] = value; - if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) || - fdctrl->data_pos == fdctrl->data_len) { - bdrv_write(cur_drv->bs, fd_sector(cur_drv), - fdctrl->fifo, FD_SECTOR_LEN); - } - /* Switch from transfer mode to status mode - * then from status mode to command mode - */ - if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) - fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); - return; - } - if (fdctrl->data_pos == 0) { - /* Command */ - switch (value & 0x5F) { - case 0x46: - /* READ variants */ - FLOPPY_DPRINTF("READ command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x4C: - /* READ_DELETED variants */ - FLOPPY_DPRINTF("READ_DELETED command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x50: - /* SCAN_EQUAL variants */ - FLOPPY_DPRINTF("SCAN_EQUAL command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x56: - /* VERIFY variants */ - FLOPPY_DPRINTF("VERIFY command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x59: - /* SCAN_LOW_OR_EQUAL variants */ - FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x5D: - /* SCAN_HIGH_OR_EQUAL variants */ - FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - default: - break; - } - switch (value & 0x7F) { - case 0x45: - /* WRITE variants */ - FLOPPY_DPRINTF("WRITE command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x49: - /* WRITE_DELETED variants */ - FLOPPY_DPRINTF("WRITE_DELETED command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - default: - break; - } - switch (value) { - case 0x03: - /* SPECIFY */ - FLOPPY_DPRINTF("SPECIFY command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 3; - goto enqueue; - case 0x04: - /* SENSE_DRIVE_STATUS */ - FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 2; - goto enqueue; - case 0x07: - /* RECALIBRATE */ - FLOPPY_DPRINTF("RECALIBRATE command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 2; - goto enqueue; - case 0x08: - /* SENSE_INTERRUPT_STATUS */ - FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n", - fdctrl->int_status); - /* No parameters cmd: returns status if no interrupt */ -#if 0 - fdctrl->fifo[0] = - fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv; -#else - /* XXX: int_status handling is broken for read/write - commands, so we do this hack. It should be suppressed - ASAP */ - fdctrl->fifo[0] = - 0x20 | (cur_drv->head << 2) | fdctrl->cur_drv; -#endif - fdctrl->fifo[1] = cur_drv->track; - fdctrl_set_fifo(fdctrl, 2, 0); - fdctrl_reset_irq(fdctrl); - fdctrl->int_status = 0xC0; - return; - case 0x0E: - /* DUMPREG */ - FLOPPY_DPRINTF("DUMPREG command\n"); - /* Drives position */ - fdctrl->fifo[0] = drv0(fdctrl)->track; - fdctrl->fifo[1] = drv1(fdctrl)->track; - fdctrl->fifo[2] = 0; - fdctrl->fifo[3] = 0; - /* timers */ - fdctrl->fifo[4] = fdctrl->timer0; - fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en; - fdctrl->fifo[6] = cur_drv->last_sect; - fdctrl->fifo[7] = (fdctrl->lock << 7) | - (cur_drv->perpendicular << 2); - fdctrl->fifo[8] = fdctrl->config; - fdctrl->fifo[9] = fdctrl->precomp_trk; - fdctrl_set_fifo(fdctrl, 10, 0); - return; - case 0x0F: - /* SEEK */ - FLOPPY_DPRINTF("SEEK command\n"); - /* 2 parameters cmd */ - fdctrl->data_len = 3; - goto enqueue; - case 0x10: - /* VERSION */ - FLOPPY_DPRINTF("VERSION command\n"); - /* No parameters cmd */ - /* Controller's version */ - fdctrl->fifo[0] = fdctrl->version; - fdctrl_set_fifo(fdctrl, 1, 1); - return; - case 0x12: - /* PERPENDICULAR_MODE */ - FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 2; - goto enqueue; - case 0x13: - /* CONFIGURE */ - FLOPPY_DPRINTF("CONFIGURE command\n"); - /* 3 parameters cmd */ - fdctrl->data_len = 4; - goto enqueue; - case 0x14: - /* UNLOCK */ - FLOPPY_DPRINTF("UNLOCK command\n"); - /* No parameters cmd */ - fdctrl->lock = 0; - fdctrl->fifo[0] = 0; - fdctrl_set_fifo(fdctrl, 1, 0); - return; - case 0x17: - /* POWERDOWN_MODE */ - FLOPPY_DPRINTF("POWERDOWN_MODE command\n"); - /* 2 parameters cmd */ - fdctrl->data_len = 3; - goto enqueue; - case 0x18: - /* PART_ID */ - FLOPPY_DPRINTF("PART_ID command\n"); - /* No parameters cmd */ - fdctrl->fifo[0] = 0x41; /* Stepping 1 */ - fdctrl_set_fifo(fdctrl, 1, 0); - return; - case 0x2C: - /* SAVE */ - FLOPPY_DPRINTF("SAVE command\n"); - /* No parameters cmd */ - fdctrl->fifo[0] = 0; - fdctrl->fifo[1] = 0; - /* Drives position */ - fdctrl->fifo[2] = drv0(fdctrl)->track; - fdctrl->fifo[3] = drv1(fdctrl)->track; - fdctrl->fifo[4] = 0; - fdctrl->fifo[5] = 0; - /* timers */ - fdctrl->fifo[6] = fdctrl->timer0; - fdctrl->fifo[7] = fdctrl->timer1; - fdctrl->fifo[8] = cur_drv->last_sect; - fdctrl->fifo[9] = (fdctrl->lock << 7) | - (cur_drv->perpendicular << 2); - fdctrl->fifo[10] = fdctrl->config; - fdctrl->fifo[11] = fdctrl->precomp_trk; - fdctrl->fifo[12] = fdctrl->pwrd; - fdctrl->fifo[13] = 0; - fdctrl->fifo[14] = 0; - fdctrl_set_fifo(fdctrl, 15, 1); - return; - case 0x33: - /* OPTION */ - FLOPPY_DPRINTF("OPTION command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 2; - goto enqueue; - case 0x42: - /* READ_TRACK */ - FLOPPY_DPRINTF("READ_TRACK command\n"); - /* 8 parameters cmd */ - fdctrl->data_len = 9; - goto enqueue; - case 0x4A: - /* READ_ID */ - FLOPPY_DPRINTF("READ_ID command\n"); - /* 1 parameter cmd */ - fdctrl->data_len = 2; - goto enqueue; - case 0x4C: - /* RESTORE */ - FLOPPY_DPRINTF("RESTORE command\n"); - /* 17 parameters cmd */ - fdctrl->data_len = 18; - goto enqueue; - case 0x4D: - /* FORMAT_TRACK */ - FLOPPY_DPRINTF("FORMAT_TRACK command\n"); - /* 5 parameters cmd */ - fdctrl->data_len = 6; - goto enqueue; - case 0x8E: - /* DRIVE_SPECIFICATION_COMMAND */ - FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n"); - /* 5 parameters cmd */ - fdctrl->data_len = 6; - goto enqueue; - case 0x8F: - /* RELATIVE_SEEK_OUT */ - FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n"); - /* 2 parameters cmd */ - fdctrl->data_len = 3; - goto enqueue; - case 0x94: - /* LOCK */ - FLOPPY_DPRINTF("LOCK command\n"); - /* No parameters cmd */ - fdctrl->lock = 1; - fdctrl->fifo[0] = 0x10; - fdctrl_set_fifo(fdctrl, 1, 1); - return; - case 0xCD: - /* FORMAT_AND_WRITE */ - FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n"); - /* 10 parameters cmd */ - fdctrl->data_len = 11; - goto enqueue; - case 0xCF: - /* RELATIVE_SEEK_IN */ - FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n"); - /* 2 parameters cmd */ - fdctrl->data_len = 3; - goto enqueue; - default: - /* Unknown command */ - FLOPPY_ERROR("unknown command: 0x%02x\n", value); - fdctrl_unimplemented(fdctrl); - return; - } - } -enqueue: - FLOPPY_DPRINTF("%s: %02x\n", __func__, value); - fdctrl->fifo[fdctrl->data_pos] = value; - if (++fdctrl->data_pos == fdctrl->data_len) { - /* We now have all parameters - * and will be able to treat the command - */ - if (fdctrl->data_state & FD_STATE_FORMAT) { - fdctrl_format_sector(fdctrl); - return; - } - switch (fdctrl->fifo[0] & 0x1F) { - case 0x06: - { - /* READ variants */ - FLOPPY_DPRINTF("treat READ command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_READ); - return; - } - case 0x0C: - /* READ_DELETED variants */ -// FLOPPY_DPRINTF("treat READ_DELETED command\n"); - FLOPPY_ERROR("treat READ_DELETED command\n"); - fdctrl_start_transfer_del(fdctrl, FD_DIR_READ); - return; - case 0x16: - /* VERIFY variants */ -// FLOPPY_DPRINTF("treat VERIFY command\n"); - FLOPPY_ERROR("treat VERIFY command\n"); - fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00); - return; - case 0x10: - /* SCAN_EQUAL variants */ -// FLOPPY_DPRINTF("treat SCAN_EQUAL command\n"); - FLOPPY_ERROR("treat SCAN_EQUAL command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_SCANE); - return; - case 0x19: - /* SCAN_LOW_OR_EQUAL variants */ -// FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n"); - FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_SCANL); - return; - case 0x1D: - /* SCAN_HIGH_OR_EQUAL variants */ -// FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n"); - FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_SCANH); - return; - default: - break; - } - switch (fdctrl->fifo[0] & 0x3F) { - case 0x05: - /* WRITE variants */ - FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]); - fdctrl_start_transfer(fdctrl, FD_DIR_WRITE); - return; - case 0x09: - /* WRITE_DELETED variants */ -// FLOPPY_DPRINTF("treat WRITE_DELETED command\n"); - FLOPPY_ERROR("treat WRITE_DELETED command\n"); - fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE); - return; - default: - break; - } - switch (fdctrl->fifo[0]) { - case 0x03: - /* SPECIFY */ - FLOPPY_DPRINTF("treat SPECIFY command\n"); - fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF; - fdctrl->timer1 = fdctrl->fifo[2] >> 1; - fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ; - /* No result back */ - fdctrl_reset_fifo(fdctrl); - break; - case 0x04: - /* SENSE_DRIVE_STATUS */ - FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; - /* 1 Byte status back */ - fdctrl->fifo[0] = (cur_drv->ro << 6) | - (cur_drv->track == 0 ? 0x10 : 0x00) | - (cur_drv->head << 2) | - fdctrl->cur_drv | - 0x28; - fdctrl_set_fifo(fdctrl, 1, 0); - break; - case 0x07: - /* RECALIBRATE */ - FLOPPY_DPRINTF("treat RECALIBRATE command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_recalibrate(cur_drv); - fdctrl_reset_fifo(fdctrl); - /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, 0x20); - break; - case 0x0F: - /* SEEK */ - FLOPPY_DPRINTF("treat SEEK command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_start(cur_drv); - if (fdctrl->fifo[2] <= cur_drv->track) - cur_drv->dir = 1; - else - cur_drv->dir = 0; - fdctrl_reset_fifo(fdctrl); - if (fdctrl->fifo[2] > cur_drv->max_track) { - fdctrl_raise_irq(fdctrl, 0x60); - } else { - cur_drv->track = fdctrl->fifo[2]; - /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, 0x20); - } - break; - case 0x12: - /* PERPENDICULAR_MODE */ - FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n"); - if (fdctrl->fifo[1] & 0x80) - cur_drv->perpendicular = fdctrl->fifo[1] & 0x7; - /* No result back */ - fdctrl_reset_fifo(fdctrl); - break; - case 0x13: - /* CONFIGURE */ - FLOPPY_DPRINTF("treat CONFIGURE command\n"); - fdctrl->config = fdctrl->fifo[2]; - fdctrl->precomp_trk = fdctrl->fifo[3]; - /* No result back */ - fdctrl_reset_fifo(fdctrl); - break; - case 0x17: - /* POWERDOWN_MODE */ - FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n"); - fdctrl->pwrd = fdctrl->fifo[1]; - fdctrl->fifo[0] = fdctrl->fifo[1]; - fdctrl_set_fifo(fdctrl, 1, 1); - break; - case 0x33: - /* OPTION */ - FLOPPY_DPRINTF("treat OPTION command\n"); - /* No result back */ - fdctrl_reset_fifo(fdctrl); - break; - case 0x42: - /* READ_TRACK */ -// FLOPPY_DPRINTF("treat READ_TRACK command\n"); - FLOPPY_ERROR("treat READ_TRACK command\n"); - fdctrl_start_transfer(fdctrl, FD_DIR_READ); - break; - case 0x4A: - /* READ_ID */ - FLOPPY_DPRINTF("treat READ_ID command\n"); - /* XXX: should set main status register to busy */ - cur_drv->head = (fdctrl->fifo[1] >> 2) & 1; - qemu_mod_timer(fdctrl->result_timer, - qemu_get_clock(vm_clock) + (ticks_per_sec / 50)); - break; - case 0x4C: - /* RESTORE */ - FLOPPY_DPRINTF("treat RESTORE command\n"); - /* Drives position */ - drv0(fdctrl)->track = fdctrl->fifo[3]; - drv1(fdctrl)->track = fdctrl->fifo[4]; - /* timers */ - fdctrl->timer0 = fdctrl->fifo[7]; - fdctrl->timer1 = fdctrl->fifo[8]; - cur_drv->last_sect = fdctrl->fifo[9]; - fdctrl->lock = fdctrl->fifo[10] >> 7; - cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF; - fdctrl->config = fdctrl->fifo[11]; - fdctrl->precomp_trk = fdctrl->fifo[12]; - fdctrl->pwrd = fdctrl->fifo[13]; - fdctrl_reset_fifo(fdctrl); - break; - case 0x4D: - /* FORMAT_TRACK */ - FLOPPY_DPRINTF("treat FORMAT_TRACK command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fdctrl->data_state |= FD_STATE_FORMAT; - if (fdctrl->fifo[0] & 0x80) - fdctrl->data_state |= FD_STATE_MULTI; - else - fdctrl->data_state &= ~FD_STATE_MULTI; - fdctrl->data_state &= ~FD_STATE_SEEK; - cur_drv->bps = - fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2]; -#if 0 - cur_drv->last_sect = - cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] : - fdctrl->fifo[3] / 2; -#else - cur_drv->last_sect = fdctrl->fifo[3]; -#endif - /* Bochs BIOS is buggy and don't send format informations - * for each sector. So, pretend all's done right now... - */ - fdctrl->data_state &= ~FD_STATE_FORMAT; - fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); - break; - case 0x8E: - /* DRIVE_SPECIFICATION_COMMAND */ - FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n"); - if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) { - /* Command parameters done */ - if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) { - fdctrl->fifo[0] = fdctrl->fifo[1]; - fdctrl->fifo[2] = 0; - fdctrl->fifo[3] = 0; - fdctrl_set_fifo(fdctrl, 4, 1); - } else { - fdctrl_reset_fifo(fdctrl); - } - } else if (fdctrl->data_len > 7) { - /* ERROR */ - fdctrl->fifo[0] = 0x80 | - (cur_drv->head << 2) | fdctrl->cur_drv; - fdctrl_set_fifo(fdctrl, 1, 1); - } - break; - case 0x8F: - /* RELATIVE_SEEK_OUT */ - FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_start(cur_drv); - cur_drv->dir = 0; - if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) { - cur_drv->track = cur_drv->max_track - 1; - } else { - cur_drv->track += fdctrl->fifo[2]; - } - fdctrl_reset_fifo(fdctrl); - fdctrl_raise_irq(fdctrl, 0x20); - break; - case 0xCD: - /* FORMAT_AND_WRITE */ -// FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n"); - FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n"); - fdctrl_unimplemented(fdctrl); - break; - case 0xCF: - /* RELATIVE_SEEK_IN */ - FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n"); - fdctrl->cur_drv = fdctrl->fifo[1] & 1; - cur_drv = get_cur_drv(fdctrl); - fd_start(cur_drv); - cur_drv->dir = 1; - if (fdctrl->fifo[2] > cur_drv->track) { - cur_drv->track = 0; - } else { - cur_drv->track -= fdctrl->fifo[2]; - } - fdctrl_reset_fifo(fdctrl); - /* Raise Interrupt */ - fdctrl_raise_irq(fdctrl, 0x20); - break; - } - } -} - -static void fdctrl_result_timer(void *opaque) -{ - fdctrl_t *fdctrl = opaque; - fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); -} diff --git a/hw/fmopl.c b/hw/fmopl.c deleted file mode 100644 index 2b0e82b..0000000 --- a/hw/fmopl.c +++ /dev/null @@ -1,1390 +0,0 @@ -/* -** -** File: fmopl.c -- software implementation of FM sound generator -** -** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development -** -** Version 0.37a -** -*/ - -/* - preliminary : - Problem : - note: -*/ - -/* This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define INLINE __inline -#define HAS_YM3812 1 - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <math.h> -//#include "driver.h" /* use M.A.M.E. */ -#include "fmopl.h" - -#ifndef PI -#define PI 3.14159265358979323846 -#endif - -/* -------------------- for debug --------------------- */ -/* #define OPL_OUTPUT_LOG */ -#ifdef OPL_OUTPUT_LOG -static FILE *opl_dbg_fp = NULL; -static FM_OPL *opl_dbg_opl[16]; -static int opl_dbg_maxchip,opl_dbg_chip; -#endif - -/* -------------------- preliminary define section --------------------- */ -/* attack/decay rate time rate */ -#define OPL_ARRATE 141280 /* RATE 4 = 2826.24ms @ 3.6MHz */ -#define OPL_DRRATE 1956000 /* RATE 4 = 39280.64ms @ 3.6MHz */ - -#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */ - -#define FREQ_BITS 24 /* frequency turn */ - -/* counter bits = 20 , octerve 7 */ -#define FREQ_RATE (1<<(FREQ_BITS-20)) -#define TL_BITS (FREQ_BITS+2) - -/* final output shift , limit minimum and maximum */ -#define OPL_OUTSB (TL_BITS+3-16) /* OPL output final shift 16bit */ -#define OPL_MAXOUT (0x7fff<<OPL_OUTSB) -#define OPL_MINOUT (-0x8000<<OPL_OUTSB) - -/* -------------------- quality selection --------------------- */ - -/* sinwave entries */ -/* used static memory = SIN_ENT * 4 (byte) */ -#define SIN_ENT 2048 - -/* output level entries (envelope,sinwave) */ -/* envelope counter lower bits */ -#define ENV_BITS 16 -/* envelope output entries */ -#define EG_ENT 4096 -/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */ -/* used static memory = EG_ENT*4 (byte) */ - -#define EG_OFF ((2*EG_ENT)<<ENV_BITS) /* OFF */ -#define EG_DED EG_OFF -#define EG_DST (EG_ENT<<ENV_BITS) /* DECAY START */ -#define EG_AED EG_DST -#define EG_AST 0 /* ATTACK START */ - -#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step */ - -/* LFO table entries */ -#define VIB_ENT 512 -#define VIB_SHIFT (32-9) -#define AMS_ENT 512 -#define AMS_SHIFT (32-9) - -#define VIB_RATE 256 - -/* -------------------- local defines , macros --------------------- */ - -/* register number to channel number , slot offset */ -#define SLOT1 0 -#define SLOT2 1 - -/* envelope phase */ -#define ENV_MOD_RR 0x00 -#define ENV_MOD_DR 0x01 -#define ENV_MOD_AR 0x02 - -/* -------------------- tables --------------------- */ -static const int slot_array[32]= -{ - 0, 2, 4, 1, 3, 5,-1,-1, - 6, 8,10, 7, 9,11,-1,-1, - 12,14,16,13,15,17,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1 -}; - -/* key scale level */ -/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */ -#define DV (EG_STEP/2) -static const UINT32 KSL_TABLE[8*16]= -{ - /* OCT 0 */ - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - /* OCT 1 */ - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV, - 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV, - /* OCT 2 */ - 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, - 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV, - 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV, - 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV, - /* OCT 3 */ - 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV, - 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV, - 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV, - 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV, - /* OCT 4 */ - 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV, - 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV, - 9.000/DV, 9.750/DV,10.125/DV,10.500/DV, - 10.875/DV,11.250/DV,11.625/DV,12.000/DV, - /* OCT 5 */ - 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV, - 9.000/DV,10.125/DV,10.875/DV,11.625/DV, - 12.000/DV,12.750/DV,13.125/DV,13.500/DV, - 13.875/DV,14.250/DV,14.625/DV,15.000/DV, - /* OCT 6 */ - 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV, - 12.000/DV,13.125/DV,13.875/DV,14.625/DV, - 15.000/DV,15.750/DV,16.125/DV,16.500/DV, - 16.875/DV,17.250/DV,17.625/DV,18.000/DV, - /* OCT 7 */ - 0.000/DV, 9.000/DV,12.000/DV,13.875/DV, - 15.000/DV,16.125/DV,16.875/DV,17.625/DV, - 18.000/DV,18.750/DV,19.125/DV,19.500/DV, - 19.875/DV,20.250/DV,20.625/DV,21.000/DV -}; -#undef DV - -/* sustain lebel table (3db per step) */ -/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ -#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST -static const INT32 SL_TABLE[16]={ - SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), - SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) -}; -#undef SC - -#define TL_MAX (EG_ENT*2) /* limit(tl + ksr + envelope) + sinwave */ -/* TotalLevel : 48 24 12 6 3 1.5 0.75 (dB) */ -/* TL_TABLE[ 0 to TL_MAX ] : plus section */ -/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */ -static INT32 *TL_TABLE; - -/* pointers to TL_TABLE with sinwave output offset */ -static INT32 **SIN_TABLE; - -/* LFO table */ -static INT32 *AMS_TABLE; -static INT32 *VIB_TABLE; - -/* envelope output curve table */ -/* attack + decay + OFF */ -static INT32 ENV_CURVE[2*EG_ENT+1]; - -/* multiple table */ -#define ML 2 -static const UINT32 MUL_TABLE[16]= { -/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */ - 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML, - 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML -}; -#undef ML - -/* dummy attack / decay rate ( when rate == 0 ) */ -static INT32 RATE_0[16]= -{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - -/* -------------------- static state --------------------- */ - -/* lock level of common table */ -static int num_lock = 0; - -/* work table */ -static void *cur_chip = NULL; /* current chip point */ -/* currenct chip state */ -/* static OPLSAMPLE *bufL,*bufR; */ -static OPL_CH *S_CH; -static OPL_CH *E_CH; -OPL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2; - -static INT32 outd[1]; -static INT32 ams; -static INT32 vib; -INT32 *ams_table; -INT32 *vib_table; -static INT32 amsIncr; -static INT32 vibIncr; -static INT32 feedback2; /* connect for SLOT 2 */ - -/* log output level */ -#define LOG_ERR 3 /* ERROR */ -#define LOG_WAR 2 /* WARNING */ -#define LOG_INF 1 /* INFORMATION */ - -//#define LOG_LEVEL LOG_INF -#define LOG_LEVEL LOG_ERR - -//#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x -#define LOG(n,x) - -/* --------------------- subroutines --------------------- */ - -INLINE int Limit( int val, int max, int min ) { - if ( val > max ) - val = max; - else if ( val < min ) - val = min; - - return val; -} - -/* status set and IRQ handling */ -INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) -{ - /* set status flag */ - OPL->status |= flag; - if(!(OPL->status & 0x80)) - { - if(OPL->status & OPL->statusmask) - { /* IRQ on */ - OPL->status |= 0x80; - /* callback user interrupt handler (IRQ is OFF to ON) */ - if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); - } - } -} - -/* status reset and IRQ handling */ -INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) -{ - /* reset status flag */ - OPL->status &=~flag; - if((OPL->status & 0x80)) - { - if (!(OPL->status & OPL->statusmask) ) - { - OPL->status &= 0x7f; - /* callback user interrupt handler (IRQ is ON to OFF) */ - if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); - } - } -} - -/* IRQ mask set */ -INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) -{ - OPL->statusmask = flag; - /* IRQ handling check */ - OPL_STATUS_SET(OPL,0); - OPL_STATUS_RESET(OPL,0); -} - -/* ----- key on ----- */ -INLINE void OPL_KEYON(OPL_SLOT *SLOT) -{ - /* sin wave restart */ - SLOT->Cnt = 0; - /* set attack */ - SLOT->evm = ENV_MOD_AR; - SLOT->evs = SLOT->evsa; - SLOT->evc = EG_AST; - SLOT->eve = EG_AED; -} -/* ----- key off ----- */ -INLINE void OPL_KEYOFF(OPL_SLOT *SLOT) -{ - if( SLOT->evm > ENV_MOD_RR) - { - /* set envelope counter from envleope output */ - SLOT->evm = ENV_MOD_RR; - if( !(SLOT->evc&EG_DST) ) - //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST; - SLOT->evc = EG_DST; - SLOT->eve = EG_DED; - SLOT->evs = SLOT->evsr; - } -} - -/* ---------- calcrate Envelope Generator & Phase Generator ---------- */ -/* return : envelope output */ -INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT ) -{ - /* calcrate envelope generator */ - if( (SLOT->evc+=SLOT->evs) >= SLOT->eve ) - { - switch( SLOT->evm ){ - case ENV_MOD_AR: /* ATTACK -> DECAY1 */ - /* next DR */ - SLOT->evm = ENV_MOD_DR; - SLOT->evc = EG_DST; - SLOT->eve = SLOT->SL; - SLOT->evs = SLOT->evsd; - break; - case ENV_MOD_DR: /* DECAY -> SL or RR */ - SLOT->evc = SLOT->SL; - SLOT->eve = EG_DED; - if(SLOT->eg_typ) - { - SLOT->evs = 0; - } - else - { - SLOT->evm = ENV_MOD_RR; - SLOT->evs = SLOT->evsr; - } - break; - case ENV_MOD_RR: /* RR -> OFF */ - SLOT->evc = EG_OFF; - SLOT->eve = EG_OFF+1; - SLOT->evs = 0; - break; - } - } - /* calcrate envelope */ - return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0); -} - -/* set algorythm connection */ -static void set_algorythm( OPL_CH *CH) -{ - INT32 *carrier = &outd[0]; - CH->connect1 = CH->CON ? carrier : &feedback2; - CH->connect2 = carrier; -} - -/* ---------- frequency counter for operater update ---------- */ -INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) -{ - int ksr; - - /* frequency step counter */ - SLOT->Incr = CH->fc * SLOT->mul; - ksr = CH->kcode >> SLOT->KSR; - - if( SLOT->ksr != ksr ) - { - SLOT->ksr = ksr; - /* attack , decay rate recalcration */ - SLOT->evsa = SLOT->AR[ksr]; - SLOT->evsd = SLOT->DR[ksr]; - SLOT->evsr = SLOT->RR[ksr]; - } - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); -} - -/* set multi,am,vib,EG-TYP,KSR,mul */ -INLINE void set_mul(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->mul = MUL_TABLE[v&0x0f]; - SLOT->KSR = (v&0x10) ? 0 : 2; - SLOT->eg_typ = (v&0x20)>>5; - SLOT->vib = (v&0x40); - SLOT->ams = (v&0x80); - CALC_FCSLOT(CH,SLOT); -} - -/* set ksl & tl */ -INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */ - - SLOT->ksl = ksl ? 3-ksl : 31; - SLOT->TL = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */ - - if( !(OPL->mode&0x80) ) - { /* not CSM latch total level */ - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); - } -} - -/* set attack rate & decay rate */ -INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - int ar = v>>4; - int dr = v&0x0f; - - SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0; - SLOT->evsa = SLOT->AR[SLOT->ksr]; - if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa; - - SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0; - SLOT->evsd = SLOT->DR[SLOT->ksr]; - if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd; -} - -/* set sustain level & release rate */ -INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - int sl = v>>4; - int rr = v & 0x0f; - - SLOT->SL = SL_TABLE[sl]; - if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL; - SLOT->RR = &OPL->DR_TABLE[rr<<2]; - SLOT->evsr = SLOT->RR[SLOT->ksr]; - if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr; -} - -/* operator output calcrator */ -#define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env] -/* ---------- calcrate one of channel ---------- */ -INLINE void OPL_CALC_CH( OPL_CH *CH ) -{ - UINT32 env_out; - OPL_SLOT *SLOT; - - feedback2 = 0; - /* SLOT 1 */ - SLOT = &CH->SLOT[SLOT1]; - env_out=OPL_CALC_SLOT(SLOT); - if( env_out < EG_ENT-1 ) - { - /* PG */ - if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); - else SLOT->Cnt += SLOT->Incr; - /* connectoion */ - if(CH->FB) - { - int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; - CH->op1_out[1] = CH->op1_out[0]; - *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1); - } - else - { - *CH->connect1 += OP_OUT(SLOT,env_out,0); - } - }else - { - CH->op1_out[1] = CH->op1_out[0]; - CH->op1_out[0] = 0; - } - /* SLOT 2 */ - SLOT = &CH->SLOT[SLOT2]; - env_out=OPL_CALC_SLOT(SLOT); - if( env_out < EG_ENT-1 ) - { - /* PG */ - if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); - else SLOT->Cnt += SLOT->Incr; - /* connectoion */ - outd[0] += OP_OUT(SLOT,env_out, feedback2); - } -} - -/* ---------- calcrate rythm block ---------- */ -#define WHITE_NOISE_db 6.0 -INLINE void OPL_CALC_RH( OPL_CH *CH ) -{ - UINT32 env_tam,env_sd,env_top,env_hh; - int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP); - INT32 tone8; - - OPL_SLOT *SLOT; - int env_out; - - /* BD : same as FM serial mode and output level is large */ - feedback2 = 0; - /* SLOT 1 */ - SLOT = &CH[6].SLOT[SLOT1]; - env_out=OPL_CALC_SLOT(SLOT); - if( env_out < EG_ENT-1 ) - { - /* PG */ - if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); - else SLOT->Cnt += SLOT->Incr; - /* connectoion */ - if(CH[6].FB) - { - int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB; - CH[6].op1_out[1] = CH[6].op1_out[0]; - feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1); - } - else - { - feedback2 = OP_OUT(SLOT,env_out,0); - } - }else - { - feedback2 = 0; - CH[6].op1_out[1] = CH[6].op1_out[0]; - CH[6].op1_out[0] = 0; - } - /* SLOT 2 */ - SLOT = &CH[6].SLOT[SLOT2]; - env_out=OPL_CALC_SLOT(SLOT); - if( env_out < EG_ENT-1 ) - { - /* PG */ - if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE); - else SLOT->Cnt += SLOT->Incr; - /* connectoion */ - outd[0] += OP_OUT(SLOT,env_out, feedback2)*2; - } - - // SD (17) = mul14[fnum7] + white noise - // TAM (15) = mul15[fnum8] - // TOP (18) = fnum6(mul18[fnum8]+whitenoise) - // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise - env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise; - env_tam=OPL_CALC_SLOT(SLOT8_1); - env_top=OPL_CALC_SLOT(SLOT8_2); - env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise; - - /* PG */ - if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE); - else SLOT7_1->Cnt += 2*SLOT7_1->Incr; - if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE); - else SLOT7_2->Cnt += (CH[7].fc*8); - if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE); - else SLOT8_1->Cnt += SLOT8_1->Incr; - if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE); - else SLOT8_2->Cnt += (CH[8].fc*48); - - tone8 = OP_OUT(SLOT8_2,whitenoise,0 ); - - /* SD */ - if( env_sd < EG_ENT-1 ) - outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8; - /* TAM */ - if( env_tam < EG_ENT-1 ) - outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2; - /* TOP-CY */ - if( env_top < EG_ENT-1 ) - outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2; - /* HH */ - if( env_hh < EG_ENT-1 ) - outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2; -} - -/* ----------- initialize time tabls ----------- */ -static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE ) -{ - int i; - double rate; - - /* make attack rate & decay rate tables */ - for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0; - for (i = 4;i <= 60;i++){ - rate = OPL->freqbase; /* frequency rate */ - if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ - rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */ - rate *= (double)(EG_ENT<<ENV_BITS); - OPL->AR_TABLE[i] = rate / ARRATE; - OPL->DR_TABLE[i] = rate / DRRATE; - } - for (i = 60;i < 76;i++) - { - OPL->AR_TABLE[i] = EG_AED-1; - OPL->DR_TABLE[i] = OPL->DR_TABLE[60]; - } -#if 0 - for (i = 0;i < 64 ;i++){ /* make for overflow area */ - LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i, - ((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate), - ((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) )); - } -#endif -} - -/* ---------- generic table initialize ---------- */ -static int OPLOpenTable( void ) -{ - int s,t; - double rate; - int i,j; - double pom; - - /* allocate dynamic tables */ - if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL) - return 0; - if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL) - { - free(TL_TABLE); - return 0; - } - if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL) - { - free(TL_TABLE); - free(SIN_TABLE); - return 0; - } - if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL) - { - free(TL_TABLE); - free(SIN_TABLE); - free(AMS_TABLE); - return 0; - } - /* make total level table */ - for (t = 0;t < EG_ENT-1 ;t++){ - rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20); /* dB -> voltage */ - TL_TABLE[ t] = (int)rate; - TL_TABLE[TL_MAX+t] = -TL_TABLE[t]; -/* LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/ - } - /* fill volume off area */ - for ( t = EG_ENT-1; t < TL_MAX ;t++){ - TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0; - } - - /* make sinwave table (total level offet) */ - /* degree 0 = degree 180 = off */ - SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1]; - for (s = 1;s <= SIN_ENT/4;s++){ - pom = sin(2*PI*s/SIN_ENT); /* sin */ - pom = 20*log10(1/pom); /* decibel */ - j = pom / EG_STEP; /* TL_TABLE steps */ - - /* degree 0 - 90 , degree 180 - 90 : plus section */ - SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j]; - /* degree 180 - 270 , degree 360 - 270 : minus section */ - SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j]; -/* LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/ - } - for (s = 0;s < SIN_ENT;s++) - { - SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT]; - SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)]; - SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s]; - } - - /* envelope counter -> envelope output table */ - for (i=0; i<EG_ENT; i++) - { - /* ATTACK curve */ - pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT; - /* if( pom >= EG_ENT ) pom = EG_ENT-1; */ - ENV_CURVE[i] = (int)pom; - /* DECAY ,RELEASE curve */ - ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i; - } - /* off */ - ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1; - /* make LFO ams table */ - for (i=0; i<AMS_ENT; i++) - { - pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */ - AMS_TABLE[i] = (1.0/EG_STEP)*pom; /* 1dB */ - AMS_TABLE[AMS_ENT+i] = (4.8/EG_STEP)*pom; /* 4.8dB */ - } - /* make LFO vibrate table */ - for (i=0; i<VIB_ENT; i++) - { - /* 100cent = 1seminote = 6% ?? */ - pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */ - VIB_TABLE[i] = VIB_RATE + (pom*0.07); /* +- 7cent */ - VIB_TABLE[VIB_ENT+i] = VIB_RATE + (pom*0.14); /* +-14cent */ - /* LOG(LOG_INF,("vib %d=%d\n",i,VIB_TABLE[VIB_ENT+i])); */ - } - return 1; -} - - -static void OPLCloseTable( void ) -{ - free(TL_TABLE); - free(SIN_TABLE); - free(AMS_TABLE); - free(VIB_TABLE); -} - -/* CSM Key Controll */ -INLINE void CSMKeyControll(OPL_CH *CH) -{ - OPL_SLOT *slot1 = &CH->SLOT[SLOT1]; - OPL_SLOT *slot2 = &CH->SLOT[SLOT2]; - /* all key off */ - OPL_KEYOFF(slot1); - OPL_KEYOFF(slot2); - /* total level latch */ - slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); - slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); - /* key on */ - CH->op1_out[0] = CH->op1_out[1] = 0; - OPL_KEYON(slot1); - OPL_KEYON(slot2); -} - -/* ---------- opl initialize ---------- */ -static void OPL_initalize(FM_OPL *OPL) -{ - int fn; - - /* frequency base */ - OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0; - /* Timer base time */ - OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 ); - /* make time tables */ - init_timetables( OPL , OPL_ARRATE , OPL_DRRATE ); - /* make fnumber -> increment counter table */ - for( fn=0 ; fn < 1024 ; fn++ ) - { - OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2; - } - /* LFO freq.table */ - OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0; - OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0; -} - -/* ---------- write a OPL registers ---------- */ -static void OPLWriteReg(FM_OPL *OPL, int r, int v) -{ - OPL_CH *CH; - int slot; - int block_fnum; - - switch(r&0xe0) - { - case 0x00: /* 00-1f:controll */ - switch(r&0x1f) - { - case 0x01: - /* wave selector enable */ - if(OPL->type&OPL_TYPE_WAVESEL) - { - OPL->wavesel = v&0x20; - if(!OPL->wavesel) - { - /* preset compatible mode */ - int c; - for(c=0;c<OPL->max_ch;c++) - { - OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0]; - OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0]; - } - } - } - return; - case 0x02: /* Timer 1 */ - OPL->T[0] = (256-v)*4; - break; - case 0x03: /* Timer 2 */ - OPL->T[1] = (256-v)*16; - return; - case 0x04: /* IRQ clear / mask and Timer enable */ - if(v&0x80) - { /* IRQ flag clear */ - OPL_STATUS_RESET(OPL,0x7f); - } - else - { /* set IRQ mask ,timer enable*/ - UINT8 st1 = v&1; - UINT8 st2 = (v>>1)&1; - /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ - OPL_STATUS_RESET(OPL,v&0x78); - OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01); - /* timer 2 */ - if(OPL->st[1] != st2) - { - double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0; - OPL->st[1] = st2; - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); - } - /* timer 1 */ - if(OPL->st[0] != st1) - { - double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0; - OPL->st[0] = st1; - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); - } - } - return; -#if BUILD_Y8950 - case 0x06: /* Key Board OUT */ - if(OPL->type&OPL_TYPE_KEYBOARD) - { - if(OPL->keyboardhandler_w) - OPL->keyboardhandler_w(OPL->keyboard_param,v); - else - LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n")); - } - return; - case 0x07: /* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ - if(OPL->type&OPL_TYPE_ADPCM) - YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); - return; - case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ - OPL->mode = v; - v&=0x1f; /* for DELTA-T unit */ - case 0x09: /* START ADD */ - case 0x0a: - case 0x0b: /* STOP ADD */ - case 0x0c: - case 0x0d: /* PRESCALE */ - case 0x0e: - case 0x0f: /* ADPCM data */ - case 0x10: /* DELTA-N */ - case 0x11: /* DELTA-N */ - case 0x12: /* EG-CTRL */ - if(OPL->type&OPL_TYPE_ADPCM) - YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); - return; -#if 0 - case 0x15: /* DAC data */ - case 0x16: - case 0x17: /* SHIFT */ - return; - case 0x18: /* I/O CTRL (Direction) */ - if(OPL->type&OPL_TYPE_IO) - OPL->portDirection = v&0x0f; - return; - case 0x19: /* I/O DATA */ - if(OPL->type&OPL_TYPE_IO) - { - OPL->portLatch = v; - if(OPL->porthandler_w) - OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); - } - return; - case 0x1a: /* PCM data */ - return; -#endif -#endif - } - break; - case 0x20: /* am,vib,ksr,eg type,mul */ - slot = slot_array[r&0x1f]; - if(slot == -1) return; - set_mul(OPL,slot,v); - return; - case 0x40: - slot = slot_array[r&0x1f]; - if(slot == -1) return; - set_ksl_tl(OPL,slot,v); - return; - case 0x60: - slot = slot_array[r&0x1f]; - if(slot == -1) return; - set_ar_dr(OPL,slot,v); - return; - case 0x80: - slot = slot_array[r&0x1f]; - if(slot == -1) return; - set_sl_rr(OPL,slot,v); - return; - case 0xa0: - switch(r) - { - case 0xbd: - /* amsep,vibdep,r,bd,sd,tom,tc,hh */ - { - UINT8 rkey = OPL->rythm^v; - OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0]; - OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0]; - OPL->rythm = v&0x3f; - if(OPL->rythm&0x20) - { -#if 0 - usrintf_showmessage("OPL Rythm mode select"); -#endif - /* BD key on/off */ - if(rkey&0x10) - { - if(v&0x10) - { - OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0; - OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]); - OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]); - } - else - { - OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]); - OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]); - } - } - /* SD key on/off */ - if(rkey&0x08) - { - if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]); - else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]); - }/* TAM key on/off */ - if(rkey&0x04) - { - if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]); - else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]); - } - /* TOP-CY key on/off */ - if(rkey&0x02) - { - if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]); - else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]); - } - /* HH key on/off */ - if(rkey&0x01) - { - if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]); - else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]); - } - } - } - return; - } - /* keyon,block,fnum */ - if( (r&0x0f) > 8) return; - CH = &OPL->P_CH[r&0x0f]; - if(!(r&0x10)) - { /* a0-a8 */ - block_fnum = (CH->block_fnum&0x1f00) | v; - } - else - { /* b0-b8 */ - int keyon = (v>>5)&1; - block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); - if(CH->keyon != keyon) - { - if( (CH->keyon=keyon) ) - { - CH->op1_out[0] = CH->op1_out[1] = 0; - OPL_KEYON(&CH->SLOT[SLOT1]); - OPL_KEYON(&CH->SLOT[SLOT2]); - } - else - { - OPL_KEYOFF(&CH->SLOT[SLOT1]); - OPL_KEYOFF(&CH->SLOT[SLOT2]); - } - } - } - /* update */ - if(CH->block_fnum != block_fnum) - { - int blockRv = 7-(block_fnum>>10); - int fnum = block_fnum&0x3ff; - CH->block_fnum = block_fnum; - - CH->ksl_base = KSL_TABLE[block_fnum>>6]; - CH->fc = OPL->FN_TABLE[fnum]>>blockRv; - CH->kcode = CH->block_fnum>>9; - if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1; - CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); - CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); - } - return; - case 0xc0: - /* FB,C */ - if( (r&0x0f) > 8) return; - CH = &OPL->P_CH[r&0x0f]; - { - int feedback = (v>>1)&7; - CH->FB = feedback ? (8+1) - feedback : 0; - CH->CON = v&1; - set_algorythm(CH); - } - return; - case 0xe0: /* wave type */ - slot = slot_array[r&0x1f]; - if(slot == -1) return; - CH = &OPL->P_CH[slot/2]; - if(OPL->wavesel) - { - /* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */ - CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT]; - } - return; - } -} - -/* lock/unlock for common table */ -static int OPL_LockTable(void) -{ - num_lock++; - if(num_lock>1) return 0; - /* first time */ - cur_chip = NULL; - /* allocate total level table (128kb space) */ - if( !OPLOpenTable() ) - { - num_lock--; - return -1; - } - return 0; -} - -static void OPL_UnLockTable(void) -{ - if(num_lock) num_lock--; - if(num_lock) return; - /* last time */ - cur_chip = NULL; - OPLCloseTable(); -} - -#if (BUILD_YM3812 || BUILD_YM3526) -/*******************************************************************************/ -/* YM3812 local section */ -/*******************************************************************************/ - -/* ---------- update one of chip ----------- */ -void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) -{ - int i; - int data; - OPLSAMPLE *buf = buffer; - UINT32 amsCnt = OPL->amsCnt; - UINT32 vibCnt = OPL->vibCnt; - UINT8 rythm = OPL->rythm&0x20; - OPL_CH *CH,*R_CH; - - if( (void *)OPL != cur_chip ){ - cur_chip = (void *)OPL; - /* channel pointers */ - S_CH = OPL->P_CH; - E_CH = &S_CH[9]; - /* rythm slot */ - SLOT7_1 = &S_CH[7].SLOT[SLOT1]; - SLOT7_2 = &S_CH[7].SLOT[SLOT2]; - SLOT8_1 = &S_CH[8].SLOT[SLOT1]; - SLOT8_2 = &S_CH[8].SLOT[SLOT2]; - /* LFO state */ - amsIncr = OPL->amsIncr; - vibIncr = OPL->vibIncr; - ams_table = OPL->ams_table; - vib_table = OPL->vib_table; - } - R_CH = rythm ? &S_CH[6] : E_CH; - for( i=0; i < length ; i++ ) - { - /* channel A channel B channel C */ - /* LFO */ - ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; - vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; - outd[0] = 0; - /* FM part */ - for(CH=S_CH ; CH < R_CH ; CH++) - OPL_CALC_CH(CH); - /* Rythn part */ - if(rythm) - OPL_CALC_RH(S_CH); - /* limit check */ - data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); - /* store to sound buffer */ - buf[i] = data >> OPL_OUTSB; - } - - OPL->amsCnt = amsCnt; - OPL->vibCnt = vibCnt; -#ifdef OPL_OUTPUT_LOG - if(opl_dbg_fp) - { - for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++) - if( opl_dbg_opl[opl_dbg_chip] == OPL) break; - fprintf(opl_dbg_fp,"%c%c%c",0x20+opl_dbg_chip,length&0xff,length/256); - } -#endif -} -#endif /* (BUILD_YM3812 || BUILD_YM3526) */ - -#if BUILD_Y8950 - -void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) -{ - int i; - int data; - OPLSAMPLE *buf = buffer; - UINT32 amsCnt = OPL->amsCnt; - UINT32 vibCnt = OPL->vibCnt; - UINT8 rythm = OPL->rythm&0x20; - OPL_CH *CH,*R_CH; - YM_DELTAT *DELTAT = OPL->deltat; - - /* setup DELTA-T unit */ - YM_DELTAT_DECODE_PRESET(DELTAT); - - if( (void *)OPL != cur_chip ){ - cur_chip = (void *)OPL; - /* channel pointers */ - S_CH = OPL->P_CH; - E_CH = &S_CH[9]; - /* rythm slot */ - SLOT7_1 = &S_CH[7].SLOT[SLOT1]; - SLOT7_2 = &S_CH[7].SLOT[SLOT2]; - SLOT8_1 = &S_CH[8].SLOT[SLOT1]; - SLOT8_2 = &S_CH[8].SLOT[SLOT2]; - /* LFO state */ - amsIncr = OPL->amsIncr; - vibIncr = OPL->vibIncr; - ams_table = OPL->ams_table; - vib_table = OPL->vib_table; - } - R_CH = rythm ? &S_CH[6] : E_CH; - for( i=0; i < length ; i++ ) - { - /* channel A channel B channel C */ - /* LFO */ - ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; - vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; - outd[0] = 0; - /* deltaT ADPCM */ - if( DELTAT->portstate ) - YM_DELTAT_ADPCM_CALC(DELTAT); - /* FM part */ - for(CH=S_CH ; CH < R_CH ; CH++) - OPL_CALC_CH(CH); - /* Rythn part */ - if(rythm) - OPL_CALC_RH(S_CH); - /* limit check */ - data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT ); - /* store to sound buffer */ - buf[i] = data >> OPL_OUTSB; - } - OPL->amsCnt = amsCnt; - OPL->vibCnt = vibCnt; - /* deltaT START flag */ - if( !DELTAT->portstate ) - OPL->status &= 0xfe; -} -#endif - -/* ---------- reset one of chip ---------- */ -void OPLResetChip(FM_OPL *OPL) -{ - int c,s; - int i; - - /* reset chip */ - OPL->mode = 0; /* normal mode */ - OPL_STATUS_RESET(OPL,0x7f); - /* reset with register write */ - OPLWriteReg(OPL,0x01,0); /* wabesel disable */ - OPLWriteReg(OPL,0x02,0); /* Timer1 */ - OPLWriteReg(OPL,0x03,0); /* Timer2 */ - OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ - for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); - /* reset OPerator paramater */ - for( c = 0 ; c < OPL->max_ch ; c++ ) - { - OPL_CH *CH = &OPL->P_CH[c]; - /* OPL->P_CH[c].PAN = OPN_CENTER; */ - for(s = 0 ; s < 2 ; s++ ) - { - /* wave table */ - CH->SLOT[s].wavetable = &SIN_TABLE[0]; - /* CH->SLOT[s].evm = ENV_MOD_RR; */ - CH->SLOT[s].evc = EG_OFF; - CH->SLOT[s].eve = EG_OFF+1; - CH->SLOT[s].evs = 0; - } - } -#if BUILD_Y8950 - if(OPL->type&OPL_TYPE_ADPCM) - { - YM_DELTAT *DELTAT = OPL->deltat; - - DELTAT->freqbase = OPL->freqbase; - DELTAT->output_pointer = outd; - DELTAT->portshift = 5; - DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS; - YM_DELTAT_ADPCM_Reset(DELTAT,0); - } -#endif -} - -/* ---------- Create one of vietual YM3812 ---------- */ -/* 'rate' is sampling rate and 'bufsiz' is the size of the */ -FM_OPL *OPLCreate(int type, int clock, int rate) -{ - char *ptr; - FM_OPL *OPL; - int state_size; - int max_ch = 9; /* normaly 9 channels */ - - if( OPL_LockTable() ==-1) return NULL; - /* allocate OPL state space */ - state_size = sizeof(FM_OPL); - state_size += sizeof(OPL_CH)*max_ch; -#if BUILD_Y8950 - if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); -#endif - /* allocate memory block */ - ptr = malloc(state_size); - if(ptr==NULL) return NULL; - /* clear */ - memset(ptr,0,state_size); - OPL = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL); - OPL->P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch; -#if BUILD_Y8950 - if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT); -#endif - /* set channel state pointer */ - OPL->type = type; - OPL->clock = clock; - OPL->rate = rate; - OPL->max_ch = max_ch; - /* init grobal tables */ - OPL_initalize(OPL); - /* reset chip */ - OPLResetChip(OPL); -#ifdef OPL_OUTPUT_LOG - if(!opl_dbg_fp) - { - opl_dbg_fp = fopen("opllog.opl","wb"); - opl_dbg_maxchip = 0; - } - if(opl_dbg_fp) - { - opl_dbg_opl[opl_dbg_maxchip] = OPL; - fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip, - type, - clock&0xff, - (clock/0x100)&0xff, - (clock/0x10000)&0xff, - (clock/0x1000000)&0xff); - opl_dbg_maxchip++; - } -#endif - return OPL; -} - -/* ---------- Destroy one of vietual YM3812 ---------- */ -void OPLDestroy(FM_OPL *OPL) -{ -#ifdef OPL_OUTPUT_LOG - if(opl_dbg_fp) - { - fclose(opl_dbg_fp); - opl_dbg_fp = NULL; - } -#endif - OPL_UnLockTable(); - free(OPL); -} - -/* ---------- Option handlers ---------- */ - -void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) -{ - OPL->TimerHandler = TimerHandler; - OPL->TimerParam = channelOffset; -} -void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) -{ - OPL->IRQHandler = IRQHandler; - OPL->IRQParam = param; -} -void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) -{ - OPL->UpdateHandler = UpdateHandler; - OPL->UpdateParam = param; -} -#if BUILD_Y8950 -void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) -{ - OPL->porthandler_w = PortHandler_w; - OPL->porthandler_r = PortHandler_r; - OPL->port_param = param; -} - -void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) -{ - OPL->keyboardhandler_w = KeyboardHandler_w; - OPL->keyboardhandler_r = KeyboardHandler_r; - OPL->keyboard_param = param; -} -#endif -/* ---------- YM3812 I/O interface ---------- */ -int OPLWrite(FM_OPL *OPL,int a,int v) -{ - if( !(a&1) ) - { /* address port */ - OPL->address = v & 0xff; - } - else - { /* data port */ - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); -#ifdef OPL_OUTPUT_LOG - if(opl_dbg_fp) - { - for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++) - if( opl_dbg_opl[opl_dbg_chip] == OPL) break; - fprintf(opl_dbg_fp,"%c%c%c",0x10+opl_dbg_chip,OPL->address,v); - } -#endif - OPLWriteReg(OPL,OPL->address,v); - } - return OPL->status>>7; -} - -unsigned char OPLRead(FM_OPL *OPL,int a) -{ - if( !(a&1) ) - { /* status port */ - return OPL->status & (OPL->statusmask|0x80); - } - /* data port */ - switch(OPL->address) - { - case 0x05: /* KeyBoard IN */ - if(OPL->type&OPL_TYPE_KEYBOARD) - { - if(OPL->keyboardhandler_r) - return OPL->keyboardhandler_r(OPL->keyboard_param); - else - LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n")); - } - return 0; -#if 0 - case 0x0f: /* ADPCM-DATA */ - return 0; -#endif - case 0x19: /* I/O DATA */ - if(OPL->type&OPL_TYPE_IO) - { - if(OPL->porthandler_r) - return OPL->porthandler_r(OPL->port_param); - else - LOG(LOG_WAR,("OPL:read unmapped I/O port\n")); - } - return 0; - case 0x1a: /* PCM-DATA */ - return 0; - } - return 0; -} - -int OPLTimerOver(FM_OPL *OPL,int c) -{ - if( c ) - { /* Timer B */ - OPL_STATUS_SET(OPL,0x20); - } - else - { /* Timer A */ - OPL_STATUS_SET(OPL,0x40); - /* CSM mode key,TL controll */ - if( OPL->mode & 0x80 ) - { /* CSM mode total level latch and auto key on */ - int ch; - if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); - for(ch=0;ch<9;ch++) - CSMKeyControll( &OPL->P_CH[ch] ); - } - } - /* reload timer */ - if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); - return OPL->status>>7; -} diff --git a/hw/fmopl.h b/hw/fmopl.h deleted file mode 100644 index a01ff90..0000000 --- a/hw/fmopl.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef __FMOPL_H_ -#define __FMOPL_H_ - -/* --- select emulation chips --- */ -#define BUILD_YM3812 (HAS_YM3812) -//#define BUILD_YM3526 (HAS_YM3526) -//#define BUILD_Y8950 (HAS_Y8950) - -/* --- system optimize --- */ -/* select bit size of output : 8 or 16 */ -#define OPL_OUTPUT_BIT 16 - -/* compiler dependence */ -#ifndef OSD_CPU_H -#define OSD_CPU_H -typedef unsigned char UINT8; /* unsigned 8bit */ -typedef unsigned short UINT16; /* unsigned 16bit */ -typedef unsigned int UINT32; /* unsigned 32bit */ -typedef signed char INT8; /* signed 8bit */ -typedef signed short INT16; /* signed 16bit */ -typedef signed int INT32; /* signed 32bit */ -#endif - -#if (OPL_OUTPUT_BIT==16) -typedef INT16 OPLSAMPLE; -#endif -#if (OPL_OUTPUT_BIT==8) -typedef unsigned char OPLSAMPLE; -#endif - - -#if BUILD_Y8950 -#include "ymdeltat.h" -#endif - -typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec); -typedef void (*OPL_IRQHANDLER)(int param,int irq); -typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us); -typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data); -typedef unsigned char (*OPL_PORTHANDLER_R)(int param); - -/* !!!!! here is private section , do not access there member direct !!!!! */ - -#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ -#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ -#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ -#define OPL_TYPE_IO 0x08 /* I/O port */ - -/* Saving is necessary for member of the 'R' mark for suspend/resume */ -/* ---------- OPL one of slot ---------- */ -typedef struct fm_opl_slot { - INT32 TL; /* total level :TL << 8 */ - INT32 TLL; /* adjusted now TL */ - UINT8 KSR; /* key scale rate :(shift down bit) */ - INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */ - INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */ - INT32 SL; /* sustin level :SL_TALBE[SL] */ - INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */ - UINT8 ksl; /* keyscale level :(shift down bits) */ - UINT8 ksr; /* key scale rate :kcode>>KSR */ - UINT32 mul; /* multiple :ML_TABLE[ML] */ - UINT32 Cnt; /* frequency count : */ - UINT32 Incr; /* frequency step : */ - /* envelope generator state */ - UINT8 eg_typ; /* envelope type flag */ - UINT8 evm; /* envelope phase */ - INT32 evc; /* envelope counter */ - INT32 eve; /* envelope counter end point */ - INT32 evs; /* envelope counter step */ - INT32 evsa; /* envelope step for AR :AR[ksr] */ - INT32 evsd; /* envelope step for DR :DR[ksr] */ - INT32 evsr; /* envelope step for RR :RR[ksr] */ - /* LFO */ - UINT8 ams; /* ams flag */ - UINT8 vib; /* vibrate flag */ - /* wave selector */ - INT32 **wavetable; -}OPL_SLOT; - -/* ---------- OPL one of channel ---------- */ -typedef struct fm_opl_channel { - OPL_SLOT SLOT[2]; - UINT8 CON; /* connection type */ - UINT8 FB; /* feed back :(shift down bit) */ - INT32 *connect1; /* slot1 output pointer */ - INT32 *connect2; /* slot2 output pointer */ - INT32 op1_out[2]; /* slot1 output for selfeedback */ - /* phase generator state */ - UINT32 block_fnum; /* block+fnum : */ - UINT8 kcode; /* key code : KeyScaleCode */ - UINT32 fc; /* Freq. Increment base */ - UINT32 ksl_base; /* KeyScaleLevel Base step */ - UINT8 keyon; /* key on/off flag */ -} OPL_CH; - -/* OPL state */ -typedef struct fm_opl_f { - UINT8 type; /* chip type */ - int clock; /* master clock (Hz) */ - int rate; /* sampling rate (Hz) */ - double freqbase; /* frequency base */ - double TimerBase; /* Timer base time (==sampling time) */ - UINT8 address; /* address register */ - UINT8 status; /* status flag */ - UINT8 statusmask; /* status mask */ - UINT32 mode; /* Reg.08 : CSM , notesel,etc. */ - /* Timer */ - int T[2]; /* timer counter */ - UINT8 st[2]; /* timer enable */ - /* FM channel slots */ - OPL_CH *P_CH; /* pointer of CH */ - int max_ch; /* maximum channel */ - /* Rythm sention */ - UINT8 rythm; /* Rythm mode , key flag */ -#if BUILD_Y8950 - /* Delta-T ADPCM unit (Y8950) */ - YM_DELTAT *deltat; /* DELTA-T ADPCM */ -#endif - /* Keyboard / I/O interface unit (Y8950) */ - UINT8 portDirection; - UINT8 portLatch; - OPL_PORTHANDLER_R porthandler_r; - OPL_PORTHANDLER_W porthandler_w; - int port_param; - OPL_PORTHANDLER_R keyboardhandler_r; - OPL_PORTHANDLER_W keyboardhandler_w; - int keyboard_param; - /* time tables */ - INT32 AR_TABLE[75]; /* atttack rate tables */ - INT32 DR_TABLE[75]; /* decay rate tables */ - UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */ - /* LFO */ - INT32 *ams_table; - INT32 *vib_table; - INT32 amsCnt; - INT32 amsIncr; - INT32 vibCnt; - INT32 vibIncr; - /* wave selector enable flag */ - UINT8 wavesel; - /* external event callback handler */ - OPL_TIMERHANDLER TimerHandler; /* TIMER handler */ - int TimerParam; /* TIMER parameter */ - OPL_IRQHANDLER IRQHandler; /* IRQ handler */ - int IRQParam; /* IRQ parameter */ - OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */ - int UpdateParam; /* stream update parameter */ -} FM_OPL; - -/* ---------- Generic interface section ---------- */ -#define OPL_TYPE_YM3526 (0) -#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) -#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) - -FM_OPL *OPLCreate(int type, int clock, int rate); -void OPLDestroy(FM_OPL *OPL); -void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset); -void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param); -void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param); -/* Y8950 port handlers */ -void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param); -void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param); - -void OPLResetChip(FM_OPL *OPL); -int OPLWrite(FM_OPL *OPL,int a,int v); -unsigned char OPLRead(FM_OPL *OPL,int a); -int OPLTimerOver(FM_OPL *OPL,int c); - -/* YM3626/YM3812 local section */ -void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); - -void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length); - -#endif diff --git a/hw/goldfish_audio.c b/hw/goldfish_audio.c new file mode 100644 index 0000000..69b2ef4 --- /dev/null +++ b/hw/goldfish_audio.c @@ -0,0 +1,521 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "goldfish_device.h" +#include "audio/audio.h" +#include "android_debug.h" + +#define DEBUG 1 + +#if DEBUG +# define D(...) VERBOSE_PRINT(audio,__VA_ARGS__) +#else +# define D(...) ((void)0) +#endif + +extern void dprint(const char* fmt, ...); + +/* define USE_QEMU_AUDIO_IN to 1 to use QEMU's audio subsystem to + * implement the audio input. if 0, this will try to read a .wav file + * directly... + */ +#define USE_QEMU_AUDIO_IN 1 + +enum { + /* audio status register */ + AUDIO_INT_STATUS = 0x00, + /* set this to enable IRQ */ + AUDIO_INT_ENABLE = 0x04, + /* set these to specify buffer addresses */ + AUDIO_SET_WRITE_BUFFER_1 = 0x08, + AUDIO_SET_WRITE_BUFFER_2 = 0x0C, + /* set number of bytes in buffer to write */ + AUDIO_WRITE_BUFFER_1 = 0x10, + AUDIO_WRITE_BUFFER_2 = 0x14, + + /* true if audio input is supported */ + AUDIO_READ_SUPPORTED = 0x18, + /* buffer to use for audio input */ + AUDIO_SET_READ_BUFFER = 0x1C, + + /* driver writes number of bytes to read */ + AUDIO_START_READ = 0x20, + + /* number of bytes available in read buffer */ + AUDIO_READ_BUFFER_AVAILABLE = 0x24, + + /* AUDIO_INT_STATUS bits */ + + /* this bit set when it is safe to write more bytes to the buffer */ + AUDIO_INT_WRITE_BUFFER_1_EMPTY = 1U << 0, + AUDIO_INT_WRITE_BUFFER_2_EMPTY = 1U << 1, + AUDIO_INT_READ_BUFFER_FULL = 1U << 2, +}; + + +struct goldfish_audio_state { + struct goldfish_device dev; + // pointers to our two write buffers + uint32_t buffer_1, buffer_2; + uint32_t read_buffer; + // buffer flags + uint32_t int_status; + // irq enable mask for int_status + uint32_t int_enable; + +#if USE_QEMU_AUDIO_IN + uint32_t read_pos; + uint32_t read_size; +#else + // path to file or device to use for input + const char* input_source; + // true if input is a wav file + int input_is_wav; + // true if we need to convert stereo -> mono + int input_is_stereo; + // file descriptor to use for input + int input_fd; +#endif + + // number of bytes available in the read buffer + int read_buffer_available; + + // set to 1 or 2 to indicate which buffer we are writing from, or zero if both buffers are empty + int current_buffer; + + // current data to write + uint8* data_1; + uint32_t data_1_length; + uint8* data_2; + uint32_t data_2_length; + + + // for QEMU sound output + QEMUSoundCard card; + SWVoiceOut *voice; +#if USE_QEMU_AUDIO_IN + SWVoiceIn* voicein; +#endif +}; + +/* update this whenever you change the goldfish_audio_state structure */ +#define AUDIO_STATE_SAVE_VERSION 1 + +#define QFIELD_STRUCT struct goldfish_audio_state +QFIELD_BEGIN(audio_state_fields) + QFIELD_INT32(buffer_1), + QFIELD_INT32(buffer_2), + QFIELD_INT32(read_buffer), + QFIELD_INT32(int_status), + QFIELD_INT32(int_enable), +#if USE_QEMU_AUDIO_IN + QFIELD_INT32(read_pos), + QFIELD_INT32(read_size), +#endif + QFIELD_INT32(read_buffer_available), + QFIELD_INT32(current_buffer), + QFIELD_INT32(data_1_length), + QFIELD_INT32(data_2_length), +QFIELD_END + +static void audio_state_save( QEMUFile* f, void* opaque ) +{ + struct goldfish_audio_state* s = opaque; + + qemu_put_struct(f, audio_state_fields, s); + + /* we can't write data_1 and data_2 directly */ + qemu_put_be32( f, s->data_1 - phys_ram_base ); + qemu_put_be32( f, s->data_2 - phys_ram_base ); +} + +static int audio_state_load( QEMUFile* f, void* opaque, int version_id ) +{ + struct goldfish_audio_state* s = opaque; + int ret; + + if (version_id != AUDIO_STATE_SAVE_VERSION) + return -1; + + ret = qemu_get_struct(f, audio_state_fields, s); + if (!ret) { + s->data_1 = qemu_get_be32(f) + phys_ram_base; + s->data_2 = qemu_get_be32(f) + phys_ram_base; + } + return -1; +} + +static void enable_audio(struct goldfish_audio_state *s, int enable) +{ + // enable or disable the output voice + AUD_set_active_out(s->voice, (enable & (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY)) != 0); + AUD_set_active_in (s->voicein, (enable & AUDIO_INT_READ_BUFFER_FULL) != 0); + // reset buffer information + s->data_1_length = 0; + s->data_2_length = 0; + s->current_buffer = 0; + s->read_pos = 0; +} + +#if USE_QEMU_AUDIO_IN +static void start_read(struct goldfish_audio_state *s, uint32_t count) +{ + //printf( "... goldfish audio start_read, count=%d\n", count ); + s->read_size = count; + s->read_buffer_available = 0; + s->read_pos = 0; +} +#else +static void start_read(struct goldfish_audio_state *s, uint32_t count) +{ + uint8 wav_header[44]; + int result; + + if (!s->input_source) return; + + if (s->input_fd < 0) { + s->input_fd = open(s->input_source, O_BINARY | O_RDONLY); + + if (s->input_fd < 0) { + fprintf(stderr, "goldfish_audio could not open %s for audio input\n", s->input_source); + s->input_source = NULL; // set to to avoid endless retries + return; + } + + // skip WAV header if we have a WAV file + if (s->input_is_wav) { + if (read(s->input_fd, wav_header, sizeof(wav_header)) != sizeof(wav_header)) { + fprintf(stderr, "goldfish_audio could not read WAV file header %s\n", s->input_source); + s->input_fd = -1; + s->input_source = NULL; // set to to avoid endless retries + return; + } + + // is the WAV file stereo? + s->input_is_stereo = (wav_header[22] == 2); + } else { + // assume input from an audio device is stereo + s->input_is_stereo = 1; + } + } + + uint8* buffer = (uint8*)phys_ram_base + s->read_buffer; + if (s->input_is_stereo) { + // need to read twice as much data + count *= 2; + } + +try_again: + result = read(s->input_fd, buffer, count); + if (result == 0 && s->input_is_wav) { + // end of file, so seek back to the beginning + lseek(s->input_fd, sizeof(wav_header), SEEK_SET); + goto try_again; + } + + if (result > 0 && s->input_is_stereo) { + // we need to convert stereo to mono + uint8* src = (uint8*)buffer; + uint8* dest = src; + int count = result/2; + while (count-- > 0) { + int sample1 = src[0] | (src[1] << 8); + int sample2 = src[2] | (src[3] << 8); + int sample = (sample1 + sample2) >> 1; + dst[0] = (uint8_t) sample; + dst[1] = (uint8_t)(sample >> 8); + src += 4; + dst += 2; + } + + // we reduced the number of bytes by 2 + result /= 2; + } + + s->read_buffer_available = (result > 0 ? result : 0); + s->int_status |= AUDIO_INT_READ_BUFFER_FULL; + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); +} +#endif + +static uint32_t goldfish_audio_read(void *opaque, target_phys_addr_t offset) +{ + uint32_t ret; + struct goldfish_audio_state *s = opaque; + offset -= s->dev.base; + switch(offset) { + case AUDIO_INT_STATUS: + // return current buffer status flags + ret = s->int_status & s->int_enable; + if(ret) { + goldfish_device_set_irq(&s->dev, 0, 0); + } + return ret; + + case AUDIO_READ_SUPPORTED: +#if USE_QEMU_AUDIO_IN + D("%s: AUDIO_READ_SUPPORTED returns %d", __FUNCTION__, + (s->voicein != NULL)); + return (s->voicein != NULL); +#else + return (s->input_source ? 1 : 0); +#endif + + case AUDIO_READ_BUFFER_AVAILABLE: + D("%s: AUDIO_READ_BUFFER_AVAILABLE returns %d", __FUNCTION__, + s->read_buffer_available); + return s->read_buffer_available; + + default: + cpu_abort (cpu_single_env, "goldfish_audio_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_audio_write(void *opaque, target_phys_addr_t offset, uint32_t val) +{ + struct goldfish_audio_state *s = opaque; + offset -= s->dev.base; + + switch(offset) { + case AUDIO_INT_ENABLE: + /* enable buffer empty interrupts */ + D("%s: AUDIO_INT_ENABLE %d", __FUNCTION__, val ); + enable_audio(s, val); + s->int_enable = val; + s->int_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY); + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + break; + case AUDIO_SET_WRITE_BUFFER_1: + /* save pointer to buffer 1 */ + s->buffer_1 = val; + break; + case AUDIO_SET_WRITE_BUFFER_2: + /* save pointer to buffer 2 */ + s->buffer_2 = val; + break; + case AUDIO_WRITE_BUFFER_1: + /* record that data in buffer 1 is ready to write */ + if (s->current_buffer == 0) s->current_buffer = 1; + s->data_1 = phys_ram_base + s->buffer_1; + s->data_1_length = val; + s->int_status &= ~AUDIO_INT_WRITE_BUFFER_1_EMPTY; + break; + case AUDIO_WRITE_BUFFER_2: + /* record that data in buffer 2 is ready to write */ + if (s->current_buffer == 0) s->current_buffer = 2; + s->data_2 = phys_ram_base + s->buffer_2; + s->data_2_length = val; + s->int_status &= ~AUDIO_INT_WRITE_BUFFER_2_EMPTY; + break; + + case AUDIO_SET_READ_BUFFER: + /* save pointer to the read buffer */ + s->read_buffer = val; + D( "%s: AUDIO_SET_READ_BUFFER %p", __FUNCTION__, (void*)val ); + break; + + case AUDIO_START_READ: + D( "%s: AUDIO_START_READ %d", __FUNCTION__, val ); + start_read(s, val); + s->int_status &= ~AUDIO_INT_READ_BUFFER_FULL; + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + break; + + default: + cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset %x\n", offset); + } +} + +static void goldfish_audio_callback(void *opaque, int free) +{ + struct goldfish_audio_state *s = opaque; + int new_status = 0; + + /* loop until free is zero or both buffers are empty */ + while (free && s->current_buffer) { + + /* write data in buffer 1 */ + while (free && s->current_buffer == 1) { + int write = s->data_1_length; + if (write > free) write = free; + + int written = AUD_write(s->voice, s->data_1, write); + if (written) { + D("%s: sent %d bytes to audio output", __FUNCTION__, write); + s->data_1 += written; + s->data_1_length -= written; + free -= written; + + if (s->data_1_length == 0) { + new_status |= AUDIO_INT_WRITE_BUFFER_1_EMPTY; + s->current_buffer = (s->data_2_length ? 2 : 0); + } + } else { + break; + } + } + + /* write data in buffer 2 */ + while (free && s->current_buffer == 2) { + int write = s->data_2_length; + if (write > free) write = free; + + int written = AUD_write(s->voice, s->data_2, write); + if (written) { + D("%s: sent %d bytes to audio output", __FUNCTION__, write); + s->data_2 += written; + s->data_2_length -= written; + free -= written; + + if (s->data_2_length == 0) { + new_status |= AUDIO_INT_WRITE_BUFFER_2_EMPTY; + s->current_buffer = (s->data_1_length ? 1 : 0); + } + } else { + break; + } + } + } + + if (new_status && new_status != s->int_status) { + s->int_status |= new_status; + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + } +} + +#if USE_QEMU_AUDIO_IN +static void +goldfish_audio_in_callback(void *opaque, int avail) +{ + struct goldfish_audio_state *s = opaque; + int new_status = 0; + + if (s->read_pos >= s->read_size) + return; + + if (0 && s->read_size > 0) + D("%s: in %d (pos=%d size=%d)", __FUNCTION__, + avail, s->read_pos, s->read_size ); + + while (avail > 0) { + int pos = s->read_pos; + int missing = s->read_size - pos; + uint8* buffer = (uint8*)phys_ram_base + s->read_buffer + pos; + int read; + int avail2 = (avail > missing) ? missing : avail; + + read = AUD_read(s->voicein, buffer, avail2); + if (read == 0) + break; + + if (avail2 > 0) + D("%s: AUD_read(%d) returned %d", __FUNCTION__, avail2, read); + + s->read_buffer_available += read; + + avail -= read; + pos += read; + if (pos == s->read_size) { + new_status |= AUDIO_INT_READ_BUFFER_FULL; + D("%s: AUDIO_INT_READ_BUFFER_FULL available=%d", __FUNCTION__, s->read_buffer_available); + } + s->read_pos = pos; + } + + if (new_status && new_status != s->int_status) { + s->int_status |= new_status; + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + } +} +#endif /* USE_QEMU_AUDIO_IN */ + +static CPUReadMemoryFunc *goldfish_audio_readfn[] = { + goldfish_audio_read, + goldfish_audio_read, + goldfish_audio_read +}; + +static CPUWriteMemoryFunc *goldfish_audio_writefn[] = { + goldfish_audio_write, + goldfish_audio_write, + goldfish_audio_write +}; + +void goldfish_audio_init(uint32_t base, int id, const char* input_source) +{ + struct goldfish_audio_state *s; + audsettings_t as; + + s = (struct goldfish_audio_state *)qemu_mallocz(sizeof(*s)); + s->dev.name = "goldfish_audio"; + s->dev.id = id; + s->dev.base = base; + s->dev.size = 0x1000; + s->dev.irq_count = 1; + +#ifndef USE_QEMU_AUDIO_IN + s->input_fd = -1; + if (input_source) { + s->input_source = input_source; + char* extension = strrchr(input_source, '.'); + if (extension && strcasecmp(extension, ".wav") == 0) { + s->input_is_wav = 1; + } + } +#endif + + AUD_register_card( &glob_audio_state, "goldfish_audio", &s->card); + + as.freq = 44100; + as.nchannels = 2; + as.fmt = AUD_FMT_S16; + as.endianness = AUDIO_HOST_ENDIANNESS; + + s->voice = AUD_open_out ( + &s->card, + s->voice, + "goldfish_audio", + s, + goldfish_audio_callback, + &as + ); + if (!s->voice) { + dprint("warning: opening audio output failed\n"); + return; + } + +#if USE_QEMU_AUDIO_IN + as.freq = 8000; + as.nchannels = 1; + as.fmt = AUD_FMT_S16; + as.endianness = AUDIO_HOST_ENDIANNESS; + + s->voicein = AUD_open_in ( + &s->card, + NULL, + "goldfish_audio_in", + s, + goldfish_audio_in_callback, + &as + ); + if (!s->voicein) { + dprint("warning: opening audio input failed\n"); + } +#endif + + goldfish_device_add(&s->dev, goldfish_audio_readfn, goldfish_audio_writefn, s); + + register_savevm( "audio_state", 0, AUDIO_STATE_SAVE_VERSION, + audio_state_save, audio_state_load, s ); +} + diff --git a/hw/goldfish_battery.c b/hw/goldfish_battery.c new file mode 100644 index 0000000..f8452db --- /dev/null +++ b/hw/goldfish_battery.c @@ -0,0 +1,261 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "goldfish_device.h" +#include "power_supply.h" + + +enum { + /* status register */ + BATTERY_INT_STATUS = 0x00, + /* set this to enable IRQ */ + BATTERY_INT_ENABLE = 0x04, + + BATTERY_AC_ONLINE = 0x08, + BATTERY_STATUS = 0x0C, + BATTERY_HEALTH = 0x10, + BATTERY_PRESENT = 0x14, + BATTERY_CAPACITY = 0x18, + + BATTERY_STATUS_CHANGED = 1U << 0, + AC_STATUS_CHANGED = 1U << 1, + BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED, +}; + + +struct goldfish_battery_state { + struct goldfish_device dev; + // IRQs + uint32_t int_status; + // irq enable mask for int_status + uint32_t int_enable; + + int ac_online; + int status; + int health; + int present; + int capacity; +}; + +/* update this each time you update the battery_state struct */ +#define BATTERY_STATE_SAVE_VERSION 1 + +#define QFIELD_STRUCT struct goldfish_battery_state +QFIELD_BEGIN(goldfish_battery_fields) + QFIELD_INT32(int_status), + QFIELD_INT32(int_enable), + QFIELD_INT32(ac_online), + QFIELD_INT32(status), + QFIELD_INT32(health), + QFIELD_INT32(present), + QFIELD_INT32(capacity), +QFIELD_END + +static void goldfish_battery_save(QEMUFile* f, void* opaque) +{ + struct goldfish_battery_state* s = opaque; + + qemu_put_struct(f, goldfish_battery_fields, s); +} + +static int goldfish_battery_load(QEMUFile* f, void* opaque, int version_id) +{ + struct goldfish_battery_state* s = opaque; + + if (version_id != BATTERY_STATE_SAVE_VERSION) + return -1; + + return qemu_get_struct(f, goldfish_battery_fields, s); +} + +static struct goldfish_battery_state *battery_state; + +static uint32_t goldfish_battery_read(void *opaque, target_phys_addr_t offset) +{ + uint32_t ret; + struct goldfish_battery_state *s = opaque; + offset -= s->dev.base; + switch(offset) { + case BATTERY_INT_STATUS: + // return current buffer status flags + ret = s->int_status & s->int_enable; + if (ret) { + goldfish_device_set_irq(&s->dev, 0, 0); + s->int_status = 0; + } + return ret; + + case BATTERY_INT_ENABLE: + return s->int_enable; + case BATTERY_AC_ONLINE: + return s->ac_online; + case BATTERY_STATUS: + return s->status; + case BATTERY_HEALTH: + return s->health; + case BATTERY_PRESENT: + return s->present; + case BATTERY_CAPACITY: + return s->capacity; + + default: + cpu_abort (cpu_single_env, "goldfish_battery_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_battery_write(void *opaque, target_phys_addr_t offset, uint32_t val) +{ + struct goldfish_battery_state *s = opaque; + offset -= s->dev.base; + + switch(offset) { + case BATTERY_INT_ENABLE: + /* enable interrupts */ + s->int_enable = val; +// s->int_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY); +// goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + break; + + default: + cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset %x\n", offset); + } +} + +static CPUReadMemoryFunc *goldfish_battery_readfn[] = { + goldfish_battery_read, + goldfish_battery_read, + goldfish_battery_read +}; + + +static CPUWriteMemoryFunc *goldfish_battery_writefn[] = { + goldfish_battery_write, + goldfish_battery_write, + goldfish_battery_write +}; + +void goldfish_battery_init() +{ + struct goldfish_battery_state *s; + + s = (struct goldfish_battery_state *)qemu_mallocz(sizeof(*s)); + s->dev.name = "goldfish-battery"; + s->dev.base = 0; // will be allocated dynamically + s->dev.size = 0x1000; + s->dev.irq_count = 1; + + // default values for the battery + s->ac_online = 1; + s->status = POWER_SUPPLY_STATUS_CHARGING; + s->health = POWER_SUPPLY_HEALTH_GOOD; + s->present = 1; // battery is present + s->capacity = 50; // 50% charged + + battery_state = s; + + goldfish_device_add(&s->dev, goldfish_battery_readfn, goldfish_battery_writefn, s); + + register_savevm( "battery_state", 0, BATTERY_STATE_SAVE_VERSION, + goldfish_battery_save, goldfish_battery_load, s); +} + +void goldfish_battery_set_prop(int ac, int property, int value) +{ + int new_status = (ac ? AC_STATUS_CHANGED : BATTERY_STATUS_CHANGED); + + if (ac) { + switch (property) { + case POWER_SUPPLY_PROP_ONLINE: + battery_state->ac_online = value; + break; + } + } else { + switch (property) { + case POWER_SUPPLY_PROP_STATUS: + battery_state->status = value; + break; + case POWER_SUPPLY_PROP_HEALTH: + battery_state->health = value; + break; + case POWER_SUPPLY_PROP_PRESENT: + battery_state->present = value; + break; + case POWER_SUPPLY_PROP_CAPACITY: + battery_state->capacity = value; + break; + } + } + + if (new_status != battery_state->int_status) { + battery_state->int_status |= new_status; + goldfish_device_set_irq(&battery_state->dev, 0, (battery_state->int_status & battery_state->int_enable)); + } +} + +void goldfish_battery_display(void (* callback)(void *data, const char* string), void *data) +{ + char buffer[100]; + char* value; + + sprintf(buffer, "AC: %s\r\n", (battery_state->ac_online ? "online" : "offline")); + callback(data, buffer); + + switch (battery_state->status) { + case POWER_SUPPLY_STATUS_CHARGING: + value = "Charging"; + break; + case POWER_SUPPLY_STATUS_DISCHARGING: + value = "Discharging"; + break; + case POWER_SUPPLY_STATUS_NOT_CHARGING: + value = "Not charging"; + break; + case POWER_SUPPLY_STATUS_FULL: + value = "Full"; + break; + default: + value = "Unknown"; + break; + } + sprintf(buffer, "status: %s\r\n", value); + callback(data, buffer); + + switch (battery_state->health) { + case POWER_SUPPLY_HEALTH_GOOD: + value = "Good"; + break; + case POWER_SUPPLY_HEALTH_OVERHEAT: + value = "Overhead"; + break; + case POWER_SUPPLY_HEALTH_DEAD: + value = "Dead"; + break; + case POWER_SUPPLY_HEALTH_OVERVOLTAGE: + value = "Overvoltage"; + break; + case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE: + value = "Unspecified failure"; + break; + default: + value = "Unknown"; + break; + } + sprintf(buffer, "health: %s\r\n", value); + callback(data, buffer); + + sprintf(buffer, "present: %s\r\n", (battery_state->present ? "true" : "false")); + callback(data, buffer); + + sprintf(buffer, "capacity: %d\r\n", battery_state->capacity); + callback(data, buffer); +} diff --git a/hw/goldfish_device.c b/hw/goldfish_device.c new file mode 100644 index 0000000..a7d80a6 --- /dev/null +++ b/hw/goldfish_device.c @@ -0,0 +1,200 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "arm_pic.h" +#include "goldfish_device.h" + +#define PDEV_BUS_OP_DONE (0x00) +#define PDEV_BUS_OP_REMOVE_DEV (0x04) +#define PDEV_BUS_OP_ADD_DEV (0x08) + +#define PDEV_BUS_OP_INIT (0x00) + +#define PDEV_BUS_OP (0x00) +#define PDEV_BUS_GET_NAME (0x04) +#define PDEV_BUS_NAME_LEN (0x08) +#define PDEV_BUS_ID (0x0c) +#define PDEV_BUS_IO_BASE (0x10) +#define PDEV_BUS_IO_SIZE (0x14) +#define PDEV_BUS_IRQ (0x18) +#define PDEV_BUS_IRQ_COUNT (0x1c) + +struct bus_state { + struct goldfish_device dev; + struct goldfish_device *current; +}; + +qemu_irq *goldfish_pic; +static struct goldfish_device *first_device; +static struct goldfish_device *last_device; +uint32_t goldfish_free_base; +uint32_t goldfish_free_irq; + +void goldfish_device_set_irq(struct goldfish_device *dev, int irq, int level) +{ + if(irq >= dev->irq_count) + cpu_abort (cpu_single_env, "goldfish_device_set_irq: Bad irq %d >= %d\n", irq, dev->irq_count); + else + qemu_set_irq(goldfish_pic[dev->irq + irq], level); +} + +int goldfish_add_device_no_io(struct goldfish_device *dev) +{ + if(dev->base == 0) { + dev->base = goldfish_free_base; + goldfish_free_base += dev->size; + } + if(dev->irq == 0 && dev->irq_count > 0) { + dev->irq = goldfish_free_irq; + goldfish_free_irq += dev->irq_count; + } + //printf("goldfish_add_device: %s, base %x %x, irq %d %d\n", + // dev->name, dev->base, dev->size, dev->irq, dev->irq_count); + dev->next = NULL; + if(last_device) { + last_device->next = dev; + } + else { + first_device = dev; + } + last_device = dev; + return 0; +} + +int goldfish_device_add(struct goldfish_device *dev, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, + void *opaque) +{ + int iomemtype; + goldfish_add_device_no_io(dev); + iomemtype = cpu_register_io_memory(0, mem_read, + mem_write, opaque); + cpu_register_physical_memory(dev->base, dev->size, iomemtype); + return 0; +} + +static uint32_t goldfish_bus_read(void *opaque, target_phys_addr_t offset) +{ + struct bus_state *s = (struct bus_state *)opaque; + offset -= s->dev.base; + + switch (offset) { + case PDEV_BUS_OP: + if(s->current) { + s->current->reported_state = 1; + s->current = s->current->next; + } + else { + s->current = first_device; + } + while(s->current && s->current->reported_state == 1) + s->current = s->current->next; + if(s->current) + return PDEV_BUS_OP_ADD_DEV; + else { + goldfish_device_set_irq(&s->dev, 0, 0); + return PDEV_BUS_OP_DONE; + } + + case PDEV_BUS_NAME_LEN: + return s->current ? strlen(s->current->name) : 0; + case PDEV_BUS_ID: + return s->current ? s->current->id : 0; + case PDEV_BUS_IO_BASE: + return s->current ? s->current->base : 0; + case PDEV_BUS_IO_SIZE: + return s->current ? s->current->size : 0; + case PDEV_BUS_IRQ: + return s->current ? s->current->irq : 0; + case PDEV_BUS_IRQ_COUNT: + return s->current ? s->current->irq_count : 0; + default: + cpu_abort (cpu_single_env, "goldfish_bus_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_bus_op_init(struct bus_state *s) +{ + struct goldfish_device *dev = first_device; + while(dev) { + dev->reported_state = 0; + dev = dev->next; + } + s->current = NULL; + goldfish_device_set_irq(&s->dev, 0, first_device != NULL); +} + +static void goldfish_bus_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + struct bus_state *s = (struct bus_state *)opaque; + offset -= s->dev.base; + + switch(offset) { + case PDEV_BUS_OP: + switch(value) { + case PDEV_BUS_OP_INIT: + goldfish_bus_op_init(s); + break; + default: + cpu_abort (cpu_single_env, "goldfish_bus_write: Bad PDEV_BUS_OP value %x\n", value); + }; + break; + case PDEV_BUS_GET_NAME: + if(s->current) + pmemcpy(value, s->current->name, strlen(s->current->name)); + break; + default: + cpu_abort (cpu_single_env, "goldfish_bus_write: Bad offset %x\n", offset); + } +} + +static CPUReadMemoryFunc *goldfish_bus_readfn[] = { + goldfish_bus_read, + goldfish_bus_read, + goldfish_bus_read +}; + +static CPUWriteMemoryFunc *goldfish_bus_writefn[] = { + goldfish_bus_write, + goldfish_bus_write, + goldfish_bus_write +}; + + +static struct bus_state bus_state = { + .dev = { + .name = "goldfish_device_bus", + .id = -1, + .base = 0x10001000, + .size = 0x1000, + .irq = 1, + .irq_count = 1, + } +}; + +void goldfish_device_init(qemu_irq *pic, uint32_t base, uint32_t size, uint32_t irq, uint32_t irq_count) +{ + goldfish_pic = pic; + goldfish_free_base = base; + goldfish_free_irq = irq; +} + +int goldfish_device_bus_init(uint32_t base, uint32_t irq) +{ + bus_state.dev.base = base; + bus_state.dev.irq = irq; + + return goldfish_device_add(&bus_state.dev, goldfish_bus_readfn, goldfish_bus_writefn, &bus_state); +} + diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h new file mode 100644 index 0000000..abe102e --- /dev/null +++ b/hw/goldfish_device.h @@ -0,0 +1,58 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#ifndef GOLDFISH_DEVICE_H +#define GOLDFISH_DEVICE_H + +struct goldfish_device { + struct goldfish_device *next; + struct goldfish_device *prev; + uint32_t reported_state; + void *cookie; + const char *name; + uint32_t id; + uint32_t base; // filled in by goldfish_device_add if 0 + uint32_t size; + uint32_t irq; // filled in by goldfish_device_add if 0 + uint32_t irq_count; +}; + + +void goldfish_device_set_irq(struct goldfish_device *dev, int irq, int level); +int goldfish_device_add(struct goldfish_device *dev, + CPUReadMemoryFunc **mem_read, + CPUWriteMemoryFunc **mem_write, + void *opaque); + +int goldfish_add_device_no_io(struct goldfish_device *dev); + +void goldfish_device_init(qemu_irq *pic, uint32_t base, uint32_t size, uint32_t irq, uint32_t irq_count); +int goldfish_device_bus_init(uint32_t base, uint32_t irq); + +// device init functions: +qemu_irq *goldfish_interrupt_init(uint32_t base, qemu_irq parent_irq, qemu_irq parent_fiq); +void goldfish_timer_and_rtc_init(uint32_t timerbase, int timerirq); +int goldfish_tty_add(CharDriverState *cs, int id, uint32_t base, int irq); +void goldfish_fb_init(DisplayState *ds, int id); +void goldfish_audio_init(uint32_t base, int id, const char* input_source); +void goldfish_battery_init(); +void goldfish_battery_set_prop(int ac, int property, int value); +void goldfish_battery_display(void (* callback)(void *data, const char* string), void *data); +void goldfish_mmc_init(uint32_t base, int id, BlockDriverState* bs); +void *goldfish_switch_add(char *name, uint32_t (*writefn)(void *opaque, uint32_t state), void *writeopaque, int id); +void goldfish_switch_set_state(void *opaque, uint32_t state); + +// these do not add a device +void trace_dev_init(uint32_t base); +void events_dev_init(uint32_t base, qemu_irq irq); +void nand_dev_init(uint32_t base); + +#endif diff --git a/hw/goldfish_events_device.c b/hw/goldfish_events_device.c new file mode 100644 index 0000000..66ac2fc --- /dev/null +++ b/hw/goldfish_events_device.c @@ -0,0 +1,423 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "android_events.h" +#include "irq.h" + +#if 0 +// From kernel... +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_SW 0x05 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_PINKIE 0x125 +#define BTN_BASE 0x126 +#define BTN_BASE2 0x127 +#define BTN_BASE3 0x128 +#define BTN_BASE4 0x129 +#define BTN_BASE5 0x12a +#define BTN_BASE6 0x12b +#define BTN_DEAD 0x12f + +#define BTN_GAMEPAD 0x130 +#define BTN_A 0x130 +#define BTN_B 0x131 +#define BTN_C 0x132 +#define BTN_X 0x133 +#define BTN_Y 0x134 +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c +#define BTN_THUMBL 0x13d +#define BTN_THUMBR 0x13e + +#define BTN_DIGI 0x140 +#define BTN_TOOL_PEN 0x140 +#define BTN_TOOL_RUBBER 0x141 +#define BTN_TOOL_BRUSH 0x142 +#define BTN_TOOL_PENCIL 0x143 +#define BTN_TOOL_AIRBRUSH 0x144 +#define BTN_TOOL_FINGER 0x145 +#define BTN_TOOL_MOUSE 0x146 +#define BTN_TOOL_LENS 0x147 +#define BTN_TOUCH 0x14a +#define BTN_STYLUS 0x14b +#define BTN_STYLUS2 0x14c +#define BTN_TOOL_DOUBLETAP 0x14d +#define BTN_TOOL_TRIPLETAP 0x14e + +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 + +#define REL_X 0x00 +#define REL_Y 0x01 + +#define ABS_X 0x00 +#define ABS_Y 0x01 +#define ABS_Z 0x02 +#define ABS_RX 0x03 +#define ABS_RY 0x04 +#define ABS_RZ 0x05 +#define ABS_THROTTLE 0x06 +#define ABS_RUDDER 0x07 +#define ABS_WHEEL 0x08 +#define ABS_GAS 0x09 +#define ABS_BRAKE 0x0a +#define ABS_HAT0X 0x10 +#define ABS_HAT0Y 0x11 +#define ABS_HAT1X 0x12 +#define ABS_HAT1Y 0x13 +#define ABS_HAT2X 0x14 +#define ABS_HAT2Y 0x15 +#define ABS_HAT3X 0x16 +#define ABS_HAT3Y 0x17 +#define ABS_PRESSURE 0x18 +#define ABS_DISTANCE 0x19 +#define ABS_TILT_X 0x1a +#define ABS_TILT_Y 0x1b +#define ABS_TOOL_WIDTH 0x1c +#define ABS_VOLUME 0x20 +#define ABS_MISC 0x28 +#define ABS_MAX 0x3f +#endif + +#define MAX_EVENTS 256*4 + +enum { + REG_READ = 0x00, + REG_SET_PAGE = 0x00, + REG_LEN = 0x04, + REG_DATA = 0x08, + + PAGE_NAME = 0x00000, + PAGE_EVBITS = 0x10000, + PAGE_ABSDATA = 0x20000 | EV_ABS, +}; + +typedef struct +{ + uint32_t base; + qemu_irq irq; + int pending; + int page; + + unsigned events[MAX_EVENTS]; + unsigned first; + unsigned last; + + const char *name; + struct { + size_t len; + uint8_t *bits; + } ev_bits[EV_MAX + 1]; + int32_t *abs_info; + size_t abs_info_count; +} events_state; + +/* modify this each time you change the events_device structure. you + * will also need to upadte events_state_load and events_state_save + */ +#define EVENTS_STATE_SAVE_VERSION 1 + +#undef QFIELD_STRUCT +#define QFIELD_STRUCT events_state + +QFIELD_BEGIN(events_state_fields) + QFIELD_INT32(pending), + QFIELD_INT32(page), + QFIELD_BUFFER(events), + QFIELD_INT32(first), + QFIELD_INT32(last), +QFIELD_END + +static void events_state_save(QEMUFile* f, void* opaque) +{ + events_state* s = opaque; + + qemu_put_struct(f, events_state_fields, s); +} + +static int events_state_load(QEMUFile* f, void* opaque, int version_id) +{ + events_state* s = opaque; + + if (version_id != EVENTS_STATE_SAVE_VERSION) + return -1; + + return qemu_get_struct(f, events_state_fields, s); +} + +extern const char* android_skin_keycharmap; + +static void enqueue_event(events_state *s, unsigned int type, unsigned int code, int value) +{ + int enqueued = s->last - s->first; + + if (enqueued < 0) + enqueued += MAX_EVENTS; + + if (enqueued + 3 >= MAX_EVENTS-1) { + fprintf(stderr, "##KBD: Full queue, lose event\n"); + return; + } + + if(s->first == s->last){ + qemu_irq_raise(s->irq); + } + + //fprintf(stderr, "##KBD: type=%d code=%d value=%d\n", type, code, value); + + s->events[s->last] = type; + s->last = (s->last + 1) & (MAX_EVENTS-1); + s->events[s->last] = code; + s->last = (s->last + 1) & (MAX_EVENTS-1); + s->events[s->last] = value; + s->last = (s->last + 1) & (MAX_EVENTS-1); +} + +static unsigned dequeue_event(events_state *s) +{ + unsigned n; + + if(s->first == s->last) { + return 0; + } + + n = s->events[s->first]; + + s->first = (s->first + 1) & (MAX_EVENTS - 1); + + if(s->first == s->last) { + qemu_irq_lower(s->irq); + } + + return n; +} + +static int get_page_len(events_state *s) +{ + int page = s->page; + if (page == PAGE_NAME) + return strlen(s->name); + if (page >= PAGE_EVBITS && page <= PAGE_EVBITS + EV_MAX) + return s->ev_bits[page - PAGE_EVBITS].len; + if (page == PAGE_ABSDATA) + return s->abs_info_count * sizeof(s->abs_info[0]); + return 0; +} + +static int get_page_data(events_state *s, int offset) +{ + int page_len = get_page_len(s); + int page = s->page; + if (offset > page_len) + return 0; + if (page == PAGE_NAME) + return s->name[offset]; + if (page >= PAGE_EVBITS && page <= PAGE_EVBITS + EV_MAX) + return s->ev_bits[page - PAGE_EVBITS].bits[offset]; + if (page == PAGE_ABSDATA) + return s->abs_info[offset / sizeof(s->abs_info[0])]; + return 0; +} + +static uint32_t events_read(void *x, target_phys_addr_t off) +{ + events_state *s = (events_state *) x; + int offset = off - s->base; + if (offset == REG_READ) + return dequeue_event(s); + else if (offset == REG_LEN) + return get_page_len(s); + else if (offset >= REG_DATA) + return get_page_data(s, offset - REG_DATA); + return 0; // this shouldn't happen, if the driver does the right thing +} + +static void events_write(void *x, target_phys_addr_t off, uint32_t val) +{ + events_state *s = (events_state *) x; + int offset = off - s->base; + if (offset == REG_SET_PAGE) + s->page = val; +} + +static CPUReadMemoryFunc *events_readfn[] = { + events_read, + events_read, + events_read +}; + +static CPUWriteMemoryFunc *events_writefn[] = { + events_write, + events_write, + events_write +}; + +static void events_put_keycode(void *x, int keycode) +{ + events_state *s = (events_state *) x; + + enqueue_event(s, EV_KEY, keycode&0x1ff, (keycode&0x200) ? 1 : 0); +} + +static void events_put_mouse(void *opaque, int dx, int dy, int dz, int buttons_state) +{ + events_state *s = (events_state *) opaque; + if (dz == 0) { + enqueue_event(s, EV_ABS, ABS_X, dx); + enqueue_event(s, EV_ABS, ABS_Y, dy); + enqueue_event(s, EV_ABS, ABS_Z, dz); + enqueue_event(s, EV_KEY, BTN_TOUCH, buttons_state&1); + } else { + enqueue_event(s, EV_REL, REL_X, dx); + enqueue_event(s, EV_REL, REL_Y, dy); + } + enqueue_event(s, EV_SYN, 0, 0); +} + +static void events_put_generic(void* opaque, int type, int code, int value) +{ + events_state *s = (events_state *) opaque; + + enqueue_event(s, type, code, value); +} + +static int events_set_bits(events_state *s, int type, int bitl, int bith) +{ + uint8_t *bits; + uint8_t maskl, maskh; + int il, ih; + il = bitl / 8; + ih = bith / 8; + if (ih >= s->ev_bits[type].len) { + bits = qemu_mallocz(ih + 1); + if (bits == NULL) + return -ENOMEM; + memcpy(bits, s->ev_bits[type].bits, s->ev_bits[type].len); + qemu_free(s->ev_bits[type].bits); + s->ev_bits[type].bits = bits; + s->ev_bits[type].len = ih + 1; + } + else + bits = s->ev_bits[type].bits; + maskl = 0xffU << (bitl & 7); + maskh = 0xffU >> (7 - (bith & 7)); + if (il >= ih) + maskh &= maskl; + else { + bits[il] |= maskl; + while (++il < ih) + bits[il] = 0xff; + } + bits[ih] |= maskh; + return 0; +} + +#if 0 +static int events_set_abs_info(events_state *s, int axis, int32_t min, int32_t max, int32_t fuzz, int32_t flat) +{ + int32_t *info; + if (axis * 4 >= s->abs_info_count) { + info = qemu_mallocz((axis + 1) * 4 * sizeof(int32_t)); + if (info == NULL) + return -ENOMEM; + memcpy(info, s->abs_info, s->abs_info_count); + qemu_free(s->abs_info); + s->abs_info = info; + s->abs_info_count = (axis + 1) * 4; + } + else + info = s->abs_info; + info += axis * 4; + *info++ = min; + *info++ = max; + *info++ = fuzz; + *info++ = flat; +} +#endif + +void events_dev_init(uint32_t base, qemu_irq irq) +{ + events_state *s; + int iomemtype; + + s = (events_state *) qemu_mallocz(sizeof(events_state)); + s->name = android_skin_keycharmap; + events_set_bits(s, EV_SYN, EV_SYN, EV_ABS); + events_set_bits(s, EV_SYN, EV_SW, EV_SW); + events_set_bits(s, EV_KEY, 1, 0x1ff); + events_set_bits(s, EV_REL, REL_X, REL_Y); + events_set_bits(s, EV_ABS, ABS_X, ABS_Z); + events_set_bits(s, EV_SW, 0, 0); + iomemtype = cpu_register_io_memory(0, events_readfn, events_writefn, s); + + cpu_register_physical_memory(base, 0xfff, iomemtype); + + qemu_add_kbd_event_handler(events_put_keycode, s); + qemu_add_mouse_event_handler(events_put_mouse, s, 1); + qemu_add_generic_event_handler(events_put_generic, s); + + s->base = base; + s->irq = irq; + + s->first = 0; + s->last = 0; + + register_savevm( "events_state", 0, EVENTS_STATE_SAVE_VERSION, + events_state_save, events_state_load, s ); +} + diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c new file mode 100644 index 0000000..0924735 --- /dev/null +++ b/hw/goldfish_fb.c @@ -0,0 +1,405 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "android.h" +#include "goldfish_device.h" +#include "framebuffer.h" + +enum { + FB_GET_WIDTH = 0x00, + FB_GET_HEIGHT = 0x04, + FB_INT_STATUS = 0x08, + FB_INT_ENABLE = 0x0c, + FB_SET_BASE = 0x10, + FB_SET_ROTATION = 0x14, + FB_SET_BLANK = 0x18, + FB_GET_PHYS_WIDTH = 0x1c, + FB_GET_PHYS_HEIGHT = 0x20, + + FB_INT_VSYNC = 1U << 0, + FB_INT_BASE_UPDATE_DONE = 1U << 1 +}; + +struct goldfish_fb_state { + struct goldfish_device dev; + QFrameBuffer* qfbuff; + uint32_t fb_base; + uint32_t base_valid : 1; + uint32_t need_update : 1; + uint32_t need_int : 1; + uint32_t set_rotation : 2; + uint32_t blank : 1; + uint32_t int_status; + uint32_t int_enable; + int rotation; /* 0, 1, 2 or 3 */ +}; + +#define GOLDFISH_FB_SAVE_VERSION 1 + +static void goldfish_fb_save(QEMUFile* f, void* opaque) +{ + struct goldfish_fb_state* s = opaque; + + QFrameBuffer* q = s->qfbuff; + + qemu_put_be32(f, q->width); + qemu_put_be32(f, q->height); + qemu_put_be32(f, q->pitch); + qemu_put_byte(f, q->rotation); + + qemu_put_be32(f, s->fb_base); + qemu_put_byte(f, s->base_valid); + qemu_put_byte(f, s->need_update); + qemu_put_byte(f, s->need_int); + qemu_put_byte(f, s->set_rotation); + qemu_put_byte(f, s->blank); + qemu_put_be32(f, s->int_status); + qemu_put_be32(f, s->int_enable); + qemu_put_be32(f, s->rotation); +} + +static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id) +{ + struct goldfish_fb_state* s = opaque; + + QFrameBuffer* q = s->qfbuff; + int ret = -1; + int ds_w, ds_h, ds_pitch, ds_rot; + + if (version_id != GOLDFISH_FB_SAVE_VERSION) + goto Exit; + + ds_w = qemu_get_be32(f); + ds_h = qemu_get_be32(f); + ds_pitch = qemu_get_be32(f); + ds_rot = qemu_get_byte(f); + + if (q->width != ds_w || + q->height != ds_h || + q->pitch != ds_pitch || + q->rotation != ds_rot ) + { + /* XXX: We should be able to force a resize/rotation from here ? */ + fprintf(stderr, "%s: framebuffer dimensions mismatch\n", __FUNCTION__); + goto Exit; + } + + s->fb_base = qemu_get_be32(f); + s->base_valid = qemu_get_byte(f); + s->need_update = qemu_get_byte(f); + s->need_int = qemu_get_byte(f); + s->set_rotation = qemu_get_byte(f); + s->blank = qemu_get_byte(f); + s->int_status = qemu_get_be32(f); + s->int_enable = qemu_get_be32(f); + s->rotation = qemu_get_be32(f); + + /* force a refresh */ + s->need_update = 1; + + ret = 0; +Exit: + return ret; +} + + +#define STATS 0 + +#if STATS +static int stats_counter; +static long stats_total; +static int stats_full_updates; +static long stats_total_full_updates; +#endif + +static void goldfish_fb_update_display(void *opaque) +{ + struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; + uint32_t addr; + uint32_t base; + + uint8_t* dst_line; + uint8_t* src_line; + int y_first, y_last = 0; + int full_update = 0; + int width, height, pitch; + + base = s->fb_base; + if(base == 0) + return; + + if((s->int_enable & FB_INT_VSYNC) && !(s->int_status & FB_INT_VSYNC)) { + s->int_status |= FB_INT_VSYNC; + goldfish_device_set_irq(&s->dev, 0, 1); + } + + y_first = -1; + addr = base; + if(s->need_update) { + full_update = 1; + if(s->need_int) { + s->int_status |= FB_INT_BASE_UPDATE_DONE; + if(s->int_enable & FB_INT_BASE_UPDATE_DONE) + goldfish_device_set_irq(&s->dev, 0, 1); + } + s->need_int = 0; + s->need_update = 0; + } + + src_line = phys_ram_base + base; + dst_line = s->qfbuff->pixels; + pitch = s->qfbuff->pitch; + width = s->qfbuff->width; + height = s->qfbuff->height; + +#if STATS + if (full_update) + stats_full_updates += 1; + if (++stats_counter == 120) { + stats_total += stats_counter; + stats_total_full_updates += stats_full_updates; + + printf( "full update stats: peak %.2f %% total %.2f %%\n", + stats_full_updates*100.0/stats_counter, + stats_total_full_updates*100.0/stats_total ); + + stats_counter = 0; + stats_full_updates = 0; + } +#endif /* STATS */ + + if (s->blank) + { + memset( dst_line, 0, height*pitch ); + y_first = 0; + y_last = height-1; + } + else if (full_update) + { + int yy; + + for (yy = 0; yy < height; yy++, dst_line += pitch, src_line += width*2) + { + uint16_t* src = (uint16_t*) src_line; + uint16_t* dst = (uint16_t*) dst_line; + int nn; + + for (nn = 0; nn < width; nn++) { + unsigned spix = src[nn]; + unsigned dpix = dst[nn]; +#if WORDS_BIGENDIAN + spix = ((spix << 8) | (spix >> 8)) & 0xffff; +#else + if (spix != dpix) + break; +#endif + } + + if (nn == width) + continue; + +#if WORDS_BIGENDIAN + for ( ; nn < width; nn++ ) { + unsigned spix = src[nn]; + dst[nn] = (uint16_t)((spix << 8) | (spix >> 8)); + } +#else + memcpy( dst+nn, src+nn, (width-nn)*2 ); +#endif + + y_first = (y_first < 0) ? yy : y_first; + y_last = yy; + } + } + else /* not a full update, should not happen very often with Android */ + { + int yy; + + for (yy = 0; yy < height; yy++, dst_line += pitch, src_line += width*2) + { + uint16_t* src = (uint16_t*) src_line; + uint16_t* dst = (uint16_t*) dst_line; + int len = width*2; +#if WORDS_BIGENDIAN + int nn; +#endif + int dirty = 0; + + while (len > 0) { + int len2 = TARGET_PAGE_SIZE - (addr & (TARGET_PAGE_SIZE-1)); + + if (len2 > len) + len2 = len; + + dirty |= cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG); + addr += len2; + len -= len2; + } + + if (!dirty) + continue; + +#if WORDS_BIGENDIAN + for (nn = 0; nn < width; nn++ ) { + unsigned spix = src[nn]; + dst[nn] = (uint16_t)((spix << 8) | (spix >> 8)); + } +#else + memcpy( dst, src, width*2 ); +#endif + + y_first = (y_first < 0) ? yy : y_first; + y_last = yy; + } + } + + if (y_first < 0) + return; + + y_last += 1; + //printf("goldfish_fb_update_display %d %d, base %x\n", first, last, base); + + cpu_physical_memory_reset_dirty(base + y_first * width * 2, + base + y_last * width * 2, + VGA_DIRTY_FLAG); + + qframebuffer_update( s->qfbuff, 0, y_first, width, y_last-y_first ); +} + +static void goldfish_fb_invalidate_display(void * opaque) +{ + // is this called? + struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; + s->need_update = 1; +} + +static void goldfish_fb_detach_display(void* opaque) +{ + struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque; + s->qfbuff = NULL; +} + +static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset) +{ + uint32_t ret; + struct goldfish_fb_state *s = opaque; + offset -= s->dev.base; + switch(offset) { + case FB_GET_WIDTH: + ret = s->qfbuff->width; + //printf("FB_GET_WIDTH => %d\n", ret); + return ret; + + case FB_GET_HEIGHT: + ret = s->qfbuff->height; + //printf( "FB_GET_HEIGHT = %d\n", ret); + return ret; + + case FB_INT_STATUS: + ret = s->int_status & s->int_enable; + if(ret) { + s->int_status &= ~ret; + goldfish_device_set_irq(&s->dev, 0, 0); + } + return ret; + + case FB_GET_PHYS_WIDTH: + ret = s->qfbuff->phys_width_mm; + //printf( "FB_GET_PHYS_WIDTH => %d\n", ret ); + return ret; + + case FB_GET_PHYS_HEIGHT: + ret = s->qfbuff->phys_height_mm; + //printf( "FB_GET_PHYS_HEIGHT => %d\n", ret ); + return ret; + + default: + cpu_abort (cpu_single_env, "goldfish_fb_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_fb_write(void *opaque, target_phys_addr_t offset, + uint32_t val) +{ + struct goldfish_fb_state *s = opaque; + offset -= s->dev.base; + switch(offset) { + case FB_INT_ENABLE: + s->int_enable = val; + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + break; + case FB_SET_BASE: { + int need_resize = !s->base_valid; + s->fb_base = val; + s->int_status &= ~FB_INT_BASE_UPDATE_DONE; + s->need_update = 1; + s->need_int = 1; + s->base_valid = 1; + if(s->set_rotation != s->rotation) { + //printf("FB_SET_BASE: rotation : %d => %d\n", s->rotation, s->set_rotation); + s->rotation = s->set_rotation; + need_resize = 1; + } + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + if (need_resize) { + //printf("FB_SET_BASE: need resize (rotation=%d)\n", s->rotation ); + qframebuffer_rotate( s->qfbuff, s->rotation ); + } + } break; + case FB_SET_ROTATION: + //printf( "FB_SET_ROTATION %d\n", val); + s->set_rotation = val; + break; + case FB_SET_BLANK: + s->blank = val; + s->need_update = 1; + break; + default: + cpu_abort (cpu_single_env, "goldfish_fb_write: Bad offset %x\n", offset); + } +} + +static CPUReadMemoryFunc *goldfish_fb_readfn[] = { + goldfish_fb_read, + goldfish_fb_read, + goldfish_fb_read +}; + +static CPUWriteMemoryFunc *goldfish_fb_writefn[] = { + goldfish_fb_write, + goldfish_fb_write, + goldfish_fb_write +}; + +void goldfish_fb_init(DisplayState *ds, int id) +{ + struct goldfish_fb_state *s; + + s = (struct goldfish_fb_state *)qemu_mallocz(sizeof(*s)); + s->dev.name = "goldfish_fb"; + s->dev.id = id; + s->dev.size = 0x1000; + s->dev.irq_count = 1; + + s->qfbuff = qframebuffer_fifo_get(); + qframebuffer_add_producer( s->qfbuff, s, + goldfish_fb_update_display, + goldfish_fb_invalidate_display, + goldfish_fb_detach_display ); + + goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s); + + register_savevm( "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION, + goldfish_fb_save, goldfish_fb_load, s); +} + diff --git a/hw/goldfish_interrupt.c b/hw/goldfish_interrupt.c new file mode 100644 index 0000000..c89130d --- /dev/null +++ b/hw/goldfish_interrupt.c @@ -0,0 +1,190 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "arm_pic.h" +#include "goldfish_device.h" +#include "irq.h" + +enum { + INTERRUPT_STATUS = 0x00, // number of pending interrupts + INTERRUPT_NUMBER = 0x04, + INTERRUPT_DISABLE_ALL = 0x08, + INTERRUPT_DISABLE = 0x0c, + INTERRUPT_ENABLE = 0x10 +}; + +struct goldfish_int_state { + struct goldfish_device dev; + uint32_t level; + uint32_t pending_count; + uint32_t irq_enabled; + uint32_t fiq_enabled; + qemu_irq parent_irq; + qemu_irq parent_fiq; +}; + +#define GOLDFISH_INT_SAVE_VERSION 1 + +#define QFIELD_STRUCT struct goldfish_int_state +QFIELD_BEGIN(goldfish_int_fields) + QFIELD_INT32(level), + QFIELD_INT32(pending_count), + QFIELD_INT32(irq_enabled), + QFIELD_INT32(fiq_enabled), +QFIELD_END + +static void goldfish_int_save(QEMUFile* f, void* opaque) +{ + struct goldfish_int_state* s = opaque; + + qemu_put_struct(f, goldfish_int_fields, s); +} + +static int goldfish_int_load(QEMUFile* f, void* opaque, int version_id) +{ + struct goldfish_int_state* s = opaque; + + if (version_id != GOLDFISH_INT_SAVE_VERSION) + return -1; + + return qemu_get_struct(f, goldfish_int_fields, s); +} + +static void goldfish_int_update(struct goldfish_int_state *s) +{ + uint32_t flags; + + flags = (s->level & s->irq_enabled); + qemu_set_irq(s->parent_irq, flags != 0); + + flags = (s->level & s->fiq_enabled); + qemu_set_irq(s->parent_fiq, flags != 0); +} + +static void goldfish_int_set_irq(void *opaque, int irq, int level) +{ + struct goldfish_int_state *s = (struct goldfish_int_state *)opaque; + uint32_t mask = (1U << irq); + + if(level) { + if(!(s->level & mask)) { + if(s->irq_enabled & mask) + s->pending_count++; + s->level |= mask; + } + } + else { + if(s->level & mask) { + if(s->irq_enabled & mask) + s->pending_count--; + s->level &= ~mask; + } + } + goldfish_int_update(s); +} + +static uint32_t goldfish_int_read(void *opaque, target_phys_addr_t offset) +{ + struct goldfish_int_state *s = (struct goldfish_int_state *)opaque; + offset -= s->dev.base; + + switch (offset) { + case INTERRUPT_STATUS: /* IRQ_STATUS */ + return s->pending_count; + case INTERRUPT_NUMBER: { + int i; + uint32_t pending = s->level & s->irq_enabled; + for(i = 0; i < 32; i++) { + if(pending & (1U << i)) + return i; + } + return 0; + } + default: + cpu_abort (cpu_single_env, "goldfish_int_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_int_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + struct goldfish_int_state *s = (struct goldfish_int_state *)opaque; + uint32_t mask = (1U << value); + offset -= s->dev.base; + + switch (offset) { + case INTERRUPT_DISABLE_ALL: + s->pending_count = 0; + s->level = 0; + break; + + case INTERRUPT_DISABLE: + if(s->irq_enabled & mask) { + if(s->level & mask) + s->pending_count--; + s->irq_enabled &= ~mask; + } + break; + case INTERRUPT_ENABLE: + if(!(s->irq_enabled & mask)) { + s->irq_enabled |= mask; + if(s->level & mask) + s->pending_count++; + } + break; + + default: + cpu_abort (cpu_single_env, "goldfish_int_write: Bad offset %x\n", offset); + return; + } + goldfish_int_update(s); +} + +static CPUReadMemoryFunc *goldfish_int_readfn[] = { + goldfish_int_read, + goldfish_int_read, + goldfish_int_read +}; + +static CPUWriteMemoryFunc *goldfish_int_writefn[] = { + goldfish_int_write, + goldfish_int_write, + goldfish_int_write +}; + +qemu_irq* goldfish_interrupt_init(uint32_t base, qemu_irq parent_irq, qemu_irq parent_fiq) +{ + int ret; + struct goldfish_int_state *s; + qemu_irq* qi; + + s = qemu_mallocz(sizeof(*s)); + qi = qemu_allocate_irqs(goldfish_int_set_irq, s, 32); + s->dev.name = "goldfish_interrupt_controller"; + s->dev.id = -1; + s->dev.base = base; + s->dev.size = 0x1000; + s->parent_irq = parent_irq; + s->parent_fiq = parent_fiq; + + ret = goldfish_device_add(&s->dev, goldfish_int_readfn, goldfish_int_writefn, s); + if(ret) { + qemu_free(s); + return NULL; + } + + register_savevm( "goldfish_int", 0, GOLDFISH_INT_SAVE_VERSION, + goldfish_int_save, goldfish_int_load, s); + + return qi; +} + diff --git a/hw/goldfish_memlog.c b/hw/goldfish_memlog.c new file mode 100644 index 0000000..e2a89a6 --- /dev/null +++ b/hw/goldfish_memlog.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include <unistd.h> +#include <fcntl.h> +#include <string.h> + +#include "vl.h" +#include "goldfish_device.h" +#include "audio/audio.h" + +extern void dprint(const char* fmt, ...); + +int fd = -1; + +static uint32_t memlog_read(void *opaque, target_phys_addr_t offset) +{ + struct goldfish_device *dev = opaque; + offset -= dev->base; + + return 0; +} + +unsigned info[8]; + +static void memlog_write(void *opaque, target_phys_addr_t offset, uint32_t val) +{ + char buf[128]; + struct goldfish_device *dev = opaque; + offset -= dev->base; + + info[offset / 4] = val; + + if (offset == 0) { + /* write PID and VADDR to logfile */ + sprintf(buf,"%08x %08x\n", info[0], info[1]); + write(fd, buf, strlen(buf)); + } +} + + +static CPUReadMemoryFunc *memlog_readfn[] = { + memlog_read, + memlog_read, + memlog_read +}; + +static CPUWriteMemoryFunc *memlog_writefn[] = { + memlog_write, + memlog_write, + memlog_write +}; + +struct goldfish_device memlog_dev; + +void goldfish_memlog_init(uint32_t base) +{ + struct goldfish_device *dev = &memlog_dev; + + dev->name = "goldfish_memlog"; + dev->id = 0; + dev->base = base; + dev->size = 0x1000; + dev->irq_count = 0; + + fd = open("mem.log", /* O_CREAT | */ O_TRUNC | O_WRONLY, 0644); + + goldfish_device_add(dev, memlog_readfn, memlog_writefn, dev); +} + diff --git a/hw/goldfish_mmc.c b/hw/goldfish_mmc.c new file mode 100644 index 0000000..a00340c --- /dev/null +++ b/hw/goldfish_mmc.c @@ -0,0 +1,465 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "goldfish_device.h" +#include "mmc.h" +#include "sd.h" + +enum { + /* status register */ + MMC_INT_STATUS = 0x00, + /* set this to enable IRQ */ + MMC_INT_ENABLE = 0x04, + /* set this to specify buffer address */ + MMC_SET_BUFFER = 0x08, + + /* MMC command number */ + MMC_CMD = 0x0C, + + /* MMC argument */ + MMC_ARG = 0x10, + + /* MMC response (or R2 bits 0 - 31) */ + MMC_RESP_0 = 0x14, + + /* MMC R2 response bits 32 - 63 */ + MMC_RESP_1 = 0x18, + + /* MMC R2 response bits 64 - 95 */ + MMC_RESP_2 = 0x1C, + + /* MMC R2 response bits 96 - 127 */ + MMC_RESP_3 = 0x20, + + MMC_BLOCK_LENGTH = 0x24, + MMC_BLOCK_COUNT = 0x28, + + /* MMC state flags */ + MMC_STATE = 0x2C, + + /* MMC_INT_STATUS bits */ + + MMC_STAT_END_OF_CMD = 1U << 0, + MMC_STAT_END_OF_DATA = 1U << 1, + MMC_STAT_STATE_CHANGE = 1U << 2, + + /* MMC_STATE bits */ + MMC_STATE_INSERTED = 1U << 0, + MMC_STATE_READ_ONLY = 1U << 1, +}; + + +struct goldfish_mmc_state { + struct goldfish_device dev; + BlockDriverState *bs; + // pointer to our buffer + uint8_t* buffer; + // offsets for read and write operations + uint32_t read_offset, write_offset; + // buffer status flags + uint32_t int_status; + // irq enable mask for int_status + uint32_t int_enable; + + // MMC command argument + uint32_t arg; + uint32_t resp[4]; + + uint32_t block_length; + uint32_t block_count; + int is_SDHC; +}; + +#define GOLDFISH_MMC_SAVE_VERSION 1 +#define QFIELD_STRUCT struct goldfish_mmc_state +QFIELD_BEGIN(goldfish_mmc_fields) + QFIELD_INT32(read_offset), + QFIELD_INT32(write_offset), + QFIELD_INT32(int_status), + QFIELD_INT32(int_enable), + QFIELD_INT32(arg), + QFIELD_INT32(resp[0]), + QFIELD_INT32(resp[1]), + QFIELD_INT32(resp[2]), + QFIELD_INT32(resp[3]), + QFIELD_INT32(block_length), + QFIELD_INT32(block_count), + QFIELD_INT32(is_SDHC), +QFIELD_END + +static void goldfish_mmc_save(QEMUFile* f, void* opaque) +{ + struct goldfish_mmc_state* s = opaque; + + qemu_put_be32(f, s->buffer - phys_ram_base); + qemu_put_struct(f, goldfish_mmc_fields, s); +} + +static int goldfish_mmc_load(QEMUFile* f, void* opaque, int version_id) +{ + struct goldfish_mmc_state* s = opaque; + + if (version_id != GOLDFISH_MMC_SAVE_VERSION) + return -1; + + s->buffer = qemu_get_be32(f) + phys_ram_base; + return qemu_get_struct(f, goldfish_mmc_fields, s); +} + +struct mmc_opcode { + const char* name; + int cmd; +} mmc_opcodes[] = { + { "MMC_GO_IDLE_STATE", 0 }, + { "MMC_SEND_OP_COND", 1 }, + { "MMC_ALL_SEND_CID", 2 }, + { "MMC_SET_RELATIVE_ADDR", 3 }, + { "MMC_SET_DSR", 4 }, + { "MMC_SWITCH", 6 }, + { "MMC_SELECT_CARD", 7 }, + { "MMC_SEND_EXT_CSD", 8 }, + { "MMC_SEND_CSD", 9 }, + { "MMC_SEND_CID", 10 }, + { "MMC_READ_DAT_UNTIL_STOP", 11 }, + { "MMC_STOP_TRANSMISSION", 12 }, + { "MMC_SEND_STATUS", 13 }, + { "MMC_GO_INACTIVE_STATE", 15 }, + { "MMC_SET_BLOCKLEN", 16 }, + { "MMC_READ_SINGLE_BLOCK", 17 }, + { "MMC_READ_MULTIPLE_BLOCK", 18 }, + { "MMC_WRITE_DAT_UNTIL_STOP", 20 }, + { "MMC_SET_BLOCK_COUNT", 23 }, + { "MMC_WRITE_BLOCK", 24 }, + { "MMC_WRITE_MULTIPLE_BLOCK", 25 }, + { "MMC_PROGRAM_CID", 26 }, + { "MMC_PROGRAM_CSD", 27 }, + { "MMC_SET_WRITE_PROT", 28 }, + { "MMC_CLR_WRITE_PROT", 29 }, + { "MMC_SEND_WRITE_PROT", 30 }, + { "MMC_ERASE_GROUP_START", 35 }, + { "MMC_ERASE_GROUP_END", 36 }, + { "MMC_ERASE", 38 }, + { "MMC_FAST_IO", 39 }, + { "MMC_GO_IRQ_STATE", 40 }, + { "MMC_LOCK_UNLOCK", 42 }, + { "MMC_APP_CMD", 55 }, + { "MMC_GEN_CMD", 56 }, + { "SD_APP_OP_COND", 41 }, + { "SD_APP_SEND_SCR", 51 }, + { "UNKNOWN" -1 } +}; + +static const char* get_command_name(int command) +{ + struct mmc_opcode* opcode = mmc_opcodes; + + while (opcode->cmd != command && opcode->cmd != -1) opcode++; + return opcode->name; +} + +static void goldfish_mmc_do_command(struct goldfish_mmc_state *s, uint32_t cmd, uint32_t arg) +{ + int result; + int new_status = MMC_STAT_END_OF_CMD; + int opcode = cmd & 63; + +// fprintf(stderr, "goldfish_mmc_do_command opcode: %s (0x%04X), arg: %d\n", get_command_name(opcode), cmd, arg); + + s->resp[0] = 0; + s->resp[1] = 0; + s->resp[2] = 0; + s->resp[3] = 0; + +#define SET_R1_CURRENT_STATE(s) ((s << 9) & 0x00001E00) /* sx, b (4 bits) */ + + switch (opcode) { + case MMC_SEND_CSD: { + int64_t sector_count = 0; + uint64_t capacity; + uint8_t exponent; + uint32_t m; + + bdrv_get_geometry(s->bs, §or_count); + capacity = sector_count * 512; + if (capacity > 2147483648U) { + // if storages is > 2 gig, then emulate SDHC card + s->is_SDHC = 1; + + // CSD bits borrowed from a real SDHC card, with capacity bits zeroed out + s->resp[3] = 0x400E0032; + s->resp[2] = 0x5B590000; + s->resp[1] = 0x00007F80; + s->resp[0] = 0x0A4040DF; + + // stuff in the real capacity + // m = UNSTUFF_BITS(resp, 48, 22); + m = (uint32_t)(capacity / (512*1024)) - 1; + // m must fit into 22 bits + if (m & 0xFFC00000) { + fprintf(stderr, "SD card too big (%lld bytes). Maximum SDHC card size is 128 gigabytes.\n", capacity); + abort(); + } + + // low 16 bits go in high end of resp[1] + s->resp[1] |= ((m & 0x0000FFFF) << 16); + // high 6 bits go in low end of resp[2] + s->resp[2] |= (m >> 16); + } else { + // emulate standard SD card + s->is_SDHC = 0; + + // CSD bits borrowed from a real SD card, with capacity bits zeroed out + s->resp[3] = 0x00260032; + s->resp[2] = 0x5F5A8000; + s->resp[1] = 0x3EF84FFF; + s->resp[0] = 0x928040CB; + + // stuff in the real capacity + // e = UNSTUFF_BITS(resp, 47, 3); + // m = UNSTUFF_BITS(resp, 62, 12); + // csd->capacity = (1 + m) << (e + 2); + // need to reverse the formula and calculate e and m + exponent = 0; + capacity = sector_count * 512; + if (capacity > 2147483648U) { + fprintf(stderr, "SD card too big (%lld bytes). Maximum SD card size is 2 gigabytes.\n", capacity); + abort(); + } + capacity >>= 10; // convert to Kbytes + while (capacity > 4096) { + // (capacity - 1) must fit into 12 bits + exponent++; + capacity >>= 1; + } + capacity -= 1; + exponent -= 2; + if (exponent > 7) + cpu_abort(cpu_single_env, "exponent %d too big\n", exponent); + + s->resp[2] |= (((uint32_t)capacity >> 2) & 0x3FF); // high 10 bits to bottom of resp[2] + s->resp[1] |= (((uint32_t)capacity & 3) << 30); // low 2 bits to top of resp[1] + s->resp[1] |= (exponent << (47 - 32)); + } + break; + } + + case MMC_SEND_EXT_CSD: + s->resp[0] = arg; + break; + + case MMC_APP_CMD: + s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336 + break; + + case SD_APP_OP_COND: + s->resp[0] = 0x80FF8000; + break; + + case SD_APP_SEND_SCR: + { + uint32_t* scr = (uint32_t*)s->buffer; + scr[0] = 0x00002502; + scr[1] = 0x00000000; + s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336 + new_status |= MMC_STAT_END_OF_DATA; + break; + } + case MMC_SET_RELATIVE_ADDR: + s->resp[0] = -518519520; + break; + + case MMC_ALL_SEND_CID: + s->resp[3] = 55788627; + s->resp[2] = 1429221959; + s->resp[1] = -2147479692; + s->resp[0] = -436179883; + break; + + case MMC_SELECT_CARD: + s->resp[0] = SET_R1_CURRENT_STATE(3) | R1_READY_FOR_DATA; // 1792 + break; + + case MMC_SWITCH: + if (arg == 0x00FFFFF1 || arg == 0x80FFFFF1) { + uint8_t* switchbuf = s->buffer; + memset(switchbuf, 0, 64); + switchbuf[13] = 2; + new_status |= MMC_STAT_END_OF_DATA; + } + s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336 + break; + + case MMC_SET_BLOCKLEN: + s->block_length = arg; + s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304 + break; + + case MMC_READ_SINGLE_BLOCK: + s->block_count = 1; + // fall through + case MMC_READ_MULTIPLE_BLOCK: { + if (s->is_SDHC) { + // arg is block offset + } else { + // arg is byte offset + if (arg & 511) fprintf(stderr, "offset %d is not multiple of 512 when reading\n", arg); + arg /= s->block_length; + } + result = bdrv_read(s->bs, arg, s->buffer, s->block_count); + new_status |= MMC_STAT_END_OF_DATA; + s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304 + break; + } + + case MMC_WRITE_BLOCK: + s->block_count = 1; + // fall through + case MMC_WRITE_MULTIPLE_BLOCK: { + if (s->is_SDHC) { + // arg is block offset + } else { + // arg is byte offset + if (arg & 511) fprintf(stderr, "offset %d is not multiple of 512 when writing\n", arg); + arg /= s->block_length; + } + // arg is byte offset + result = bdrv_write(s->bs, arg, s->buffer, s->block_count); +// bdrv_flush(s->bs); + new_status |= MMC_STAT_END_OF_DATA; + s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304 + break; + } + + case MMC_STOP_TRANSMISSION: + s->resp[0] = SET_R1_CURRENT_STATE(5) | R1_READY_FOR_DATA; // 2816 + break; + + case MMC_SEND_STATUS: + s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304 + break; + } + + s->int_status |= new_status; + + if ((s->int_status & s->int_enable)) { + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + } +} + +static uint32_t goldfish_mmc_read(void *opaque, target_phys_addr_t offset) +{ + uint32_t ret; + struct goldfish_mmc_state *s = opaque; + + offset -= s->dev.base; + switch(offset) { + case MMC_INT_STATUS: + // return current buffer status flags + return s->int_status & s->int_enable; + case MMC_RESP_0: + return s->resp[0]; + case MMC_RESP_1: + return s->resp[1]; + case MMC_RESP_2: + return s->resp[2]; + case MMC_RESP_3: + return s->resp[3]; + case MMC_STATE: { + ret = MMC_STATE_INSERTED; + if (bdrv_is_read_only(s->bs)) { + ret |= MMC_STATE_READ_ONLY; + } + return ret; + } + default: + cpu_abort(cpu_single_env, "goldfish_mmc_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_mmc_write(void *opaque, target_phys_addr_t offset, uint32_t val) +{ + struct goldfish_mmc_state *s = opaque; + int status, old_status; + + offset -= s->dev.base; + + switch(offset) { + + case MMC_INT_STATUS: + status = s->int_status; + old_status = status; + status &= ~val; + s->int_status = status; + if(status != old_status) { + goldfish_device_set_irq(&s->dev, 0, status); + } + break; + + case MMC_INT_ENABLE: + /* enable buffer interrupts */ + s->int_enable = val; + s->int_status = 0; + goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable)); + break; + case MMC_SET_BUFFER: + /* save pointer to buffer 1 */ + s->buffer = phys_ram_base + val; + break; + case MMC_CMD: + goldfish_mmc_do_command(s, val, s->arg); + break; + case MMC_ARG: + s->arg = val; + break; + case MMC_BLOCK_LENGTH: + s->block_length = val + 1; + break; + case MMC_BLOCK_COUNT: + s->block_count = val + 1; + break; + + default: + cpu_abort (cpu_single_env, "goldfish_mmc_write: Bad offset %x\n", offset); + } +} + +static CPUReadMemoryFunc *goldfish_mmc_readfn[] = { + goldfish_mmc_read, + goldfish_mmc_read, + goldfish_mmc_read +}; + +static CPUWriteMemoryFunc *goldfish_mmc_writefn[] = { + goldfish_mmc_write, + goldfish_mmc_write, + goldfish_mmc_write +}; + +void goldfish_mmc_init(uint32_t base, int id, BlockDriverState* bs) +{ + struct goldfish_mmc_state *s; + + s = (struct goldfish_mmc_state *)qemu_mallocz(sizeof(*s)); + s->dev.name = "goldfish_mmc"; + s->dev.id = id; + s->dev.base = base; + s->dev.size = 0x1000; + s->dev.irq_count = 1; + s->bs = bs; + + goldfish_device_add(&s->dev, goldfish_mmc_readfn, goldfish_mmc_writefn, s); + + register_savevm( "goldfish_mmc", 0, GOLDFISH_MMC_SAVE_VERSION, + goldfish_mmc_save, goldfish_mmc_load, s); +} + diff --git a/hw/goldfish_nand.c b/hw/goldfish_nand.c new file mode 100644 index 0000000..e3042bf --- /dev/null +++ b/hw/goldfish_nand.c @@ -0,0 +1,639 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "goldfish_nand_reg.h" +#include "goldfish_nand.h" +#include "android_utils.h" +#include "android_debug.h" +#include "android.h" + +#define DEBUG 1 +#if DEBUG +# define D(...) VERBOSE_PRINT(nand,__VA_ARGS__) +# define D_ACTIVE VERBOSE_CHECK(nand) +# define T(...) VERBOSE_PRINT(nand_limits,__VA_ARGS__) +# define T_ACTIVE VERBOSE_CHECK(nand_limits) +#else +# define D(...) ((void)0) +# define D_ACTIVE 0 +# define T(...) ((void)0) +# define T_ACTIVE 0 +#endif + +/* lseek uses 64-bit offsets on Darwin. */ +/* prefer lseek64 on Linux */ +#ifdef __APPLE__ +# define llseek lseek +#elif defined(__linux__) +# define llseek lseek64 +#endif + +#define XLOG xlog + +static void +xlog( const char* format, ... ) +{ + va_list args; + va_start(args, format); + fprintf(stderr, "NAND: "); + vfprintf(stderr, format, args); + va_end(args); +} + +typedef struct { + char* devname; + size_t devname_len; + char* data; + int fd; + uint32_t flags; + uint32_t page_size; + uint32_t extra_size; + uint32_t erase_size; + uint64_t size; +} nand_dev; + +nand_threshold android_nand_write_threshold; +nand_threshold android_nand_read_threshold; + +#ifdef CONFIG_NAND_THRESHOLD + +/* update a threshold, return 1 if limit is hit, 0 otherwise */ +static void +nand_threshold_update( nand_threshold* t, uint32_t len ) +{ + if (t->counter < t->limit) { + uint64_t avail = t->limit - t->counter; + if (avail > len) + avail = len; + + if (t->counter == 0) { + T("%s: starting threshold counting to %lld", + __FUNCTION__, t->limit); + } + t->counter += avail; + if (t->counter >= t->limit) { + /* threshold reach, send a signal to an external process */ + T( "%s: sending signal %d to pid %d !", + __FUNCTION__, t->signal, t->pid ); + + kill( t->pid, t->signal ); + } + } + return; +} + +#define NAND_UPDATE_READ_THRESHOLD(len) \ + nand_threshold_update( &android_nand_read_threshold, (uint32_t)(len) ) + +#define NAND_UPDATE_WRITE_THRESHOLD(len) \ + nand_threshold_update( &android_nand_write_threshold, (uint32_t)(len) ) + +#else /* !NAND_THRESHOLD */ + +#define NAND_UPDATE_READ_THRESHOLD(len) \ + do {} while (0) + +#define NAND_UPDATE_WRITE_THRESHOLD(len) \ + do {} while (0) + +#endif /* !NAND_THRESHOLD */ + +static nand_dev *nand_devs = NULL; +static uint32_t nand_dev_count = 0; + +typedef struct { + uint32_t base; + + // register state + uint32_t dev; + uint32_t addr_low; + uint32_t addr_high; + uint32_t transfer_size; + uint32_t data; + uint32_t result; +} nand_dev_state; + +/* update this everytime you change the nand_dev_state structure */ +#define NAND_DEV_STATE_SAVE_VERSION 1 + +#define QFIELD_STRUCT nand_dev_state +QFIELD_BEGIN(nand_dev_state_fields) + QFIELD_INT32(dev), + QFIELD_INT32(addr_low), + QFIELD_INT32(addr_high), + QFIELD_INT32(transfer_size), + QFIELD_INT32(data), + QFIELD_INT32(result), +QFIELD_END + +static void nand_dev_state_save(QEMUFile* f, void* opaque) +{ + nand_dev_state* s = opaque; + + qemu_put_struct(f, nand_dev_state_fields, s); +} + +static int nand_dev_state_load(QEMUFile* f, void* opaque, int version_id) +{ + nand_dev_state* s = opaque; + + if (version_id != NAND_DEV_STATE_SAVE_VERSION) + return -1; + + return qemu_get_struct(f, nand_dev_state_fields, s); +} + + +extern void vmemcpy(target_ulong ptr, char *buf, int size); /* copy memory from the simulated virtual space to a buffer in QEMU */ +extern void pmemcpy(target_ulong ptr, char *buf, int size); /* copy memory from the QEMU buffer to simulated virtual space */ + +static int do_read(int fd, void* buf, size_t size) +{ + int ret; + do { + ret = read(fd, buf, size); + } while (ret < 0 && errno == EINTR); + + return ret; +} + +static int do_write(int fd, const void* buf, size_t size) +{ + int ret; + do { + ret = write(fd, buf, size); + } while (ret < 0 && errno == EINTR); + + return ret; +} + +static uint32_t nand_dev_read_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len) +{ + uint32_t len = total_len; + size_t read_len = dev->erase_size; + int eof = 0; + + NAND_UPDATE_READ_THRESHOLD(total_len); + + lseek(dev->fd, addr, SEEK_SET); + while(len > 0) { + if(read_len < dev->erase_size) { + memset(dev->data, 0xff, dev->erase_size); + read_len = dev->erase_size; + eof = 1; + } + if(len < read_len) + read_len = len; + if(!eof) { + read_len = do_read(dev->fd, dev->data, read_len); + } + pmemcpy(data, dev->data, read_len); + data += read_len; + len -= read_len; + } + return total_len; +} + +static uint32_t nand_dev_write_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len) +{ + uint32_t len = total_len; + size_t write_len = dev->erase_size; + int ret; + + NAND_UPDATE_WRITE_THRESHOLD(total_len); + + lseek(dev->fd, addr, SEEK_SET); + while(len > 0) { + if(len < write_len) + write_len = len; + vmemcpy(data, dev->data, write_len); + ret = do_write(dev->fd, dev->data, write_len); + if(ret < write_len) { + XLOG("nand_dev_write_file, write failed: %s\n", strerror(errno)); + break; + } + data += write_len; + len -= write_len; + } + return total_len - len; +} + +static uint32_t nand_dev_erase_file(nand_dev *dev, uint64_t addr, uint32_t total_len) +{ + uint32_t len = total_len; + size_t write_len = dev->erase_size; + int ret; + + lseek(dev->fd, addr, SEEK_SET); + memset(dev->data, 0xff, dev->erase_size); + while(len > 0) { + if(len < write_len) + write_len = len; + ret = do_write(dev->fd, dev->data, write_len); + if(ret < write_len) { + XLOG( "nand_dev_write_file, write failed: %s\n", strerror(errno)); + break; + } + len -= write_len; + } + return total_len - len; +} + +/* this is a huge hack required to make the PowerPC emulator binary usable + * on Mac OS X. If you define this function as 'static', the emulated kernel + * will panic when attempting to mount the /data partition. + * + * worse, if you do *not* define the function as static on Linux-x86, the + * emulated kernel will also panic !? + * + * I still wonder if this is a compiler bug, or due to some nasty thing the + * emulator does with CPU registers during execution of the translated code. + */ +#if !(defined __APPLE__ && defined __powerpc__) +static +#endif +uint32_t nand_dev_do_cmd(nand_dev_state *s, uint32_t cmd) +{ + uint32_t size; + uint64_t addr; + nand_dev *dev; + + addr = s->addr_low | ((uint64_t)s->addr_high << 32); + size = s->transfer_size; + if(s->dev >= nand_dev_count) + return 0; + dev = nand_devs + s->dev; + + switch(cmd) { + case NAND_CMD_GET_DEV_NAME: + if(size > dev->devname_len) + size = dev->devname_len; + pmemcpy(s->data, dev->devname, size); + return size; + case NAND_CMD_READ: + if(addr >= dev->size) + return 0; + if(size + addr > dev->size) + size = dev->size - addr; + if(dev->fd >= 0) + return nand_dev_read_file(dev, s->data, addr, size); + pmemcpy(s->data, &dev->data[addr], size); + return size; + case NAND_CMD_WRITE: + if(dev->flags & NAND_DEV_FLAG_READ_ONLY) + return 0; + if(addr >= dev->size) + return 0; + if(size + addr > dev->size) + size = dev->size - addr; + if(dev->fd >= 0) + return nand_dev_write_file(dev, s->data, addr, size); + vmemcpy(s->data, &dev->data[addr], size); + return size; + case NAND_CMD_ERASE: + if(dev->flags & NAND_DEV_FLAG_READ_ONLY) + return 0; + if(addr >= dev->size) + return 0; + if(size + addr > dev->size) + size = dev->size - addr; + if(dev->fd >= 0) + return nand_dev_erase_file(dev, addr, size); + memset(&dev->data[addr], 0xff, size); + return size; + case NAND_CMD_BLOCK_BAD_GET: // no bad block support + return 0; + case NAND_CMD_BLOCK_BAD_SET: + if(dev->flags & NAND_DEV_FLAG_READ_ONLY) + return 0; + return 0; + default: + cpu_abort(cpu_single_env, "nand_dev_do_cmd: Bad command %x\n", cmd); + return 0; + } +} + +/* I/O write */ +static void nand_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + nand_dev_state *s = (nand_dev_state *)opaque; + + offset -= s->base; + switch (offset) { + case NAND_DEV: + s->dev = value; + if(s->dev >= nand_dev_count) { + cpu_abort(cpu_single_env, "nand_dev_write: Bad dev %x\n", value); + } + break; + case NAND_ADDR_HIGH: + s->addr_high = value; + break; + case NAND_ADDR_LOW: + s->addr_low = value; + break; + case NAND_TRANSFER_SIZE: + s->transfer_size = value; + break; + case NAND_DATA: + s->data = value; + break; + case NAND_COMMAND: + s->result = nand_dev_do_cmd(s, value); + break; + default: + cpu_abort(cpu_single_env, "nand_dev_write: Bad offset %x\n", offset); + break; + } +} + +/* I/O read */ +static uint32_t nand_dev_read(void *opaque, target_phys_addr_t offset) +{ + nand_dev_state *s = (nand_dev_state *)opaque; + nand_dev *dev; + + offset -= s->base; + switch (offset) { + case NAND_VERSION: + return NAND_VERSION_CURRENT; + case NAND_NUM_DEV: + return nand_dev_count; + case NAND_RESULT: + return s->result; + } + + if(s->dev >= nand_dev_count) + return 0; + + dev = nand_devs + s->dev; + + switch (offset) { + case NAND_DEV_FLAGS: + return dev->flags; + + case NAND_DEV_NAME_LEN: + return dev->devname_len; + + case NAND_DEV_PAGE_SIZE: + return dev->page_size; + + case NAND_DEV_EXTRA_SIZE: + return dev->extra_size; + + case NAND_DEV_ERASE_SIZE: + return dev->erase_size; + + case NAND_DEV_SIZE_LOW: + return (uint32_t)dev->size; + + case NAND_DEV_SIZE_HIGH: + return (uint32_t)(dev->size >> 32); + + default: + cpu_abort(cpu_single_env, "nand_dev_read: Bad offset %x\n", offset); + return 0; + } +} + +static CPUReadMemoryFunc *nand_dev_readfn[] = { + nand_dev_read, + nand_dev_read, + nand_dev_read +}; + +static CPUWriteMemoryFunc *nand_dev_writefn[] = { + nand_dev_write, + nand_dev_write, + nand_dev_write +}; + +/* initialize the QFB device */ +void nand_dev_init(uint32_t base) +{ + int iomemtype; + static int instance_id = 0; + nand_dev_state *s; + + s = (nand_dev_state *)qemu_mallocz(sizeof(nand_dev_state)); + iomemtype = cpu_register_io_memory(0, nand_dev_readfn, nand_dev_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + s->base = base; + + register_savevm( "nand_dev", instance_id++, NAND_DEV_STATE_SAVE_VERSION, + nand_dev_state_save, nand_dev_state_load, s); +} + +static int arg_match(const char *a, const char *b, size_t b_len) +{ + while(*a && b_len--) { + if(*a++ != *b++) + return 0; + } + return b_len == 0; +} + +void nand_add_dev(const char *arg) +{ + uint64_t dev_size = 0; + const char *next_arg; + const char *value; + size_t arg_len, value_len; + nand_dev *new_devs, *dev; + char *devname = NULL; + size_t devname_len = 0; + char *initfilename = NULL; + char *rwfilename = NULL; + int initfd = -1; + int rwfd = -1; + int read_only = 0; + int pad; + ssize_t read_size; + uint32_t page_size = 2048; + uint32_t extra_size = 64; + uint32_t erase_pages = 64; + + while(arg) { + next_arg = strchr(arg, ','); + value = strchr(arg, '='); + if(next_arg != NULL) { + arg_len = next_arg - arg; + next_arg++; + if(value >= next_arg) + value = NULL; + } + else + arg_len = strlen(arg); + if(value != NULL) { + size_t new_arg_len = value - arg; + value_len = arg_len - new_arg_len - 1; + arg_len = new_arg_len; + value++; + } + else + value_len = 0; + + if(devname == NULL) { + if(value != NULL) + goto bad_arg_and_value; + devname_len = arg_len; + devname = malloc(arg_len); + if(devname == NULL) + goto out_of_memory; + memcpy(devname, arg, arg_len); + } + else if(value == NULL) { + if(arg_match("readonly", arg, arg_len)) { + read_only = 1; + } + else { + XLOG("bad arg: %.*s\n", arg_len, arg); + exit(1); + } + } + else { + if(arg_match("size", arg, arg_len)) { + char *ep; + dev_size = strtoull(value, &ep, 0); + if(ep != value + value_len) + goto bad_arg_and_value; + } + else if(arg_match("pagesize", arg, arg_len)) { + char *ep; + page_size = strtoul(value, &ep, 0); + if(ep != value + value_len) + goto bad_arg_and_value; + } + else if(arg_match("extrasize", arg, arg_len)) { + char *ep; + extra_size = strtoul(value, &ep, 0); + if(ep != value + value_len) + goto bad_arg_and_value; + } + else if(arg_match("erasepages", arg, arg_len)) { + char *ep; + erase_pages = strtoul(value, &ep, 0); + if(ep != value + value_len) + goto bad_arg_and_value; + } + else if(arg_match("initfile", arg, arg_len)) { + initfilename = malloc(value_len + 1); + if(initfilename == NULL) + goto out_of_memory; + memcpy(initfilename, value, value_len); + initfilename[value_len] = '\0'; + } + else if(arg_match("file", arg, arg_len)) { + rwfilename = malloc(value_len + 1); + if(rwfilename == NULL) + goto out_of_memory; + memcpy(rwfilename, value, value_len); + rwfilename[value_len] = '\0'; + } + else { + goto bad_arg_and_value; + } + } + + arg = next_arg; + } + + if (rwfilename == NULL) { + /* we create a temporary file to store everything */ + TempFile* tmp = tempfile_create(); + + if (tmp == NULL) { + XLOG("could not create temp file for %.*s NAND disk image: %s", + devname_len, devname, strerror(errno)); + exit(1); + } + rwfilename = (char*) tempfile_path(tmp); + if (VERBOSE_CHECK(init)) + dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename); + } + + if(rwfilename) { + rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR)); + if(rwfd < 0 && read_only) { + XLOG("could not open file %s, %s\n", rwfilename, strerror(errno)); + exit(1); + } + /* this could be a writable temporary file. use atexit_close_fd to ensure + * that it is properly cleaned up at exit on Win32 + */ + if (!read_only) + atexit_close_fd(rwfd); + } + + if(initfilename) { + initfd = open(initfilename, O_BINARY | O_RDONLY); + if(initfd < 0) { + XLOG("could not open file %s, %s\n", initfilename, strerror(errno)); + exit(1); + } + if(dev_size == 0) { + dev_size = lseek(initfd, 0, SEEK_END); + lseek(initfd, 0, SEEK_SET); + } + } + + new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1)); + if(new_devs == NULL) + goto out_of_memory; + nand_devs = new_devs; + dev = &new_devs[nand_dev_count]; + + dev->page_size = page_size; + dev->extra_size = extra_size; + dev->erase_size = erase_pages * (page_size + extra_size); + pad = dev_size % dev->erase_size; + if (pad != 0) { + dev_size += (dev->erase_size - pad); + XLOG("rounding devsize up to a full eraseunit, now %llx\n", dev_size); + } + dev->devname = devname; + dev->devname_len = devname_len; + dev->size = dev_size; + dev->data = malloc(dev->erase_size); + if(dev->data == NULL) + goto out_of_memory; + dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0; + + if (initfd >= 0) { + do { + read_size = do_read(initfd, dev->data, dev->erase_size); + if(read_size < 0) { + XLOG("could not read file %s, %s\n", initfilename, strerror(errno)); + exit(1); + } + if(do_write(rwfd, dev->data, read_size) != read_size) { + XLOG("could not write file %s, %s\n", initfilename, strerror(errno)); + exit(1); + } + } while(read_size == dev->erase_size); + close(initfd); + } + dev->fd = rwfd; + + nand_dev_count++; + + return; + +out_of_memory: + XLOG("out of memory\n"); + exit(1); + +bad_arg_and_value: + XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value); + exit(1); +} + diff --git a/hw/goldfish_nand.h b/hw/goldfish_nand.h new file mode 100644 index 0000000..dcc59d8 --- /dev/null +++ b/hw/goldfish_nand.h @@ -0,0 +1,28 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#ifndef NAND_DEVICE_H +#define NAND_DEVICE_H + +void nand_dev_init(uint32_t base); +void nand_add_dev(const char *arg); + +typedef struct { + uint64_t limit; + uint64_t counter; + int pid; + int signal; +} nand_threshold; + +extern nand_threshold android_nand_read_threshold; +extern nand_threshold android_nand_write_threshold; + +#endif diff --git a/hw/goldfish_nand_reg.h b/hw/goldfish_nand_reg.h new file mode 100644 index 0000000..ea91461 --- /dev/null +++ b/hw/goldfish_nand_reg.h @@ -0,0 +1,54 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#ifndef NAND_DEVICE_REG_H +#define NAND_DEVICE_REG_H + +enum nand_cmd { + NAND_CMD_GET_DEV_NAME, // Write device name for NAND_DEV to NAND_DATA (vaddr) + NAND_CMD_READ, + NAND_CMD_WRITE, + NAND_CMD_ERASE, + NAND_CMD_BLOCK_BAD_GET, // NAND_RESULT is 1 if block is bad, 0 if it is not + NAND_CMD_BLOCK_BAD_SET +}; + +enum nand_dev_flags { + NAND_DEV_FLAG_READ_ONLY = 0x00000001 +}; + +#define NAND_VERSION_CURRENT (1) + +enum nand_reg { + // Global + NAND_VERSION = 0x000, + NAND_NUM_DEV = 0x004, + NAND_DEV = 0x008, + + // Dev info + NAND_DEV_FLAGS = 0x010, + NAND_DEV_NAME_LEN = 0x014, + NAND_DEV_PAGE_SIZE = 0x018, + NAND_DEV_EXTRA_SIZE = 0x01c, + NAND_DEV_ERASE_SIZE = 0x020, + NAND_DEV_SIZE_LOW = 0x028, + NAND_DEV_SIZE_HIGH = 0x02c, + + // Command + NAND_RESULT = 0x040, + NAND_COMMAND = 0x044, + NAND_DATA = 0x048, + NAND_TRANSFER_SIZE = 0x04c, + NAND_ADDR_LOW = 0x050, + NAND_ADDR_HIGH = 0x054, +}; + +#endif diff --git a/hw/goldfish_switch.c b/hw/goldfish_switch.c new file mode 100644 index 0000000..04fcad7 --- /dev/null +++ b/hw/goldfish_switch.c @@ -0,0 +1,172 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "goldfish_device.h" + +enum { + SW_NAME_LEN = 0x00, + SW_NAME_PTR = 0x04, + SW_FLAGS = 0x08, + SW_STATE = 0x0c, + SW_INT_STATUS = 0x10, + SW_INT_ENABLE = 0x14, + + SW_FLAGS_OUTPUT = 1U << 0 +}; + + +struct switch_state { + struct goldfish_device dev; + char *name; + uint32_t state; + uint32_t state_changed : 1; + uint32_t int_enable : 1; + uint32_t (*writefn)(void *opaque, uint32_t state); + void *writeopaque; +}; + +#define GOLDFISH_SWITCH_SAVE_VERSION 1 + +static void goldfish_switch_save(QEMUFile* f, void* opaque) +{ + struct switch_state* s = opaque; + + qemu_put_be32(f, s->state); + qemu_put_byte(f, s->state_changed); + qemu_put_byte(f, s->int_enable); +} + +static int goldfish_switch_load(QEMUFile* f, void* opaque, int version_id) +{ + struct switch_state* s = opaque; + + if (version_id != GOLDFISH_SWITCH_SAVE_VERSION) + return -1; + + s->state = qemu_get_be32(f); + s->state_changed = qemu_get_byte(f); + s->int_enable = qemu_get_byte(f); + + return 0; +} + +static uint32_t goldfish_switch_read(void *opaque, target_phys_addr_t offset) +{ + struct switch_state *s = (struct switch_state *)opaque; + offset -= s->dev.base; + + //printf("goldfish_switch_read %x %x\n", offset, size); + + switch (offset) { + case SW_NAME_LEN: + return strlen(s->name); + case SW_FLAGS: + return s->writefn ? SW_FLAGS_OUTPUT : 0; + case SW_STATE: + return s->state; + case SW_INT_STATUS: + if(s->state_changed && s->int_enable) { + s->state_changed = 0; + goldfish_device_set_irq(&s->dev, 0, 0); + return 1; + } + return 0; + default: + cpu_abort (cpu_single_env, "goldfish_switch_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_switch_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + struct switch_state *s = (struct switch_state *)opaque; + offset -= s->dev.base; + + //printf("goldfish_switch_read %x %x %x\n", offset, value, size); + + switch(offset) { + case SW_NAME_PTR: + pmemcpy(value, s->name, strlen(s->name)); + break; + + case SW_STATE: + if(s->writefn) { + uint32_t new_state; + new_state = s->writefn(s->writeopaque, value); + if(new_state != s->state) { + goldfish_switch_set_state(s, new_state); + } + } + else + cpu_abort (cpu_single_env, "goldfish_switch_write: write to SW_STATE on input\n"); + break; + + case SW_INT_ENABLE: + value &= 1; + if(s->state_changed && s->int_enable != value) + goldfish_device_set_irq(&s->dev, 0, value); + s->int_enable = value; + break; + + default: + cpu_abort (cpu_single_env, "goldfish_switch_write: Bad offset %x\n", offset); + } +} + +static CPUReadMemoryFunc *goldfish_switch_readfn[] = { + goldfish_switch_read, + goldfish_switch_read, + goldfish_switch_read +}; + +static CPUWriteMemoryFunc *goldfish_switch_writefn[] = { + goldfish_switch_write, + goldfish_switch_write, + goldfish_switch_write +}; + +void goldfish_switch_set_state(void *opaque, uint32_t state) +{ + struct switch_state *s = opaque; + s->state_changed = 1; + s->state = state; + if(s->int_enable) + goldfish_device_set_irq(&s->dev, 0, 1); +} + +void *goldfish_switch_add(char *name, uint32_t (*writefn)(void *opaque, uint32_t state), void *writeopaque, int id) +{ + int ret; + struct switch_state *s; + + s = qemu_mallocz(sizeof(*s)); + s->dev.name = "goldfish-switch"; + s->dev.id = id; + s->dev.size = 0x1000; + s->dev.irq_count = 1; + s->name = name; + s->writefn = writefn; + s->writeopaque = writeopaque; + + + ret = goldfish_device_add(&s->dev, goldfish_switch_readfn, goldfish_switch_writefn, s); + if(ret) { + qemu_free(s); + return NULL; + } + + register_savevm( "goldfish_switch", 0, GOLDFISH_SWITCH_SAVE_VERSION, + goldfish_switch_save, goldfish_switch_load, s); + + return s; +} + diff --git a/hw/goldfish_timer.c b/hw/goldfish_timer.c new file mode 100644 index 0000000..bb345a5 --- /dev/null +++ b/hw/goldfish_timer.c @@ -0,0 +1,255 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "arm_pic.h" +#include "goldfish_device.h" + +enum { + TIMER_TIME_LOW = 0x00, // get low bits of current time and update TIMER_TIME_HIGH + TIMER_TIME_HIGH = 0x04, // get high bits of time at last TIMER_TIME_LOW read + TIMER_ALARM_LOW = 0x08, // set low bits of alarm and activate it + TIMER_ALARM_HIGH = 0x0c, // set high bits of next alarm + TIMER_CLEAR_INTERRUPT = 0x10, + TIMER_CLEAR_ALARM = 0x14 +}; + +struct timer_state { + struct goldfish_device dev; + uint32_t alarm_low; + int32_t alarm_high; + int64_t now; + int armed; + QEMUTimer *timer; +}; + +#define GOLDFISH_TIMER_SAVE_VERSION 1 + +static void goldfish_timer_save(QEMUFile* f, void* opaque) +{ + struct timer_state* s = opaque; + + qemu_put_be64(f, s->now); /* in case the kernel is in the middle of a timer read */ + qemu_put_byte(f, s->armed); + if (s->armed) { + int64_t now = qemu_get_clock(vm_clock); + int64_t alarm = muldiv64(s->alarm_low | (int64_t)s->alarm_high << 32, ticks_per_sec, 1000000000); + qemu_put_be64(f, alarm-now); + } +} + +static int goldfish_timer_load(QEMUFile* f, void* opaque, int version_id) +{ + struct timer_state* s = opaque; + + if (version_id != GOLDFISH_TIMER_SAVE_VERSION) + return -1; + + s->now = qemu_get_be64(f); + s->armed = qemu_get_byte(f); + if (s->armed) { + int64_t now = qemu_get_clock(vm_clock); + int64_t diff = qemu_get_be64(f); + int64_t alarm = now + diff; + + if (alarm <= now) { + goldfish_device_set_irq(&s->dev, 0, 1); + s->armed = 0; + } else { + qemu_mod_timer(s->timer, alarm); + } + } + return 0; +} + +static uint32_t goldfish_timer_read(void *opaque, target_phys_addr_t offset) +{ + struct timer_state *s = (struct timer_state *)opaque; + offset -= s->dev.base; + switch(offset) { + case TIMER_TIME_LOW: + s->now = muldiv64(qemu_get_clock(vm_clock), 1000000000, ticks_per_sec); + return s->now; + case TIMER_TIME_HIGH: + return s->now >> 32; + default: + cpu_abort (cpu_single_env, "goldfish_timer_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_timer_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + struct timer_state *s = (struct timer_state *)opaque; + int64_t alarm, now; + offset -= s->dev.base; + switch(offset) { + case TIMER_ALARM_LOW: + s->alarm_low = value; + alarm = muldiv64(s->alarm_low | (int64_t)s->alarm_high << 32, ticks_per_sec, 1000000000); + now = qemu_get_clock(vm_clock); + if (alarm <= now) { + goldfish_device_set_irq(&s->dev, 0, 1); + } else { + qemu_mod_timer(s->timer, alarm); + s->armed = 1; + } + break; + case TIMER_ALARM_HIGH: + s->alarm_high = value; + //printf("alarm_high %d\n", s->alarm_high); + break; + case TIMER_CLEAR_ALARM: + qemu_del_timer(s->timer); + s->armed = 0; + /* fall through */ + case TIMER_CLEAR_INTERRUPT: + goldfish_device_set_irq(&s->dev, 0, 0); + break; + default: + cpu_abort (cpu_single_env, "goldfish_timer_write: Bad offset %x\n", offset); + } +} + +static void goldfish_timer_tick(void *opaque) +{ + struct timer_state *s = (struct timer_state *)opaque; + + s->armed = 0; + goldfish_device_set_irq(&s->dev, 0, 1); +} + +struct rtc_state { + struct goldfish_device dev; + uint32_t alarm_low; + int32_t alarm_high; + int64_t now; +}; + +/* we save the RTC for the case where the kernel is in the middle of a rtc_read + * (i.e. it has read the low 32-bit of s->now, but not the high 32-bits yet */ +#define GOLDFISH_RTC_SAVE_VERSION 1 + +static void goldfish_rtc_save(QEMUFile* f, void* opaque) +{ + struct rtc_state* s = opaque; + + qemu_put_be64(f, s->now); +} + +static int goldfish_rtc_load(QEMUFile* f, void* opaque, int version_id) +{ + struct rtc_state* s = opaque; + + if (version_id != GOLDFISH_RTC_SAVE_VERSION) + return -1; + + /* this is an old value that is not correct. but that's ok anyway */ + s->now = qemu_get_be64(f); + return 0; +} + +static uint32_t goldfish_rtc_read(void *opaque, target_phys_addr_t offset) +{ + struct rtc_state *s = (struct rtc_state *)opaque; + offset -= s->dev.base; + switch(offset) { + case 0x0: + s->now = (int64_t)time(NULL) * 1000000000; + return s->now; + case 0x4: + return s->now >> 32; + default: + cpu_abort (cpu_single_env, "goldfish_rtc_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_rtc_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + struct rtc_state *s = (struct rtc_state *)opaque; + int64_t alarm; + offset -= s->dev.base; + switch(offset) { + case 0x8: + s->alarm_low = value; + alarm = s->alarm_low | (int64_t)s->alarm_high << 32; + //printf("next alarm at %lld, tps %lld\n", alarm, ticks_per_sec); + //qemu_mod_timer(s->timer, alarm); + break; + case 0xc: + s->alarm_high = value; + //printf("alarm_high %d\n", s->alarm_high); + break; + case 0x10: + goldfish_device_set_irq(&s->dev, 0, 0); + break; + default: + cpu_abort (cpu_single_env, "goldfish_rtc_write: Bad offset %x\n", offset); + } +} + +static struct timer_state timer_state = { + .dev = { + .name = "goldfish_timer", + .id = -1, + .size = 0x1000, + .irq_count = 1, + } +}; + +static struct timer_state rtc_state = { + .dev = { + .name = "goldfish_rtc", + .id = -1, + .size = 0x1000, + .irq_count = 1, + } +}; + +static CPUReadMemoryFunc *goldfish_timer_readfn[] = { + goldfish_timer_read, + goldfish_timer_read, + goldfish_timer_read +}; + +static CPUWriteMemoryFunc *goldfish_timer_writefn[] = { + goldfish_timer_write, + goldfish_timer_write, + goldfish_timer_write +}; + +static CPUReadMemoryFunc *goldfish_rtc_readfn[] = { + goldfish_rtc_read, + goldfish_rtc_read, + goldfish_rtc_read +}; + +static CPUWriteMemoryFunc *goldfish_rtc_writefn[] = { + goldfish_rtc_write, + goldfish_rtc_write, + goldfish_rtc_write +}; + +void goldfish_timer_and_rtc_init(uint32_t timerbase, int timerirq) +{ + timer_state.dev.base = timerbase; + timer_state.dev.irq = timerirq; + timer_state.timer = qemu_new_timer(vm_clock, goldfish_timer_tick, &timer_state); + goldfish_device_add(&timer_state.dev, goldfish_timer_readfn, goldfish_timer_writefn, &timer_state); + register_savevm( "goldfish_timer", 0, GOLDFISH_TIMER_SAVE_VERSION, + goldfish_timer_save, goldfish_timer_load, &timer_state); + + goldfish_device_add(&rtc_state.dev, goldfish_rtc_readfn, goldfish_rtc_writefn, &rtc_state); + register_savevm( "goldfish_rtc", 0, GOLDFISH_RTC_SAVE_VERSION, + goldfish_rtc_save, goldfish_rtc_load, &rtc_state); +} + diff --git a/hw/goldfish_trace.c b/hw/goldfish_trace.c new file mode 100644 index 0000000..47822b3 --- /dev/null +++ b/hw/goldfish_trace.c @@ -0,0 +1,252 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +/* + * Virtual hardware for bridging the FUSE kernel module + * in the emulated OS and outside file system + */ +#include "vl.h" + +#include "goldfish_trace.h" + +//#define DEBUG 1 + +extern void cpu_loop_exit(void); + +extern int tracing; + +/* for execve */ +static char path[CLIENT_PAGE_SIZE]; +static char arg[CLIENT_PAGE_SIZE]; +static unsigned long vstart; // VM start +static unsigned long vend; // VM end +static unsigned long eoff; // offset in EXE file +static unsigned cmdlen; // cmdline length +static unsigned pid; // PID (really thread id) +static unsigned tgid; // thread group id (really process id) +static unsigned long dsaddr; // dynamic symbol address +static unsigned long unmap_start; // start address to unmap + +/* for context switch */ +//static unsigned long cs_pid; // context switch PID + +/* I/O write */ +static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + trace_dev_state *s = (trace_dev_state *)opaque; + + offset -= s->base; + switch (offset >> 2) { + case TRACE_DEV_REG_SWITCH: // context switch, switch to pid + trace_switch(value); +#ifdef DEBUG + printf("QEMU.trace: kernel, context switch %u\n", value); +#endif + break; + case TRACE_DEV_REG_TGID: // save the tgid for the following fork/clone + tgid = value; +#ifdef DEBUG + printf("QEMU.trace: kernel, tgid %u\n", value); +#endif + break; + case TRACE_DEV_REG_FORK: // fork, fork new pid + trace_fork(tgid, value); +#ifdef DEBUG + printf("QEMU.trace: kernel, fork %u\n", value); +#endif + break; + case TRACE_DEV_REG_CLONE: // fork, clone new pid (i.e. thread) + trace_clone(tgid, value); +#ifdef DEBUG + printf("QEMU.trace: kernel, clone %u\n", value); +#endif + break; + case TRACE_DEV_REG_EXECVE_VMSTART: // execve, vstart + vstart = value; + break; + case TRACE_DEV_REG_EXECVE_VMEND: // execve, vend + vend = value; + break; + case TRACE_DEV_REG_EXECVE_OFFSET: // execve, offset in EXE + eoff = value; + break; + case TRACE_DEV_REG_EXECVE_EXEPATH: // init exec, path of EXE + vstrcpy(value, path, CLIENT_PAGE_SIZE); + trace_init_exec(vstart, vend, eoff, path); +#ifdef DEBUG + printf("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path); +#endif + path[0] = 0; + break; + case TRACE_DEV_REG_CMDLINE_LEN: // execve, process cmdline length + cmdlen = value; + break; + case TRACE_DEV_REG_CMDLINE: // execve, process cmdline + vmemcpy(value, arg, cmdlen); + trace_execve(arg, cmdlen); +#ifdef DEBUG + { + int i; + for (i = 0; i < cmdlen; i ++) + if (i != cmdlen - 1 && arg[i] == 0) + arg[i] = ' '; + printf("QEMU.trace: kernel, execve %s[%d]\n", arg, cmdlen); + } +#endif + arg[0] = 0; + break; + case TRACE_DEV_REG_EXIT: // exit, exit current process with exit code + trace_exit(value); +#ifdef DEBUG + printf("QEMU.trace: kernel, exit %x\n", value); +#endif + break; + case TRACE_DEV_REG_NAME: // record thread name + vstrcpy(value, path, CLIENT_PAGE_SIZE); + + // Remove the trailing newline if it exists + int len = strlen(path); + if (path[len - 1] == '\n') { + path[len - 1] = 0; + } + trace_name(path); +#ifdef DEBUG + printf("QEMU.trace: kernel, name %s\n", path); +#endif + break; + case TRACE_DEV_REG_MMAP_EXEPATH: // mmap, path of EXE, the others are same as execve + vstrcpy(value, path, CLIENT_PAGE_SIZE); + trace_mmap(vstart, vend, eoff, path); +#ifdef DEBUG + printf("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path); +#endif + path[0] = 0; + break; + case TRACE_DEV_REG_INIT_PID: // init, name the pid that starts before device registered + pid = value; + break; + case TRACE_DEV_REG_INIT_NAME: // init, the comm of the init pid + vstrcpy(value, path, CLIENT_PAGE_SIZE); + trace_init_name(tgid, pid, path); +#ifdef DEBUG + printf("QEMU.trace: kernel, init name %u [%s]\n", pid, path); +#endif + path[0] = 0; + break; + + case TRACE_DEV_REG_DYN_SYM_ADDR: // dynamic symbol address + dsaddr = value; + break; + case TRACE_DEV_REG_DYN_SYM: // add dynamic symbol + vstrcpy(value, arg, CLIENT_PAGE_SIZE); + trace_dynamic_symbol_add(dsaddr, arg); +#ifdef DEBUG + printf("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, arg); +#endif + arg[0] = 0; + break; + case TRACE_DEV_REG_REMOVE_ADDR: // remove dynamic symbol addr + trace_dynamic_symbol_remove(value); +#ifdef DEBUG + printf("QEMU.trace: dynamic symbol remove %lx\n", dsaddr); +#endif + arg[0] = 0; + break; + + case TRACE_DEV_REG_PRINT_STR: // print string + vstrcpy(value, arg, CLIENT_PAGE_SIZE); + printf("%s", arg); + arg[0] = 0; + break; + case TRACE_DEV_REG_PRINT_NUM_DEC: // print number in decimal + printf("%d", value); + break; + case TRACE_DEV_REG_PRINT_NUM_HEX: // print number in hexical + printf("%x", value); + break; + + case TRACE_DEV_REG_STOP_EMU: // stop the VM execution + // To ensure that the number of instructions executed in this + // block is correct, we pretend that there was an exception. + trace_exception(0); + + cpu_single_env->exception_index = EXCP_HLT; + cpu_single_env->halted = 1; + qemu_system_shutdown_request(); + cpu_loop_exit(); + break; + + case TRACE_DEV_REG_ENABLE: // tracing enable: 0 = stop, 1 = start + if (value == 1) + start_tracing(); + else if (value == 0) { + stop_tracing(); + + // To ensure that the number of instructions executed in this + // block is correct, we pretend that there was an exception. + trace_exception(0); + } + break; + + case TRACE_DEV_REG_UNMAP_START: + unmap_start = value; + break; + case TRACE_DEV_REG_UNMAP_END: + trace_munmap(unmap_start, value); + break; + + default: + cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset); + break; + } +} + +/* I/O read */ +static uint32_t trace_dev_read(void *opaque, target_phys_addr_t offset) +{ + trace_dev_state *s = (trace_dev_state *)opaque; + + offset -= s->base; + switch (offset >> 2) { + case TRACE_DEV_REG_ENABLE: // tracing enable + return tracing; + default: + cpu_abort(cpu_single_env, "trace_dev_read: Bad offset %x\n", offset); + return 0; + } + return 0; +} + +static CPUReadMemoryFunc *trace_dev_readfn[] = { + trace_dev_read, + trace_dev_read, + trace_dev_read +}; + +static CPUWriteMemoryFunc *trace_dev_writefn[] = { + trace_dev_write, + trace_dev_write, + trace_dev_write +}; + +/* initialize the trace device */ +void trace_dev_init(uint32_t base) +{ + int iomemtype; + trace_dev_state *s; + + s = (trace_dev_state *)qemu_mallocz(sizeof(trace_dev_state)); + iomemtype = cpu_register_io_memory(0, trace_dev_readfn, trace_dev_writefn, s); + cpu_register_physical_memory(base, 0x00000fff, iomemtype); + s->base = base; + + path[0] = arg[0] = '\0'; +} diff --git a/hw/goldfish_trace.h b/hw/goldfish_trace.h new file mode 100644 index 0000000..ea627e8 --- /dev/null +++ b/hw/goldfish_trace.h @@ -0,0 +1,78 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#ifndef _TRACE_DEV_H_ +#define _TRACE_DEV_H_ + +#define CLIENT_PAGE_SIZE 4096 + +/* trace device registers */ +#define TRACE_DEV_REG_SWITCH 0 +#define TRACE_DEV_REG_FORK 1 +#define TRACE_DEV_REG_EXECVE_PID 2 +#define TRACE_DEV_REG_EXECVE_VMSTART 3 +#define TRACE_DEV_REG_EXECVE_VMEND 4 +#define TRACE_DEV_REG_EXECVE_OFFSET 5 +#define TRACE_DEV_REG_EXECVE_EXEPATH 6 +#define TRACE_DEV_REG_EXIT 7 +#define TRACE_DEV_REG_CMDLINE 8 +#define TRACE_DEV_REG_CMDLINE_LEN 9 +#define TRACE_DEV_REG_MMAP_EXEPATH 10 +#define TRACE_DEV_REG_INIT_PID 11 +#define TRACE_DEV_REG_INIT_NAME 12 +#define TRACE_DEV_REG_CLONE 13 +#define TRACE_DEV_REG_UNMAP_START 14 +#define TRACE_DEV_REG_UNMAP_END 15 +#define TRACE_DEV_REG_NAME 16 +#define TRACE_DEV_REG_TGID 17 +#define TRACE_DEV_REG_DYN_SYM 50 +#define TRACE_DEV_REG_DYN_SYM_ADDR 51 +#define TRACE_DEV_REG_REMOVE_ADDR 52 +#define TRACE_DEV_REG_PRINT_STR 60 +#define TRACE_DEV_REG_PRINT_NUM_DEC 61 +#define TRACE_DEV_REG_PRINT_NUM_HEX 62 +#define TRACE_DEV_REG_STOP_EMU 90 +#define TRACE_DEV_REG_ENABLE 100 + +/* the virtual trace device state */ +typedef struct { + uint32_t base; +} trace_dev_state; + +/* + * interfaces for copy from virtual space + * from target-arm/op_helper.c + */ +extern unsigned long v2p(target_ulong ptr, int is_user); +extern void vmemcpy(target_ulong ptr, char *buf, int size); +extern void vstrcpy(target_ulong ptr, char *buf, int max); + +/* + * interfaces to trace module to signal kernel events + */ +extern void trace_switch(int pid); +extern void trace_fork(int tgid, int pid); +extern void trace_clone(int tgid, int pid); +extern void trace_execve(const char *arg, int len); +extern void trace_exit(int exitcode); +extern void trace_mmap(unsigned long vstart, unsigned long vend, + unsigned long offset, const char *path); +extern void trace_munmap(unsigned long vstart, unsigned long vend); +extern void trace_dynamic_symbol_add(unsigned long vaddr, const char *name); +extern void trace_dynamic_symbol_remove(unsigned long vaddr); +extern void trace_init_name(int tgid, int pid, const char *name); +extern void trace_init_exec(unsigned long start, unsigned long end, + unsigned long offset, const char *exe); +extern void start_tracing(void); +extern void stop_tracing(void); +extern void trace_exception(uint32 target_pc); + +#endif diff --git a/hw/goldfish_tty.c b/hw/goldfish_tty.c new file mode 100644 index 0000000..d61712a --- /dev/null +++ b/hw/goldfish_tty.c @@ -0,0 +1,225 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "vl.h" +#include "goldfish_device.h" + +enum { + TTY_PUT_CHAR = 0x00, + TTY_BYTES_READY = 0x04, + TTY_CMD = 0x08, + + TTY_DATA_PTR = 0x10, + TTY_DATA_LEN = 0x14, + + TTY_CMD_INT_DISABLE = 0, + TTY_CMD_INT_ENABLE = 1, + TTY_CMD_WRITE_BUFFER = 2, + TTY_CMD_READ_BUFFER = 3, +}; + +struct tty_state { + struct goldfish_device dev; + CharDriverState *cs; + uint32_t ptr; + uint32_t ptr_len; + uint32_t ready; + uint8_t data[128]; + uint32_t data_count; +}; + +#define GOLDFISH_TTY_SAVE_VERSION 1 + +static void goldfish_tty_save(QEMUFile* f, void* opaque) +{ + struct tty_state* s = opaque; + + qemu_put_be32( f, s->ptr ); + qemu_put_be32( f, s->ptr_len ); + qemu_put_byte( f, s->ready ); + qemu_put_byte( f, s->data_count ); + qemu_put_buffer( f, s->data, s->data_count ); +} + +static int goldfish_tty_load(QEMUFile* f, void* opaque, int version_id) +{ + struct tty_state* s = opaque; + + if (version_id != GOLDFISH_TTY_SAVE_VERSION) + return -1; + + s->ptr = qemu_get_be32(f); + s->ptr_len = qemu_get_be32(f); + s->ready = qemu_get_byte(f); + s->data_count = qemu_get_byte(f); + qemu_get_buffer(f, s->data, s->data_count); + + return 0; +} + +static uint32_t goldfish_tty_read(void *opaque, target_phys_addr_t offset) +{ + struct tty_state *s = (struct tty_state *)opaque; + offset -= s->dev.base; + + //printf("goldfish_tty_read %x %x\n", offset, size); + + switch (offset) { + case TTY_BYTES_READY: + return s->data_count; + default: + cpu_abort (cpu_single_env, "goldfish_tty_read: Bad offset %x\n", offset); + return 0; + } +} + +static void goldfish_tty_write(void *opaque, target_phys_addr_t offset, uint32_t value) +{ + struct tty_state *s = (struct tty_state *)opaque; + offset -= s->dev.base; + + //printf("goldfish_tty_read %x %x %x\n", offset, value, size); + + switch(offset) { + case TTY_PUT_CHAR: { + uint8_t ch = value; + if(s->cs) + qemu_chr_write(s->cs, &ch, 1); + } break; + + case TTY_CMD: + switch(value) { + case TTY_CMD_INT_DISABLE: + if(s->ready) { + if(s->data_count > 0) + goldfish_device_set_irq(&s->dev, 0, 0); + s->ready = 0; + } + break; + + case TTY_CMD_INT_ENABLE: + if(!s->ready) { + if(s->data_count > 0) + goldfish_device_set_irq(&s->dev, 0, 1); + s->ready = 1; + } + break; + + case TTY_CMD_WRITE_BUFFER: + if(s->cs) { + int len; + target_ulong buf; + + buf = s->ptr; + len = s->ptr_len; + + while(len) { + int page_remain = TARGET_PAGE_SIZE - (buf & ~TARGET_PAGE_MASK); + int to_write = len; + uint8_t *phys = (uint8_t *)v2p(buf, 0); + if(to_write > page_remain) + to_write = page_remain; + qemu_chr_write(s->cs, phys, to_write); + buf += to_write; + len -= to_write; + } + //printf("goldfish_tty_write: got %d bytes from %x\n", s->ptr_len, s->ptr); + } + break; + + case TTY_CMD_READ_BUFFER: + if(s->ptr_len > s->data_count) + cpu_abort (cpu_single_env, "goldfish_tty_write: reading more data than available %d %d\n", s->ptr_len, s->data_count); + pmemcpy(s->ptr, s->data, s->ptr_len); + //printf("goldfish_tty_write: read %d bytes to %x\n", s->ptr_len, s->ptr); + if(s->data_count > s->ptr_len) + memmove(s->data, s->data + s->ptr_len, s->data_count - s->ptr_len); + s->data_count -= s->ptr_len; + if(s->data_count == 0 && s->ready) + goldfish_device_set_irq(&s->dev, 0, 0); + break; + + default: + cpu_abort (cpu_single_env, "goldfish_tty_write: Bad command %x\n", value); + }; + break; + + case TTY_DATA_PTR: + s->ptr = value; + break; + + case TTY_DATA_LEN: + s->ptr_len = value; + break; + + default: + cpu_abort (cpu_single_env, "goldfish_tty_write: Bad offset %x\n", offset); + } +} + +static int tty_can_recieve(void *opaque) +{ + struct tty_state *s = opaque; + + return (sizeof(s->data) - s->data_count); +} + +static void tty_recieve(void *opaque, const uint8_t *buf, int size) +{ + struct tty_state *s = opaque; + + memcpy(s->data + s->data_count, buf, size); + s->data_count += size; + if(s->data_count > 0 && s->ready) + goldfish_device_set_irq(&s->dev, 0, 1); +} + +static CPUReadMemoryFunc *goldfish_tty_readfn[] = { + goldfish_tty_read, + goldfish_tty_read, + goldfish_tty_read +}; + +static CPUWriteMemoryFunc *goldfish_tty_writefn[] = { + goldfish_tty_write, + goldfish_tty_write, + goldfish_tty_write +}; + +int goldfish_tty_add(CharDriverState *cs, int id, uint32_t base, int irq) +{ + int ret; + struct tty_state *s; + static int instance_id = 0; + + s = qemu_mallocz(sizeof(*s)); + s->dev.name = "goldfish_tty"; + s->dev.id = id; + s->dev.base = base; + s->dev.size = 0x1000; + s->dev.irq = irq; + s->dev.irq_count = 1; + s->cs = cs; + + if(cs) { + qemu_chr_add_read_handler(cs, tty_can_recieve, tty_recieve, s); + } + + ret = goldfish_device_add(&s->dev, goldfish_tty_readfn, goldfish_tty_writefn, s); + if(ret) { + qemu_free(s); + } else { + register_savevm( "goldfish_tty", instance_id++, GOLDFISH_TTY_SAVE_VERSION, + goldfish_tty_save, goldfish_tty_load, s); + } + return ret; +} + diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c deleted file mode 100644 index e3cbceb..0000000 --- a/hw/grackle_pci.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * QEMU Grackle (heathrow PPC) PCI host - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "vl.h" -typedef target_phys_addr_t pci_addr_t; -#include "pci_host.h" - -typedef PCIHostState GrackleState; - -static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - GrackleState *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - s->config_reg = val; -} - -static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr) -{ - GrackleState *s = opaque; - uint32_t val; - - val = s->config_reg; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *pci_grackle_config_write[] = { - &pci_grackle_config_writel, - &pci_grackle_config_writel, - &pci_grackle_config_writel, -}; - -static CPUReadMemoryFunc *pci_grackle_config_read[] = { - &pci_grackle_config_readl, - &pci_grackle_config_readl, - &pci_grackle_config_readl, -}; - -static CPUWriteMemoryFunc *pci_grackle_write[] = { - &pci_host_data_writeb, - &pci_host_data_writew, - &pci_host_data_writel, -}; - -static CPUReadMemoryFunc *pci_grackle_read[] = { - &pci_host_data_readb, - &pci_host_data_readw, - &pci_host_data_readl, -}; - -/* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ -static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level) -{ - heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level); -} - -PCIBus *pci_grackle_init(uint32_t base, void *pic) -{ - GrackleState *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data; - - s = qemu_mallocz(sizeof(GrackleState)); - s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0); - - pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, - pci_grackle_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_grackle_read, - pci_grackle_write, s); - cpu_register_physical_memory(base, 0x1000, pci_mem_config); - cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data); - d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice), - 0, NULL, NULL); - d->config[0x00] = 0x57; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = 0x02; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x09] = 0x01; - d->config[0x0a] = 0x00; // class_sub = host - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x00; // header_type - - d->config[0x18] = 0x00; // primary_bus - d->config[0x19] = 0x01; // secondary_bus - d->config[0x1a] = 0x00; // subordinate_bus - d->config[0x1c] = 0x00; - d->config[0x1d] = 0x00; - - d->config[0x20] = 0x00; // memory_base - d->config[0x21] = 0x00; - d->config[0x22] = 0x01; // memory_limit - d->config[0x23] = 0x00; - - d->config[0x24] = 0x00; // prefetchable_memory_base - d->config[0x25] = 0x00; - d->config[0x26] = 0x00; // prefetchable_memory_limit - d->config[0x27] = 0x00; - -#if 0 - /* PCI2PCI bridge same values as PearPC - check this */ - d->config[0x00] = 0x11; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = 0x26; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x02; // revision - d->config[0x0a] = 0x04; // class_sub = pci2pci - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x01; // header_type - - d->config[0x18] = 0x0; // primary_bus - d->config[0x19] = 0x1; // secondary_bus - d->config[0x1a] = 0x1; // subordinate_bus - d->config[0x1c] = 0x10; // io_base - d->config[0x1d] = 0x20; // io_limit - - d->config[0x20] = 0x80; // memory_base - d->config[0x21] = 0x80; - d->config[0x22] = 0x90; // memory_limit - d->config[0x23] = 0x80; - - d->config[0x24] = 0x00; // prefetchable_memory_base - d->config[0x25] = 0x84; - d->config[0x26] = 0x00; // prefetchable_memory_limit - d->config[0x27] = 0x85; -#endif - return s->bus; -} - diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c deleted file mode 100644 index 4980cef..0000000 --- a/hw/heathrow_pic.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Heathrow PIC support (standard PowerMac PIC) - * - * Copyright (c) 2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -//#define DEBUG - -typedef struct HeathrowPIC { - uint32_t events; - uint32_t mask; - uint32_t levels; - uint32_t level_triggered; -} HeathrowPIC; - -struct HeathrowPICS { - HeathrowPIC pics[2]; -}; - -static inline int check_irq(HeathrowPIC *pic) -{ - return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask; -} - -/* update the CPU irq state */ -static void heathrow_pic_update(HeathrowPICS *s) -{ - if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) { - cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); - } else { - cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD); - } -} - -static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - HeathrowPICS *s = opaque; - HeathrowPIC *pic; - unsigned int n; - - value = bswap32(value); -#ifdef DEBUG - printf("pic_writel: %08x: %08x\n", - addr, value); -#endif - n = ((addr & 0xfff) - 0x10) >> 4; - if (n >= 2) - return; - pic = &s->pics[n]; - switch(addr & 0xf) { - case 0x04: - pic->mask = value; - heathrow_pic_update(s); - break; - case 0x08: - /* do not reset level triggered IRQs */ - value &= ~pic->level_triggered; - pic->events &= ~value; - heathrow_pic_update(s); - break; - default: - break; - } -} - -static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) -{ - HeathrowPICS *s = opaque; - HeathrowPIC *pic; - unsigned int n; - uint32_t value; - - n = ((addr & 0xfff) - 0x10) >> 4; - if (n >= 2) { - value = 0; - } else { - pic = &s->pics[n]; - switch(addr & 0xf) { - case 0x0: - value = pic->events; - break; - case 0x4: - value = pic->mask; - break; - case 0xc: - value = pic->levels; - break; - default: - value = 0; - break; - } - } -#ifdef DEBUG - printf("pic_readl: %08x: %08x\n", - addr, value); -#endif - value = bswap32(value); - return value; -} - -static CPUWriteMemoryFunc *pic_write[] = { - &pic_writel, - &pic_writel, - &pic_writel, -}; - -static CPUReadMemoryFunc *pic_read[] = { - &pic_readl, - &pic_readl, - &pic_readl, -}; - - -void heathrow_pic_set_irq(void *opaque, int num, int level) -{ - HeathrowPICS *s = opaque; - HeathrowPIC *pic; - unsigned int irq_bit; - -#if defined(DEBUG) - { - static int last_level[64]; - if (last_level[num] != level) { - printf("set_irq: num=0x%02x level=%d\n", num, level); - last_level[num] = level; - } - } -#endif - pic = &s->pics[1 - (num >> 5)]; - irq_bit = 1 << (num & 0x1f); - if (level) { - pic->events |= irq_bit & ~pic->level_triggered; - pic->levels |= irq_bit; - } else { - pic->levels &= ~irq_bit; - } - heathrow_pic_update(s); -} - -HeathrowPICS *heathrow_pic_init(int *pmem_index) -{ - HeathrowPICS *s; - - s = qemu_mallocz(sizeof(HeathrowPICS)); - s->pics[0].level_triggered = 0; - s->pics[1].level_triggered = 0x1ff00000; - *pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s); - return s; -} diff --git a/hw/i8254.c b/hw/i8254.c deleted file mode 100644 index a409763..0000000 --- a/hw/i8254.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * QEMU 8253/8254 interval timer emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -//#define DEBUG_PIT - -#define RW_STATE_LSB 1 -#define RW_STATE_MSB 2 -#define RW_STATE_WORD0 3 -#define RW_STATE_WORD1 4 - -typedef struct PITChannelState { - int count; /* can be 65536 */ - uint16_t latched_count; - uint8_t count_latched; - uint8_t status_latched; - uint8_t status; - uint8_t read_state; - uint8_t write_state; - uint8_t write_latch; - uint8_t rw_mode; - uint8_t mode; - uint8_t bcd; /* not supported */ - uint8_t gate; /* timer start */ - int64_t count_load_time; - /* irq handling */ - int64_t next_transition_time; - QEMUTimer *irq_timer; - int irq; -} PITChannelState; - -struct PITState { - PITChannelState channels[3]; -}; - -static PITState pit_state; - -static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); - -static int pit_get_count(PITChannelState *s) -{ - uint64_t d; - int counter; - - d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ, ticks_per_sec); - switch(s->mode) { - case 0: - case 1: - case 4: - case 5: - counter = (s->count - d) & 0xffff; - break; - case 3: - /* XXX: may be incorrect for odd counts */ - counter = s->count - ((2 * d) % s->count); - break; - default: - counter = s->count - (d % s->count); - break; - } - return counter; -} - -/* get pit output bit */ -static int pit_get_out1(PITChannelState *s, int64_t current_time) -{ - uint64_t d; - int out; - - d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec); - switch(s->mode) { - default: - case 0: - out = (d >= s->count); - break; - case 1: - out = (d < s->count); - break; - case 2: - if ((d % s->count) == 0 && d != 0) - out = 1; - else - out = 0; - break; - case 3: - out = (d % s->count) < ((s->count + 1) >> 1); - break; - case 4: - case 5: - out = (d == s->count); - break; - } - return out; -} - -int pit_get_out(PITState *pit, int channel, int64_t current_time) -{ - PITChannelState *s = &pit->channels[channel]; - return pit_get_out1(s, current_time); -} - -/* return -1 if no transition will occur. */ -static int64_t pit_get_next_transition_time(PITChannelState *s, - int64_t current_time) -{ - uint64_t d, next_time, base; - int period2; - - d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec); - switch(s->mode) { - default: - case 0: - case 1: - if (d < s->count) - next_time = s->count; - else - return -1; - break; - case 2: - base = (d / s->count) * s->count; - if ((d - base) == 0 && d != 0) - next_time = base + s->count; - else - next_time = base + s->count + 1; - break; - case 3: - base = (d / s->count) * s->count; - period2 = ((s->count + 1) >> 1); - if ((d - base) < period2) - next_time = base + period2; - else - next_time = base + s->count; - break; - case 4: - case 5: - if (d < s->count) - next_time = s->count; - else if (d == s->count) - next_time = s->count + 1; - else - return -1; - break; - } - /* convert to timer units */ - next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ); - /* fix potential rounding problems */ - /* XXX: better solution: use a clock at PIT_FREQ Hz */ - if (next_time <= current_time) - next_time = current_time + 1; - return next_time; -} - -/* val must be 0 or 1 */ -void pit_set_gate(PITState *pit, int channel, int val) -{ - PITChannelState *s = &pit->channels[channel]; - - switch(s->mode) { - default: - case 0: - case 4: - /* XXX: just disable/enable counting */ - break; - case 1: - case 5: - if (s->gate < val) { - /* restart counting on rising edge */ - s->count_load_time = qemu_get_clock(vm_clock); - pit_irq_timer_update(s, s->count_load_time); - } - break; - case 2: - case 3: - if (s->gate < val) { - /* restart counting on rising edge */ - s->count_load_time = qemu_get_clock(vm_clock); - pit_irq_timer_update(s, s->count_load_time); - } - /* XXX: disable/enable counting */ - break; - } - s->gate = val; -} - -int pit_get_gate(PITState *pit, int channel) -{ - PITChannelState *s = &pit->channels[channel]; - return s->gate; -} - -int pit_get_initial_count(PITState *pit, int channel) -{ - PITChannelState *s = &pit->channels[channel]; - return s->count; -} - -int pit_get_mode(PITState *pit, int channel) -{ - PITChannelState *s = &pit->channels[channel]; - return s->mode; -} - -static inline void pit_load_count(PITChannelState *s, int val) -{ - if (val == 0) - val = 0x10000; - s->count_load_time = qemu_get_clock(vm_clock); - s->count = val; - pit_irq_timer_update(s, s->count_load_time); -} - -/* if already latched, do not latch again */ -static void pit_latch_count(PITChannelState *s) -{ - if (!s->count_latched) { - s->latched_count = pit_get_count(s); - s->count_latched = s->rw_mode; - } -} - -static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - PITState *pit = opaque; - int channel, access; - PITChannelState *s; - - addr &= 3; - if (addr == 3) { - channel = val >> 6; - if (channel == 3) { - /* read back command */ - for(channel = 0; channel < 3; channel++) { - s = &pit->channels[channel]; - if (val & (2 << channel)) { - if (!(val & 0x20)) { - pit_latch_count(s); - } - if (!(val & 0x10) && !s->status_latched) { - /* status latch */ - /* XXX: add BCD and null count */ - s->status = (pit_get_out1(s, qemu_get_clock(vm_clock)) << 7) | - (s->rw_mode << 4) | - (s->mode << 1) | - s->bcd; - s->status_latched = 1; - } - } - } - } else { - s = &pit->channels[channel]; - access = (val >> 4) & 3; - if (access == 0) { - pit_latch_count(s); - } else { - s->rw_mode = access; - s->read_state = access; - s->write_state = access; - - s->mode = (val >> 1) & 7; - s->bcd = val & 1; - /* XXX: update irq timer ? */ - } - } - } else { - s = &pit->channels[addr]; - switch(s->write_state) { - default: - case RW_STATE_LSB: - pit_load_count(s, val); - break; - case RW_STATE_MSB: - pit_load_count(s, val << 8); - break; - case RW_STATE_WORD0: - s->write_latch = val; - s->write_state = RW_STATE_WORD1; - break; - case RW_STATE_WORD1: - pit_load_count(s, s->write_latch | (val << 8)); - s->write_state = RW_STATE_WORD0; - break; - } - } -} - -static uint32_t pit_ioport_read(void *opaque, uint32_t addr) -{ - PITState *pit = opaque; - int ret, count; - PITChannelState *s; - - addr &= 3; - s = &pit->channels[addr]; - if (s->status_latched) { - s->status_latched = 0; - ret = s->status; - } else if (s->count_latched) { - switch(s->count_latched) { - default: - case RW_STATE_LSB: - ret = s->latched_count & 0xff; - s->count_latched = 0; - break; - case RW_STATE_MSB: - ret = s->latched_count >> 8; - s->count_latched = 0; - break; - case RW_STATE_WORD0: - ret = s->latched_count & 0xff; - s->count_latched = RW_STATE_MSB; - break; - } - } else { - switch(s->read_state) { - default: - case RW_STATE_LSB: - count = pit_get_count(s); - ret = count & 0xff; - break; - case RW_STATE_MSB: - count = pit_get_count(s); - ret = (count >> 8) & 0xff; - break; - case RW_STATE_WORD0: - count = pit_get_count(s); - ret = count & 0xff; - s->read_state = RW_STATE_WORD1; - break; - case RW_STATE_WORD1: - count = pit_get_count(s); - ret = (count >> 8) & 0xff; - s->read_state = RW_STATE_WORD0; - break; - } - } - return ret; -} - -static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) -{ - int64_t expire_time; - int irq_level; - - if (!s->irq_timer) - return; - expire_time = pit_get_next_transition_time(s, current_time); - irq_level = pit_get_out1(s, current_time); - pic_set_irq(s->irq, irq_level); -#ifdef DEBUG_PIT - printf("irq_level=%d next_delay=%f\n", - irq_level, - (double)(expire_time - current_time) / ticks_per_sec); -#endif - s->next_transition_time = expire_time; - if (expire_time != -1) - qemu_mod_timer(s->irq_timer, expire_time); - else - qemu_del_timer(s->irq_timer); -} - -static void pit_irq_timer(void *opaque) -{ - PITChannelState *s = opaque; - - pit_irq_timer_update(s, s->next_transition_time); -} - -static void pit_save(QEMUFile *f, void *opaque) -{ - PITState *pit = opaque; - PITChannelState *s; - int i; - - for(i = 0; i < 3; i++) { - s = &pit->channels[i]; - qemu_put_be32s(f, &s->count); - qemu_put_be16s(f, &s->latched_count); - qemu_put_8s(f, &s->count_latched); - qemu_put_8s(f, &s->status_latched); - qemu_put_8s(f, &s->status); - qemu_put_8s(f, &s->read_state); - qemu_put_8s(f, &s->write_state); - qemu_put_8s(f, &s->write_latch); - qemu_put_8s(f, &s->rw_mode); - qemu_put_8s(f, &s->mode); - qemu_put_8s(f, &s->bcd); - qemu_put_8s(f, &s->gate); - qemu_put_be64s(f, &s->count_load_time); - if (s->irq_timer) { - qemu_put_be64s(f, &s->next_transition_time); - qemu_put_timer(f, s->irq_timer); - } - } -} - -static int pit_load(QEMUFile *f, void *opaque, int version_id) -{ - PITState *pit = opaque; - PITChannelState *s; - int i; - - if (version_id != 1) - return -EINVAL; - - for(i = 0; i < 3; i++) { - s = &pit->channels[i]; - qemu_get_be32s(f, &s->count); - qemu_get_be16s(f, &s->latched_count); - qemu_get_8s(f, &s->count_latched); - qemu_get_8s(f, &s->status_latched); - qemu_get_8s(f, &s->status); - qemu_get_8s(f, &s->read_state); - qemu_get_8s(f, &s->write_state); - qemu_get_8s(f, &s->write_latch); - qemu_get_8s(f, &s->rw_mode); - qemu_get_8s(f, &s->mode); - qemu_get_8s(f, &s->bcd); - qemu_get_8s(f, &s->gate); - qemu_get_be64s(f, &s->count_load_time); - if (s->irq_timer) { - qemu_get_be64s(f, &s->next_transition_time); - qemu_get_timer(f, s->irq_timer); - } - } - return 0; -} - -static void pit_reset(void *opaque) -{ - PITState *pit = opaque; - PITChannelState *s; - int i; - - for(i = 0;i < 3; i++) { - s = &pit->channels[i]; - s->mode = 3; - s->gate = (i != 2); - pit_load_count(s, 0); - } -} - -PITState *pit_init(int base, int irq) -{ - PITState *pit = &pit_state; - PITChannelState *s; - - s = &pit->channels[0]; - /* the timer 0 is connected to an IRQ */ - s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s); - s->irq = irq; - - register_savevm("i8254", base, 1, pit_save, pit_load, pit); - - qemu_register_reset(pit_reset, pit); - register_ioport_write(base, 4, 1, pit_ioport_write, pit); - register_ioport_read(base, 3, 1, pit_ioport_read, pit); - - pit_reset(pit); - - return pit; -} diff --git a/hw/i8259.c b/hw/i8259.c deleted file mode 100644 index c747f10..0000000 --- a/hw/i8259.c +++ /dev/null @@ -1,561 +0,0 @@ -/* - * QEMU 8259 interrupt controller emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* debug PIC */ -//#define DEBUG_PIC - -//#define DEBUG_IRQ_LATENCY -//#define DEBUG_IRQ_COUNT - -typedef struct PicState { - uint8_t last_irr; /* edge detection */ - uint8_t irr; /* interrupt request register */ - uint8_t imr; /* interrupt mask register */ - uint8_t isr; /* interrupt service register */ - uint8_t priority_add; /* highest irq priority */ - uint8_t irq_base; - uint8_t read_reg_select; - uint8_t poll; - uint8_t special_mask; - uint8_t init_state; - uint8_t auto_eoi; - uint8_t rotate_on_auto_eoi; - uint8_t special_fully_nested_mode; - uint8_t init4; /* true if 4 byte init */ - uint8_t elcr; /* PIIX edge/trigger selection*/ - uint8_t elcr_mask; - PicState2 *pics_state; -} PicState; - -struct PicState2 { - /* 0 is master pic, 1 is slave pic */ - /* XXX: better separation between the two pics */ - PicState pics[2]; - IRQRequestFunc *irq_request; - void *irq_request_opaque; - /* IOAPIC callback support */ - SetIRQFunc *alt_irq_func; - void *alt_irq_opaque; -}; - -#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT) -static int irq_level[16]; -#endif -#ifdef DEBUG_IRQ_COUNT -static uint64_t irq_count[16]; -#endif - -/* set irq level. If an edge is detected, then the IRR is set to 1 */ -static inline void pic_set_irq1(PicState *s, int irq, int level) -{ - int mask; - mask = 1 << irq; - if (s->elcr & mask) { - /* level triggered */ - if (level) { - s->irr |= mask; - s->last_irr |= mask; - } else { - s->irr &= ~mask; - s->last_irr &= ~mask; - } - } else { - /* edge triggered */ - if (level) { - if ((s->last_irr & mask) == 0) - s->irr |= mask; - s->last_irr |= mask; - } else { - s->last_irr &= ~mask; - } - } -} - -/* return the highest priority found in mask (highest = smallest - number). Return 8 if no irq */ -static inline int get_priority(PicState *s, int mask) -{ - int priority; - if (mask == 0) - return 8; - priority = 0; - while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) - priority++; - return priority; -} - -/* return the pic wanted interrupt. return -1 if none */ -static int pic_get_irq(PicState *s) -{ - int mask, cur_priority, priority; - - mask = s->irr & ~s->imr; - priority = get_priority(s, mask); - if (priority == 8) - return -1; - /* compute current priority. If special fully nested mode on the - master, the IRQ coming from the slave is not taken into account - for the priority computation. */ - mask = s->isr; - if (s->special_fully_nested_mode && s == &s->pics_state->pics[0]) - mask &= ~(1 << 2); - cur_priority = get_priority(s, mask); - if (priority < cur_priority) { - /* higher priority found: an irq should be generated */ - return (priority + s->priority_add) & 7; - } else { - return -1; - } -} - -/* raise irq to CPU if necessary. must be called every time the active - irq may change */ -/* XXX: should not export it, but it is needed for an APIC kludge */ -void pic_update_irq(PicState2 *s) -{ - int irq2, irq; - - /* first look at slave pic */ - irq2 = pic_get_irq(&s->pics[1]); - if (irq2 >= 0) { - /* if irq request by slave pic, signal master PIC */ - pic_set_irq1(&s->pics[0], 2, 1); - pic_set_irq1(&s->pics[0], 2, 0); - } - /* look at requested irq */ - irq = pic_get_irq(&s->pics[0]); - if (irq >= 0) { -#if defined(DEBUG_PIC) - { - int i; - for(i = 0; i < 2; i++) { - printf("pic%d: imr=%x irr=%x padd=%d\n", - i, s->pics[i].imr, s->pics[i].irr, - s->pics[i].priority_add); - - } - } - printf("pic: cpu_interrupt\n"); -#endif - s->irq_request(s->irq_request_opaque, 1); - } -} - -#ifdef DEBUG_IRQ_LATENCY -int64_t irq_time[16]; -#endif - -void pic_set_irq_new(void *opaque, int irq, int level) -{ - PicState2 *s = opaque; - -#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) - if (level != irq_level[irq]) { -#if defined(DEBUG_PIC) - printf("pic_set_irq: irq=%d level=%d\n", irq, level); -#endif - irq_level[irq] = level; -#ifdef DEBUG_IRQ_COUNT - if (level == 1) - irq_count[irq]++; -#endif - } -#endif -#ifdef DEBUG_IRQ_LATENCY - if (level) { - irq_time[irq] = qemu_get_clock(vm_clock); - } -#endif - pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); - /* used for IOAPIC irqs */ - if (s->alt_irq_func) - s->alt_irq_func(s->alt_irq_opaque, irq, level); - pic_update_irq(s); -} - -/* obsolete function */ -void pic_set_irq(int irq, int level) -{ - pic_set_irq_new(isa_pic, irq, level); -} - -/* acknowledge interrupt 'irq' */ -static inline void pic_intack(PicState *s, int irq) -{ - if (s->auto_eoi) { - if (s->rotate_on_auto_eoi) - s->priority_add = (irq + 1) & 7; - } else { - s->isr |= (1 << irq); - } - /* We don't clear a level sensitive interrupt here */ - if (!(s->elcr & (1 << irq))) - s->irr &= ~(1 << irq); -} - -int pic_read_irq(PicState2 *s) -{ - int irq, irq2, intno; - - irq = pic_get_irq(&s->pics[0]); - if (irq >= 0) { - pic_intack(&s->pics[0], irq); - if (irq == 2) { - irq2 = pic_get_irq(&s->pics[1]); - if (irq2 >= 0) { - pic_intack(&s->pics[1], irq2); - } else { - /* spurious IRQ on slave controller */ - irq2 = 7; - } - intno = s->pics[1].irq_base + irq2; - irq = irq2 + 8; - } else { - intno = s->pics[0].irq_base + irq; - } - } else { - /* spurious IRQ on host controller */ - irq = 7; - intno = s->pics[0].irq_base + irq; - } - pic_update_irq(s); - -#ifdef DEBUG_IRQ_LATENCY - printf("IRQ%d latency=%0.3fus\n", - irq, - (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec); -#endif -#if defined(DEBUG_PIC) - printf("pic_interrupt: irq=%d\n", irq); -#endif - return intno; -} - -static void pic_reset(void *opaque) -{ - PicState *s = opaque; - - s->last_irr = 0; - s->irr = 0; - s->imr = 0; - s->isr = 0; - s->priority_add = 0; - s->irq_base = 0; - s->read_reg_select = 0; - s->poll = 0; - s->special_mask = 0; - s->init_state = 0; - s->auto_eoi = 0; - s->rotate_on_auto_eoi = 0; - s->special_fully_nested_mode = 0; - s->init4 = 0; - /* Note: ELCR is not reset */ -} - -static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - PicState *s = opaque; - int priority, cmd, irq; - -#ifdef DEBUG_PIC - printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); -#endif - addr &= 1; - if (addr == 0) { - if (val & 0x10) { - /* init */ - pic_reset(s); - /* deassert a pending interrupt */ - s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0); - s->init_state = 1; - s->init4 = val & 1; - if (val & 0x02) - hw_error("single mode not supported"); - if (val & 0x08) - hw_error("level sensitive irq not supported"); - } else if (val & 0x08) { - if (val & 0x04) - s->poll = 1; - if (val & 0x02) - s->read_reg_select = val & 1; - if (val & 0x40) - s->special_mask = (val >> 5) & 1; - } else { - cmd = val >> 5; - switch(cmd) { - case 0: - case 4: - s->rotate_on_auto_eoi = cmd >> 2; - break; - case 1: /* end of interrupt */ - case 5: - priority = get_priority(s, s->isr); - if (priority != 8) { - irq = (priority + s->priority_add) & 7; - s->isr &= ~(1 << irq); - if (cmd == 5) - s->priority_add = (irq + 1) & 7; - pic_update_irq(s->pics_state); - } - break; - case 3: - irq = val & 7; - s->isr &= ~(1 << irq); - pic_update_irq(s->pics_state); - break; - case 6: - s->priority_add = (val + 1) & 7; - pic_update_irq(s->pics_state); - break; - case 7: - irq = val & 7; - s->isr &= ~(1 << irq); - s->priority_add = (irq + 1) & 7; - pic_update_irq(s->pics_state); - break; - default: - /* no operation */ - break; - } - } - } else { - switch(s->init_state) { - case 0: - /* normal mode */ - s->imr = val; - pic_update_irq(s->pics_state); - break; - case 1: - s->irq_base = val & 0xf8; - s->init_state = 2; - break; - case 2: - if (s->init4) { - s->init_state = 3; - } else { - s->init_state = 0; - } - break; - case 3: - s->special_fully_nested_mode = (val >> 4) & 1; - s->auto_eoi = (val >> 1) & 1; - s->init_state = 0; - break; - } - } -} - -static uint32_t pic_poll_read (PicState *s, uint32_t addr1) -{ - int ret; - - ret = pic_get_irq(s); - if (ret >= 0) { - if (addr1 >> 7) { - s->pics_state->pics[0].isr &= ~(1 << 2); - s->pics_state->pics[0].irr &= ~(1 << 2); - } - s->irr &= ~(1 << ret); - s->isr &= ~(1 << ret); - if (addr1 >> 7 || ret != 2) - pic_update_irq(s->pics_state); - } else { - ret = 0x07; - pic_update_irq(s->pics_state); - } - - return ret; -} - -static uint32_t pic_ioport_read(void *opaque, uint32_t addr1) -{ - PicState *s = opaque; - unsigned int addr; - int ret; - - addr = addr1; - addr &= 1; - if (s->poll) { - ret = pic_poll_read(s, addr1); - s->poll = 0; - } else { - if (addr == 0) { - if (s->read_reg_select) - ret = s->isr; - else - ret = s->irr; - } else { - ret = s->imr; - } - } -#ifdef DEBUG_PIC - printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); -#endif - return ret; -} - -/* memory mapped interrupt status */ -/* XXX: may be the same than pic_read_irq() */ -uint32_t pic_intack_read(PicState2 *s) -{ - int ret; - - ret = pic_poll_read(&s->pics[0], 0x00); - if (ret == 2) - ret = pic_poll_read(&s->pics[1], 0x80) + 8; - /* Prepare for ISR read */ - s->pics[0].read_reg_select = 1; - - return ret; -} - -static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - PicState *s = opaque; - s->elcr = val & s->elcr_mask; -} - -static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1) -{ - PicState *s = opaque; - return s->elcr; -} - -static void pic_save(QEMUFile *f, void *opaque) -{ - PicState *s = opaque; - - qemu_put_8s(f, &s->last_irr); - qemu_put_8s(f, &s->irr); - qemu_put_8s(f, &s->imr); - qemu_put_8s(f, &s->isr); - qemu_put_8s(f, &s->priority_add); - qemu_put_8s(f, &s->irq_base); - qemu_put_8s(f, &s->read_reg_select); - qemu_put_8s(f, &s->poll); - qemu_put_8s(f, &s->special_mask); - qemu_put_8s(f, &s->init_state); - qemu_put_8s(f, &s->auto_eoi); - qemu_put_8s(f, &s->rotate_on_auto_eoi); - qemu_put_8s(f, &s->special_fully_nested_mode); - qemu_put_8s(f, &s->init4); - qemu_put_8s(f, &s->elcr); -} - -static int pic_load(QEMUFile *f, void *opaque, int version_id) -{ - PicState *s = opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_8s(f, &s->last_irr); - qemu_get_8s(f, &s->irr); - qemu_get_8s(f, &s->imr); - qemu_get_8s(f, &s->isr); - qemu_get_8s(f, &s->priority_add); - qemu_get_8s(f, &s->irq_base); - qemu_get_8s(f, &s->read_reg_select); - qemu_get_8s(f, &s->poll); - qemu_get_8s(f, &s->special_mask); - qemu_get_8s(f, &s->init_state); - qemu_get_8s(f, &s->auto_eoi); - qemu_get_8s(f, &s->rotate_on_auto_eoi); - qemu_get_8s(f, &s->special_fully_nested_mode); - qemu_get_8s(f, &s->init4); - qemu_get_8s(f, &s->elcr); - return 0; -} - -/* XXX: add generic master/slave system */ -static void pic_init1(int io_addr, int elcr_addr, PicState *s) -{ - register_ioport_write(io_addr, 2, 1, pic_ioport_write, s); - register_ioport_read(io_addr, 2, 1, pic_ioport_read, s); - if (elcr_addr >= 0) { - register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s); - register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s); - } - register_savevm("i8259", io_addr, 1, pic_save, pic_load, s); - qemu_register_reset(pic_reset, s); -} - -void pic_info(void) -{ - int i; - PicState *s; - - if (!isa_pic) - return; - - for(i=0;i<2;i++) { - s = &isa_pic->pics[i]; - term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n", - i, s->irr, s->imr, s->isr, s->priority_add, - s->irq_base, s->read_reg_select, s->elcr, - s->special_fully_nested_mode); - } -} - -void irq_info(void) -{ -#ifndef DEBUG_IRQ_COUNT - term_printf("irq statistic code not compiled.\n"); -#else - int i; - int64_t count; - - term_printf("IRQ statistics:\n"); - for (i = 0; i < 16; i++) { - count = irq_count[i]; - if (count > 0) - term_printf("%2d: %" PRId64 "\n", i, count); - } -#endif -} - -PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque) -{ - PicState2 *s; - s = qemu_mallocz(sizeof(PicState2)); - if (!s) - return NULL; - pic_init1(0x20, 0x4d0, &s->pics[0]); - pic_init1(0xa0, 0x4d1, &s->pics[1]); - s->pics[0].elcr_mask = 0xf8; - s->pics[1].elcr_mask = 0xde; - s->irq_request = irq_request; - s->irq_request_opaque = irq_request_opaque; - s->pics[0].pics_state = s; - s->pics[1].pics_state = s; - return s; -} - -void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func, - void *alt_irq_opaque) -{ - s->alt_irq_func = alt_irq_func; - s->alt_irq_opaque = alt_irq_opaque; -} diff --git a/hw/ide.c b/hw/ide.c deleted file mode 100644 index debbc0f..0000000 --- a/hw/ide.c +++ /dev/null @@ -1,2535 +0,0 @@ -/* - * QEMU IDE disk and CD-ROM Emulator - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* debug IDE devices */ -//#define DEBUG_IDE -//#define DEBUG_IDE_ATAPI - -/* Bits of HD_STATUS */ -#define ERR_STAT 0x01 -#define INDEX_STAT 0x02 -#define ECC_STAT 0x04 /* Corrected error */ -#define DRQ_STAT 0x08 -#define SEEK_STAT 0x10 -#define SRV_STAT 0x10 -#define WRERR_STAT 0x20 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits for HD_ERROR */ -#define MARK_ERR 0x01 /* Bad address mark */ -#define TRK0_ERR 0x02 /* couldn't find track 0 */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* media change request */ -#define ID_ERR 0x10 /* ID field not found */ -#define MC_ERR 0x20 /* media changed */ -#define ECC_ERR 0x40 /* Uncorrectable ECC error */ -#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ -#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ - -/* Bits of HD_NSECTOR */ -#define CD 0x01 -#define IO 0x02 -#define REL 0x04 -#define TAG_MASK 0xf8 - -#define IDE_CMD_RESET 0x04 -#define IDE_CMD_DISABLE_IRQ 0x02 - -/* ATA/ATAPI Commands pre T13 Spec */ -#define WIN_NOP 0x00 -/* - * 0x01->0x02 Reserved - */ -#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ -/* - * 0x04->0x07 Reserved - */ -#define WIN_SRST 0x08 /* ATAPI soft reset command */ -#define WIN_DEVICE_RESET 0x08 -/* - * 0x09->0x0F Reserved - */ -#define WIN_RECAL 0x10 -#define WIN_RESTORE WIN_RECAL -/* - * 0x10->0x1F Reserved - */ -#define WIN_READ 0x20 /* 28-Bit */ -#define WIN_READ_ONCE 0x21 /* 28-Bit without retries */ -#define WIN_READ_LONG 0x22 /* 28-Bit */ -#define WIN_READ_LONG_ONCE 0x23 /* 28-Bit without retries */ -#define WIN_READ_EXT 0x24 /* 48-Bit */ -#define WIN_READDMA_EXT 0x25 /* 48-Bit */ -#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */ -#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ -/* - * 0x28 - */ -#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ -/* - * 0x2A->0x2F Reserved - */ -#define WIN_WRITE 0x30 /* 28-Bit */ -#define WIN_WRITE_ONCE 0x31 /* 28-Bit without retries */ -#define WIN_WRITE_LONG 0x32 /* 28-Bit */ -#define WIN_WRITE_LONG_ONCE 0x33 /* 28-Bit without retries */ -#define WIN_WRITE_EXT 0x34 /* 48-Bit */ -#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ -#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ -#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ -#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ -#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ -/* - * 0x3A->0x3B Reserved - */ -#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */ -/* - * 0x3D->0x3F Reserved - */ -#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ -#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - without retries */ -#define WIN_VERIFY_EXT 0x42 /* 48-Bit */ -/* - * 0x43->0x4F Reserved - */ -#define WIN_FORMAT 0x50 -/* - * 0x51->0x5F Reserved - */ -#define WIN_INIT 0x60 -/* - * 0x61->0x5F Reserved - */ -#define WIN_SEEK 0x70 /* 0x70-0x7F Reserved */ -#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ -#define WIN_DIAGNOSE 0x90 -#define WIN_SPECIFY 0x91 /* set drive geometry translation */ -#define WIN_DOWNLOAD_MICROCODE 0x92 -#define WIN_STANDBYNOW2 0x94 -#define WIN_STANDBY2 0x96 -#define WIN_SETIDLE2 0x97 -#define WIN_CHECKPOWERMODE2 0x98 -#define WIN_SLEEPNOW2 0x99 -/* - * 0x9A VENDOR - */ -#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ -#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ -#define WIN_QUEUED_SERVICE 0xA2 -#define WIN_SMART 0xB0 /* self-monitoring and reporting */ -#define CFA_ERASE_SECTORS 0xC0 -#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ -#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ -#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ -#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ -#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ -#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - without retries */ -#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ -#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */ -#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ -#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ -#define WIN_GETMEDIASTATUS 0xDA -#define WIN_ACKMEDIACHANGE 0xDB /* ATA-1, ATA-2 vendor */ -#define WIN_POSTBOOT 0xDC -#define WIN_PREBOOT 0xDD -#define WIN_DOORLOCK 0xDE /* lock door on removable drives */ -#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */ -#define WIN_STANDBYNOW1 0xE0 -#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ -#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */ -#define WIN_SETIDLE1 0xE3 -#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ -#define WIN_CHECKPOWERMODE1 0xE5 -#define WIN_SLEEPNOW1 0xE6 -#define WIN_FLUSH_CACHE 0xE7 -#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ -#define WIN_WRITE_SAME 0xE9 /* read ata-2 to use */ - /* SET_FEATURES 0x22 or 0xDD */ -#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ -#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ -#define WIN_MEDIAEJECT 0xED -#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ -#define WIN_SETFEATURES 0xEF /* set special drive features */ -#define EXABYTE_ENABLE_NEST 0xF0 -#define WIN_SECURITY_SET_PASS 0xF1 -#define WIN_SECURITY_UNLOCK 0xF2 -#define WIN_SECURITY_ERASE_PREPARE 0xF3 -#define WIN_SECURITY_ERASE_UNIT 0xF4 -#define WIN_SECURITY_FREEZE_LOCK 0xF5 -#define WIN_SECURITY_DISABLE 0xF6 -#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ -#define WIN_SET_MAX 0xF9 -#define DISABLE_SEAGATE 0xFB - -/* set to 1 set disable mult support */ -#define MAX_MULT_SECTORS 16 - -/* ATAPI defines */ - -#define ATAPI_PACKET_SIZE 12 - -/* The generic packet command opcodes for CD/DVD Logical Units, - * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ -#define GPCMD_BLANK 0xa1 -#define GPCMD_CLOSE_TRACK 0x5b -#define GPCMD_FLUSH_CACHE 0x35 -#define GPCMD_FORMAT_UNIT 0x04 -#define GPCMD_GET_CONFIGURATION 0x46 -#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a -#define GPCMD_GET_PERFORMANCE 0xac -#define GPCMD_INQUIRY 0x12 -#define GPCMD_LOAD_UNLOAD 0xa6 -#define GPCMD_MECHANISM_STATUS 0xbd -#define GPCMD_MODE_SELECT_10 0x55 -#define GPCMD_MODE_SENSE_10 0x5a -#define GPCMD_PAUSE_RESUME 0x4b -#define GPCMD_PLAY_AUDIO_10 0x45 -#define GPCMD_PLAY_AUDIO_MSF 0x47 -#define GPCMD_PLAY_AUDIO_TI 0x48 -#define GPCMD_PLAY_CD 0xbc -#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e -#define GPCMD_READ_10 0x28 -#define GPCMD_READ_12 0xa8 -#define GPCMD_READ_CDVD_CAPACITY 0x25 -#define GPCMD_READ_CD 0xbe -#define GPCMD_READ_CD_MSF 0xb9 -#define GPCMD_READ_DISC_INFO 0x51 -#define GPCMD_READ_DVD_STRUCTURE 0xad -#define GPCMD_READ_FORMAT_CAPACITIES 0x23 -#define GPCMD_READ_HEADER 0x44 -#define GPCMD_READ_TRACK_RZONE_INFO 0x52 -#define GPCMD_READ_SUBCHANNEL 0x42 -#define GPCMD_READ_TOC_PMA_ATIP 0x43 -#define GPCMD_REPAIR_RZONE_TRACK 0x58 -#define GPCMD_REPORT_KEY 0xa4 -#define GPCMD_REQUEST_SENSE 0x03 -#define GPCMD_RESERVE_RZONE_TRACK 0x53 -#define GPCMD_SCAN 0xba -#define GPCMD_SEEK 0x2b -#define GPCMD_SEND_DVD_STRUCTURE 0xad -#define GPCMD_SEND_EVENT 0xa2 -#define GPCMD_SEND_KEY 0xa3 -#define GPCMD_SEND_OPC 0x54 -#define GPCMD_SET_READ_AHEAD 0xa7 -#define GPCMD_SET_STREAMING 0xb6 -#define GPCMD_START_STOP_UNIT 0x1b -#define GPCMD_STOP_PLAY_SCAN 0x4e -#define GPCMD_TEST_UNIT_READY 0x00 -#define GPCMD_VERIFY_10 0x2f -#define GPCMD_WRITE_10 0x2a -#define GPCMD_WRITE_AND_VERIFY_10 0x2e -/* This is listed as optional in ATAPI 2.6, but is (curiously) - * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji - * Table 377 as an MMC command for SCSi devices though... Most ATAPI - * drives support it. */ -#define GPCMD_SET_SPEED 0xbb -/* This seems to be a SCSI specific CD-ROM opcode - * to play data at track/index */ -#define GPCMD_PLAYAUDIO_TI 0x48 -/* - * From MS Media Status Notification Support Specification. For - * older drives only. - */ -#define GPCMD_GET_MEDIA_STATUS 0xda - -/* Mode page codes for mode sense/set */ -#define GPMODE_R_W_ERROR_PAGE 0x01 -#define GPMODE_WRITE_PARMS_PAGE 0x05 -#define GPMODE_AUDIO_CTL_PAGE 0x0e -#define GPMODE_POWER_PAGE 0x1a -#define GPMODE_FAULT_FAIL_PAGE 0x1c -#define GPMODE_TO_PROTECT_PAGE 0x1d -#define GPMODE_CAPABILITIES_PAGE 0x2a -#define GPMODE_ALL_PAGES 0x3f -/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor - * of MODE_SENSE_POWER_PAGE */ -#define GPMODE_CDROM_PAGE 0x0d - -#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ -#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ -#define ATAPI_INT_REASON_REL 0x04 -#define ATAPI_INT_REASON_TAG 0xf8 - -/* same constants as bochs */ -#define ASC_ILLEGAL_OPCODE 0x20 -#define ASC_LOGICAL_BLOCK_OOR 0x21 -#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 -#define ASC_MEDIUM_NOT_PRESENT 0x3a -#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 - -#define SENSE_NONE 0 -#define SENSE_NOT_READY 2 -#define SENSE_ILLEGAL_REQUEST 5 -#define SENSE_UNIT_ATTENTION 6 - -struct IDEState; - -typedef void EndTransferFunc(struct IDEState *); - -/* NOTE: IDEState represents in fact one drive */ -typedef struct IDEState { - /* ide config */ - int is_cdrom; - int cylinders, heads, sectors; - int64_t nb_sectors; - int mult_sectors; - int identify_set; - uint16_t identify_data[256]; - SetIRQFunc *set_irq; - void *irq_opaque; - int irq; - PCIDevice *pci_dev; - struct BMDMAState *bmdma; - int drive_serial; - /* ide regs */ - uint8_t feature; - uint8_t error; - uint32_t nsector; - uint8_t sector; - uint8_t lcyl; - uint8_t hcyl; - /* other part of tf for lba48 support */ - uint8_t hob_feature; - uint8_t hob_nsector; - uint8_t hob_sector; - uint8_t hob_lcyl; - uint8_t hob_hcyl; - - uint8_t select; - uint8_t status; - - /* 0x3f6 command, only meaningful for drive 0 */ - uint8_t cmd; - /* set for lba48 access */ - uint8_t lba48; - /* depends on bit 4 in select, only meaningful for drive 0 */ - struct IDEState *cur_drive; - BlockDriverState *bs; - /* ATAPI specific */ - uint8_t sense_key; - uint8_t asc; - int packet_transfer_size; - int elementary_transfer_size; - int io_buffer_index; - int lba; - int cd_sector_size; - int atapi_dma; /* true if dma is requested for the packet cmd */ - /* ATA DMA state */ - int io_buffer_size; - /* PIO transfer handling */ - int req_nb_sectors; /* number of sectors per interrupt */ - EndTransferFunc *end_transfer_func; - uint8_t *data_ptr; - uint8_t *data_end; - uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4]; - QEMUTimer *sector_write_timer; /* only used for win2k instal hack */ - uint32_t irq_count; /* counts IRQs when using win2k install hack */ -} IDEState; - -#define BM_STATUS_DMAING 0x01 -#define BM_STATUS_ERROR 0x02 -#define BM_STATUS_INT 0x04 - -#define BM_CMD_START 0x01 -#define BM_CMD_READ 0x08 - -#define IDE_TYPE_PIIX3 0 -#define IDE_TYPE_CMD646 1 - -/* CMD646 specific */ -#define MRDMODE 0x71 -#define MRDMODE_INTR_CH0 0x04 -#define MRDMODE_INTR_CH1 0x08 -#define MRDMODE_BLK_CH0 0x10 -#define MRDMODE_BLK_CH1 0x20 -#define UDIDETCR0 0x73 -#define UDIDETCR1 0x7B - -typedef int IDEDMAFunc(IDEState *s, - target_phys_addr_t phys_addr, - int transfer_size1); - -typedef struct BMDMAState { - uint8_t cmd; - uint8_t status; - uint32_t addr; - - struct PCIIDEState *pci_dev; - /* current transfer state */ - IDEState *ide_if; - IDEDMAFunc *dma_cb; -} BMDMAState; - -typedef struct PCIIDEState { - PCIDevice dev; - IDEState ide_if[4]; - BMDMAState bmdma[2]; - int type; /* see IDE_TYPE_xxx */ -} PCIIDEState; - -static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb); - -static void padstr(char *str, const char *src, int len) -{ - int i, v; - for(i = 0; i < len; i++) { - if (*src) - v = *src++; - else - v = ' '; - *(char *)((long)str ^ 1) = v; - str++; - } -} - -static void padstr8(uint8_t *buf, int buf_size, const char *src) -{ - int i; - for(i = 0; i < buf_size; i++) { - if (*src) - buf[i] = *src++; - else - buf[i] = ' '; - } -} - -static void put_le16(uint16_t *p, unsigned int v) -{ - *p = cpu_to_le16(v); -} - -static void ide_identify(IDEState *s) -{ - uint16_t *p; - unsigned int oldsize; - char buf[20]; - - if (s->identify_set) { - memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); - return; - } - - memset(s->io_buffer, 0, 512); - p = (uint16_t *)s->io_buffer; - put_le16(p + 0, 0x0040); - put_le16(p + 1, s->cylinders); - put_le16(p + 3, s->heads); - put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */ - put_le16(p + 5, 512); /* XXX: retired, remove ? */ - put_le16(p + 6, s->sectors); - snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); - padstr((uint8_t *)(p + 10), buf, 20); /* serial number */ - put_le16(p + 20, 3); /* XXX: retired, remove ? */ - put_le16(p + 21, 512); /* cache size in sectors */ - put_le16(p + 22, 4); /* ecc bytes */ - padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ - padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */ -#if MAX_MULT_SECTORS > 1 - put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS); -#endif - put_le16(p + 48, 1); /* dword I/O */ - put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */ - put_le16(p + 51, 0x200); /* PIO transfer cycle */ - put_le16(p + 52, 0x200); /* DMA transfer cycle */ - put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */ - put_le16(p + 54, s->cylinders); - put_le16(p + 55, s->heads); - put_le16(p + 56, s->sectors); - oldsize = s->cylinders * s->heads * s->sectors; - put_le16(p + 57, oldsize); - put_le16(p + 58, oldsize >> 16); - if (s->mult_sectors) - put_le16(p + 59, 0x100 | s->mult_sectors); - put_le16(p + 60, s->nb_sectors); - put_le16(p + 61, s->nb_sectors >> 16); - put_le16(p + 63, 0x07); /* mdma0-2 supported */ - put_le16(p + 65, 120); - put_le16(p + 66, 120); - put_le16(p + 67, 120); - put_le16(p + 68, 120); - put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */ - put_le16(p + 81, 0x16); /* conforms to ata5 */ - put_le16(p + 82, (1 << 14)); - /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ - put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); - put_le16(p + 84, (1 << 14)); - put_le16(p + 85, (1 << 14)); - /* 13=flush_cache_ext,12=flush_cache,10=lba48 */ - put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10)); - put_le16(p + 87, (1 << 14)); - put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */ - put_le16(p + 93, 1 | (1 << 14) | 0x2000); - put_le16(p + 100, s->nb_sectors); - put_le16(p + 101, s->nb_sectors >> 16); - put_le16(p + 102, s->nb_sectors >> 32); - put_le16(p + 103, s->nb_sectors >> 48); - - memcpy(s->identify_data, p, sizeof(s->identify_data)); - s->identify_set = 1; -} - -static void ide_atapi_identify(IDEState *s) -{ - uint16_t *p; - char buf[20]; - - if (s->identify_set) { - memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data)); - return; - } - - memset(s->io_buffer, 0, 512); - p = (uint16_t *)s->io_buffer; - /* Removable CDROM, 50us response, 12 byte packets */ - put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0)); - snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial); - padstr((uint8_t *)(p + 10), buf, 20); /* serial number */ - put_le16(p + 20, 3); /* buffer type */ - put_le16(p + 21, 512); /* cache size in sectors */ - put_le16(p + 22, 4); /* ecc bytes */ - padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */ - padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */ - put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ - put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */ - put_le16(p + 53, 3); /* words 64-70, 54-58 valid */ - put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */ - put_le16(p + 64, 1); /* PIO modes */ - put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */ - put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */ - put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */ - put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */ - - put_le16(p + 71, 30); /* in ns */ - put_le16(p + 72, 30); /* in ns */ - - put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */ - - memcpy(s->identify_data, p, sizeof(s->identify_data)); - s->identify_set = 1; -} - -static void ide_set_signature(IDEState *s) -{ - s->select &= 0xf0; /* clear head */ - /* put signature */ - s->nsector = 1; - s->sector = 1; - if (s->is_cdrom) { - s->lcyl = 0x14; - s->hcyl = 0xeb; - } else if (s->bs) { - s->lcyl = 0; - s->hcyl = 0; - } else { - s->lcyl = 0xff; - s->hcyl = 0xff; - } -} - -static inline void ide_abort_command(IDEState *s) -{ - s->status = READY_STAT | ERR_STAT; - s->error = ABRT_ERR; -} - -static inline void ide_set_irq(IDEState *s) -{ - BMDMAState *bm = s->bmdma; - if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) { - if (bm) { - bm->status |= BM_STATUS_INT; - } - s->set_irq(s->irq_opaque, s->irq, 1); - } -} - -/* prepare data transfer and tell what to do after */ -static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, - EndTransferFunc *end_transfer_func) -{ - s->end_transfer_func = end_transfer_func; - s->data_ptr = buf; - s->data_end = buf + size; - s->status |= DRQ_STAT; -} - -static void ide_transfer_stop(IDEState *s) -{ - s->end_transfer_func = ide_transfer_stop; - s->data_ptr = s->io_buffer; - s->data_end = s->io_buffer; - s->status &= ~DRQ_STAT; -} - -static int64_t ide_get_sector(IDEState *s) -{ - int64_t sector_num; - if (s->select & 0x40) { - /* lba */ - if (!s->lba48) { - sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) | - (s->lcyl << 8) | s->sector; - } else { - sector_num = ((int64_t)s->hob_hcyl << 40) | - ((int64_t) s->hob_lcyl << 32) | - ((int64_t) s->hob_sector << 24) | - ((int64_t) s->hcyl << 16) | - ((int64_t) s->lcyl << 8) | s->sector; - } - } else { - sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors + - (s->select & 0x0f) * s->sectors + (s->sector - 1); - } - return sector_num; -} - -static void ide_set_sector(IDEState *s, int64_t sector_num) -{ - unsigned int cyl, r; - if (s->select & 0x40) { - if (!s->lba48) { - s->select = (s->select & 0xf0) | (sector_num >> 24); - s->hcyl = (sector_num >> 16); - s->lcyl = (sector_num >> 8); - s->sector = (sector_num); - } else { - s->sector = sector_num; - s->lcyl = sector_num >> 8; - s->hcyl = sector_num >> 16; - s->hob_sector = sector_num >> 24; - s->hob_lcyl = sector_num >> 32; - s->hob_hcyl = sector_num >> 40; - } - } else { - cyl = sector_num / (s->heads * s->sectors); - r = sector_num % (s->heads * s->sectors); - s->hcyl = cyl >> 8; - s->lcyl = cyl; - s->select = (s->select & 0xf0) | ((r / s->sectors) & 0x0f); - s->sector = (r % s->sectors) + 1; - } -} - -static void ide_sector_read(IDEState *s) -{ - int64_t sector_num; - int ret, n; - - s->status = READY_STAT | SEEK_STAT; - s->error = 0; /* not needed by IDE spec, but needed by Windows */ - sector_num = ide_get_sector(s); - n = s->nsector; - if (n == 0) { - /* no more sector to read from disk */ - ide_transfer_stop(s); - } else { -#if defined(DEBUG_IDE) - printf("read sector=%Ld\n", sector_num); -#endif - if (n > s->req_nb_sectors) - n = s->req_nb_sectors; - ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); - ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); - ide_set_irq(s); - ide_set_sector(s, sector_num + n); - s->nsector -= n; - } -} - -static int ide_read_dma_cb(IDEState *s, - target_phys_addr_t phys_addr, - int transfer_size1) -{ - int len, transfer_size, n; - int64_t sector_num; - - transfer_size = transfer_size1; - while (transfer_size > 0) { - len = s->io_buffer_size - s->io_buffer_index; - if (len <= 0) { - /* transfert next data */ - n = s->nsector; - if (n == 0) - break; - if (n > MAX_MULT_SECTORS) - n = MAX_MULT_SECTORS; - sector_num = ide_get_sector(s); - bdrv_read(s->bs, sector_num, s->io_buffer, n); - s->io_buffer_index = 0; - s->io_buffer_size = n * 512; - len = s->io_buffer_size; - sector_num += n; - ide_set_sector(s, sector_num); - s->nsector -= n; - } - if (len > transfer_size) - len = transfer_size; - cpu_physical_memory_write(phys_addr, - s->io_buffer + s->io_buffer_index, len); - s->io_buffer_index += len; - transfer_size -= len; - phys_addr += len; - } - if (s->io_buffer_index >= s->io_buffer_size && s->nsector == 0) { - s->status = READY_STAT | SEEK_STAT; - ide_set_irq(s); -#ifdef DEBUG_IDE_ATAPI - printf("dma status=0x%x\n", s->status); -#endif - return 0; - } - return transfer_size1 - transfer_size; -} - -static void ide_sector_read_dma(IDEState *s) -{ - s->status = READY_STAT | SEEK_STAT | DRQ_STAT; - s->io_buffer_index = 0; - s->io_buffer_size = 0; - ide_dma_start(s, ide_read_dma_cb); -} - -static void ide_sector_write_timer_cb(void *opaque) -{ - IDEState *s = opaque; - ide_set_irq(s); -} - -static void ide_sector_write(IDEState *s) -{ - int64_t sector_num; - int ret, n, n1; - - s->status = READY_STAT | SEEK_STAT; - sector_num = ide_get_sector(s); -#if defined(DEBUG_IDE) - printf("write sector=%Ld\n", sector_num); -#endif - n = s->nsector; - if (n > s->req_nb_sectors) - n = s->req_nb_sectors; - ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); - s->nsector -= n; - if (s->nsector == 0) { - /* no more sector to write */ - ide_transfer_stop(s); - } else { - n1 = s->nsector; - if (n1 > s->req_nb_sectors) - n1 = s->req_nb_sectors; - ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write); - } - ide_set_sector(s, sector_num + n); - -#ifdef TARGET_I386 - if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { - /* It seems there is a bug in the Windows 2000 installer HDD - IDE driver which fills the disk with empty logs when the - IDE write IRQ comes too early. This hack tries to correct - that at the expense of slower write performances. Use this - option _only_ to install Windows 2000. You must disable it - for normal use. */ - qemu_mod_timer(s->sector_write_timer, - qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); - } else -#endif - { - ide_set_irq(s); - } -} - -static int ide_write_dma_cb(IDEState *s, - target_phys_addr_t phys_addr, - int transfer_size1) -{ - int len, transfer_size, n; - int64_t sector_num; - - transfer_size = transfer_size1; - for(;;) { - len = s->io_buffer_size - s->io_buffer_index; - if (len == 0) { - n = s->io_buffer_size >> 9; - sector_num = ide_get_sector(s); - bdrv_write(s->bs, sector_num, s->io_buffer, - s->io_buffer_size >> 9); - sector_num += n; - ide_set_sector(s, sector_num); - s->nsector -= n; - n = s->nsector; - if (n == 0) { - /* end of transfer */ - s->status = READY_STAT | SEEK_STAT; -#ifdef TARGET_I386 - if (win2k_install_hack && ((++s->irq_count % 16) == 0)) { - /* It seems there is a bug in the Windows 2000 installer - HDD IDE driver which fills the disk with empty logs - when the IDE write IRQ comes too early. This hack tries - to correct that at the expense of slower write - performances. Use this option _only_ to install Windows - 2000. You must disable it for normal use. */ - qemu_mod_timer(s->sector_write_timer, - qemu_get_clock(vm_clock) + (ticks_per_sec / 1000)); - } else -#endif - ide_set_irq(s); - return 0; - } - if (n > MAX_MULT_SECTORS) - n = MAX_MULT_SECTORS; - s->io_buffer_index = 0; - s->io_buffer_size = n * 512; - len = s->io_buffer_size; - } - if (transfer_size <= 0) - break; - if (len > transfer_size) - len = transfer_size; - cpu_physical_memory_read(phys_addr, - s->io_buffer + s->io_buffer_index, len); - s->io_buffer_index += len; - transfer_size -= len; - phys_addr += len; - } - return transfer_size1 - transfer_size; -} - -static void ide_sector_write_dma(IDEState *s) -{ - int n; - s->status = READY_STAT | SEEK_STAT | DRQ_STAT; - n = s->nsector; - if (n > MAX_MULT_SECTORS) - n = MAX_MULT_SECTORS; - s->io_buffer_index = 0; - s->io_buffer_size = n * 512; - ide_dma_start(s, ide_write_dma_cb); -} - -static void ide_atapi_cmd_ok(IDEState *s) -{ - s->error = 0; - s->status = READY_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - ide_set_irq(s); -} - -static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc) -{ -#ifdef DEBUG_IDE_ATAPI - printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc); -#endif - s->error = sense_key << 4; - s->status = READY_STAT | ERR_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - s->sense_key = sense_key; - s->asc = asc; - ide_set_irq(s); -} - -static inline void cpu_to_ube16(uint8_t *buf, int val) -{ - buf[0] = val >> 8; - buf[1] = val; -} - -static inline void cpu_to_ube32(uint8_t *buf, unsigned int val) -{ - buf[0] = val >> 24; - buf[1] = val >> 16; - buf[2] = val >> 8; - buf[3] = val; -} - -static inline int ube16_to_cpu(const uint8_t *buf) -{ - return (buf[0] << 8) | buf[1]; -} - -static inline int ube32_to_cpu(const uint8_t *buf) -{ - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; -} - -static void lba_to_msf(uint8_t *buf, int lba) -{ - lba += 150; - buf[0] = (lba / 75) / 60; - buf[1] = (lba / 75) % 60; - buf[2] = lba % 75; -} - -static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, - int sector_size) -{ - switch(sector_size) { - case 2048: - bdrv_read(bs, (int64_t)lba << 2, buf, 4); - break; - case 2352: - /* sync bytes */ - buf[0] = 0x00; - memset(buf + 1, 0xff, 10); - buf[11] = 0x00; - buf += 12; - /* MSF */ - lba_to_msf(buf, lba); - buf[3] = 0x01; /* mode 1 data */ - buf += 4; - /* data */ - bdrv_read(bs, (int64_t)lba << 2, buf, 4); - buf += 2048; - /* ECC */ - memset(buf, 0, 288); - break; - default: - break; - } -} - -/* The whole ATAPI transfer logic is handled in this function */ -static void ide_atapi_cmd_reply_end(IDEState *s) -{ - int byte_count_limit, size; -#ifdef DEBUG_IDE_ATAPI - printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", - s->packet_transfer_size, - s->elementary_transfer_size, - s->io_buffer_index); -#endif - if (s->packet_transfer_size <= 0) { - /* end of transfer */ - ide_transfer_stop(s); - s->status = READY_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - ide_set_irq(s); -#ifdef DEBUG_IDE_ATAPI - printf("status=0x%x\n", s->status); -#endif - } else { - /* see if a new sector must be read */ - if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) { - cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); - s->lba++; - s->io_buffer_index = 0; - } - if (s->elementary_transfer_size > 0) { - /* there are some data left to transmit in this elementary - transfer */ - size = s->cd_sector_size - s->io_buffer_index; - if (size > s->elementary_transfer_size) - size = s->elementary_transfer_size; - ide_transfer_start(s, s->io_buffer + s->io_buffer_index, - size, ide_atapi_cmd_reply_end); - s->packet_transfer_size -= size; - s->elementary_transfer_size -= size; - s->io_buffer_index += size; - } else { - /* a new transfer is needed */ - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO; - byte_count_limit = s->lcyl | (s->hcyl << 8); -#ifdef DEBUG_IDE_ATAPI - printf("byte_count_limit=%d\n", byte_count_limit); -#endif - if (byte_count_limit == 0xffff) - byte_count_limit--; - size = s->packet_transfer_size; - if (size > byte_count_limit) { - /* byte count limit must be even if this case */ - if (byte_count_limit & 1) - byte_count_limit--; - size = byte_count_limit; - } - s->lcyl = size; - s->hcyl = size >> 8; - s->elementary_transfer_size = size; - /* we cannot transmit more than one sector at a time */ - if (s->lba != -1) { - if (size > (s->cd_sector_size - s->io_buffer_index)) - size = (s->cd_sector_size - s->io_buffer_index); - } - ide_transfer_start(s, s->io_buffer + s->io_buffer_index, - size, ide_atapi_cmd_reply_end); - s->packet_transfer_size -= size; - s->elementary_transfer_size -= size; - s->io_buffer_index += size; - ide_set_irq(s); -#ifdef DEBUG_IDE_ATAPI - printf("status=0x%x\n", s->status); -#endif - } - } -} - -/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */ -static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size) -{ - if (size > max_size) - size = max_size; - s->lba = -1; /* no sector read */ - s->packet_transfer_size = size; - s->elementary_transfer_size = 0; - s->io_buffer_index = 0; - - s->status = READY_STAT; - ide_atapi_cmd_reply_end(s); -} - -/* start a CD-CDROM read command */ -static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors, - int sector_size) -{ - s->lba = lba; - s->packet_transfer_size = nb_sectors * sector_size; - s->elementary_transfer_size = 0; - s->io_buffer_index = sector_size; - s->cd_sector_size = sector_size; - - s->status = READY_STAT; - ide_atapi_cmd_reply_end(s); -} - -/* ATAPI DMA support */ -static int ide_atapi_cmd_read_dma_cb(IDEState *s, - target_phys_addr_t phys_addr, - int transfer_size1) -{ - int len, transfer_size; - - transfer_size = transfer_size1; - while (transfer_size > 0) { -#ifdef DEBUG_IDE_ATAPI - printf("transfer_size: %d phys_addr=%08x\n", transfer_size, phys_addr); -#endif - if (s->packet_transfer_size <= 0) - break; - len = s->cd_sector_size - s->io_buffer_index; - if (len <= 0) { - /* transfert next data */ - cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size); - s->lba++; - s->io_buffer_index = 0; - len = s->cd_sector_size; - } - if (len > transfer_size) - len = transfer_size; - cpu_physical_memory_write(phys_addr, - s->io_buffer + s->io_buffer_index, len); - s->packet_transfer_size -= len; - s->io_buffer_index += len; - transfer_size -= len; - phys_addr += len; - } - if (s->packet_transfer_size <= 0) { - s->status = READY_STAT; - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD; - ide_set_irq(s); -#ifdef DEBUG_IDE_ATAPI - printf("dma status=0x%x\n", s->status); -#endif - return 0; - } - return transfer_size1 - transfer_size; -} - -/* start a CD-CDROM read command with DMA */ -/* XXX: test if DMA is available */ -static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors, - int sector_size) -{ - s->lba = lba; - s->packet_transfer_size = nb_sectors * sector_size; - s->io_buffer_index = sector_size; - s->cd_sector_size = sector_size; - - s->status = READY_STAT | DRQ_STAT; - ide_dma_start(s, ide_atapi_cmd_read_dma_cb); -} - -static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, - int sector_size) -{ -#ifdef DEBUG_IDE_ATAPI - printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors); -#endif - if (s->atapi_dma) { - ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size); - } else { - ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size); - } -} - -static void ide_atapi_cmd(IDEState *s) -{ - const uint8_t *packet; - uint8_t *buf; - int max_len; - - packet = s->io_buffer; - buf = s->io_buffer; -#ifdef DEBUG_IDE_ATAPI - { - int i; - printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8)); - for(i = 0; i < ATAPI_PACKET_SIZE; i++) { - printf(" %02x", packet[i]); - } - printf("\n"); - } -#endif - switch(s->io_buffer[0]) { - case GPCMD_TEST_UNIT_READY: - if (bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_ok(s); - } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - } - break; - case GPCMD_MODE_SENSE_10: - { - int action, code; - max_len = ube16_to_cpu(packet + 7); - action = packet[2] >> 6; - code = packet[2] & 0x3f; - switch(action) { - case 0: /* current values */ - switch(code) { - case 0x01: /* error recovery */ - cpu_to_ube16(&buf[0], 16 + 6); - buf[2] = 0x70; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - - buf[8] = 0x01; - buf[9] = 0x06; - buf[10] = 0x00; - buf[11] = 0x05; - buf[12] = 0x00; - buf[13] = 0x00; - buf[14] = 0x00; - buf[15] = 0x00; - ide_atapi_cmd_reply(s, 16, max_len); - break; - case 0x2a: - cpu_to_ube16(&buf[0], 28 + 6); - buf[2] = 0x70; - buf[3] = 0; - buf[4] = 0; - buf[5] = 0; - buf[6] = 0; - buf[7] = 0; - - buf[8] = 0x2a; - buf[9] = 0x12; - buf[10] = 0x00; - buf[11] = 0x00; - - buf[12] = 0x70; - buf[13] = 3 << 5; - buf[14] = (1 << 0) | (1 << 3) | (1 << 5); - if (bdrv_is_locked(s->bs)) - buf[6] |= 1 << 1; - buf[15] = 0x00; - cpu_to_ube16(&buf[16], 706); - buf[18] = 0; - buf[19] = 2; - cpu_to_ube16(&buf[20], 512); - cpu_to_ube16(&buf[22], 706); - buf[24] = 0; - buf[25] = 0; - buf[26] = 0; - buf[27] = 0; - ide_atapi_cmd_reply(s, 28, max_len); - break; - default: - goto error_cmd; - } - break; - case 1: /* changeable values */ - goto error_cmd; - case 2: /* default values */ - goto error_cmd; - default: - case 3: /* saved values */ - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_SAVING_PARAMETERS_NOT_SUPPORTED); - break; - } - } - break; - case GPCMD_REQUEST_SENSE: - max_len = packet[4]; - memset(buf, 0, 18); - buf[0] = 0x70 | (1 << 7); - buf[2] = s->sense_key; - buf[7] = 10; - buf[12] = s->asc; - ide_atapi_cmd_reply(s, 18, max_len); - break; - case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - if (bdrv_is_inserted(s->bs)) { - bdrv_set_locked(s->bs, packet[4] & 1); - ide_atapi_cmd_ok(s); - } else { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - } - break; - case GPCMD_READ_10: - case GPCMD_READ_12: - { - int nb_sectors, lba; - - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - if (packet[0] == GPCMD_READ_10) - nb_sectors = ube16_to_cpu(packet + 7); - else - nb_sectors = ube32_to_cpu(packet + 6); - lba = ube32_to_cpu(packet + 2); - if (nb_sectors == 0) { - ide_atapi_cmd_ok(s); - break; - } - if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } - ide_atapi_cmd_read(s, lba, nb_sectors, 2048); - } - break; - case GPCMD_READ_CD: - { - int nb_sectors, lba, transfer_request; - - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8]; - lba = ube32_to_cpu(packet + 2); - if (nb_sectors == 0) { - ide_atapi_cmd_ok(s); - break; - } - if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } - transfer_request = packet[9]; - switch(transfer_request & 0xf8) { - case 0x00: - /* nothing */ - ide_atapi_cmd_ok(s); - break; - case 0x10: - /* normal read */ - ide_atapi_cmd_read(s, lba, nb_sectors, 2048); - break; - case 0xf8: - /* read all data */ - ide_atapi_cmd_read(s, lba, nb_sectors, 2352); - break; - default: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - } - break; - case GPCMD_SEEK: - { - int lba; - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - lba = ube32_to_cpu(packet + 2); - if (((int64_t)lba << 2) > s->nb_sectors) { - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_LOGICAL_BLOCK_OOR); - break; - } - ide_atapi_cmd_ok(s); - } - break; - case GPCMD_START_STOP_UNIT: - { - int start, eject; - start = packet[4] & 1; - eject = (packet[4] >> 1) & 1; - - if (eject && !start) { - /* eject the disk */ - bdrv_close(s->bs); - } - ide_atapi_cmd_ok(s); - } - break; - case GPCMD_MECHANISM_STATUS: - { - max_len = ube16_to_cpu(packet + 8); - cpu_to_ube16(buf, 0); - /* no current LBA */ - buf[2] = 0; - buf[3] = 0; - buf[4] = 0; - buf[5] = 1; - cpu_to_ube16(buf + 6, 0); - ide_atapi_cmd_reply(s, 8, max_len); - } - break; - case GPCMD_READ_TOC_PMA_ATIP: - { - int format, msf, start_track, len; - - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - max_len = ube16_to_cpu(packet + 7); - format = packet[9] >> 6; - msf = (packet[1] >> 1) & 1; - start_track = packet[6]; - switch(format) { - case 0: - len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track); - if (len < 0) - goto error_cmd; - ide_atapi_cmd_reply(s, len, max_len); - break; - case 1: - /* multi session : only a single session defined */ - memset(buf, 0, 12); - buf[1] = 0x0a; - buf[2] = 0x01; - buf[3] = 0x01; - ide_atapi_cmd_reply(s, 12, max_len); - break; - case 2: - len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track); - if (len < 0) - goto error_cmd; - ide_atapi_cmd_reply(s, len, max_len); - break; - default: - error_cmd: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_INV_FIELD_IN_CMD_PACKET); - break; - } - } - break; - case GPCMD_READ_CDVD_CAPACITY: - if (!bdrv_is_inserted(s->bs)) { - ide_atapi_cmd_error(s, SENSE_NOT_READY, - ASC_MEDIUM_NOT_PRESENT); - break; - } - /* NOTE: it is really the number of sectors minus 1 */ - cpu_to_ube32(buf, (s->nb_sectors >> 2) - 1); - cpu_to_ube32(buf + 4, 2048); - ide_atapi_cmd_reply(s, 8, 8); - break; - case GPCMD_INQUIRY: - max_len = packet[4]; - buf[0] = 0x05; /* CD-ROM */ - buf[1] = 0x80; /* removable */ - buf[2] = 0x00; /* ISO */ - buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */ - buf[4] = 31; /* additionnal length */ - buf[5] = 0; /* reserved */ - buf[6] = 0; /* reserved */ - buf[7] = 0; /* reserved */ - padstr8(buf + 8, 8, "QEMU"); - padstr8(buf + 16, 16, "QEMU CD-ROM"); - padstr8(buf + 32, 4, QEMU_VERSION); - ide_atapi_cmd_reply(s, 36, max_len); - break; - default: - ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, - ASC_ILLEGAL_OPCODE); - break; - } -} - -/* called when the inserted state of the media has changed */ -static void cdrom_change_cb(void *opaque) -{ - IDEState *s = opaque; - int64_t nb_sectors; - - /* XXX: send interrupt too */ - bdrv_get_geometry(s->bs, &nb_sectors); - s->nb_sectors = nb_sectors; -} - -static void ide_cmd_lba48_transform(IDEState *s, int lba48) -{ - s->lba48 = lba48; - - /* handle the 'magic' 0 nsector count conversion here. to avoid - * fiddling with the rest of the read logic, we just store the - * full sector count in ->nsector and ignore ->hob_nsector from now - */ - if (!s->lba48) { - if (!s->nsector) - s->nsector = 256; - } else { - if (!s->nsector && !s->hob_nsector) - s->nsector = 65536; - else { - int lo = s->nsector; - int hi = s->hob_nsector; - - s->nsector = (hi << 8) | lo; - } - } -} - -static void ide_clear_hob(IDEState *ide_if) -{ - /* any write clears HOB high bit of device control register */ - ide_if[0].select &= ~(1 << 7); - ide_if[1].select &= ~(1 << 7); -} - -static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - IDEState *ide_if = opaque; - IDEState *s; - int unit, n; - int lba48 = 0; - -#ifdef DEBUG_IDE - printf("IDE: write addr=0x%x val=0x%02x\n", addr, val); -#endif - - addr &= 7; - switch(addr) { - case 0: - break; - case 1: - ide_clear_hob(ide_if); - /* NOTE: data is written to the two drives */ - ide_if[0].hob_feature = ide_if[0].feature; - ide_if[1].hob_feature = ide_if[1].feature; - ide_if[0].feature = val; - ide_if[1].feature = val; - break; - case 2: - ide_clear_hob(ide_if); - ide_if[0].hob_nsector = ide_if[0].nsector; - ide_if[1].hob_nsector = ide_if[1].nsector; - ide_if[0].nsector = val; - ide_if[1].nsector = val; - break; - case 3: - ide_clear_hob(ide_if); - ide_if[0].hob_sector = ide_if[0].sector; - ide_if[1].hob_sector = ide_if[1].sector; - ide_if[0].sector = val; - ide_if[1].sector = val; - break; - case 4: - ide_clear_hob(ide_if); - ide_if[0].hob_lcyl = ide_if[0].lcyl; - ide_if[1].hob_lcyl = ide_if[1].lcyl; - ide_if[0].lcyl = val; - ide_if[1].lcyl = val; - break; - case 5: - ide_clear_hob(ide_if); - ide_if[0].hob_hcyl = ide_if[0].hcyl; - ide_if[1].hob_hcyl = ide_if[1].hcyl; - ide_if[0].hcyl = val; - ide_if[1].hcyl = val; - break; - case 6: - /* FIXME: HOB readback uses bit 7 */ - ide_if[0].select = (val & ~0x10) | 0xa0; - ide_if[1].select = (val | 0x10) | 0xa0; - /* select drive */ - unit = (val >> 4) & 1; - s = ide_if + unit; - ide_if->cur_drive = s; - break; - default: - case 7: - /* command */ -#if defined(DEBUG_IDE) - printf("ide: CMD=%02x\n", val); -#endif - s = ide_if->cur_drive; - /* ignore commands to non existant slave */ - if (s != ide_if && !s->bs) - break; - - switch(val) { - case WIN_IDENTIFY: - if (s->bs && !s->is_cdrom) { - ide_identify(s); - s->status = READY_STAT | SEEK_STAT; - ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); - } else { - if (s->is_cdrom) { - ide_set_signature(s); - } - ide_abort_command(s); - } - ide_set_irq(s); - break; - case WIN_SPECIFY: - case WIN_RECAL: - s->error = 0; - s->status = READY_STAT | SEEK_STAT; - ide_set_irq(s); - break; - case WIN_SETMULT: - if (s->nsector > MAX_MULT_SECTORS || - s->nsector == 0 || - (s->nsector & (s->nsector - 1)) != 0) { - ide_abort_command(s); - } else { - s->mult_sectors = s->nsector; - s->status = READY_STAT; - } - ide_set_irq(s); - break; - case WIN_VERIFY_EXT: - lba48 = 1; - case WIN_VERIFY: - case WIN_VERIFY_ONCE: - /* do sector number check ? */ - ide_cmd_lba48_transform(s, lba48); - s->status = READY_STAT; - ide_set_irq(s); - break; - case WIN_READ_EXT: - lba48 = 1; - case WIN_READ: - case WIN_READ_ONCE: - if (!s->bs) - goto abort_cmd; - ide_cmd_lba48_transform(s, lba48); - s->req_nb_sectors = 1; - ide_sector_read(s); - break; - case WIN_WRITE_EXT: - lba48 = 1; - case WIN_WRITE: - case WIN_WRITE_ONCE: - ide_cmd_lba48_transform(s, lba48); - s->error = 0; - s->status = SEEK_STAT | READY_STAT; - s->req_nb_sectors = 1; - ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); - break; - case WIN_MULTREAD_EXT: - lba48 = 1; - case WIN_MULTREAD: - if (!s->mult_sectors) - goto abort_cmd; - ide_cmd_lba48_transform(s, lba48); - s->req_nb_sectors = s->mult_sectors; - ide_sector_read(s); - break; - case WIN_MULTWRITE_EXT: - lba48 = 1; - case WIN_MULTWRITE: - if (!s->mult_sectors) - goto abort_cmd; - ide_cmd_lba48_transform(s, lba48); - s->error = 0; - s->status = SEEK_STAT | READY_STAT; - s->req_nb_sectors = s->mult_sectors; - n = s->nsector; - if (n > s->req_nb_sectors) - n = s->req_nb_sectors; - ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); - break; - case WIN_READDMA_EXT: - lba48 = 1; - case WIN_READDMA: - case WIN_READDMA_ONCE: - if (!s->bs) - goto abort_cmd; - ide_cmd_lba48_transform(s, lba48); - ide_sector_read_dma(s); - break; - case WIN_WRITEDMA_EXT: - lba48 = 1; - case WIN_WRITEDMA: - case WIN_WRITEDMA_ONCE: - if (!s->bs) - goto abort_cmd; - ide_cmd_lba48_transform(s, lba48); - ide_sector_write_dma(s); - break; - case WIN_READ_NATIVE_MAX_EXT: - lba48 = 1; - case WIN_READ_NATIVE_MAX: - ide_cmd_lba48_transform(s, lba48); - ide_set_sector(s, s->nb_sectors - 1); - s->status = READY_STAT; - ide_set_irq(s); - break; - case WIN_CHECKPOWERMODE1: - s->nsector = 0xff; /* device active or idle */ - s->status = READY_STAT; - ide_set_irq(s); - break; - case WIN_SETFEATURES: - if (!s->bs) - goto abort_cmd; - /* XXX: valid for CDROM ? */ - switch(s->feature) { - case 0x02: /* write cache enable */ - case 0x82: /* write cache disable */ - case 0xaa: /* read look-ahead enable */ - case 0x55: /* read look-ahead disable */ - s->status = READY_STAT | SEEK_STAT; - ide_set_irq(s); - break; - case 0x03: { /* set transfer mode */ - uint8_t val = s->nsector & 0x07; - - switch (s->nsector >> 3) { - case 0x00: /* pio default */ - case 0x01: /* pio mode */ - put_le16(s->identify_data + 63,0x07); - put_le16(s->identify_data + 88,0x3f); - break; - case 0x04: /* mdma mode */ - put_le16(s->identify_data + 63,0x07 | (1 << (val + 8))); - put_le16(s->identify_data + 88,0x3f); - break; - case 0x08: /* udma mode */ - put_le16(s->identify_data + 63,0x07); - put_le16(s->identify_data + 88,0x3f | (1 << (val + 8))); - break; - default: - goto abort_cmd; - } - s->status = READY_STAT | SEEK_STAT; - ide_set_irq(s); - break; - } - default: - goto abort_cmd; - } - break; - case WIN_FLUSH_CACHE: - case WIN_FLUSH_CACHE_EXT: - if (s->bs) - bdrv_flush(s->bs); - s->status = READY_STAT; - ide_set_irq(s); - break; - case WIN_STANDBYNOW1: - case WIN_IDLEIMMEDIATE: - s->status = READY_STAT; - ide_set_irq(s); - break; - /* ATAPI commands */ - case WIN_PIDENTIFY: - if (s->is_cdrom) { - ide_atapi_identify(s); - s->status = READY_STAT | SEEK_STAT; - ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); - } else { - ide_abort_command(s); - } - ide_set_irq(s); - break; - case WIN_DIAGNOSE: - ide_set_signature(s); - s->status = 0x00; /* NOTE: READY is _not_ set */ - s->error = 0x01; - break; - case WIN_SRST: - if (!s->is_cdrom) - goto abort_cmd; - ide_set_signature(s); - s->status = 0x00; /* NOTE: READY is _not_ set */ - s->error = 0x01; - break; - case WIN_PACKETCMD: - if (!s->is_cdrom) - goto abort_cmd; - /* overlapping commands not supported */ - if (s->feature & 0x02) - goto abort_cmd; - s->atapi_dma = s->feature & 1; - s->nsector = 1; - ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, - ide_atapi_cmd); - break; - default: - abort_cmd: - ide_abort_command(s); - ide_set_irq(s); - break; - } - } -} - -static uint32_t ide_ioport_read(void *opaque, uint32_t addr1) -{ - IDEState *ide_if = opaque; - IDEState *s = ide_if->cur_drive; - uint32_t addr; - int ret, hob; - - addr = addr1 & 7; - /* FIXME: HOB readback uses bit 7, but it's always set right now */ - //hob = s->select & (1 << 7); - hob = 0; - switch(addr) { - case 0: - ret = 0xff; - break; - case 1: - if (!ide_if[0].bs && !ide_if[1].bs) - ret = 0; - else if (!hob) - ret = s->error; - else - ret = s->hob_feature; - break; - case 2: - if (!ide_if[0].bs && !ide_if[1].bs) - ret = 0; - else if (!hob) - ret = s->nsector & 0xff; - else - ret = s->hob_nsector; - break; - case 3: - if (!ide_if[0].bs && !ide_if[1].bs) - ret = 0; - else if (!hob) - ret = s->sector; - else - ret = s->hob_sector; - break; - case 4: - if (!ide_if[0].bs && !ide_if[1].bs) - ret = 0; - else if (!hob) - ret = s->lcyl; - else - ret = s->hob_lcyl; - break; - case 5: - if (!ide_if[0].bs && !ide_if[1].bs) - ret = 0; - else if (!hob) - ret = s->hcyl; - else - ret = s->hob_hcyl; - break; - case 6: - if (!ide_if[0].bs && !ide_if[1].bs) - ret = 0; - else - ret = s->select; - break; - default: - case 7: - if ((!ide_if[0].bs && !ide_if[1].bs) || - (s != ide_if && !s->bs)) - ret = 0; - else - ret = s->status; - s->set_irq(s->irq_opaque, s->irq, 0); - break; - } -#ifdef DEBUG_IDE - printf("ide: read addr=0x%x val=%02x\n", addr1, ret); -#endif - return ret; -} - -static uint32_t ide_status_read(void *opaque, uint32_t addr) -{ - IDEState *ide_if = opaque; - IDEState *s = ide_if->cur_drive; - int ret; - - if ((!ide_if[0].bs && !ide_if[1].bs) || - (s != ide_if && !s->bs)) - ret = 0; - else - ret = s->status; -#ifdef DEBUG_IDE - printf("ide: read status addr=0x%x val=%02x\n", addr, ret); -#endif - return ret; -} - -static void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val) -{ - IDEState *ide_if = opaque; - IDEState *s; - int i; - -#ifdef DEBUG_IDE - printf("ide: write control addr=0x%x val=%02x\n", addr, val); -#endif - /* common for both drives */ - if (!(ide_if[0].cmd & IDE_CMD_RESET) && - (val & IDE_CMD_RESET)) { - /* reset low to high */ - for(i = 0;i < 2; i++) { - s = &ide_if[i]; - s->status = BUSY_STAT | SEEK_STAT; - s->error = 0x01; - } - } else if ((ide_if[0].cmd & IDE_CMD_RESET) && - !(val & IDE_CMD_RESET)) { - /* high to low */ - for(i = 0;i < 2; i++) { - s = &ide_if[i]; - if (s->is_cdrom) - s->status = 0x00; /* NOTE: READY is _not_ set */ - else - s->status = READY_STAT | SEEK_STAT; - ide_set_signature(s); - } - } - - ide_if[0].cmd = val; - ide_if[1].cmd = val; -} - -static void ide_data_writew(void *opaque, uint32_t addr, uint32_t val) -{ - IDEState *s = ((IDEState *)opaque)->cur_drive; - uint8_t *p; - - p = s->data_ptr; - *(uint16_t *)p = le16_to_cpu(val); - p += 2; - s->data_ptr = p; - if (p >= s->data_end) - s->end_transfer_func(s); -} - -static uint32_t ide_data_readw(void *opaque, uint32_t addr) -{ - IDEState *s = ((IDEState *)opaque)->cur_drive; - uint8_t *p; - int ret; - p = s->data_ptr; - ret = cpu_to_le16(*(uint16_t *)p); - p += 2; - s->data_ptr = p; - if (p >= s->data_end) - s->end_transfer_func(s); - return ret; -} - -static void ide_data_writel(void *opaque, uint32_t addr, uint32_t val) -{ - IDEState *s = ((IDEState *)opaque)->cur_drive; - uint8_t *p; - - p = s->data_ptr; - *(uint32_t *)p = le32_to_cpu(val); - p += 4; - s->data_ptr = p; - if (p >= s->data_end) - s->end_transfer_func(s); -} - -static uint32_t ide_data_readl(void *opaque, uint32_t addr) -{ - IDEState *s = ((IDEState *)opaque)->cur_drive; - uint8_t *p; - int ret; - - p = s->data_ptr; - ret = cpu_to_le32(*(uint32_t *)p); - p += 4; - s->data_ptr = p; - if (p >= s->data_end) - s->end_transfer_func(s); - return ret; -} - -static void ide_dummy_transfer_stop(IDEState *s) -{ - s->data_ptr = s->io_buffer; - s->data_end = s->io_buffer; - s->io_buffer[0] = 0xff; - s->io_buffer[1] = 0xff; - s->io_buffer[2] = 0xff; - s->io_buffer[3] = 0xff; -} - -static void ide_reset(IDEState *s) -{ - s->mult_sectors = MAX_MULT_SECTORS; - s->cur_drive = s; - s->select = 0xa0; - s->status = READY_STAT; - ide_set_signature(s); - /* init the transfer handler so that 0xffff is returned on data - accesses */ - s->end_transfer_func = ide_dummy_transfer_stop; - ide_dummy_transfer_stop(s); -} - -struct partition { - uint8_t boot_ind; /* 0x80 - active */ - uint8_t head; /* starting head */ - uint8_t sector; /* starting sector */ - uint8_t cyl; /* starting cylinder */ - uint8_t sys_ind; /* What partition type */ - uint8_t end_head; /* end head */ - uint8_t end_sector; /* end sector */ - uint8_t end_cyl; /* end cylinder */ - uint32_t start_sect; /* starting sector counting from 0 */ - uint32_t nr_sects; /* nr of sectors in partition */ -} __attribute__((packed)); - -/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */ -static int guess_disk_lchs(IDEState *s, - int *pcylinders, int *pheads, int *psectors) -{ - uint8_t buf[512]; - int ret, i, heads, sectors, cylinders; - struct partition *p; - uint32_t nr_sects; - - ret = bdrv_read(s->bs, 0, buf, 1); - if (ret < 0) - return -1; - /* test msdos magic */ - if (buf[510] != 0x55 || buf[511] != 0xaa) - return -1; - for(i = 0; i < 4; i++) { - p = ((struct partition *)(buf + 0x1be)) + i; - nr_sects = le32_to_cpu(p->nr_sects); - if (nr_sects && p->end_head) { - /* We make the assumption that the partition terminates on - a cylinder boundary */ - heads = p->end_head + 1; - sectors = p->end_sector & 63; - if (sectors == 0) - continue; - cylinders = s->nb_sectors / (heads * sectors); - if (cylinders < 1 || cylinders > 16383) - continue; - *pheads = heads; - *psectors = sectors; - *pcylinders = cylinders; -#if 0 - printf("guessed geometry: LCHS=%d %d %d\n", - cylinders, heads, sectors); -#endif - return 0; - } - } - return -1; -} - -static void ide_init2(IDEState *ide_state, - BlockDriverState *hd0, BlockDriverState *hd1, - SetIRQFunc *set_irq, void *irq_opaque, int irq) -{ - IDEState *s; - static int drive_serial = 1; - int i, cylinders, heads, secs, translation; - int64_t nb_sectors; - - for(i = 0; i < 2; i++) { - s = ide_state + i; - if (i == 0) - s->bs = hd0; - else - s->bs = hd1; - if (s->bs) { - bdrv_get_geometry(s->bs, &nb_sectors); - s->nb_sectors = nb_sectors; - /* if a geometry hint is available, use it */ - bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs); - if (cylinders != 0) { - s->cylinders = cylinders; - s->heads = heads; - s->sectors = secs; - } else { - if (guess_disk_lchs(s, &cylinders, &heads, &secs) == 0) { - if (heads > 16) { - /* if heads > 16, it means that a BIOS LBA - translation was active, so the default - hardware geometry is OK */ - goto default_geometry; - } else { - s->cylinders = cylinders; - s->heads = heads; - s->sectors = secs; - /* disable any translation to be in sync with - the logical geometry */ - translation = bdrv_get_translation_hint(s->bs); - if (translation == BIOS_ATA_TRANSLATION_AUTO) { - bdrv_set_translation_hint(s->bs, - BIOS_ATA_TRANSLATION_NONE); - } - } - } else { - default_geometry: - /* if no geometry, use a standard physical disk geometry */ - cylinders = nb_sectors / (16 * 63); - if (cylinders > 16383) - cylinders = 16383; - else if (cylinders < 2) - cylinders = 2; - s->cylinders = cylinders; - s->heads = 16; - s->sectors = 63; - } - bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, s->sectors); - } - if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) { - s->is_cdrom = 1; - bdrv_set_change_cb(s->bs, cdrom_change_cb, s); - } - } - s->drive_serial = drive_serial++; - s->set_irq = set_irq; - s->irq_opaque = irq_opaque; - s->irq = irq; - s->sector_write_timer = qemu_new_timer(vm_clock, - ide_sector_write_timer_cb, s); - ide_reset(s); - } -} - -static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2) -{ - register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state); - register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state); - if (iobase2) { - register_ioport_read(iobase2, 1, 1, ide_status_read, ide_state); - register_ioport_write(iobase2, 1, 1, ide_cmd_write, ide_state); - } - - /* data ports */ - register_ioport_write(iobase, 2, 2, ide_data_writew, ide_state); - register_ioport_read(iobase, 2, 2, ide_data_readw, ide_state); - register_ioport_write(iobase, 4, 4, ide_data_writel, ide_state); - register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state); -} - -/***********************************************************/ -/* ISA IDE definitions */ - -void isa_ide_init(int iobase, int iobase2, int irq, - BlockDriverState *hd0, BlockDriverState *hd1) -{ - IDEState *ide_state; - - ide_state = qemu_mallocz(sizeof(IDEState) * 2); - if (!ide_state) - return; - - ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq); - ide_init_ioport(ide_state, iobase, iobase2); -} - -/***********************************************************/ -/* PCI IDE definitions */ - -static void cmd646_update_irq(PCIIDEState *d); - -static void ide_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - PCIIDEState *d = (PCIIDEState *)pci_dev; - IDEState *ide_state; - - if (region_num <= 3) { - ide_state = &d->ide_if[(region_num >> 1) * 2]; - if (region_num & 1) { - register_ioport_read(addr + 2, 1, 1, ide_status_read, ide_state); - register_ioport_write(addr + 2, 1, 1, ide_cmd_write, ide_state); - } else { - register_ioport_write(addr, 8, 1, ide_ioport_write, ide_state); - register_ioport_read(addr, 8, 1, ide_ioport_read, ide_state); - - /* data ports */ - register_ioport_write(addr, 2, 2, ide_data_writew, ide_state); - register_ioport_read(addr, 2, 2, ide_data_readw, ide_state); - register_ioport_write(addr, 4, 4, ide_data_writel, ide_state); - register_ioport_read(addr, 4, 4, ide_data_readl, ide_state); - } - } -} - -/* XXX: full callback usage to prepare non blocking I/Os support - - error handling */ -static void ide_dma_loop(BMDMAState *bm) -{ - struct { - uint32_t addr; - uint32_t size; - } prd; - target_phys_addr_t cur_addr; - int len, i, len1; - - cur_addr = bm->addr; - /* at most one page to avoid hanging if erroneous parameters */ - for(i = 0; i < 512; i++) { - cpu_physical_memory_read(cur_addr, (uint8_t *)&prd, 8); - prd.addr = le32_to_cpu(prd.addr); - prd.size = le32_to_cpu(prd.size); -#ifdef DEBUG_IDE - printf("ide: dma: prd: %08x: addr=0x%08x size=0x%08x\n", - (int)cur_addr, prd.addr, prd.size); -#endif - len = prd.size & 0xfffe; - if (len == 0) - len = 0x10000; - while (len > 0) { - len1 = bm->dma_cb(bm->ide_if, prd.addr, len); - if (len1 == 0) - goto the_end; - prd.addr += len1; - len -= len1; - } - /* end of transfer */ - if (prd.size & 0x80000000) - break; - cur_addr += 8; - } - /* end of transfer */ - the_end: - bm->status &= ~BM_STATUS_DMAING; - bm->status |= BM_STATUS_INT; - bm->dma_cb = NULL; - bm->ide_if = NULL; -} - -static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb) -{ - BMDMAState *bm = s->bmdma; - if(!bm) - return; - bm->ide_if = s; - bm->dma_cb = dma_cb; - if (bm->status & BM_STATUS_DMAING) { - ide_dma_loop(bm); - } -} - -static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - BMDMAState *bm = opaque; -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); -#endif - if (!(val & BM_CMD_START)) { - /* XXX: do it better */ - bm->status &= ~BM_STATUS_DMAING; - bm->cmd = val & 0x09; - } else { - bm->status |= BM_STATUS_DMAING; - bm->cmd = val & 0x09; - /* start dma transfer if possible */ - if (bm->dma_cb) - ide_dma_loop(bm); - } -} - -static uint32_t bmdma_readb(void *opaque, uint32_t addr) -{ - BMDMAState *bm = opaque; - PCIIDEState *pci_dev; - uint32_t val; - - switch(addr & 3) { - case 0: - val = bm->cmd; - break; - case 1: - pci_dev = bm->pci_dev; - if (pci_dev->type == IDE_TYPE_CMD646) { - val = pci_dev->dev.config[MRDMODE]; - } else { - val = 0xff; - } - break; - case 2: - val = bm->status; - break; - case 3: - pci_dev = bm->pci_dev; - if (pci_dev->type == IDE_TYPE_CMD646) { - if (bm == &pci_dev->bmdma[0]) - val = pci_dev->dev.config[UDIDETCR0]; - else - val = pci_dev->dev.config[UDIDETCR1]; - } else { - val = 0xff; - } - break; - default: - val = 0xff; - break; - } -#ifdef DEBUG_IDE - printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val); -#endif - return val; -} - -static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - BMDMAState *bm = opaque; - PCIIDEState *pci_dev; -#ifdef DEBUG_IDE - printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val); -#endif - switch(addr & 3) { - case 1: - pci_dev = bm->pci_dev; - if (pci_dev->type == IDE_TYPE_CMD646) { - pci_dev->dev.config[MRDMODE] = - (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30); - cmd646_update_irq(pci_dev); - } - break; - case 2: - bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); - break; - case 3: - pci_dev = bm->pci_dev; - if (pci_dev->type == IDE_TYPE_CMD646) { - if (bm == &pci_dev->bmdma[0]) - pci_dev->dev.config[UDIDETCR0] = val; - else - pci_dev->dev.config[UDIDETCR1] = val; - } - break; - } -} - -static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr) -{ - BMDMAState *bm = opaque; - uint32_t val; - val = bm->addr; -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); -#endif - return val; -} - -static void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val) -{ - BMDMAState *bm = opaque; -#ifdef DEBUG_IDE - printf("%s: 0x%08x\n", __func__, val); -#endif - bm->addr = val & ~3; -} - -static void bmdma_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - PCIIDEState *d = (PCIIDEState *)pci_dev; - int i; - - for(i = 0;i < 2; i++) { - BMDMAState *bm = &d->bmdma[i]; - d->ide_if[2 * i].bmdma = bm; - d->ide_if[2 * i + 1].bmdma = bm; - bm->pci_dev = (PCIIDEState *)pci_dev; - - register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); - - register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); - register_ioport_read(addr, 4, 1, bmdma_readb, bm); - - register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); - register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); - addr += 8; - } -} - -/* XXX: call it also when the MRDMODE is changed from the PCI config - registers */ -static void cmd646_update_irq(PCIIDEState *d) -{ - int pci_level; - pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) && - !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) || - ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) && - !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1)); - pci_set_irq((PCIDevice *)d, 0, pci_level); -} - -/* the PCI irq level is the logical OR of the two channels */ -static void cmd646_set_irq(void *opaque, int channel, int level) -{ - PCIIDEState *d = opaque; - int irq_mask; - - irq_mask = MRDMODE_INTR_CH0 << channel; - if (level) - d->dev.config[MRDMODE] |= irq_mask; - else - d->dev.config[MRDMODE] &= ~irq_mask; - cmd646_update_irq(d); -} - -/* CMD646 PCI IDE controller */ -void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table, - int secondary_ide_enabled) -{ - PCIIDEState *d; - uint8_t *pci_conf; - int i; - - d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE", - sizeof(PCIIDEState), - -1, - NULL, NULL); - d->type = IDE_TYPE_CMD646; - pci_conf = d->dev.config; - pci_conf[0x00] = 0x95; // CMD646 - pci_conf[0x01] = 0x10; - pci_conf[0x02] = 0x46; - pci_conf[0x03] = 0x06; - - pci_conf[0x08] = 0x07; // IDE controller revision - pci_conf[0x09] = 0x8f; - - pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE - pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage - pci_conf[0x0e] = 0x00; // header_type - - if (secondary_ide_enabled) { - /* XXX: if not enabled, really disable the seconday IDE controller */ - pci_conf[0x51] = 0x80; /* enable IDE1 */ - } - - pci_register_io_region((PCIDevice *)d, 0, 0x8, - PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 1, 0x4, - PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 2, 0x8, - PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 3, 0x4, - PCI_ADDRESS_SPACE_IO, ide_map); - pci_register_io_region((PCIDevice *)d, 4, 0x10, - PCI_ADDRESS_SPACE_IO, bmdma_map); - - pci_conf[0x3d] = 0x01; // interrupt on pin 1 - - for(i = 0; i < 4; i++) - d->ide_if[i].pci_dev = (PCIDevice *)d; - ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], - cmd646_set_irq, d, 0); - ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], - cmd646_set_irq, d, 1); -} - -/* hd_table must contain 4 block drivers */ -/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ -void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn) -{ - PCIIDEState *d; - uint8_t *pci_conf; - - /* register a function 1 of PIIX3 */ - d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", - sizeof(PCIIDEState), - devfn, - NULL, NULL); - d->type = IDE_TYPE_PIIX3; - - pci_conf = d->dev.config; - pci_conf[0x00] = 0x86; // Intel - pci_conf[0x01] = 0x80; - pci_conf[0x02] = 0x10; - pci_conf[0x03] = 0x70; - pci_conf[0x09] = 0x80; // legacy ATA mode - pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE - pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage - pci_conf[0x0e] = 0x00; // header_type - - pci_register_io_region((PCIDevice *)d, 4, 0x10, - PCI_ADDRESS_SPACE_IO, bmdma_map); - - ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], - pic_set_irq_new, isa_pic, 14); - ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], - pic_set_irq_new, isa_pic, 15); - ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6); - ide_init_ioport(&d->ide_if[2], 0x170, 0x376); -} - -/***********************************************************/ -/* MacIO based PowerPC IDE */ - -/* PowerMac IDE memory IO */ -static void pmac_ide_writeb (void *opaque, - target_phys_addr_t addr, uint32_t val) -{ - addr = (addr & 0xFFF) >> 4; - switch (addr) { - case 1 ... 7: - ide_ioport_write(opaque, addr, val); - break; - case 8: - case 22: - ide_cmd_write(opaque, 0, val); - break; - default: - break; - } -} - -static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr) -{ - uint8_t retval; - - addr = (addr & 0xFFF) >> 4; - switch (addr) { - case 1 ... 7: - retval = ide_ioport_read(opaque, addr); - break; - case 8: - case 22: - retval = ide_status_read(opaque, 0); - break; - default: - retval = 0xFF; - break; - } - return retval; -} - -static void pmac_ide_writew (void *opaque, - target_phys_addr_t addr, uint32_t val) -{ - addr = (addr & 0xFFF) >> 4; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - if (addr == 0) { - ide_data_writew(opaque, 0, val); - } -} - -static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr) -{ - uint16_t retval; - - addr = (addr & 0xFFF) >> 4; - if (addr == 0) { - retval = ide_data_readw(opaque, 0); - } else { - retval = 0xFFFF; - } -#ifdef TARGET_WORDS_BIGENDIAN - retval = bswap16(retval); -#endif - return retval; -} - -static void pmac_ide_writel (void *opaque, - target_phys_addr_t addr, uint32_t val) -{ - addr = (addr & 0xFFF) >> 4; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - if (addr == 0) { - ide_data_writel(opaque, 0, val); - } -} - -static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr) -{ - uint32_t retval; - - addr = (addr & 0xFFF) >> 4; - if (addr == 0) { - retval = ide_data_readl(opaque, 0); - } else { - retval = 0xFFFFFFFF; - } -#ifdef TARGET_WORDS_BIGENDIAN - retval = bswap32(retval); -#endif - return retval; -} - -static CPUWriteMemoryFunc *pmac_ide_write[] = { - pmac_ide_writeb, - pmac_ide_writew, - pmac_ide_writel, -}; - -static CPUReadMemoryFunc *pmac_ide_read[] = { - pmac_ide_readb, - pmac_ide_readw, - pmac_ide_readl, -}; - -/* hd_table must contain 4 block drivers */ -/* PowerMac uses memory mapped registers, not I/O. Return the memory - I/O index to access the ide. */ -int pmac_ide_init (BlockDriverState **hd_table, - SetIRQFunc *set_irq, void *irq_opaque, int irq) -{ - IDEState *ide_if; - int pmac_ide_memory; - - ide_if = qemu_mallocz(sizeof(IDEState) * 2); - ide_init2(&ide_if[0], hd_table[0], hd_table[1], - set_irq, irq_opaque, irq); - - pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, - pmac_ide_write, &ide_if[0]); - return pmac_ide_memory; -} diff --git a/hw/integratorcp.c b/hw/integratorcp.c deleted file mode 100644 index f438af7..0000000 --- a/hw/integratorcp.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * ARM Integrator CP System emulation. - * - * Copyright (c) 2005-2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the GPL - */ - -#include "vl.h" -#include "arm_pic.h" - -void DMA_run (void) -{ -} - -typedef struct { - uint32_t flash_offset; - uint32_t cm_osc; - uint32_t cm_ctrl; - uint32_t cm_lock; - uint32_t cm_auxosc; - uint32_t cm_sdram; - uint32_t cm_init; - uint32_t cm_flags; - uint32_t cm_nvflags; - uint32_t int_level; - uint32_t irq_enabled; - uint32_t fiq_enabled; -} integratorcm_state; - -static uint8_t integrator_spd[128] = { - 128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1, - 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40 -}; - -static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset) -{ - integratorcm_state *s = (integratorcm_state *)opaque; - offset -= 0x10000000; - if (offset >= 0x100 && offset < 0x200) { - /* CM_SPD */ - if (offset >= 0x180) - return 0; - return integrator_spd[offset >> 2]; - } - switch (offset >> 2) { - case 0: /* CM_ID */ - return 0x411a3001; - case 1: /* CM_PROC */ - return 0; - case 2: /* CM_OSC */ - return s->cm_osc; - case 3: /* CM_CTRL */ - return s->cm_ctrl; - case 4: /* CM_STAT */ - return 0x00100000; - case 5: /* CM_LOCK */ - if (s->cm_lock == 0xa05f) { - return 0x1a05f; - } else { - return s->cm_lock; - } - case 6: /* CM_LMBUSCNT */ - /* ??? High frequency timer. */ - cpu_abort(cpu_single_env, "integratorcm_read: CM_LMBUSCNT"); - case 7: /* CM_AUXOSC */ - return s->cm_auxosc; - case 8: /* CM_SDRAM */ - return s->cm_sdram; - case 9: /* CM_INIT */ - return s->cm_init; - case 10: /* CM_REFCT */ - /* ??? High frequency timer. */ - cpu_abort(cpu_single_env, "integratorcm_read: CM_REFCT"); - case 12: /* CM_FLAGS */ - return s->cm_flags; - case 14: /* CM_NVFLAGS */ - return s->cm_nvflags; - case 16: /* CM_IRQ_STAT */ - return s->int_level & s->irq_enabled; - case 17: /* CM_IRQ_RSTAT */ - return s->int_level; - case 18: /* CM_IRQ_ENSET */ - return s->irq_enabled; - case 20: /* CM_SOFT_INTSET */ - return s->int_level & 1; - case 24: /* CM_FIQ_STAT */ - return s->int_level & s->fiq_enabled; - case 25: /* CM_FIQ_RSTAT */ - return s->int_level; - case 26: /* CM_FIQ_ENSET */ - return s->fiq_enabled; - case 32: /* CM_VOLTAGE_CTL0 */ - case 33: /* CM_VOLTAGE_CTL1 */ - case 34: /* CM_VOLTAGE_CTL2 */ - case 35: /* CM_VOLTAGE_CTL3 */ - /* ??? Voltage control unimplemented. */ - return 0; - default: - cpu_abort (cpu_single_env, - "integratorcm_read: Unimplemented offset 0x%x\n", offset); - return 0; - } -} - -static void integratorcm_do_remap(integratorcm_state *s, int flash) -{ - if (flash) { - cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM); - } else { - cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM); - } - //??? tlb_flush (cpu_single_env, 1); -} - -static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value) -{ - if (value & 8) { - cpu_abort(cpu_single_env, "Board reset\n"); - } - if ((s->cm_init ^ value) & 4) { - integratorcm_do_remap(s, (value & 4) == 0); - } - if ((s->cm_init ^ value) & 1) { - printf("Green LED %s\n", (value & 1) ? "on" : "off"); - } - s->cm_init = (s->cm_init & ~ 5) | (value ^ 5); -} - -static void integratorcm_update(integratorcm_state *s) -{ - /* ??? The CPU irq/fiq is raised when either the core module or base PIC - are active. */ - if (s->int_level & (s->irq_enabled | s->fiq_enabled)) - cpu_abort(cpu_single_env, "Core module interrupt\n"); -} - -static void integratorcm_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - integratorcm_state *s = (integratorcm_state *)opaque; - offset -= 0x10000000; - switch (offset >> 2) { - case 2: /* CM_OSC */ - if (s->cm_lock == 0xa05f) - s->cm_osc = value; - break; - case 3: /* CM_CTRL */ - integratorcm_set_ctrl(s, value); - break; - case 5: /* CM_LOCK */ - s->cm_lock = value & 0xffff; - break; - case 7: /* CM_AUXOSC */ - if (s->cm_lock == 0xa05f) - s->cm_auxosc = value; - break; - case 8: /* CM_SDRAM */ - s->cm_sdram = value; - break; - case 9: /* CM_INIT */ - /* ??? This can change the memory bus frequency. */ - s->cm_init = value; - break; - case 12: /* CM_FLAGSS */ - s->cm_flags |= value; - break; - case 13: /* CM_FLAGSC */ - s->cm_flags &= ~value; - break; - case 14: /* CM_NVFLAGSS */ - s->cm_nvflags |= value; - break; - case 15: /* CM_NVFLAGSS */ - s->cm_nvflags &= ~value; - break; - case 18: /* CM_IRQ_ENSET */ - s->irq_enabled |= value; - integratorcm_update(s); - break; - case 19: /* CM_IRQ_ENCLR */ - s->irq_enabled &= ~value; - integratorcm_update(s); - break; - case 20: /* CM_SOFT_INTSET */ - s->int_level |= (value & 1); - integratorcm_update(s); - break; - case 21: /* CM_SOFT_INTCLR */ - s->int_level &= ~(value & 1); - integratorcm_update(s); - break; - case 26: /* CM_FIQ_ENSET */ - s->fiq_enabled |= value; - integratorcm_update(s); - break; - case 27: /* CM_FIQ_ENCLR */ - s->fiq_enabled &= ~value; - integratorcm_update(s); - break; - case 32: /* CM_VOLTAGE_CTL0 */ - case 33: /* CM_VOLTAGE_CTL1 */ - case 34: /* CM_VOLTAGE_CTL2 */ - case 35: /* CM_VOLTAGE_CTL3 */ - /* ??? Voltage control unimplemented. */ - break; - default: - cpu_abort (cpu_single_env, - "integratorcm_write: Unimplemented offset 0x%x\n", offset); - break; - } -} - -/* Integrator/CM control registers. */ - -static CPUReadMemoryFunc *integratorcm_readfn[] = { - integratorcm_read, - integratorcm_read, - integratorcm_read -}; - -static CPUWriteMemoryFunc *integratorcm_writefn[] = { - integratorcm_write, - integratorcm_write, - integratorcm_write -}; - -static void integratorcm_init(int memsz, uint32_t flash_offset) -{ - int iomemtype; - integratorcm_state *s; - - s = (integratorcm_state *)qemu_mallocz(sizeof(integratorcm_state)); - s->cm_osc = 0x01000048; - /* ??? What should the high bits of this value be? */ - s->cm_auxosc = 0x0007feff; - s->cm_sdram = 0x00011122; - if (memsz >= 256) { - integrator_spd[31] = 64; - s->cm_sdram |= 0x10; - } else if (memsz >= 128) { - integrator_spd[31] = 32; - s->cm_sdram |= 0x0c; - } else if (memsz >= 64) { - integrator_spd[31] = 16; - s->cm_sdram |= 0x08; - } else if (memsz >= 32) { - integrator_spd[31] = 4; - s->cm_sdram |= 0x04; - } else { - integrator_spd[31] = 2; - } - memcpy(integrator_spd + 73, "QEMU-MEMORY", 11); - s->cm_init = 0x00000112; - s->flash_offset = flash_offset; - - iomemtype = cpu_register_io_memory(0, integratorcm_readfn, - integratorcm_writefn, s); - cpu_register_physical_memory(0x10000000, 0x007fffff, iomemtype); - integratorcm_do_remap(s, 1); - /* ??? Save/restore. */ -} - -/* Integrator/CP hardware emulation. */ -/* Primary interrupt controller. */ - -typedef struct icp_pic_state -{ - arm_pic_handler handler; - uint32_t base; - uint32_t level; - uint32_t irq_enabled; - uint32_t fiq_enabled; - void *parent; - int parent_irq; - int parent_fiq; -} icp_pic_state; - -static void icp_pic_update(icp_pic_state *s) -{ - uint32_t flags; - - if (s->parent_irq != -1) { - flags = (s->level & s->irq_enabled); - pic_set_irq_new(s->parent, s->parent_irq, flags != 0); - } - if (s->parent_fiq != -1) { - flags = (s->level & s->fiq_enabled); - pic_set_irq_new(s->parent, s->parent_fiq, flags != 0); - } -} - -static void icp_pic_set_irq(void *opaque, int irq, int level) -{ - icp_pic_state *s = (icp_pic_state *)opaque; - if (level) - s->level |= 1 << irq; - else - s->level &= ~(1 << irq); - icp_pic_update(s); -} - -static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset) -{ - icp_pic_state *s = (icp_pic_state *)opaque; - - offset -= s->base; - switch (offset >> 2) { - case 0: /* IRQ_STATUS */ - return s->level & s->irq_enabled; - case 1: /* IRQ_RAWSTAT */ - return s->level; - case 2: /* IRQ_ENABLESET */ - return s->irq_enabled; - case 4: /* INT_SOFTSET */ - return s->level & 1; - case 8: /* FRQ_STATUS */ - return s->level & s->fiq_enabled; - case 9: /* FRQ_RAWSTAT */ - return s->level; - case 10: /* FRQ_ENABLESET */ - return s->fiq_enabled; - case 3: /* IRQ_ENABLECLR */ - case 5: /* INT_SOFTCLR */ - case 11: /* FRQ_ENABLECLR */ - default: - printf ("icp_pic_read: Bad register offset 0x%x\n", offset); - return 0; - } -} - -static void icp_pic_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - icp_pic_state *s = (icp_pic_state *)opaque; - offset -= s->base; - - switch (offset >> 2) { - case 2: /* IRQ_ENABLESET */ - s->irq_enabled |= value; - break; - case 3: /* IRQ_ENABLECLR */ - s->irq_enabled &= ~value; - break; - case 4: /* INT_SOFTSET */ - if (value & 1) - pic_set_irq_new(s, 0, 1); - break; - case 5: /* INT_SOFTCLR */ - if (value & 1) - pic_set_irq_new(s, 0, 0); - break; - case 10: /* FRQ_ENABLESET */ - s->fiq_enabled |= value; - break; - case 11: /* FRQ_ENABLECLR */ - s->fiq_enabled &= ~value; - break; - case 0: /* IRQ_STATUS */ - case 1: /* IRQ_RAWSTAT */ - case 8: /* FRQ_STATUS */ - case 9: /* FRQ_RAWSTAT */ - default: - printf ("icp_pic_write: Bad register offset 0x%x\n", offset); - return; - } - icp_pic_update(s); -} - -static CPUReadMemoryFunc *icp_pic_readfn[] = { - icp_pic_read, - icp_pic_read, - icp_pic_read -}; - -static CPUWriteMemoryFunc *icp_pic_writefn[] = { - icp_pic_write, - icp_pic_write, - icp_pic_write -}; - -static icp_pic_state *icp_pic_init(uint32_t base, void *parent, - int parent_irq, int parent_fiq) -{ - icp_pic_state *s; - int iomemtype; - - s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state)); - if (!s) - return NULL; - s->handler = icp_pic_set_irq; - s->base = base; - s->parent = parent; - s->parent_irq = parent_irq; - s->parent_fiq = parent_fiq; - iomemtype = cpu_register_io_memory(0, icp_pic_readfn, - icp_pic_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); - /* ??? Save/restore. */ - return s; -} - -/* CP control registers. */ -typedef struct { - uint32_t base; -} icp_control_state; - -static uint32_t icp_control_read(void *opaque, target_phys_addr_t offset) -{ - icp_control_state *s = (icp_control_state *)opaque; - offset -= s->base; - switch (offset >> 2) { - case 0: /* CP_IDFIELD */ - return 0x41034003; - case 1: /* CP_FLASHPROG */ - return 0; - case 2: /* CP_INTREG */ - return 0; - case 3: /* CP_DECODE */ - return 0x11; - default: - cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n", offset); - return 0; - } -} - -static void icp_control_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - icp_control_state *s = (icp_control_state *)opaque; - offset -= s->base; - switch (offset >> 2) { - case 1: /* CP_FLASHPROG */ - case 2: /* CP_INTREG */ - case 3: /* CP_DECODE */ - /* Nothing interesting implemented yet. */ - break; - default: - cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n", offset); - } -} -static CPUReadMemoryFunc *icp_control_readfn[] = { - icp_control_read, - icp_control_read, - icp_control_read -}; - -static CPUWriteMemoryFunc *icp_control_writefn[] = { - icp_control_write, - icp_control_write, - icp_control_write -}; - -static void icp_control_init(uint32_t base) -{ - int iomemtype; - icp_control_state *s; - - s = (icp_control_state *)qemu_mallocz(sizeof(icp_control_state)); - iomemtype = cpu_register_io_memory(0, icp_control_readfn, - icp_control_writefn, s); - cpu_register_physical_memory(base, 0x007fffff, iomemtype); - s->base = base; - /* ??? Save/restore. */ -} - - -/* Board init. */ - -static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, uint32_t cpuid) -{ - CPUState *env; - uint32_t bios_offset; - icp_pic_state *pic; - void *cpu_pic; - - env = cpu_init(); - cpu_arm_set_model(env, cpuid); - bios_offset = ram_size + vga_ram_size; - /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */ - /* ??? RAM shoud repeat to fill physical memory space. */ - /* SDRAM at address zero*/ - cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); - /* And again at address 0x80000000 */ - cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM); - - integratorcm_init(ram_size >> 20, bios_offset); - cpu_pic = arm_pic_init_cpu(env); - pic = icp_pic_init(0x14000000, cpu_pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); - icp_pic_init(0xca000000, pic, 26, -1); - icp_pit_init(0x13000000, pic, 5); - pl011_init(0x16000000, pic, 1, serial_hds[0]); - pl011_init(0x17000000, pic, 2, serial_hds[1]); - icp_control_init(0xcb000000); - pl050_init(0x18000000, pic, 3, 0); - pl050_init(0x19000000, pic, 4, 1); - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "smc91c111") == 0) { - smc91c111_init(&nd_table[0], 0xc8000000, pic, 27); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } - } - pl110_init(ds, 0xc0000000, pic, 22, 0); - - arm_load_kernel(ram_size, kernel_filename, kernel_cmdline, - initrd_filename, 0x113); -} - -static void integratorcp926_init(int ram_size, int vga_ram_size, - int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) -{ - integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, - snapshot, kernel_filename, kernel_cmdline, - initrd_filename, ARM_CPUID_ARM926); -} - -static void integratorcp1026_init(int ram_size, int vga_ram_size, - int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) -{ - integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename, - snapshot, kernel_filename, kernel_cmdline, - initrd_filename, ARM_CPUID_ARM1026); -} - -QEMUMachine integratorcp926_machine = { - "integratorcp926", - "ARM Integrator/CP (ARM926EJ-S)", - integratorcp926_init, -}; - -QEMUMachine integratorcp1026_machine = { - "integratorcp1026", - "ARM Integrator/CP (ARM1026EJ-S)", - integratorcp1026_init, -}; diff --git a/hw/iommu.c b/hw/iommu.c deleted file mode 100644 index e7d96c8..0000000 --- a/hw/iommu.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * QEMU SPARC iommu emulation - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* debug iommu */ -//#define DEBUG_IOMMU - -#ifdef DEBUG_IOMMU -#define DPRINTF(fmt, args...) \ -do { printf("IOMMU: " fmt , ##args); } while (0) -#else -#define DPRINTF(fmt, args...) -#endif - -#define IOMMU_NREGS (3*4096/4) -#define IOMMU_CTRL (0x0000 >> 2) -#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ -#define IOMMU_CTRL_VERS 0x0f000000 /* Version */ -#define IOMMU_VERSION 0x04000000 -#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */ -#define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */ -#define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */ -#define IOMMU_RNGE_64MB 0x00000008 /* 0xfc000000 -> 0xffffffff */ -#define IOMMU_RNGE_128MB 0x0000000c /* 0xf8000000 -> 0xffffffff */ -#define IOMMU_RNGE_256MB 0x00000010 /* 0xf0000000 -> 0xffffffff */ -#define IOMMU_RNGE_512MB 0x00000014 /* 0xe0000000 -> 0xffffffff */ -#define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */ -#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */ -#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */ -#define IOMMU_CTRL_MASK 0x0000001d - -#define IOMMU_BASE (0x0004 >> 2) -#define IOMMU_BASE_MASK 0x07fffc00 - -#define IOMMU_TLBFLUSH (0x0014 >> 2) -#define IOMMU_TLBFLUSH_MASK 0xffffffff - -#define IOMMU_PGFLUSH (0x0018 >> 2) -#define IOMMU_PGFLUSH_MASK 0xffffffff - -#define IOMMU_SBCFG0 (0x1010 >> 2) /* SBUS configration per-slot */ -#define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configration per-slot */ -#define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configration per-slot */ -#define IOMMU_SBCFG3 (0x101c >> 2) /* SBUS configration per-slot */ -#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */ -#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */ -#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */ -#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses - produced by this device as pure - physical. */ -#define IOMMU_SBCFG_MASK 0x00010003 - -#define IOMMU_ARBEN (0x2000 >> 2) /* SBUS arbitration enable */ -#define IOMMU_ARBEN_MASK 0x001f0000 -#define IOMMU_MID 0x00000008 - -/* The format of an iopte in the page tables */ -#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */ -#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */ -#define IOPTE_WRITE 0x00000004 /* Writeable */ -#define IOPTE_VALID 0x00000002 /* IOPTE is valid */ -#define IOPTE_WAZ 0x00000001 /* Write as zeros */ - -#define PAGE_SHIFT 12 -#define PAGE_SIZE (1 << PAGE_SHIFT) -#define PAGE_MASK (PAGE_SIZE - 1) - -typedef struct IOMMUState { - uint32_t addr; - uint32_t regs[IOMMU_NREGS]; - uint32_t iostart; -} IOMMUState; - -static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr) -{ - IOMMUState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - switch (saddr) { - default: - DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]); - return s->regs[saddr]; - break; - } - return 0; -} - -static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - IOMMUState *s = opaque; - uint32_t saddr; - - saddr = (addr - s->addr) >> 2; - DPRINTF("write reg[%d] = %x\n", saddr, val); - switch (saddr) { - case IOMMU_CTRL: - switch (val & IOMMU_CTRL_RNGE) { - case IOMMU_RNGE_16MB: - s->iostart = 0xff000000; - break; - case IOMMU_RNGE_32MB: - s->iostart = 0xfe000000; - break; - case IOMMU_RNGE_64MB: - s->iostart = 0xfc000000; - break; - case IOMMU_RNGE_128MB: - s->iostart = 0xf8000000; - break; - case IOMMU_RNGE_256MB: - s->iostart = 0xf0000000; - break; - case IOMMU_RNGE_512MB: - s->iostart = 0xe0000000; - break; - case IOMMU_RNGE_1GB: - s->iostart = 0xc0000000; - break; - default: - case IOMMU_RNGE_2GB: - s->iostart = 0x80000000; - break; - } - DPRINTF("iostart = %x\n", s->iostart); - s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION); - break; - case IOMMU_BASE: - s->regs[saddr] = val & IOMMU_BASE_MASK; - break; - case IOMMU_TLBFLUSH: - DPRINTF("tlb flush %x\n", val); - s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK; - break; - case IOMMU_PGFLUSH: - DPRINTF("page flush %x\n", val); - s->regs[saddr] = val & IOMMU_PGFLUSH_MASK; - break; - case IOMMU_SBCFG0: - case IOMMU_SBCFG1: - case IOMMU_SBCFG2: - case IOMMU_SBCFG3: - s->regs[saddr] = val & IOMMU_SBCFG_MASK; - break; - case IOMMU_ARBEN: - // XXX implement SBus probing: fault when reading unmapped - // addresses, fault cause and address stored to MMU/IOMMU - s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID; - break; - default: - s->regs[saddr] = val; - break; - } -} - -static CPUReadMemoryFunc *iommu_mem_read[3] = { - iommu_mem_readw, - iommu_mem_readw, - iommu_mem_readw, -}; - -static CPUWriteMemoryFunc *iommu_mem_write[3] = { - iommu_mem_writew, - iommu_mem_writew, - iommu_mem_writew, -}; - -uint32_t iommu_translate_local(void *opaque, uint32_t addr) -{ - IOMMUState *s = opaque; - uint32_t iopte, pa, tmppte; - - iopte = s->regs[1] << 4; - addr &= ~s->iostart; - iopte += (addr >> (PAGE_SHIFT - 2)) & ~3; - pa = ldl_phys(iopte); - tmppte = pa; - pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK); - DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte); - return pa; -} - -static void iommu_save(QEMUFile *f, void *opaque) -{ - IOMMUState *s = opaque; - int i; - - qemu_put_be32s(f, &s->addr); - for (i = 0; i < IOMMU_NREGS; i++) - qemu_put_be32s(f, &s->regs[i]); - qemu_put_be32s(f, &s->iostart); -} - -static int iommu_load(QEMUFile *f, void *opaque, int version_id) -{ - IOMMUState *s = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - qemu_get_be32s(f, &s->addr); - for (i = 0; i < IOMMU_NREGS; i++) - qemu_put_be32s(f, &s->regs[i]); - qemu_get_be32s(f, &s->iostart); - - return 0; -} - -static void iommu_reset(void *opaque) -{ - IOMMUState *s = opaque; - - memset(s->regs, 0, IOMMU_NREGS * 4); - s->iostart = 0; - s->regs[0] = IOMMU_VERSION; -} - -void *iommu_init(uint32_t addr) -{ - IOMMUState *s; - int iommu_io_memory; - - s = qemu_mallocz(sizeof(IOMMUState)); - if (!s) - return NULL; - - s->addr = addr; - - iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s); - cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory); - - register_savevm("iommu", addr, 1, iommu_save, iommu_load, s); - qemu_register_reset(iommu_reset, s); - return s; -} - diff --git a/hw/irq.c b/hw/irq.c new file mode 100644 index 0000000..3621b8e --- /dev/null +++ b/hw/irq.c @@ -0,0 +1,71 @@ +/* + * QEMU IRQ/GPIO common code. + * + * Copyright (c) 2007 CodeSourcery. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" +#include "irq.h" + +struct IRQState { + qemu_irq_handler handler; + void *opaque; + int n; +}; + +void qemu_set_irq(qemu_irq irq, int level) +{ + if (!irq) + return; + + irq->handler(irq->opaque, irq->n, level); +} + +qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n) +{ + qemu_irq *s; + struct IRQState *p; + int i; + + s = (qemu_irq *)qemu_mallocz(sizeof(qemu_irq) * n); + p = (struct IRQState *)qemu_mallocz(sizeof(struct IRQState) * n); + for (i = 0; i < n; i++) { + p->handler = handler; + p->opaque = opaque; + p->n = i; + s[i] = p; + p++; + } + return s; +} + +static void qemu_notirq(void *opaque, int line, int level) +{ + struct IRQState *irq = opaque; + + irq->handler(irq->opaque, irq->n, !level); +} + +qemu_irq qemu_irq_invert(qemu_irq irq) +{ + /* The default state for IRQs is low, so raise the output now. */ + qemu_irq_raise(irq); + return qemu_allocate_irqs(qemu_notirq, irq, 1)[0]; +} diff --git a/hw/irq.h b/hw/irq.h new file mode 100644 index 0000000..814511a --- /dev/null +++ b/hw/irq.h @@ -0,0 +1,32 @@ +#ifndef QEMU_IRQ_H +#define QEMU_IRQ_H + +/* Generic IRQ/GPIO pin infrastructure. */ + +typedef void (*qemu_irq_handler)(void *opaque, int n, int level); + +void qemu_set_irq(qemu_irq irq, int level); + +static inline void qemu_irq_raise(qemu_irq irq) +{ + qemu_set_irq(irq, 1); +} + +static inline void qemu_irq_lower(qemu_irq irq) +{ + qemu_set_irq(irq, 0); +} + +static inline void qemu_irq_pulse(qemu_irq irq) +{ + qemu_set_irq(irq, 1); + qemu_set_irq(irq, 0); +} + +/* Returns an array of N IRQs. */ +qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n); + +/* Returns a new IRQ with opposite polarity. */ +qemu_irq qemu_irq_invert(qemu_irq irq); + +#endif diff --git a/hw/lance.c b/hw/lance.c deleted file mode 100644 index d167937..0000000 --- a/hw/lance.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * QEMU Lance emulation - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* debug LANCE card */ -//#define DEBUG_LANCE - -#ifdef DEBUG_LANCE -#define DPRINTF(fmt, args...) \ -do { printf("LANCE: " fmt , ##args); } while (0) -#else -#define DPRINTF(fmt, args...) -#endif - -#ifndef LANCE_LOG_TX_BUFFERS -#define LANCE_LOG_TX_BUFFERS 4 -#define LANCE_LOG_RX_BUFFERS 4 -#endif - -#define LE_CSR0 0 -#define LE_CSR1 1 -#define LE_CSR2 2 -#define LE_CSR3 3 -#define LE_NREGS (LE_CSR3 + 1) -#define LE_MAXREG LE_CSR3 - -#define LE_RDP 0 -#define LE_RAP 1 - -#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ - -#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ -#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ -#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */ -#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */ -#define LE_C0_MERR 0x0800 /* ME: Memory error */ -#define LE_C0_RINT 0x0400 /* Received interrupt */ -#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */ -#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */ -#define LE_C0_INTR 0x0080 /* Interrupt or error */ -#define LE_C0_INEA 0x0040 /* Interrupt enable */ -#define LE_C0_RXON 0x0020 /* Receiver on */ -#define LE_C0_TXON 0x0010 /* Transmitter on */ -#define LE_C0_TDMD 0x0008 /* Transmitter demand */ -#define LE_C0_STOP 0x0004 /* Stop the card */ -#define LE_C0_STRT 0x0002 /* Start the card */ -#define LE_C0_INIT 0x0001 /* Init the card */ - -#define LE_C3_BSWP 0x4 /* SWAP */ -#define LE_C3_ACON 0x2 /* ALE Control */ -#define LE_C3_BCON 0x1 /* Byte control */ - -/* Receive message descriptor 1 */ -#define LE_R1_OWN 0x80 /* Who owns the entry */ -#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ -#define LE_R1_FRA 0x20 /* FRA: Frame error */ -#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ -#define LE_R1_CRC 0x08 /* CRC error */ -#define LE_R1_BUF 0x04 /* BUF: Buffer error */ -#define LE_R1_SOP 0x02 /* Start of packet */ -#define LE_R1_EOP 0x01 /* End of packet */ -#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ - -#define LE_T1_OWN 0x80 /* Lance owns the packet */ -#define LE_T1_ERR 0x40 /* Error summary */ -#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ -#define LE_T1_EONE 0x08 /* Error: one retry needed */ -#define LE_T1_EDEF 0x04 /* Error: deferred */ -#define LE_T1_SOP 0x02 /* Start of packet */ -#define LE_T1_EOP 0x01 /* End of packet */ -#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ - -#define LE_T3_BUF 0x8000 /* Buffer error */ -#define LE_T3_UFL 0x4000 /* Error underflow */ -#define LE_T3_LCOL 0x1000 /* Error late collision */ -#define LE_T3_CLOS 0x0800 /* Error carrier loss */ -#define LE_T3_RTY 0x0400 /* Error retry */ -#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ - -#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) -#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) - -#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) -#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) - -#define PKT_BUF_SZ 1544 -#define RX_BUFF_SIZE PKT_BUF_SZ -#define TX_BUFF_SIZE PKT_BUF_SZ - -struct lance_rx_desc { - unsigned short rmd0; /* low address of packet */ - unsigned char rmd1_bits; /* descriptor bits */ - unsigned char rmd1_hadr; /* high address of packet */ - short length; /* This length is 2s complement (negative)! - * Buffer length - */ - unsigned short mblength; /* This is the actual number of bytes received */ -}; - -struct lance_tx_desc { - unsigned short tmd0; /* low address of packet */ - unsigned char tmd1_bits; /* descriptor bits */ - unsigned char tmd1_hadr; /* high address of packet */ - short length; /* Length is 2s complement (negative)! */ - unsigned short misc; -}; - -/* The LANCE initialization block, described in databook. */ -/* On the Sparc, this block should be on a DMA region */ -struct lance_init_block { - unsigned short mode; /* Pre-set mode (reg. 15) */ - unsigned char phys_addr[6]; /* Physical ethernet address */ - unsigned filter[2]; /* Multicast filter. */ - - /* Receive and transmit ring base, along with extra bits. */ - unsigned short rx_ptr; /* receive descriptor addr */ - unsigned short rx_len; /* receive len and high addr */ - unsigned short tx_ptr; /* transmit descriptor addr */ - unsigned short tx_len; /* transmit len and high addr */ - - /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ - struct lance_rx_desc brx_ring[RX_RING_SIZE]; - struct lance_tx_desc btx_ring[TX_RING_SIZE]; - - char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE]; - char pad[2]; /* align rx_buf for copy_and_sum(). */ - char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE]; -}; - -#define LEDMA_REGS 4 -#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1) - -typedef struct LANCEState { - VLANClientState *vc; - uint8_t macaddr[6]; /* init mac address */ - uint32_t leptr; - uint16_t addr; - uint16_t regs[LE_NREGS]; - uint8_t phys[6]; /* mac address */ - int irq; - unsigned int rxptr, txptr; - uint32_t ledmaregs[LEDMA_REGS]; -} LANCEState; - -static void lance_send(void *opaque); - -static void lance_reset(void *opaque) -{ - LANCEState *s = opaque; - memcpy(s->phys, s->macaddr, 6); - s->rxptr = 0; - s->txptr = 0; - memset(s->regs, 0, LE_NREGS * 2); - s->regs[LE_CSR0] = LE_C0_STOP; - memset(s->ledmaregs, 0, LEDMA_REGS * 4); -} - -static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) -{ - LANCEState *s = opaque; - uint32_t saddr; - - saddr = addr & LE_MAXREG; - switch (saddr >> 1) { - case LE_RDP: - DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]); - return s->regs[s->addr]; - case LE_RAP: - DPRINTF("read areg = %4.4x\n", s->addr); - return s->addr; - default: - DPRINTF("read unknown(%d)\n", saddr>>1); - break; - } - return 0; -} - -static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - LANCEState *s = opaque; - uint32_t saddr; - uint16_t reg; - - saddr = addr & LE_MAXREG; - switch (saddr >> 1) { - case LE_RDP: - DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val); - switch(s->addr) { - case LE_CSR0: - if (val & LE_C0_STOP) { - s->regs[LE_CSR0] = LE_C0_STOP; - break; - } - - reg = s->regs[LE_CSR0]; - - // 1 = clear for some bits - reg &= ~(val & 0x7f00); - - // generated bits - reg &= ~(LE_C0_ERR | LE_C0_INTR); - if (reg & 0x7100) - reg |= LE_C0_ERR; - if (reg & 0x7f00) - reg |= LE_C0_INTR; - - // direct bit - reg &= ~LE_C0_INEA; - reg |= val & LE_C0_INEA; - - // exclusive bits - if (val & LE_C0_INIT) { - reg |= LE_C0_IDON | LE_C0_INIT; - reg &= ~LE_C0_STOP; - } - else if (val & LE_C0_STRT) { - reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON; - reg &= ~LE_C0_STOP; - } - - s->regs[LE_CSR0] = reg; - break; - case LE_CSR1: - s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff); - s->regs[s->addr] = val; - break; - case LE_CSR2: - s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16); - s->regs[s->addr] = val; - break; - case LE_CSR3: - s->regs[s->addr] = val; - break; - } - break; - case LE_RAP: - DPRINTF("write areg = %4.4x\n", val); - if (val < LE_NREGS) - s->addr = val; - break; - default: - DPRINTF("write unknown(%d) = %4.4x\n", saddr>>1, val); - break; - } - lance_send(s); -} - -static CPUReadMemoryFunc *lance_mem_read[3] = { - lance_mem_readw, - lance_mem_readw, - lance_mem_readw, -}; - -static CPUWriteMemoryFunc *lance_mem_write[3] = { - lance_mem_writew, - lance_mem_writew, - lance_mem_writew, -}; - - -#define MIN_BUF_SIZE 60 - -static int lance_can_receive(void *opaque) -{ - return 1; -} - -static void lance_receive(void *opaque, const uint8_t *buf, int size) -{ - LANCEState *s = opaque; - uint32_t dmaptr = s->leptr + s->ledmaregs[3]; - struct lance_init_block *ib; - unsigned int i, old_rxptr; - uint16_t temp16; - uint8_t temp8; - - DPRINTF("receive size %d\n", size); - if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) - return; - - ib = (void *) iommu_translate(dmaptr); - - old_rxptr = s->rxptr; - for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) { - cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); - if (temp8 == (LE_R1_OWN)) { - s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK; - temp16 = size + 4; - bswap16s(&temp16); - cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp16, 2); - cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size); - temp8 = LE_R1_POK; - cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1); - s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; - if (s->regs[LE_CSR0] & LE_C0_INEA) - pic_set_irq(s->irq, 1); - DPRINTF("got packet, len %d\n", size); - return; - } - } -} - -static void lance_send(void *opaque) -{ - LANCEState *s = opaque; - uint32_t dmaptr = s->leptr + s->ledmaregs[3]; - struct lance_init_block *ib; - unsigned int i, old_txptr; - uint16_t temp16; - uint8_t temp8; - char pkt_buf[PKT_BUF_SZ]; - - DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]); - if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) - return; - - ib = (void *) iommu_translate(dmaptr); - - DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", dmaptr, ib, &ib->btx_ring); - old_txptr = s->txptr; - for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) { - cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); - if (temp8 == (LE_T1_POK|LE_T1_OWN)) { - cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp16, 2); - bswap16s(&temp16); - temp16 = (~temp16) + 1; - cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16); - DPRINTF("sending packet, len %d\n", temp16); - qemu_send_packet(s->vc, pkt_buf, temp16); - temp8 = LE_T1_POK; - cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1); - s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; - s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; - } - } - if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) - pic_set_irq(s->irq, 1); -} - -static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) -{ - LANCEState *s = opaque; - uint32_t saddr; - - saddr = (addr & LEDMA_MAXADDR) >> 2; - return s->ledmaregs[saddr]; -} - -static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - LANCEState *s = opaque; - uint32_t saddr; - - saddr = (addr & LEDMA_MAXADDR) >> 2; - s->ledmaregs[saddr] = val; -} - -static CPUReadMemoryFunc *ledma_mem_read[3] = { - ledma_mem_readl, - ledma_mem_readl, - ledma_mem_readl, -}; - -static CPUWriteMemoryFunc *ledma_mem_write[3] = { - ledma_mem_writel, - ledma_mem_writel, - ledma_mem_writel, -}; - -static void lance_save(QEMUFile *f, void *opaque) -{ - LANCEState *s = opaque; - int i; - - qemu_put_be32s(f, &s->leptr); - qemu_put_be16s(f, &s->addr); - for (i = 0; i < LE_NREGS; i ++) - qemu_put_be16s(f, &s->regs[i]); - qemu_put_buffer(f, s->phys, 6); - qemu_put_be32s(f, &s->irq); - for (i = 0; i < LEDMA_REGS; i ++) - qemu_put_be32s(f, &s->ledmaregs[i]); -} - -static int lance_load(QEMUFile *f, void *opaque, int version_id) -{ - LANCEState *s = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - qemu_get_be32s(f, &s->leptr); - qemu_get_be16s(f, &s->addr); - for (i = 0; i < LE_NREGS; i ++) - qemu_get_be16s(f, &s->regs[i]); - qemu_get_buffer(f, s->phys, 6); - qemu_get_be32s(f, &s->irq); - for (i = 0; i < LEDMA_REGS; i ++) - qemu_get_be32s(f, &s->ledmaregs[i]); - return 0; -} - -void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr) -{ - LANCEState *s; - int lance_io_memory, ledma_io_memory; - - s = qemu_mallocz(sizeof(LANCEState)); - if (!s) - return; - - s->irq = irq; - - lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); - cpu_register_physical_memory(leaddr, 4, lance_io_memory); - - ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); - cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); - - memcpy(s->macaddr, nd->macaddr, 6); - - lance_reset(s); - - s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, s); - - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - s->macaddr[0], - s->macaddr[1], - s->macaddr[2], - s->macaddr[3], - s->macaddr[4], - s->macaddr[5]); - - register_savevm("lance", leaddr, 1, lance_save, lance_load, s); - qemu_register_reset(lance_reset, s); -} - diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c deleted file mode 100644 index 24dff0e..0000000 --- a/hw/lsi53c895a.c +++ /dev/null @@ -1,1571 +0,0 @@ -/* - * QEMU LSI53C895A SCSI Host Bus Adapter emulation - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the LGPL. - */ - -/* ??? Need to check if the {read,write}[wl] routines work properly on - big-endian targets. */ - -#include "vl.h" - -//#define DEBUG_LSI -//#define DEBUG_LSI_REG - -#ifdef DEBUG_LSI -#define DPRINTF(fmt, args...) \ -do { printf("lsi_scsi: " fmt , ##args); } while (0) -#define BADF(fmt, args...) \ -do { fprintf(stderr, "lsi_scsi: " fmt , ##args); exit(1);} while (0) -#else -#define DPRINTF(fmt, args...) do {} while(0) -#define BADF(fmt, args...) \ -do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0) -#endif - -#define LSI_SCNTL0_TRG 0x01 -#define LSI_SCNTL0_AAP 0x02 -#define LSI_SCNTL0_EPC 0x08 -#define LSI_SCNTL0_WATN 0x10 -#define LSI_SCNTL0_START 0x20 - -#define LSI_SCNTL1_SST 0x01 -#define LSI_SCNTL1_IARB 0x02 -#define LSI_SCNTL1_AESP 0x04 -#define LSI_SCNTL1_RST 0x08 -#define LSI_SCNTL1_CON 0x10 -#define LSI_SCNTL1_DHP 0x20 -#define LSI_SCNTL1_ADB 0x40 -#define LSI_SCNTL1_EXC 0x80 - -#define LSI_SCNTL2_WSR 0x01 -#define LSI_SCNTL2_VUE0 0x02 -#define LSI_SCNTL2_VUE1 0x04 -#define LSI_SCNTL2_WSS 0x08 -#define LSI_SCNTL2_SLPHBEN 0x10 -#define LSI_SCNTL2_SLPMD 0x20 -#define LSI_SCNTL2_CHM 0x40 -#define LSI_SCNTL2_SDU 0x80 - -#define LSI_ISTAT0_DIP 0x01 -#define LSI_ISTAT0_SIP 0x02 -#define LSI_ISTAT0_INTF 0x04 -#define LSI_ISTAT0_CON 0x08 -#define LSI_ISTAT0_SEM 0x10 -#define LSI_ISTAT0_SIGP 0x20 -#define LSI_ISTAT0_SRST 0x40 -#define LSI_ISTAT0_ABRT 0x80 - -#define LSI_ISTAT1_SI 0x01 -#define LSI_ISTAT1_SRUN 0x02 -#define LSI_ISTAT1_FLSH 0x04 - -#define LSI_SSTAT0_SDP0 0x01 -#define LSI_SSTAT0_RST 0x02 -#define LSI_SSTAT0_WOA 0x04 -#define LSI_SSTAT0_LOA 0x08 -#define LSI_SSTAT0_AIP 0x10 -#define LSI_SSTAT0_OLF 0x20 -#define LSI_SSTAT0_ORF 0x40 -#define LSI_SSTAT0_ILF 0x80 - -#define LSI_SIST0_PAR 0x01 -#define LSI_SIST0_RST 0x02 -#define LSI_SIST0_UDC 0x04 -#define LSI_SIST0_SGE 0x08 -#define LSI_SIST0_RSL 0x10 -#define LSI_SIST0_SEL 0x20 -#define LSI_SIST0_CMP 0x40 -#define LSI_SIST0_MA 0x80 - -#define LSI_SIST1_HTH 0x01 -#define LSI_SIST1_GEN 0x02 -#define LSI_SIST1_STO 0x04 -#define LSI_SIST1_SBMC 0x10 - -#define LSI_SOCL_IO 0x01 -#define LSI_SOCL_CD 0x02 -#define LSI_SOCL_MSG 0x04 -#define LSI_SOCL_ATN 0x08 -#define LSI_SOCL_SEL 0x10 -#define LSI_SOCL_BSY 0x20 -#define LSI_SOCL_ACK 0x40 -#define LSI_SOCL_REQ 0x80 - -#define LSI_DSTAT_IID 0x01 -#define LSI_DSTAT_SIR 0x04 -#define LSI_DSTAT_SSI 0x08 -#define LSI_DSTAT_ABRT 0x10 -#define LSI_DSTAT_BF 0x20 -#define LSI_DSTAT_MDPE 0x40 -#define LSI_DSTAT_DFE 0x80 - -#define LSI_DCNTL_COM 0x01 -#define LSI_DCNTL_IRQD 0x02 -#define LSI_DCNTL_STD 0x04 -#define LSI_DCNTL_IRQM 0x08 -#define LSI_DCNTL_SSM 0x10 -#define LSI_DCNTL_PFEN 0x20 -#define LSI_DCNTL_PFF 0x40 -#define LSI_DCNTL_CLSE 0x80 - -#define LSI_DMODE_MAN 0x01 -#define LSI_DMODE_BOF 0x02 -#define LSI_DMODE_ERMP 0x04 -#define LSI_DMODE_ERL 0x08 -#define LSI_DMODE_DIOM 0x10 -#define LSI_DMODE_SIOM 0x20 - -#define LSI_CTEST2_DACK 0x01 -#define LSI_CTEST2_DREQ 0x02 -#define LSI_CTEST2_TEOP 0x04 -#define LSI_CTEST2_PCICIE 0x08 -#define LSI_CTEST2_CM 0x10 -#define LSI_CTEST2_CIO 0x20 -#define LSI_CTEST2_SIGP 0x40 -#define LSI_CTEST2_DDIR 0x80 - -#define LSI_CTEST5_BL2 0x04 -#define LSI_CTEST5_DDIR 0x08 -#define LSI_CTEST5_MASR 0x10 -#define LSI_CTEST5_DFSN 0x20 -#define LSI_CTEST5_BBCK 0x40 -#define LSI_CTEST5_ADCK 0x80 - -#define LSI_CCNTL0_DILS 0x01 -#define LSI_CCNTL0_DISFC 0x10 -#define LSI_CCNTL0_ENNDJ 0x20 -#define LSI_CCNTL0_PMJCTL 0x40 -#define LSI_CCNTL0_ENPMJ 0x80 - -#define PHASE_DO 0 -#define PHASE_DI 1 -#define PHASE_CMD 2 -#define PHASE_ST 3 -#define PHASE_MO 6 -#define PHASE_MI 7 -#define PHASE_MASK 7 - -/* The HBA is ID 7, so for simplicitly limit to 7 devices. */ -#define LSI_MAX_DEVS 7 - -typedef struct { - PCIDevice pci_dev; - int mmio_io_addr; - int ram_io_addr; - uint32_t script_ram_base; - uint32_t data_len; - - int carry; /* ??? Should this be an a visible register somewhere? */ - int sense; - uint8_t msg; - /* Nonzero if a Wait Reselect instruction has been issued. */ - int waiting; - SCSIDevice *scsi_dev[LSI_MAX_DEVS]; - SCSIDevice *current_dev; - int current_lun; - - uint32_t dsa; - uint32_t temp; - uint32_t dnad; - uint32_t dbc; - uint8_t istat0; - uint8_t istat1; - uint8_t dcmd; - uint8_t dstat; - uint8_t dien; - uint8_t sist0; - uint8_t sist1; - uint8_t sien0; - uint8_t sien1; - uint8_t mbox0; - uint8_t mbox1; - uint8_t dfifo; - uint8_t ctest3; - uint8_t ctest4; - uint8_t ctest5; - uint8_t ccntl0; - uint8_t ccntl1; - uint32_t dsp; - uint32_t dsps; - uint8_t dmode; - uint8_t dcntl; - uint8_t scntl0; - uint8_t scntl1; - uint8_t scntl2; - uint8_t scntl3; - uint8_t sstat0; - uint8_t sstat1; - uint8_t scid; - uint8_t sxfer; - uint8_t socl; - uint8_t sdid; - uint8_t sfbr; - uint8_t stest1; - uint8_t stest2; - uint8_t stest3; - uint8_t stime0; - uint8_t respid0; - uint8_t respid1; - uint32_t mmrs; - uint32_t mmws; - uint32_t sfs; - uint32_t drs; - uint32_t sbms; - uint32_t dmbs; - uint32_t dnad64; - uint32_t pmjad1; - uint32_t pmjad2; - uint32_t rbc; - uint32_t ua; - uint32_t ia; - uint32_t sbc; - uint32_t csbc; - uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */ - - /* Script ram is stored as 32-bit words in host byteorder. */ - uint32_t script_ram[2048]; -} LSIState; - -static void lsi_soft_reset(LSIState *s) -{ - DPRINTF("Reset\n"); - s->carry = 0; - - s->waiting = 0; - s->dsa = 0; - s->dnad = 0; - s->dbc = 0; - s->temp = 0; - memset(s->scratch, 0, sizeof(s->scratch)); - s->istat0 = 0; - s->istat1 = 0; - s->dcmd = 0; - s->dstat = 0; - s->dien = 0; - s->sist0 = 0; - s->sist1 = 0; - s->sien0 = 0; - s->sien1 = 0; - s->mbox0 = 0; - s->mbox1 = 0; - s->dfifo = 0; - s->ctest3 = 0; - s->ctest4 = 0; - s->ctest5 = 0; - s->ccntl0 = 0; - s->ccntl1 = 0; - s->dsp = 0; - s->dsps = 0; - s->dmode = 0; - s->dcntl = 0; - s->scntl0 = 0xc0; - s->scntl1 = 0; - s->scntl2 = 0; - s->scntl3 = 0; - s->sstat0 = 0; - s->sstat1 = 0; - s->scid = 7; - s->sxfer = 0; - s->socl = 0; - s->stest1 = 0; - s->stest2 = 0; - s->stest3 = 0; - s->stime0 = 0; - s->respid0 = 0x80; - s->respid1 = 0; - s->mmrs = 0; - s->mmws = 0; - s->sfs = 0; - s->drs = 0; - s->sbms = 0; - s->dmbs = 0; - s->dnad64 = 0; - s->pmjad1 = 0; - s->pmjad2 = 0; - s->rbc = 0; - s->ua = 0; - s->ia = 0; - s->sbc = 0; - s->csbc = 0; -} - -static uint8_t lsi_reg_readb(LSIState *s, int offset); -static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val); - -static inline uint32_t read_dword(LSIState *s, uint32_t addr) -{ - uint32_t buf; - - /* Optimize reading from SCRIPTS RAM. */ - if ((addr & 0xffffe000) == s->script_ram_base) { - return s->script_ram[(addr & 0x1fff) >> 2]; - } - cpu_physical_memory_read(addr, (uint8_t *)&buf, 4); - return cpu_to_le32(buf); -} - -static void lsi_stop_script(LSIState *s) -{ - s->istat1 &= ~LSI_ISTAT1_SRUN; -} - -static void lsi_update_irq(LSIState *s) -{ - int level; - static int last_level; - - /* It's unclear whether the DIP/SIP bits should be cleared when the - Interrupt Status Registers are cleared or when istat0 is read. - We currently do the formwer, which seems to work. */ - level = 0; - if (s->dstat) { - if (s->dstat & s->dien) - level = 1; - s->istat0 |= LSI_ISTAT0_DIP; - } else { - s->istat0 &= ~LSI_ISTAT0_DIP; - } - - if (s->sist0 || s->sist1) { - if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1)) - level = 1; - s->istat0 |= LSI_ISTAT0_SIP; - } else { - s->istat0 &= ~LSI_ISTAT0_SIP; - } - if (s->istat0 & LSI_ISTAT0_INTF) - level = 1; - - if (level != last_level) { - DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n", - level, s->dstat, s->sist1, s->sist0); - last_level = level; - } - pci_set_irq(&s->pci_dev, 0, level); -} - -/* Stop SCRIPTS execution and raise a SCSI interrupt. */ -static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1) -{ - uint32_t mask0; - uint32_t mask1; - - DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", - stat1, stat0, s->sist1, s->sist0); - s->sist0 |= stat0; - s->sist1 |= stat1; - /* Stop processor on fatal or unmasked interrupt. As a special hack - we don't stop processing when raising STO. Instead continue - execution and stop at the next insn that accesses the SCSI bus. */ - mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL); - mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH); - mask1 &= ~LSI_SIST1_STO; - if (s->sist0 & mask0 || s->sist1 & mask1) { - lsi_stop_script(s); - } - lsi_update_irq(s); -} - -/* Stop SCRIPTS execution and raise a DMA interrupt. */ -static void lsi_script_dma_interrupt(LSIState *s, int stat) -{ - DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat); - s->dstat |= stat; - lsi_update_irq(s); - lsi_stop_script(s); -} - -static inline void lsi_set_phase(LSIState *s, int phase) -{ - s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase; -} - -static void lsi_bad_phase(LSIState *s, int out, int new_phase) -{ - /* Trigger a phase mismatch. */ - if (s->ccntl0 & LSI_CCNTL0_ENPMJ) { - if ((s->ccntl0 & LSI_CCNTL0_PMJCTL) || out) { - s->dsp = s->pmjad1; - } else { - s->dsp = s->pmjad2; - } - DPRINTF("Data phase mismatch jump to %08x\n", s->dsp); - } else { - DPRINTF("Phase mismatch interrupt\n"); - lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0); - lsi_stop_script(s); - } - lsi_set_phase(s, new_phase); -} - -static void lsi_do_dma(LSIState *s, int out) -{ - uint8_t buf[TARGET_PAGE_SIZE]; - uint32_t addr; - uint32_t count; - int n; - - count = s->dbc; - addr = s->dnad; - DPRINTF("DMA %s addr=0x%08x len=%d avail=%d\n", out ? "out" : "in", - addr, count, s->data_len); - /* ??? Too long transfers are truncated. Don't know if this is the - correct behavior. */ - if (count > s->data_len) { - /* If the DMA length is greater then the device data length then - a phase mismatch will occur. */ - count = s->data_len; - s->dbc = count; - lsi_bad_phase(s, out, PHASE_ST); - } - - s->csbc += count; - - /* ??? Set SFBR to first data byte. */ - while (count) { - n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count; - if (out) { - cpu_physical_memory_read(addr, buf, n); - scsi_write_data(s->current_dev, buf, n); - } else { - scsi_read_data(s->current_dev, buf, n); - cpu_physical_memory_write(addr, buf, n); - } - addr += n; - count -= n; - } -} - - -static void lsi_do_command(LSIState *s) -{ - uint8_t buf[16]; - int n; - - DPRINTF("Send command len=%d\n", s->dbc); - if (s->dbc > 16) - s->dbc = 16; - cpu_physical_memory_read(s->dnad, buf, s->dbc); - s->sfbr = buf[0]; - n = scsi_send_command(s->current_dev, 0, buf, s->current_lun); - if (n > 0) { - s->data_len = n; - lsi_set_phase(s, PHASE_DI); - } else if (n < 0) { - s->data_len = -n; - lsi_set_phase(s, PHASE_DO); - } -} - -static void lsi_command_complete(void *opaque, uint32_t tag, int sense) -{ - LSIState *s = (LSIState *)opaque; - - DPRINTF("Command complete sense=%d\n", sense); - s->sense = sense; - lsi_set_phase(s, PHASE_ST); -} - -static void lsi_do_status(LSIState *s) -{ - DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense); - if (s->dbc != 1) - BADF("Bad Status move\n"); - s->dbc = 1; - s->msg = s->sense; - cpu_physical_memory_write(s->dnad, &s->msg, 1); - s->sfbr = s->msg; - lsi_set_phase(s, PHASE_MI); - s->msg = 0; /* COMMAND COMPLETE */ -} - -static void lsi_disconnect(LSIState *s) -{ - s->scntl1 &= ~LSI_SCNTL1_CON; - s->sstat1 &= ~PHASE_MASK; -} - -static void lsi_do_msgin(LSIState *s) -{ - DPRINTF("Message in len=%d\n", s->dbc); - s->dbc = 1; - s->sfbr = s->msg; - cpu_physical_memory_write(s->dnad, &s->msg, 1); - if (s->msg == 0) { - lsi_disconnect(s); - } else { - /* ??? Check if ATN (not yet implemented) is asserted and maybe - switch to PHASE_MO. */ - lsi_set_phase(s, PHASE_CMD); - } -} - -static void lsi_do_msgout(LSIState *s) -{ - uint8_t msg; - - DPRINTF("MSG out len=%d\n", s->dbc); - if (s->dbc != 1) { - /* Multibyte messages not implemented. */ - s->msg = 7; /* MESSAGE REJECT */ - //s->dbc = 1; - //lsi_bad_phase(s, 1, PHASE_MI); - lsi_set_phase(s, PHASE_MI); - return; - } - cpu_physical_memory_read(s->dnad, &msg, 1); - s->sfbr = msg; - s->dnad++; - - switch (msg) { - case 0x00: - DPRINTF("Got Disconnect\n"); - lsi_disconnect(s); - return; - case 0x08: - DPRINTF("Got No Operation\n"); - lsi_set_phase(s, PHASE_CMD); - return; - } - if ((msg & 0x80) == 0) { - DPRINTF("Unimplemented message 0x%d\n", msg); - s->msg = 7; /* MESSAGE REJECT */ - lsi_bad_phase(s, 1, PHASE_MI); - return; - } - s->current_lun = msg & 7; - DPRINTF("Select LUN %d\n", s->current_lun); - lsi_set_phase(s, PHASE_CMD); -} - -/* Sign extend a 24-bit value. */ -static inline int32_t sxt24(int32_t n) -{ - return (n << 8) >> 8; -} - -static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count) -{ - int n; - uint8_t buf[TARGET_PAGE_SIZE]; - - DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); - while (count) { - n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count; - cpu_physical_memory_read(src, buf, n); - cpu_physical_memory_write(dest, buf, n); - src += n; - dest += n; - count -= n; - } -} - -static void lsi_execute_script(LSIState *s) -{ - uint32_t insn; - uint32_t addr; - int opcode; - - s->istat1 |= LSI_ISTAT1_SRUN; -again: - insn = read_dword(s, s->dsp); - addr = read_dword(s, s->dsp + 4); - DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr); - s->dsps = addr; - s->dcmd = insn >> 24; - s->dsp += 8; - switch (insn >> 30) { - case 0: /* Block move. */ - if (s->sist1 & LSI_SIST1_STO) { - DPRINTF("Delayed select timeout\n"); - lsi_stop_script(s); - break; - } - s->dbc = insn & 0xffffff; - s->rbc = s->dbc; - if (insn & (1 << 29)) { - /* Indirect addressing. */ - addr = read_dword(s, addr); - } else if (insn & (1 << 28)) { - uint32_t buf[2]; - int32_t offset; - /* Table indirect addressing. */ - offset = sxt24(addr); - cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8); - s->dbc = cpu_to_le32(buf[0]); - addr = cpu_to_le32(buf[1]); - } - if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { - DPRINTF("Wrong phase got %d expected %d\n", - s->sstat1 & PHASE_MASK, (insn >> 24) & 7); - lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0); - break; - } - s->dnad = addr; - switch (s->sstat1 & 0x7) { - case PHASE_DO: - lsi_do_dma(s, 1); - break; - case PHASE_DI: - lsi_do_dma(s, 0); - break; - case PHASE_CMD: - lsi_do_command(s); - break; - case PHASE_ST: - lsi_do_status(s); - break; - case PHASE_MO: - lsi_do_msgout(s); - break; - case PHASE_MI: - lsi_do_msgin(s); - break; - default: - BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK); - exit(1); - } - s->dfifo = s->dbc & 0xff; - s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3); - s->sbc = s->dbc; - s->rbc -= s->dbc; - s->ua = addr + s->dbc; - /* ??? Set ESA. */ - s->ia = s->dsp - 8; - break; - - case 1: /* IO or Read/Write instruction. */ - opcode = (insn >> 27) & 7; - if (opcode < 5) { - uint32_t id; - - if (insn & (1 << 25)) { - id = read_dword(s, s->dsa + sxt24(insn)); - } else { - id = addr; - } - id = (id >> 16) & 0xf; - if (insn & (1 << 26)) { - addr = s->dsp + sxt24(addr); - } - s->dnad = addr; - switch (opcode) { - case 0: /* Select */ - s->sstat0 |= LSI_SSTAT0_WOA; - s->scntl1 &= ~LSI_SCNTL1_IARB; - s->sdid = id; - if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) { - DPRINTF("Selected absent target %d\n", id); - lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO); - lsi_disconnect(s); - break; - } - DPRINTF("Selected target %d%s\n", - id, insn & (1 << 3) ? " ATN" : ""); - /* ??? Linux drivers compain when this is set. Maybe - it only applies in low-level mode (unimplemented). - lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ - s->current_dev = s->scsi_dev[id]; - s->scntl1 |= LSI_SCNTL1_CON; - if (insn & (1 << 3)) { - s->socl |= LSI_SOCL_ATN; - } - lsi_set_phase(s, PHASE_MO); - break; - case 1: /* Disconnect */ - DPRINTF("Wait Disconect\n"); - s->scntl1 &= ~LSI_SCNTL1_CON; - break; - case 2: /* Wait Reselect */ - DPRINTF("Wait Reselect\n"); - s->waiting = 1; - break; - case 3: /* Set */ - DPRINTF("Set%s%s%s%s\n", - insn & (1 << 3) ? " ATN" : "", - insn & (1 << 6) ? " ACK" : "", - insn & (1 << 9) ? " TM" : "", - insn & (1 << 10) ? " CC" : ""); - if (insn & (1 << 3)) { - s->socl |= LSI_SOCL_ATN; - lsi_set_phase(s, PHASE_MO); - } - if (insn & (1 << 9)) { - BADF("Target mode not implemented\n"); - exit(1); - } - if (insn & (1 << 10)) - s->carry = 1; - break; - case 4: /* Clear */ - DPRINTF("Clear%s%s%s%s\n", - insn & (1 << 3) ? " ATN" : "", - insn & (1 << 6) ? " ACK" : "", - insn & (1 << 9) ? " TM" : "", - insn & (1 << 10) ? " CC" : ""); - if (insn & (1 << 3)) { - s->socl &= ~LSI_SOCL_ATN; - } - if (insn & (1 << 10)) - s->carry = 0; - break; - } - } else { - uint8_t op0; - uint8_t op1; - uint8_t data8; - int reg; - int operator; -#ifdef DEBUG_LSI - static const char *opcode_names[3] = - {"Write", "Read", "Read-Modify-Write"}; - static const char *operator_names[8] = - {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"}; -#endif - - reg = ((insn >> 16) & 0x7f) | (insn & 0x80); - data8 = (insn >> 8) & 0xff; - opcode = (insn >> 27) & 7; - operator = (insn >> 24) & 7; - DPRINTF("%s reg 0x%x %s data8 %d%s\n", - opcode_names[opcode - 5], reg, - operator_names[operator], data8, - (insn & (1 << 23)) ? " SFBR" : ""); - op0 = op1 = 0; - switch (opcode) { - case 5: /* From SFBR */ - op0 = s->sfbr; - op1 = data8; - break; - case 6: /* To SFBR */ - if (operator) - op0 = lsi_reg_readb(s, reg); - op1 = data8; - break; - case 7: /* Read-modify-write */ - if (operator) - op0 = lsi_reg_readb(s, reg); - if (insn & (1 << 23)) { - op1 = s->sfbr; - } else { - op1 = data8; - } - break; - } - - switch (operator) { - case 0: /* move */ - op0 = op1; - break; - case 1: /* Shift left */ - op1 = op0 >> 7; - op0 = (op0 << 1) | s->carry; - s->carry = op1; - break; - case 2: /* OR */ - op0 |= op1; - break; - case 3: /* XOR */ - op0 |= op1; - break; - case 4: /* AND */ - op0 &= op1; - break; - case 5: /* SHR */ - op1 = op0 & 1; - op0 = (op0 >> 1) | (s->carry << 7); - break; - case 6: /* ADD */ - op0 += op1; - s->carry = op0 < op1; - break; - case 7: /* ADC */ - op0 += op1 + s->carry; - if (s->carry) - s->carry = op0 <= op1; - else - s->carry = op0 < op1; - break; - } - - switch (opcode) { - case 5: /* From SFBR */ - case 7: /* Read-modify-write */ - lsi_reg_writeb(s, reg, op0); - break; - case 6: /* To SFBR */ - s->sfbr = op0; - break; - } - } - break; - - case 2: /* Transfer Control. */ - { - int cond; - int jmp; - - if ((insn & 0x002e0000) == 0) { - DPRINTF("NOP\n"); - break; - } - if (s->sist1 & LSI_SIST1_STO) { - DPRINTF("Delayed select timeout\n"); - lsi_stop_script(s); - break; - } - cond = jmp = (insn & (1 << 19)) != 0; - if (cond == jmp && (insn & (1 << 21))) { - DPRINTF("Compare carry %d\n", s->carry == jmp); - cond = s->carry != 0; - } - if (cond == jmp && (insn & (1 << 17))) { - DPRINTF("Compare phase %d %c= %d\n", - (s->sstat1 & PHASE_MASK), - jmp ? '=' : '!', - ((insn >> 24) & 7)); - cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); - } - if (cond == jmp && (insn & (1 << 18))) { - uint8_t mask; - - mask = (~insn >> 8) & 0xff; - DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n", - s->sfbr, mask, jmp ? '=' : '!', insn & mask); - cond = (s->sfbr & mask) == (insn & mask); - } - if (cond == jmp) { - if (insn & (1 << 23)) { - /* Relative address. */ - addr = s->dsp + sxt24(addr); - } - switch ((insn >> 27) & 7) { - case 0: /* Jump */ - DPRINTF("Jump to 0x%08x\n", addr); - s->dsp = addr; - break; - case 1: /* Call */ - DPRINTF("Call 0x%08x\n", addr); - s->temp = s->dsp; - s->dsp = addr; - break; - case 2: /* Return */ - DPRINTF("Return to 0x%08x\n", s->temp); - s->dsp = s->temp; - break; - case 3: /* Interrupt */ - DPRINTF("Interrupt 0x%08x\n", s->dsps); - if ((insn & (1 << 20)) != 0) { - s->istat0 |= LSI_ISTAT0_INTF; - lsi_update_irq(s); - } else { - lsi_script_dma_interrupt(s, LSI_DSTAT_SIR); - } - break; - default: - DPRINTF("Illegal transfer control\n"); - lsi_script_dma_interrupt(s, LSI_DSTAT_IID); - break; - } - } else { - DPRINTF("Control condition failed\n"); - } - } - break; - - case 3: - if ((insn & (1 << 29)) == 0) { - /* Memory move. */ - uint32_t dest; - /* ??? The docs imply the destination address is loaded into - the TEMP register. However the Linux drivers rely on - the value being presrved. */ - dest = read_dword(s, s->dsp); - s->dsp += 4; - lsi_memcpy(s, dest, addr, insn & 0xffffff); - } else { - uint8_t data[7]; - int reg; - int n; - int i; - - if (insn & (1 << 28)) { - addr = s->dsa + sxt24(addr); - } - n = (insn & 7); - reg = (insn >> 16) & 0xff; - if (insn & (1 << 24)) { - DPRINTF("Load reg 0x%x size %d addr 0x%08x\n", reg, n, addr); - cpu_physical_memory_read(addr, data, n); - for (i = 0; i < n; i++) { - lsi_reg_writeb(s, reg + i, data[i]); - } - } else { - DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); - for (i = 0; i < n; i++) { - data[i] = lsi_reg_readb(s, reg + i); - } - cpu_physical_memory_write(addr, data, n); - } - } - } - /* ??? Need to avoid infinite loops. */ - if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) { - if (s->dcntl & LSI_DCNTL_SSM) { - lsi_script_dma_interrupt(s, LSI_DSTAT_SSI); - } else { - goto again; - } - } - DPRINTF("SCRIPTS execution stopped\n"); -} - -static uint8_t lsi_reg_readb(LSIState *s, int offset) -{ - uint8_t tmp; -#define CASE_GET_REG32(name, addr) \ - case addr: return s->name & 0xff; \ - case addr + 1: return (s->name >> 8) & 0xff; \ - case addr + 2: return (s->name >> 16) & 0xff; \ - case addr + 3: return (s->name >> 24) & 0xff; - -#ifdef DEBUG_LSI_REG - DPRINTF("Read reg %x\n", offset); -#endif - switch (offset) { - case 0x00: /* SCNTL0 */ - return s->scntl0; - case 0x01: /* SCNTL1 */ - return s->scntl1; - case 0x02: /* SCNTL2 */ - return s->scntl2; - case 0x03: /* SCNTL3 */ - return s->scntl3; - case 0x04: /* SCID */ - return s->scid; - case 0x05: /* SXFER */ - return s->sxfer; - case 0x06: /* SDID */ - return s->sdid; - case 0x07: /* GPREG0 */ - return 0x7f; - case 0xb: /* SBCL */ - /* ??? This is not correct. However it's (hopefully) only - used for diagnostics, so should be ok. */ - return 0; - case 0xc: /* DSTAT */ - tmp = s->dstat | 0x80; - if ((s->istat0 & LSI_ISTAT0_INTF) == 0) - s->dstat = 0; - lsi_update_irq(s); - return tmp; - case 0x0d: /* SSTAT0 */ - return s->sstat0; - case 0x0e: /* SSTAT1 */ - return s->sstat1; - case 0x0f: /* SSTAT2 */ - return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2; - CASE_GET_REG32(dsa, 0x10) - case 0x14: /* ISTAT0 */ - return s->istat0; - case 0x16: /* MBOX0 */ - return s->mbox0; - case 0x17: /* MBOX1 */ - return s->mbox1; - case 0x18: /* CTEST0 */ - return 0xff; - case 0x19: /* CTEST1 */ - return 0; - case 0x1a: /* CTEST2 */ - tmp = LSI_CTEST2_DACK | LSI_CTEST2_CM; - if (s->istat0 & LSI_ISTAT0_SIGP) { - s->istat0 &= ~LSI_ISTAT0_SIGP; - tmp |= LSI_CTEST2_SIGP; - } - return tmp; - case 0x1b: /* CTEST3 */ - return s->ctest3; - CASE_GET_REG32(temp, 0x1c) - case 0x20: /* DFIFO */ - return 0; - case 0x21: /* CTEST4 */ - return s->ctest4; - case 0x22: /* CTEST5 */ - return s->ctest5; - case 0x24: /* DBC[0:7] */ - return s->dbc & 0xff; - case 0x25: /* DBC[8:15] */ - return (s->dbc >> 8) & 0xff; - case 0x26: /* DBC[16->23] */ - return (s->dbc >> 16) & 0xff; - case 0x27: /* DCMD */ - return s->dcmd; - CASE_GET_REG32(dsp, 0x2c) - CASE_GET_REG32(dsps, 0x30) - CASE_GET_REG32(scratch[0], 0x34) - case 0x38: /* DMODE */ - return s->dmode; - case 0x39: /* DIEN */ - return s->dien; - case 0x3b: /* DCNTL */ - return s->dcntl; - case 0x40: /* SIEN0 */ - return s->sien0; - case 0x41: /* SIEN1 */ - return s->sien1; - case 0x42: /* SIST0 */ - tmp = s->sist0; - s->sist0 = 0; - lsi_update_irq(s); - return tmp; - case 0x43: /* SIST1 */ - tmp = s->sist1; - s->sist1 = 0; - lsi_update_irq(s); - return tmp; - case 0x47: /* GPCNTL0 */ - return 0x0f; - case 0x48: /* STIME0 */ - return s->stime0; - case 0x4a: /* RESPID0 */ - return s->respid0; - case 0x4b: /* RESPID1 */ - return s->respid1; - case 0x4d: /* STEST1 */ - return s->stest1; - case 0x4e: /* STEST2 */ - return s->stest2; - case 0x4f: /* STEST3 */ - return s->stest3; - case 0x52: /* STEST4 */ - return 0xe0; - case 0x56: /* CCNTL0 */ - return s->ccntl0; - case 0x57: /* CCNTL1 */ - return s->ccntl1; - case 0x58: case 0x59: /* SBDL */ - return 0; - CASE_GET_REG32(mmrs, 0xa0) - CASE_GET_REG32(mmws, 0xa4) - CASE_GET_REG32(sfs, 0xa8) - CASE_GET_REG32(drs, 0xac) - CASE_GET_REG32(sbms, 0xb0) - CASE_GET_REG32(dmbs, 0xb4) - CASE_GET_REG32(dnad64, 0xb8) - CASE_GET_REG32(pmjad1, 0xc0) - CASE_GET_REG32(pmjad2, 0xc4) - CASE_GET_REG32(rbc, 0xc8) - CASE_GET_REG32(ua, 0xcc) - CASE_GET_REG32(ia, 0xd4) - CASE_GET_REG32(sbc, 0xd8) - CASE_GET_REG32(csbc, 0xdc) - } - if (offset >= 0x5c && offset < 0xa0) { - int n; - int shift; - n = (offset - 0x58) >> 2; - shift = (offset & 3) * 8; - return (s->scratch[n] >> shift) & 0xff; - } - BADF("readb 0x%x\n", offset); - exit(1); -#undef CASE_GET_REG32 -} - -static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) -{ -#define CASE_SET_REG32(name, addr) \ - case addr : s->name &= 0xffffff00; s->name |= val; break; \ - case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \ - case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \ - case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break; - -#ifdef DEBUG_LSI_REG - DPRINTF("Write reg %x = %02x\n", offset, val); -#endif - switch (offset) { - case 0x00: /* SCNTL0 */ - s->scntl0 = val; - if (val & LSI_SCNTL0_START) { - BADF("Start sequence not implemented\n"); - } - break; - case 0x01: /* SCNTL1 */ - s->scntl1 = val & ~LSI_SCNTL1_SST; - if (val & LSI_SCNTL1_IARB) { - BADF("Immediate Arbritration not implemented\n"); - } - if (val & LSI_SCNTL1_RST) { - s->sstat0 |= LSI_SSTAT0_RST; - lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); - } else { - s->sstat0 &= ~LSI_SSTAT0_RST; - } - break; - case 0x02: /* SCNTL2 */ - val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS); - s->scntl3 = val; - break; - case 0x03: /* SCNTL3 */ - s->scntl3 = val; - break; - case 0x04: /* SCID */ - s->scid = val; - break; - case 0x05: /* SXFER */ - s->sxfer = val; - break; - case 0x07: /* GPREG0 */ - break; - case 0x0c: case 0x0d: case 0x0e: case 0x0f: - /* Linux writes to these readonly registers on startup. */ - return; - CASE_SET_REG32(dsa, 0x10) - case 0x14: /* ISTAT0 */ - s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0); - if (val & LSI_ISTAT0_ABRT) { - lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT); - } - if (val & LSI_ISTAT0_INTF) { - s->istat0 &= ~LSI_ISTAT0_INTF; - lsi_update_irq(s); - } - if (s->waiting && val & LSI_ISTAT0_SIGP) { - DPRINTF("Woken by SIGP\n"); - s->waiting = 0; - s->dsp = s->dnad; - lsi_execute_script(s); - } - if (val & LSI_ISTAT0_SRST) { - lsi_soft_reset(s); - } - case 0x16: /* MBOX0 */ - s->mbox0 = val; - case 0x17: /* MBOX1 */ - s->mbox1 = val; - case 0x1b: /* CTEST3 */ - s->ctest3 = val & 0x0f; - break; - CASE_SET_REG32(temp, 0x1c) - case 0x21: /* CTEST4 */ - if (val & 7) { - BADF("Unimplemented CTEST4-FBL 0x%x\n", val); - } - s->ctest4 = val; - break; - case 0x22: /* CTEST5 */ - if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) { - BADF("CTEST5 DMA increment not implemented\n"); - } - s->ctest5 = val; - break; - case 0x2c: /* DSPS[0:7] */ - s->dsp &= 0xffffff00; - s->dsp |= val; - break; - case 0x2d: /* DSPS[8:15] */ - s->dsp &= 0xffff00ff; - s->dsp |= val << 8; - break; - case 0x2e: /* DSPS[16:23] */ - s->dsp &= 0xff00ffff; - s->dsp |= val << 16; - break; - case 0x2f: /* DSPS[14:31] */ - s->dsp &= 0x00ffffff; - s->dsp |= val << 24; - if ((s->dmode & LSI_DMODE_MAN) == 0 - && (s->istat1 & LSI_ISTAT1_SRUN) == 0) - lsi_execute_script(s); - break; - CASE_SET_REG32(dsps, 0x30) - CASE_SET_REG32(scratch[0], 0x34) - case 0x38: /* DMODE */ - if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) { - BADF("IO mappings not implemented\n"); - } - s->dmode = val; - break; - case 0x39: /* DIEN */ - s->dien = val; - lsi_update_irq(s); - break; - case 0x3b: /* DCNTL */ - s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD); - if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0) - lsi_execute_script(s); - break; - case 0x40: /* SIEN0 */ - s->sien0 = val; - lsi_update_irq(s); - break; - case 0x41: /* SIEN1 */ - s->sien1 = val; - lsi_update_irq(s); - break; - case 0x47: /* GPCNTL0 */ - break; - case 0x48: /* STIME0 */ - s->stime0 = val; - break; - case 0x49: /* STIME1 */ - if (val & 0xf) { - DPRINTF("General purpose timer not implemented\n"); - /* ??? Raising the interrupt immediately seems to be sufficient - to keep the FreeBSD driver happy. */ - lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN); - } - break; - case 0x4a: /* RESPID0 */ - s->respid0 = val; - break; - case 0x4b: /* RESPID1 */ - s->respid1 = val; - break; - case 0x4d: /* STEST1 */ - s->stest1 = val; - break; - case 0x4e: /* STEST2 */ - if (val & 1) { - BADF("Low level mode not implemented\n"); - } - s->stest2 = val; - break; - case 0x4f: /* STEST3 */ - if (val & 0x41) { - BADF("SCSI FIFO test mode not implemented\n"); - } - s->stest3 = val; - break; - case 0x56: /* CCNTL0 */ - s->ccntl0 = val; - break; - case 0x57: /* CCNTL1 */ - s->ccntl1 = val; - break; - CASE_SET_REG32(mmrs, 0xa0) - CASE_SET_REG32(mmws, 0xa4) - CASE_SET_REG32(sfs, 0xa8) - CASE_SET_REG32(drs, 0xac) - CASE_SET_REG32(sbms, 0xb0) - CASE_SET_REG32(dmbs, 0xb4) - CASE_SET_REG32(dnad64, 0xb8) - CASE_SET_REG32(pmjad1, 0xc0) - CASE_SET_REG32(pmjad2, 0xc4) - CASE_SET_REG32(rbc, 0xc8) - CASE_SET_REG32(ua, 0xcc) - CASE_SET_REG32(ia, 0xd4) - CASE_SET_REG32(sbc, 0xd8) - CASE_SET_REG32(csbc, 0xdc) - default: - if (offset >= 0x5c && offset < 0xa0) { - int n; - int shift; - n = (offset - 0x58) >> 2; - shift = (offset & 3) * 8; - s->scratch[n] &= ~(0xff << shift); - s->scratch[n] |= (val & 0xff) << shift; - } else { - BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val); - } - } -#undef CASE_SET_REG32 -} - -static void lsi_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - LSIState *s = (LSIState *)opaque; - - lsi_reg_writeb(s, addr & 0xff, val); -} - -static void lsi_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - LSIState *s = (LSIState *)opaque; - - addr &= 0xff; - lsi_reg_writeb(s, addr, val & 0xff); - lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); -} - -static void lsi_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - LSIState *s = (LSIState *)opaque; - - addr &= 0xff; - lsi_reg_writeb(s, addr, val & 0xff); - lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); - lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff); - lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff); -} - -static uint32_t lsi_mmio_readb(void *opaque, target_phys_addr_t addr) -{ - LSIState *s = (LSIState *)opaque; - - return lsi_reg_readb(s, addr & 0xff); -} - -static uint32_t lsi_mmio_readw(void *opaque, target_phys_addr_t addr) -{ - LSIState *s = (LSIState *)opaque; - uint32_t val; - - addr &= 0xff; - val = lsi_reg_readb(s, addr); - val |= lsi_reg_readb(s, addr + 1) << 8; - return val; -} - -static uint32_t lsi_mmio_readl(void *opaque, target_phys_addr_t addr) -{ - LSIState *s = (LSIState *)opaque; - uint32_t val; - addr &= 0xff; - val = lsi_reg_readb(s, addr); - val |= lsi_reg_readb(s, addr + 1) << 8; - val |= lsi_reg_readb(s, addr + 2) << 16; - val |= lsi_reg_readb(s, addr + 3) << 24; - return val; -} - -static CPUReadMemoryFunc *lsi_mmio_readfn[3] = { - lsi_mmio_readb, - lsi_mmio_readw, - lsi_mmio_readl, -}; - -static CPUWriteMemoryFunc *lsi_mmio_writefn[3] = { - lsi_mmio_writeb, - lsi_mmio_writew, - lsi_mmio_writel, -}; - -static void lsi_ram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - LSIState *s = (LSIState *)opaque; - uint32_t newval; - int shift; - - addr &= 0x1fff; - newval = s->script_ram[addr >> 2]; - shift = (addr & 3) * 8; - newval &= ~(0xff << shift); - newval |= val << shift; - s->script_ram[addr >> 2] = newval; -} - -static void lsi_ram_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - LSIState *s = (LSIState *)opaque; - uint32_t newval; - - addr &= 0x1fff; - newval = s->script_ram[addr >> 2]; - if (addr & 2) { - newval = (newval & 0xffff) | (val << 16); - } else { - newval = (newval & 0xffff0000) | val; - } - s->script_ram[addr >> 2] = newval; -} - - -static void lsi_ram_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - LSIState *s = (LSIState *)opaque; - - addr &= 0x1fff; - s->script_ram[addr >> 2] = val; -} - -static uint32_t lsi_ram_readb(void *opaque, target_phys_addr_t addr) -{ - LSIState *s = (LSIState *)opaque; - uint32_t val; - - addr &= 0x1fff; - val = s->script_ram[addr >> 2]; - val >>= (addr & 3) * 8; - return val & 0xff; -} - -static uint32_t lsi_ram_readw(void *opaque, target_phys_addr_t addr) -{ - LSIState *s = (LSIState *)opaque; - uint32_t val; - - addr &= 0x1fff; - val = s->script_ram[addr >> 2]; - if (addr & 2) - val >>= 16; - return le16_to_cpu(val); -} - -static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr) -{ - LSIState *s = (LSIState *)opaque; - - addr &= 0x1fff; - return le32_to_cpu(s->script_ram[addr >> 2]); -} - -static CPUReadMemoryFunc *lsi_ram_readfn[3] = { - lsi_ram_readb, - lsi_ram_readw, - lsi_ram_readl, -}; - -static CPUWriteMemoryFunc *lsi_ram_writefn[3] = { - lsi_ram_writeb, - lsi_ram_writew, - lsi_ram_writel, -}; - -static uint32_t lsi_io_readb(void *opaque, uint32_t addr) -{ - LSIState *s = (LSIState *)opaque; - return lsi_reg_readb(s, addr & 0xff); -} - -static uint32_t lsi_io_readw(void *opaque, uint32_t addr) -{ - LSIState *s = (LSIState *)opaque; - uint32_t val; - addr &= 0xff; - val = lsi_reg_readb(s, addr); - val |= lsi_reg_readb(s, addr + 1) << 8; - return val; -} - -static uint32_t lsi_io_readl(void *opaque, uint32_t addr) -{ - LSIState *s = (LSIState *)opaque; - uint32_t val; - addr &= 0xff; - val = lsi_reg_readb(s, addr); - val |= lsi_reg_readb(s, addr + 1) << 8; - val |= lsi_reg_readb(s, addr + 2) << 16; - val |= lsi_reg_readb(s, addr + 3) << 24; - return val; -} - -static void lsi_io_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - LSIState *s = (LSIState *)opaque; - lsi_reg_writeb(s, addr & 0xff, val); -} - -static void lsi_io_writew(void *opaque, uint32_t addr, uint32_t val) -{ - LSIState *s = (LSIState *)opaque; - addr &= 0xff; - lsi_reg_writeb(s, addr, val & 0xff); - lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); -} - -static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val) -{ - LSIState *s = (LSIState *)opaque; - addr &= 0xff; - lsi_reg_writeb(s, addr, val & 0xff); - lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff); - lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff); - lsi_reg_writeb(s, addr + 2, (val >> 24) & 0xff); -} - -static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - LSIState *s = (LSIState *)pci_dev; - - DPRINTF("Mapping IO at %08x\n", addr); - - register_ioport_write(addr, 256, 1, lsi_io_writeb, s); - register_ioport_read(addr, 256, 1, lsi_io_readb, s); - register_ioport_write(addr, 256, 2, lsi_io_writew, s); - register_ioport_read(addr, 256, 2, lsi_io_readw, s); - register_ioport_write(addr, 256, 4, lsi_io_writel, s); - register_ioport_read(addr, 256, 4, lsi_io_readl, s); -} - -static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - LSIState *s = (LSIState *)pci_dev; - - DPRINTF("Mapping ram at %08x\n", addr); - s->script_ram_base = addr; - cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr); -} - -static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - LSIState *s = (LSIState *)pci_dev; - - DPRINTF("Mapping registers at %08x\n", addr); - cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr); -} - -void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id) -{ - LSIState *s = (LSIState *)opaque; - - if (id < 0) { - for (id = 0; id < LSI_MAX_DEVS; id++) { - if (s->scsi_dev[id] == NULL) - break; - } - } - if (id >= LSI_MAX_DEVS) { - BADF("Bad Device ID %d\n", id); - return; - } - if (s->scsi_dev[id]) { - DPRINTF("Destroying device %d\n", id); - scsi_disk_destroy(s->scsi_dev[id]); - } - DPRINTF("Attaching block device %d\n", id); - s->scsi_dev[id] = scsi_disk_init(bd, lsi_command_complete, s); -} - -void *lsi_scsi_init(PCIBus *bus, int devfn) -{ - LSIState *s; - - s = (LSIState *)pci_register_device(bus, "LSI53C895A SCSI HBA", - sizeof(*s), devfn, NULL, NULL); - if (s == NULL) { - fprintf(stderr, "lsi-scsi: Failed to register PCI device\n"); - return NULL; - } - - s->pci_dev.config[0x00] = 0x00; - s->pci_dev.config[0x01] = 0x10; - s->pci_dev.config[0x02] = 0x12; - s->pci_dev.config[0x03] = 0x00; - s->pci_dev.config[0x0b] = 0x01; - s->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */ - - s->mmio_io_addr = cpu_register_io_memory(0, lsi_mmio_readfn, - lsi_mmio_writefn, s); - s->ram_io_addr = cpu_register_io_memory(0, lsi_ram_readfn, - lsi_ram_writefn, s); - - pci_register_io_region((struct PCIDevice *)s, 0, 256, - PCI_ADDRESS_SPACE_IO, lsi_io_mapfunc); - pci_register_io_region((struct PCIDevice *)s, 1, 0x400, - PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc); - pci_register_io_region((struct PCIDevice *)s, 2, 0x2000, - PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc); - - lsi_soft_reset(s); - - return s; -} - diff --git a/hw/m48t59.c b/hw/m48t59.c deleted file mode 100644 index daa1c52..0000000 --- a/hw/m48t59.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms - * - * Copyright (c) 2003-2005 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -#include "m48t59.h" - -//#define DEBUG_NVRAM - -#if defined(DEBUG_NVRAM) -#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) -#else -#define NVRAM_PRINTF(fmt, args...) do { } while (0) -#endif - -/* - * The M48T08 and M48T59 chips are very similar. The newer '59 has - * alarm and a watchdog timer and related control registers. In the - * PPC platform there is also a nvram lock function. - */ -struct m48t59_t { - /* Model parameters */ - int type; // 8 = m48t08, 59 = m48t59 - /* Hardware parameters */ - int IRQ; - int mem_index; - uint32_t mem_base; - uint32_t io_base; - uint16_t size; - /* RTC management */ - time_t time_offset; - time_t stop_time; - /* Alarm & watchdog */ - time_t alarm; - struct QEMUTimer *alrm_timer; - struct QEMUTimer *wd_timer; - /* NVRAM storage */ - uint8_t lock; - uint16_t addr; - uint8_t *buffer; -}; - -/* Fake timer functions */ -/* Generic helpers for BCD */ -static inline uint8_t toBCD (uint8_t value) -{ - return (((value / 10) % 10) << 4) | (value % 10); -} - -static inline uint8_t fromBCD (uint8_t BCD) -{ - return ((BCD >> 4) * 10) + (BCD & 0x0F); -} - -/* RTC management helpers */ -static void get_time (m48t59_t *NVRAM, struct tm *tm) -{ - time_t t; - - t = time(NULL) + NVRAM->time_offset; -#ifdef _WIN32 - memcpy(tm,localtime(&t),sizeof(*tm)); -#else - localtime_r (&t, tm) ; -#endif -} - -static void set_time (m48t59_t *NVRAM, struct tm *tm) -{ - time_t now, new_time; - - new_time = mktime(tm); - now = time(NULL); - NVRAM->time_offset = new_time - now; -} - -/* Alarm management */ -static void alarm_cb (void *opaque) -{ - struct tm tm, tm_now; - uint64_t next_time; - m48t59_t *NVRAM = opaque; - - pic_set_irq(NVRAM->IRQ, 1); - if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && - (NVRAM->buffer[0x1FF4] & 0x80) == 0 && - (NVRAM->buffer[0x1FF3] & 0x80) == 0 && - (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once a month */ - get_time(NVRAM, &tm_now); - memcpy(&tm, &tm_now, sizeof(struct tm)); - tm.tm_mon++; - if (tm.tm_mon == 13) { - tm.tm_mon = 1; - tm.tm_year++; - } - next_time = mktime(&tm); - } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && - (NVRAM->buffer[0x1FF4] & 0x80) == 0 && - (NVRAM->buffer[0x1FF3] & 0x80) == 0 && - (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once a day */ - next_time = 24 * 60 * 60 + mktime(&tm_now); - } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && - (NVRAM->buffer[0x1FF4] & 0x80) != 0 && - (NVRAM->buffer[0x1FF3] & 0x80) == 0 && - (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once an hour */ - next_time = 60 * 60 + mktime(&tm_now); - } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 && - (NVRAM->buffer[0x1FF4] & 0x80) != 0 && - (NVRAM->buffer[0x1FF3] & 0x80) != 0 && - (NVRAM->buffer[0x1FF2] & 0x80) == 0) { - /* Repeat once a minute */ - next_time = 60 + mktime(&tm_now); - } else { - /* Repeat once a second */ - next_time = 1 + mktime(&tm_now); - } - qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000); - pic_set_irq(NVRAM->IRQ, 0); -} - - -static void get_alarm (m48t59_t *NVRAM, struct tm *tm) -{ -#ifdef _WIN32 - memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm)); -#else - localtime_r (&NVRAM->alarm, tm); -#endif -} - -static void set_alarm (m48t59_t *NVRAM, struct tm *tm) -{ - NVRAM->alarm = mktime(tm); - if (NVRAM->alrm_timer != NULL) { - qemu_del_timer(NVRAM->alrm_timer); - NVRAM->alrm_timer = NULL; - } - if (NVRAM->alarm - time(NULL) > 0) - qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); -} - -/* Watchdog management */ -static void watchdog_cb (void *opaque) -{ - m48t59_t *NVRAM = opaque; - - NVRAM->buffer[0x1FF0] |= 0x80; - if (NVRAM->buffer[0x1FF7] & 0x80) { - NVRAM->buffer[0x1FF7] = 0x00; - NVRAM->buffer[0x1FFC] &= ~0x40; - /* May it be a hw CPU Reset instead ? */ - qemu_system_reset_request(); - } else { - pic_set_irq(NVRAM->IRQ, 1); - pic_set_irq(NVRAM->IRQ, 0); - } -} - -static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value) -{ - uint64_t interval; /* in 1/16 seconds */ - - if (NVRAM->wd_timer != NULL) { - qemu_del_timer(NVRAM->wd_timer); - NVRAM->wd_timer = NULL; - } - NVRAM->buffer[0x1FF0] &= ~0x80; - if (value != 0) { - interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F); - qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + - ((interval * 1000) >> 4)); - } -} - -/* Direct access to NVRAM */ -void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val) -{ - struct tm tm; - int tmp; - - if (addr > 0x1FF8 && addr < 0x2000) - NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val); - if (NVRAM->type == 8 && - (addr >= 0x1ff0 && addr <= 0x1ff7)) - goto do_write; - switch (addr) { - case 0x1FF0: - /* flags register : read-only */ - break; - case 0x1FF1: - /* unused */ - break; - case 0x1FF2: - /* alarm seconds */ - tmp = fromBCD(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_alarm(NVRAM, &tm); - tm.tm_sec = tmp; - NVRAM->buffer[0x1FF2] = val; - set_alarm(NVRAM, &tm); - } - break; - case 0x1FF3: - /* alarm minutes */ - tmp = fromBCD(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_alarm(NVRAM, &tm); - tm.tm_min = tmp; - NVRAM->buffer[0x1FF3] = val; - set_alarm(NVRAM, &tm); - } - break; - case 0x1FF4: - /* alarm hours */ - tmp = fromBCD(val & 0x3F); - if (tmp >= 0 && tmp <= 23) { - get_alarm(NVRAM, &tm); - tm.tm_hour = tmp; - NVRAM->buffer[0x1FF4] = val; - set_alarm(NVRAM, &tm); - } - break; - case 0x1FF5: - /* alarm date */ - tmp = fromBCD(val & 0x1F); - if (tmp != 0) { - get_alarm(NVRAM, &tm); - tm.tm_mday = tmp; - NVRAM->buffer[0x1FF5] = val; - set_alarm(NVRAM, &tm); - } - break; - case 0x1FF6: - /* interrupts */ - NVRAM->buffer[0x1FF6] = val; - break; - case 0x1FF7: - /* watchdog */ - NVRAM->buffer[0x1FF7] = val; - set_up_watchdog(NVRAM, val); - break; - case 0x1FF8: - /* control */ - NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90; - break; - case 0x1FF9: - /* seconds (BCD) */ - tmp = fromBCD(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_time(NVRAM, &tm); - tm.tm_sec = tmp; - set_time(NVRAM, &tm); - } - if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) { - if (val & 0x80) { - NVRAM->stop_time = time(NULL); - } else { - NVRAM->time_offset += NVRAM->stop_time - time(NULL); - NVRAM->stop_time = 0; - } - } - NVRAM->buffer[0x1FF9] = val & 0x80; - break; - case 0x1FFA: - /* minutes (BCD) */ - tmp = fromBCD(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_time(NVRAM, &tm); - tm.tm_min = tmp; - set_time(NVRAM, &tm); - } - break; - case 0x1FFB: - /* hours (BCD) */ - tmp = fromBCD(val & 0x3F); - if (tmp >= 0 && tmp <= 23) { - get_time(NVRAM, &tm); - tm.tm_hour = tmp; - set_time(NVRAM, &tm); - } - break; - case 0x1FFC: - /* day of the week / century */ - tmp = fromBCD(val & 0x07); - get_time(NVRAM, &tm); - tm.tm_wday = tmp; - set_time(NVRAM, &tm); - NVRAM->buffer[0x1FFC] = val & 0x40; - break; - case 0x1FFD: - /* date */ - tmp = fromBCD(val & 0x1F); - if (tmp != 0) { - get_time(NVRAM, &tm); - tm.tm_mday = tmp; - set_time(NVRAM, &tm); - } - break; - case 0x1FFE: - /* month */ - tmp = fromBCD(val & 0x1F); - if (tmp >= 1 && tmp <= 12) { - get_time(NVRAM, &tm); - tm.tm_mon = tmp - 1; - set_time(NVRAM, &tm); - } - break; - case 0x1FFF: - /* year */ - tmp = fromBCD(val); - if (tmp >= 0 && tmp <= 99) { - get_time(NVRAM, &tm); - if (NVRAM->type == 8) - tm.tm_year = fromBCD(val) + 68; // Base year is 1968 - else - tm.tm_year = fromBCD(val); - set_time(NVRAM, &tm); - } - break; - default: - /* Check lock registers state */ - if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1)) - break; - if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2)) - break; - do_write: - if (addr < NVRAM->size) { - NVRAM->buffer[addr] = val & 0xFF; - } - break; - } -} - -uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr) -{ - struct tm tm; - uint32_t retval = 0xFF; - - if (NVRAM->type == 8 && - (addr >= 0x1ff0 && addr <= 0x1ff7)) - goto do_read; - switch (addr) { - case 0x1FF0: - /* flags register */ - goto do_read; - case 0x1FF1: - /* unused */ - retval = 0; - break; - case 0x1FF2: - /* alarm seconds */ - goto do_read; - case 0x1FF3: - /* alarm minutes */ - goto do_read; - case 0x1FF4: - /* alarm hours */ - goto do_read; - case 0x1FF5: - /* alarm date */ - goto do_read; - case 0x1FF6: - /* interrupts */ - goto do_read; - case 0x1FF7: - /* A read resets the watchdog */ - set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]); - goto do_read; - case 0x1FF8: - /* control */ - goto do_read; - case 0x1FF9: - /* seconds (BCD) */ - get_time(NVRAM, &tm); - retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec); - break; - case 0x1FFA: - /* minutes (BCD) */ - get_time(NVRAM, &tm); - retval = toBCD(tm.tm_min); - break; - case 0x1FFB: - /* hours (BCD) */ - get_time(NVRAM, &tm); - retval = toBCD(tm.tm_hour); - break; - case 0x1FFC: - /* day of the week / century */ - get_time(NVRAM, &tm); - retval = NVRAM->buffer[0x1FFC] | tm.tm_wday; - break; - case 0x1FFD: - /* date */ - get_time(NVRAM, &tm); - retval = toBCD(tm.tm_mday); - break; - case 0x1FFE: - /* month */ - get_time(NVRAM, &tm); - retval = toBCD(tm.tm_mon + 1); - break; - case 0x1FFF: - /* year */ - get_time(NVRAM, &tm); - if (NVRAM->type == 8) - retval = toBCD(tm.tm_year - 68); // Base year is 1968 - else - retval = toBCD(tm.tm_year); - break; - default: - /* Check lock registers state */ - if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1)) - break; - if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2)) - break; - do_read: - if (addr < NVRAM->size) { - retval = NVRAM->buffer[addr]; - } - break; - } - if (addr > 0x1FF9 && addr < 0x2000) - NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval); - - return retval; -} - -void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr) -{ - NVRAM->addr = addr; -} - -void m48t59_toggle_lock (m48t59_t *NVRAM, int lock) -{ - NVRAM->lock ^= 1 << lock; -} - -/* IO access to NVRAM */ -static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) -{ - m48t59_t *NVRAM = opaque; - - addr -= NVRAM->io_base; - NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val); - switch (addr) { - case 0: - NVRAM->addr &= ~0x00FF; - NVRAM->addr |= val; - break; - case 1: - NVRAM->addr &= ~0xFF00; - NVRAM->addr |= val << 8; - break; - case 3: - m48t59_write(NVRAM, val, NVRAM->addr); - NVRAM->addr = 0x0000; - break; - default: - break; - } -} - -static uint32_t NVRAM_readb (void *opaque, uint32_t addr) -{ - m48t59_t *NVRAM = opaque; - uint32_t retval; - - addr -= NVRAM->io_base; - switch (addr) { - case 3: - retval = m48t59_read(NVRAM, NVRAM->addr); - break; - default: - retval = -1; - break; - } - NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval); - - return retval; -} - -static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - m48t59_t *NVRAM = opaque; - - addr -= NVRAM->mem_base; - m48t59_write(NVRAM, addr, value & 0xff); -} - -static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - m48t59_t *NVRAM = opaque; - - addr -= NVRAM->mem_base; - m48t59_write(NVRAM, addr, (value >> 8) & 0xff); - m48t59_write(NVRAM, addr + 1, value & 0xff); -} - -static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - m48t59_t *NVRAM = opaque; - - addr -= NVRAM->mem_base; - m48t59_write(NVRAM, addr, (value >> 24) & 0xff); - m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff); - m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff); - m48t59_write(NVRAM, addr + 3, value & 0xff); -} - -static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) -{ - m48t59_t *NVRAM = opaque; - uint32_t retval; - - addr -= NVRAM->mem_base; - retval = m48t59_read(NVRAM, addr); - return retval; -} - -static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) -{ - m48t59_t *NVRAM = opaque; - uint32_t retval; - - addr -= NVRAM->mem_base; - retval = m48t59_read(NVRAM, addr) << 8; - retval |= m48t59_read(NVRAM, addr + 1); - return retval; -} - -static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) -{ - m48t59_t *NVRAM = opaque; - uint32_t retval; - - addr -= NVRAM->mem_base; - retval = m48t59_read(NVRAM, addr) << 24; - retval |= m48t59_read(NVRAM, addr + 1) << 16; - retval |= m48t59_read(NVRAM, addr + 2) << 8; - retval |= m48t59_read(NVRAM, addr + 3); - return retval; -} - -static CPUWriteMemoryFunc *nvram_write[] = { - &nvram_writeb, - &nvram_writew, - &nvram_writel, -}; - -static CPUReadMemoryFunc *nvram_read[] = { - &nvram_readb, - &nvram_readw, - &nvram_readl, -}; - -/* Initialisation routine */ -m48t59_t *m48t59_init (int IRQ, target_ulong mem_base, - uint32_t io_base, uint16_t size, - int type) -{ - m48t59_t *s; - - s = qemu_mallocz(sizeof(m48t59_t)); - if (!s) - return NULL; - s->buffer = qemu_mallocz(size); - if (!s->buffer) { - qemu_free(s); - return NULL; - } - s->IRQ = IRQ; - s->size = size; - s->mem_base = mem_base; - s->io_base = io_base; - s->addr = 0; - s->type = type; - if (io_base != 0) { - register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s); - register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); - } - if (mem_base != 0) { - s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); - cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); - } - if (type == 59) { - s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s); - s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); - } - s->lock = 0; - - return s; -} diff --git a/hw/m48t59.h b/hw/m48t59.h deleted file mode 100644 index af22dc1..0000000 --- a/hw/m48t59.h +++ /dev/null @@ -1,13 +0,0 @@ -#if !defined (__M48T59_H__) -#define __M48T59_H__ - -typedef struct m48t59_t m48t59_t; - -void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val); -uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr); -void m48t59_toggle_lock (m48t59_t *NVRAM, int lock); -m48t59_t *m48t59_init (int IRQ, target_ulong mem_base, - uint32_t io_base, uint16_t size, - int type); - -#endif /* !defined (__M48T59_H__) */ diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c deleted file mode 100644 index 9d4cbed..0000000 --- a/hw/mc146818rtc.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * QEMU MC146818 RTC emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -//#define DEBUG_CMOS - -#define RTC_SECONDS 0 -#define RTC_SECONDS_ALARM 1 -#define RTC_MINUTES 2 -#define RTC_MINUTES_ALARM 3 -#define RTC_HOURS 4 -#define RTC_HOURS_ALARM 5 -#define RTC_ALARM_DONT_CARE 0xC0 - -#define RTC_DAY_OF_WEEK 6 -#define RTC_DAY_OF_MONTH 7 -#define RTC_MONTH 8 -#define RTC_YEAR 9 - -#define RTC_REG_A 10 -#define RTC_REG_B 11 -#define RTC_REG_C 12 -#define RTC_REG_D 13 - -#define REG_A_UIP 0x80 - -#define REG_B_SET 0x80 -#define REG_B_PIE 0x40 -#define REG_B_AIE 0x20 -#define REG_B_UIE 0x10 - -struct RTCState { - uint8_t cmos_data[128]; - uint8_t cmos_index; - struct tm current_tm; - int irq; - /* periodic timer */ - QEMUTimer *periodic_timer; - int64_t next_periodic_time; - /* second update */ - int64_t next_second_time; - QEMUTimer *second_timer; - QEMUTimer *second_timer2; -}; - -static void rtc_set_time(RTCState *s); -static void rtc_copy_date(RTCState *s); - -static void rtc_timer_update(RTCState *s, int64_t current_time) -{ - int period_code, period; - int64_t cur_clock, next_irq_clock; - - period_code = s->cmos_data[RTC_REG_A] & 0x0f; - if (period_code != 0 && - (s->cmos_data[RTC_REG_B] & REG_B_PIE)) { - if (period_code <= 2) - period_code += 7; - /* period in 32 Khz cycles */ - period = 1 << (period_code - 1); - /* compute 32 khz clock */ - cur_clock = muldiv64(current_time, 32768, ticks_per_sec); - next_irq_clock = (cur_clock & ~(period - 1)) + period; - s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1; - qemu_mod_timer(s->periodic_timer, s->next_periodic_time); - } else { - qemu_del_timer(s->periodic_timer); - } -} - -static void rtc_periodic_timer(void *opaque) -{ - RTCState *s = opaque; - - rtc_timer_update(s, s->next_periodic_time); - s->cmos_data[RTC_REG_C] |= 0xc0; - pic_set_irq(s->irq, 1); -} - -static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data) -{ - RTCState *s = opaque; - - if ((addr & 1) == 0) { - s->cmos_index = data & 0x7f; - } else { -#ifdef DEBUG_CMOS - printf("cmos: write index=0x%02x val=0x%02x\n", - s->cmos_index, data); -#endif - switch(s->cmos_index) { - case RTC_SECONDS_ALARM: - case RTC_MINUTES_ALARM: - case RTC_HOURS_ALARM: - /* XXX: not supported */ - s->cmos_data[s->cmos_index] = data; - break; - case RTC_SECONDS: - case RTC_MINUTES: - case RTC_HOURS: - case RTC_DAY_OF_WEEK: - case RTC_DAY_OF_MONTH: - case RTC_MONTH: - case RTC_YEAR: - s->cmos_data[s->cmos_index] = data; - /* if in set mode, do not update the time */ - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { - rtc_set_time(s); - } - break; - case RTC_REG_A: - /* UIP bit is read only */ - s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) | - (s->cmos_data[RTC_REG_A] & REG_A_UIP); - rtc_timer_update(s, qemu_get_clock(vm_clock)); - break; - case RTC_REG_B: - if (data & REG_B_SET) { - /* set mode: reset UIP mode */ - s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - data &= ~REG_B_UIE; - } else { - /* if disabling set mode, update the time */ - if (s->cmos_data[RTC_REG_B] & REG_B_SET) { - rtc_set_time(s); - } - } - s->cmos_data[RTC_REG_B] = data; - rtc_timer_update(s, qemu_get_clock(vm_clock)); - break; - case RTC_REG_C: - case RTC_REG_D: - /* cannot write to them */ - break; - default: - s->cmos_data[s->cmos_index] = data; - break; - } - } -} - -static inline int to_bcd(RTCState *s, int a) -{ - if (s->cmos_data[RTC_REG_B] & 0x04) { - return a; - } else { - return ((a / 10) << 4) | (a % 10); - } -} - -static inline int from_bcd(RTCState *s, int a) -{ - if (s->cmos_data[RTC_REG_B] & 0x04) { - return a; - } else { - return ((a >> 4) * 10) + (a & 0x0f); - } -} - -static void rtc_set_time(RTCState *s) -{ - struct tm *tm = &s->current_tm; - - tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]); - tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]); - tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f); - if (!(s->cmos_data[RTC_REG_B] & 0x02) && - (s->cmos_data[RTC_HOURS] & 0x80)) { - tm->tm_hour += 12; - } - tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]); - tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]); - tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1; - tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100; -} - -static void rtc_copy_date(RTCState *s) -{ - const struct tm *tm = &s->current_tm; - - s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec); - s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min); - if (s->cmos_data[RTC_REG_B] & 0x02) { - /* 24 hour format */ - s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour); - } else { - /* 12 hour format */ - s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12); - if (tm->tm_hour >= 12) - s->cmos_data[RTC_HOURS] |= 0x80; - } - s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday); - s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday); - s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1); - s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100); -} - -/* month is between 0 and 11. */ -static int get_days_in_month(int month, int year) -{ - static const int days_tab[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - int d; - if ((unsigned )month >= 12) - return 31; - d = days_tab[month]; - if (month == 1) { - if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) - d++; - } - return d; -} - -/* update 'tm' to the next second */ -static void rtc_next_second(struct tm *tm) -{ - int days_in_month; - - tm->tm_sec++; - if ((unsigned)tm->tm_sec >= 60) { - tm->tm_sec = 0; - tm->tm_min++; - if ((unsigned)tm->tm_min >= 60) { - tm->tm_min = 0; - tm->tm_hour++; - if ((unsigned)tm->tm_hour >= 24) { - tm->tm_hour = 0; - /* next day */ - tm->tm_wday++; - if ((unsigned)tm->tm_wday >= 7) - tm->tm_wday = 0; - days_in_month = get_days_in_month(tm->tm_mon, - tm->tm_year + 1900); - tm->tm_mday++; - if (tm->tm_mday < 1) { - tm->tm_mday = 1; - } else if (tm->tm_mday > days_in_month) { - tm->tm_mday = 1; - tm->tm_mon++; - if (tm->tm_mon >= 12) { - tm->tm_mon = 0; - tm->tm_year++; - } - } - } - } - } -} - - -static void rtc_update_second(void *opaque) -{ - RTCState *s = opaque; - int64_t delay; - - /* if the oscillator is not in normal operation, we do not update */ - if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) { - s->next_second_time += ticks_per_sec; - qemu_mod_timer(s->second_timer, s->next_second_time); - } else { - rtc_next_second(&s->current_tm); - - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { - /* update in progress bit */ - s->cmos_data[RTC_REG_A] |= REG_A_UIP; - } - /* should be 244 us = 8 / 32768 seconds, but currently the - timers do not have the necessary resolution. */ - delay = (ticks_per_sec * 1) / 100; - if (delay < 1) - delay = 1; - qemu_mod_timer(s->second_timer2, - s->next_second_time + delay); - } -} - -static void rtc_update_second2(void *opaque) -{ - RTCState *s = opaque; - - if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) { - rtc_copy_date(s); - } - - /* check alarm */ - if (s->cmos_data[RTC_REG_B] & REG_B_AIE) { - if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 || - s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) && - ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 || - s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) && - ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 || - s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) { - - s->cmos_data[RTC_REG_C] |= 0xa0; - pic_set_irq(s->irq, 1); - } - } - - /* update ended interrupt */ - if (s->cmos_data[RTC_REG_B] & REG_B_UIE) { - s->cmos_data[RTC_REG_C] |= 0x90; - pic_set_irq(s->irq, 1); - } - - /* clear update in progress bit */ - s->cmos_data[RTC_REG_A] &= ~REG_A_UIP; - - s->next_second_time += ticks_per_sec; - qemu_mod_timer(s->second_timer, s->next_second_time); -} - -static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) -{ - RTCState *s = opaque; - int ret; - if ((addr & 1) == 0) { - return 0xff; - } else { - switch(s->cmos_index) { - case RTC_SECONDS: - case RTC_MINUTES: - case RTC_HOURS: - case RTC_DAY_OF_WEEK: - case RTC_DAY_OF_MONTH: - case RTC_MONTH: - case RTC_YEAR: - ret = s->cmos_data[s->cmos_index]; - break; - case RTC_REG_A: - ret = s->cmos_data[s->cmos_index]; - break; - case RTC_REG_C: - ret = s->cmos_data[s->cmos_index]; - pic_set_irq(s->irq, 0); - s->cmos_data[RTC_REG_C] = 0x00; - break; - default: - ret = s->cmos_data[s->cmos_index]; - break; - } -#ifdef DEBUG_CMOS - printf("cmos: read index=0x%02x val=0x%02x\n", - s->cmos_index, ret); -#endif - return ret; - } -} - -void rtc_set_memory(RTCState *s, int addr, int val) -{ - if (addr >= 0 && addr <= 127) - s->cmos_data[addr] = val; -} - -void rtc_set_date(RTCState *s, const struct tm *tm) -{ - s->current_tm = *tm; - rtc_copy_date(s); -} - -static void rtc_save(QEMUFile *f, void *opaque) -{ - RTCState *s = opaque; - - qemu_put_buffer(f, s->cmos_data, 128); - qemu_put_8s(f, &s->cmos_index); - - qemu_put_be32s(f, &s->current_tm.tm_sec); - qemu_put_be32s(f, &s->current_tm.tm_min); - qemu_put_be32s(f, &s->current_tm.tm_hour); - qemu_put_be32s(f, &s->current_tm.tm_wday); - qemu_put_be32s(f, &s->current_tm.tm_mday); - qemu_put_be32s(f, &s->current_tm.tm_mon); - qemu_put_be32s(f, &s->current_tm.tm_year); - - qemu_put_timer(f, s->periodic_timer); - qemu_put_be64s(f, &s->next_periodic_time); - - qemu_put_be64s(f, &s->next_second_time); - qemu_put_timer(f, s->second_timer); - qemu_put_timer(f, s->second_timer2); -} - -static int rtc_load(QEMUFile *f, void *opaque, int version_id) -{ - RTCState *s = opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_buffer(f, s->cmos_data, 128); - qemu_get_8s(f, &s->cmos_index); - - qemu_get_be32s(f, &s->current_tm.tm_sec); - qemu_get_be32s(f, &s->current_tm.tm_min); - qemu_get_be32s(f, &s->current_tm.tm_hour); - qemu_get_be32s(f, &s->current_tm.tm_wday); - qemu_get_be32s(f, &s->current_tm.tm_mday); - qemu_get_be32s(f, &s->current_tm.tm_mon); - qemu_get_be32s(f, &s->current_tm.tm_year); - - qemu_get_timer(f, s->periodic_timer); - qemu_get_be64s(f, &s->next_periodic_time); - - qemu_get_be64s(f, &s->next_second_time); - qemu_get_timer(f, s->second_timer); - qemu_get_timer(f, s->second_timer2); - return 0; -} - -RTCState *rtc_init(int base, int irq) -{ - RTCState *s; - - s = qemu_mallocz(sizeof(RTCState)); - if (!s) - return NULL; - - s->irq = irq; - s->cmos_data[RTC_REG_A] = 0x26; - s->cmos_data[RTC_REG_B] = 0x02; - s->cmos_data[RTC_REG_C] = 0x00; - s->cmos_data[RTC_REG_D] = 0x80; - - s->periodic_timer = qemu_new_timer(vm_clock, - rtc_periodic_timer, s); - s->second_timer = qemu_new_timer(vm_clock, - rtc_update_second, s); - s->second_timer2 = qemu_new_timer(vm_clock, - rtc_update_second2, s); - - s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100; - qemu_mod_timer(s->second_timer2, s->next_second_time); - - register_ioport_write(base, 2, 1, cmos_ioport_write, s); - register_ioport_read(base, 2, 1, cmos_ioport_read, s); - - register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s); - return s; -} - diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c deleted file mode 100644 index 22d742a..0000000 --- a/hw/mips_r4k.c +++ /dev/null @@ -1,291 +0,0 @@ -#include "vl.h" - -#define BIOS_FILENAME "mips_bios.bin" -//#define BIOS_FILENAME "system.bin" -#define KERNEL_LOAD_ADDR 0x80010000 -#define INITRD_LOAD_ADDR 0x80800000 - -#define VIRT_TO_PHYS_ADDEND (-0x80000000LL) - -extern FILE *logfile; - -static PITState *pit; - -static void pic_irq_request(void *opaque, int level) -{ - CPUState *env = first_cpu; - if (level) { - env->CP0_Cause |= 0x00000400; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } else { - env->CP0_Cause &= ~0x00000400; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); - } -} - -void cpu_mips_irqctrl_init (void) -{ -} - -/* XXX: do not use a global */ -uint32_t cpu_mips_get_random (CPUState *env) -{ - static uint32_t seed = 0; - uint32_t idx; - seed = seed * 314159 + 1; - idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired; - return idx; -} - -/* MIPS R4K timer */ -uint32_t cpu_mips_get_count (CPUState *env) -{ - return env->CP0_Count + - (uint32_t)muldiv64(qemu_get_clock(vm_clock), - 100 * 1000 * 1000, ticks_per_sec); -} - -static void cpu_mips_update_count (CPUState *env, uint32_t count, - uint32_t compare) -{ - uint64_t now, next; - uint32_t tmp; - - tmp = count; - if (count == compare) - tmp++; - now = qemu_get_clock(vm_clock); - next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000); - if (next == now) - next++; -#if 0 - if (logfile) { - fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n", - __func__, now, count, compare, next - now); - } -#endif - /* Store new count and compare registers */ - env->CP0_Compare = compare; - env->CP0_Count = - count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec); - /* Adjust timer */ - qemu_mod_timer(env->timer, next); -} - -void cpu_mips_store_count (CPUState *env, uint32_t value) -{ - cpu_mips_update_count(env, value, env->CP0_Compare); -} - -void cpu_mips_store_compare (CPUState *env, uint32_t value) -{ - cpu_mips_update_count(env, cpu_mips_get_count(env), value); - env->CP0_Cause &= ~0x00008000; - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); -} - -static void mips_timer_cb (void *opaque) -{ - CPUState *env; - - env = opaque; -#if 0 - if (logfile) { - fprintf(logfile, "%s\n", __func__); - } -#endif - cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare); - env->CP0_Cause |= 0x00008000; - cpu_interrupt(env, CPU_INTERRUPT_HARD); -} - -void cpu_mips_clock_init (CPUState *env) -{ - env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env); - env->CP0_Compare = 0; - cpu_mips_update_count(env, 1, 0); -} - - -static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); -#endif - cpu_outb(NULL, addr & 0xffff, value); -} - -static uint32_t io_readb (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inb(NULL, addr & 0xffff); -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); -#endif - return ret; -} - -static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); -#endif -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap16(value); -#endif - cpu_outw(NULL, addr & 0xffff, value); -} - -static uint32_t io_readw (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inw(NULL, addr & 0xffff); -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap16(ret); -#endif -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); -#endif - return ret; -} - -static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value); -#endif -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap32(value); -#endif - cpu_outl(NULL, addr & 0xffff, value); -} - -static uint32_t io_readl (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inl(NULL, addr & 0xffff); - -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap32(ret); -#endif -#if 0 - if (logfile) - fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret); -#endif - return ret; -} - -CPUWriteMemoryFunc *io_write[] = { - &io_writeb, - &io_writew, - &io_writel, -}; - -CPUReadMemoryFunc *io_read[] = { - &io_readb, - &io_readw, - &io_readl, -}; - -void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) -{ - char buf[1024]; - int64_t entry = 0; - unsigned long bios_offset; - int io_memory; - int ret; - CPUState *env; - long kernel_size; - - env = cpu_init(); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - - /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); - - /* Try to load a BIOS image. If this fails, we continue regardless, - but initialize the hardware ourselves. When a kernel gets - preloaded we also initialize the hardware, since the BIOS wasn't - run. */ - bios_offset = ram_size + vga_ram_size; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - ret = load_image(buf, phys_ram_base + bios_offset); - if (ret == BIOS_SIZE) { - cpu_register_physical_memory((uint32_t)(0x1fc00000), - BIOS_SIZE, bios_offset | IO_MEM_ROM); - } else { - /* not fatal */ - fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n", - buf); - } - - kernel_size = 0; - if (kernel_filename) { - kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry); - if (kernel_size >= 0) - env->PC = entry; - else { - kernel_size = load_image(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - env->PC = KERNEL_LOAD_ADDR; - } - - /* load initrd */ - if (initrd_filename) { - if (load_image(initrd_filename, - phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND) - == (target_ulong) -1) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } - - /* Store command line. */ - strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline); - /* FIXME: little endian support */ - *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678); - *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size); - } - - /* Init internal devices */ - cpu_mips_clock_init(env); - cpu_mips_irqctrl_init(); - - /* Register 64 KB of ISA IO space at 0x14000000 */ - io_memory = cpu_register_io_memory(0, io_read, io_write, NULL); - cpu_register_physical_memory(0x14000000, 0x00010000, io_memory); - isa_mem_base = 0x10000000; - - isa_pic = pic_init(pic_irq_request, env); - pit = pit_init(0x40, 0); - serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); - vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0, 0); - - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "ne2k_isa") == 0) { - isa_ne2000_init(0x300, 9, &nd_table[0]); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } - } -} - -QEMUMachine mips_machine = { - "mips", - "mips r4k platform", - mips_r4k_init, -}; diff --git a/hw/mmc.h b/hw/mmc.h new file mode 100644 index 0000000..3ae3ea9 --- /dev/null +++ b/hw/mmc.h @@ -0,0 +1,214 @@ +/* + * Header for MultiMediaCard (MMC) + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Based strongly on code by: + * + * Author: Yong-iL Joh <tolkien@mizi.com> + * Date : $Date: 2002/06/18 12:37:30 $ + * + * Author: Andrew Christian + * 15 May 2002 + */ + +#ifndef MMC_MMC_H +#define MMC_MMC_H + +/* Standard MMC commands (4.1) type argument response */ + /* class 1 */ +#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ +#define MMC_ALL_SEND_CID 2 /* bcr R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ +#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ +#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ +#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ +#define MMC_STOP_TRANSMISSION 12 /* ac R1b */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ + + /* class 2 */ +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ + + /* class 3 */ +#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ + + /* class 4 */ +#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ +#define MMC_PROGRAM_CID 26 /* adtc R1 */ +#define MMC_PROGRAM_CSD 27 /* adtc R1 */ + + /* class 6 */ +#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + + /* class 5 */ +#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ +#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ +#define MMC_ERASE 38 /* ac R1b */ + + /* class 9 */ +#define MMC_FAST_IO 39 /* ac <Complex> R4 */ +#define MMC_GO_IRQ_STATE 40 /* bcr R5 */ + + /* class 7 */ +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ + + /* class 8 */ +#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ +#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */ + +/* + * MMC_SWITCH argument format: + * + * [31:26] Always 0 + * [25:24] Access Mode + * [23:16] Location of target Byte in EXT_CSD + * [15:08] Value Byte + * [07:03] Always 0 + * [02:00] Command Set + */ + +/* + MMC status in R1 + Type + e : error bit + s : status bit + r : detected and set for the actual command response + x : detected and set during command execution. the host must poll + the card by sending status command in order to read these bits. + Clear condition + a : according to the card state + b : always related to the previous command. Reception of + a valid command will clear it (with a delay of one command) + c : clear by read + */ + +#define R1_OUT_OF_RANGE (1 << 31) /* er, c */ +#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ +#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ +#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ +#define R1_ERASE_PARAM (1 << 27) /* ex, c */ +#define R1_WP_VIOLATION (1 << 26) /* erx, c */ +#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ +#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ +#define R1_COM_CRC_ERROR (1 << 23) /* er, b */ +#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ +#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ +#define R1_CC_ERROR (1 << 20) /* erx, c */ +#define R1_ERROR (1 << 19) /* erx, c */ +#define R1_UNDERRUN (1 << 18) /* ex, c */ +#define R1_OVERRUN (1 << 17) /* ex, c */ +#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ +#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ +#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ +#define R1_ERASE_RESET (1 << 13) /* sr, c */ +#define R1_STATUS(x) (x & 0xFFFFE000) +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R1_APP_CMD (1 << 5) /* sr, c */ + + +/* + * OCR bits are mostly in host.h + */ +#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */ + +/* + * Card Command Classes (CCC) + */ +#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */ + /* (CMD0,1,2,3,4,7,9,10,12,13,15) */ +#define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */ + /* (CMD11) */ +#define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */ + /* (CMD16,17,18) */ +#define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */ + /* (CMD20) */ +#define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */ + /* (CMD16,24,25,26,27) */ +#define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */ + /* (CMD32,33,34,35,36,37,38,39) */ +#define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */ + /* (CMD28,29,30) */ +#define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */ + /* (CMD16,CMD42) */ +#define CCC_APP_SPEC (1<<8) /* (8) Application specific */ + /* (CMD55,56,57,ACMD*) */ +#define CCC_IO_MODE (1<<9) /* (9) I/O mode */ + /* (CMD5,39,40,52,53) */ +#define CCC_SWITCH (1<<10) /* (10) High speed switch */ + /* (CMD6,34,35,36,37,50) */ + /* (11) Reserved */ + /* (CMD?) */ + +/* + * CSD field definitions + */ + +#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ +#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ +#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */ +#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */ + +#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ +#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ +#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ +#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */ +#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */ + +/* + * EXT_CSD fields + */ + +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_CMD_SET_NORMAL (1<<0) +#define EXT_CSD_CMD_SET_SECURE (1<<1) +#define EXT_CSD_CMD_SET_CPSECURE (1<<2) + +#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ + +#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ + +/* + * MMC_SWITCH access modes + */ + +#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ +#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ + +#endif /* MMC_MMC_PROTOCOL_H */ + diff --git a/hw/ne2000.c b/hw/ne2000.c deleted file mode 100644 index e23c6df..0000000 --- a/hw/ne2000.c +++ /dev/null @@ -1,816 +0,0 @@ -/* - * QEMU NE2000 emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* debug NE2000 card */ -//#define DEBUG_NE2000 - -#define MAX_ETH_FRAME_SIZE 1514 - -#define E8390_CMD 0x00 /* The command register (for all pages) */ -/* Page 0 register offsets. */ -#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ -#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ -#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ -#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ -#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ -#define EN0_TSR 0x04 /* Transmit status reg RD */ -#define EN0_TPSR 0x04 /* Transmit starting page WR */ -#define EN0_NCR 0x05 /* Number of collision reg RD */ -#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ -#define EN0_FIFO 0x06 /* FIFO RD */ -#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ -#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ -#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ -#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ -#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ -#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ -#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ -#define EN0_RTL8029ID0 0x0a /* Realtek ID byte #1 RD */ -#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ -#define EN0_RTL8029ID1 0x0b /* Realtek ID byte #2 RD */ -#define EN0_RSR 0x0c /* rx status reg RD */ -#define EN0_RXCR 0x0c /* RX configuration reg WR */ -#define EN0_TXCR 0x0d /* TX configuration reg WR */ -#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ -#define EN0_DCFG 0x0e /* Data configuration reg WR */ -#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ -#define EN0_IMR 0x0f /* Interrupt mask reg WR */ -#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ - -#define EN1_PHYS 0x11 -#define EN1_CURPAG 0x17 -#define EN1_MULT 0x18 - -#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */ -#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */ - -#define EN3_CONFIG0 0x33 -#define EN3_CONFIG1 0x34 -#define EN3_CONFIG2 0x35 -#define EN3_CONFIG3 0x36 - -/* Register accessed at EN_CMD, the 8390 base addr. */ -#define E8390_STOP 0x01 /* Stop and reset the chip */ -#define E8390_START 0x02 /* Start the chip, clear reset */ -#define E8390_TRANS 0x04 /* Transmit a frame */ -#define E8390_RREAD 0x08 /* Remote read */ -#define E8390_RWRITE 0x10 /* Remote write */ -#define E8390_NODMA 0x20 /* Remote DMA */ -#define E8390_PAGE0 0x00 /* Select page chip registers */ -#define E8390_PAGE1 0x40 /* using the two high-order bits */ -#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ - -/* Bits in EN0_ISR - Interrupt status register */ -#define ENISR_RX 0x01 /* Receiver, no error */ -#define ENISR_TX 0x02 /* Transmitter, no error */ -#define ENISR_RX_ERR 0x04 /* Receiver, with error */ -#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ -#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ -#define ENISR_COUNTERS 0x20 /* Counters need emptying */ -#define ENISR_RDC 0x40 /* remote dma complete */ -#define ENISR_RESET 0x80 /* Reset completed */ -#define ENISR_ALL 0x3f /* Interrupts we will enable */ - -/* Bits in received packet status byte and EN0_RSR*/ -#define ENRSR_RXOK 0x01 /* Received a good packet */ -#define ENRSR_CRC 0x02 /* CRC error */ -#define ENRSR_FAE 0x04 /* frame alignment error */ -#define ENRSR_FO 0x08 /* FIFO overrun */ -#define ENRSR_MPA 0x10 /* missed pkt */ -#define ENRSR_PHY 0x20 /* physical/multicast address */ -#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ -#define ENRSR_DEF 0x80 /* deferring */ - -/* Transmitted packet status, EN0_TSR. */ -#define ENTSR_PTX 0x01 /* Packet transmitted without error */ -#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ -#define ENTSR_COL 0x04 /* The transmit collided at least once. */ -#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ -#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ -#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ -#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ -#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ - -#define NE2000_PMEM_SIZE (32*1024) -#define NE2000_PMEM_START (16*1024) -#define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START) -#define NE2000_MEM_SIZE NE2000_PMEM_END - -typedef struct NE2000State { - uint8_t cmd; - uint32_t start; - uint32_t stop; - uint8_t boundary; - uint8_t tsr; - uint8_t tpsr; - uint16_t tcnt; - uint16_t rcnt; - uint32_t rsar; - uint8_t rsr; - uint8_t rxcr; - uint8_t isr; - uint8_t dcfg; - uint8_t imr; - uint8_t phys[6]; /* mac address */ - uint8_t curpag; - uint8_t mult[8]; /* multicast mask array */ - int irq; - PCIDevice *pci_dev; - VLANClientState *vc; - uint8_t macaddr[6]; - uint8_t mem[NE2000_MEM_SIZE]; -} NE2000State; - -static void ne2000_reset(NE2000State *s) -{ - int i; - - s->isr = ENISR_RESET; - memcpy(s->mem, s->macaddr, 6); - s->mem[14] = 0x57; - s->mem[15] = 0x57; - - /* duplicate prom data */ - for(i = 15;i >= 0; i--) { - s->mem[2 * i] = s->mem[i]; - s->mem[2 * i + 1] = s->mem[i]; - } -} - -static void ne2000_update_irq(NE2000State *s) -{ - int isr; - isr = (s->isr & s->imr) & 0x7f; -#if defined(DEBUG_NE2000) - printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n", - s->irq, isr ? 1 : 0, s->isr, s->imr); -#endif - if (s->irq == 16) { - /* PCI irq */ - pci_set_irq(s->pci_dev, 0, (isr != 0)); - } else { - /* ISA irq */ - pic_set_irq(s->irq, (isr != 0)); - } -} - -#define POLYNOMIAL 0x04c11db6 - -/* From FreeBSD */ -/* XXX: optimize */ -static int compute_mcast_idx(const uint8_t *ep) -{ - uint32_t crc; - int carry, i, j; - uint8_t b; - - crc = 0xffffffff; - for (i = 0; i < 6; i++) { - b = *ep++; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); - crc <<= 1; - b >>= 1; - if (carry) - crc = ((crc ^ POLYNOMIAL) | carry); - } - } - return (crc >> 26); -} - -static int ne2000_buffer_full(NE2000State *s) -{ - int avail, index, boundary; - - index = s->curpag << 8; - boundary = s->boundary << 8; - if (index <= boundary) - avail = boundary - index; - else - avail = (s->stop - s->start) - (index - boundary); - if (avail < (MAX_ETH_FRAME_SIZE + 4)) - return 1; - return 0; -} - -static int ne2000_can_receive(void *opaque) -{ - NE2000State *s = opaque; - - if (s->cmd & E8390_STOP) - return 1; - return !ne2000_buffer_full(s); -} - -#define MIN_BUF_SIZE 60 - -static void ne2000_receive(void *opaque, const uint8_t *buf, int size) -{ - NE2000State *s = opaque; - uint8_t *p; - int total_len, next, avail, len, index, mcast_idx; - uint8_t buf1[60]; - static const uint8_t broadcast_macaddr[6] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - -#if defined(DEBUG_NE2000) - printf("NE2000: received len=%d\n", size); -#endif - - if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) - return; - - /* XXX: check this */ - if (s->rxcr & 0x10) { - /* promiscuous: receive all */ - } else { - if (!memcmp(buf, broadcast_macaddr, 6)) { - /* broadcast address */ - if (!(s->rxcr & 0x04)) - return; - } else if (buf[0] & 0x01) { - /* multicast */ - if (!(s->rxcr & 0x08)) - return; - mcast_idx = compute_mcast_idx(buf); - if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) - return; - } else if (s->mem[0] == buf[0] && - s->mem[2] == buf[1] && - s->mem[4] == buf[2] && - s->mem[6] == buf[3] && - s->mem[8] == buf[4] && - s->mem[10] == buf[5]) { - /* match */ - } else { - return; - } - } - - - /* if too small buffer, then expand it */ - if (size < MIN_BUF_SIZE) { - memcpy(buf1, buf, size); - memset(buf1 + size, 0, MIN_BUF_SIZE - size); - buf = buf1; - size = MIN_BUF_SIZE; - } - - index = s->curpag << 8; - /* 4 bytes for header */ - total_len = size + 4; - /* address for next packet (4 bytes for CRC) */ - next = index + ((total_len + 4 + 255) & ~0xff); - if (next >= s->stop) - next -= (s->stop - s->start); - /* prepare packet header */ - p = s->mem + index; - s->rsr = ENRSR_RXOK; /* receive status */ - /* XXX: check this */ - if (buf[0] & 0x01) - s->rsr |= ENRSR_PHY; - p[0] = s->rsr; - p[1] = next >> 8; - p[2] = total_len; - p[3] = total_len >> 8; - index += 4; - - /* write packet data */ - while (size > 0) { - avail = s->stop - index; - len = size; - if (len > avail) - len = avail; - memcpy(s->mem + index, buf, len); - buf += len; - index += len; - if (index == s->stop) - index = s->start; - size -= len; - } - s->curpag = next >> 8; - - /* now we can signal we have receive something */ - s->isr |= ENISR_RX; - ne2000_update_irq(s); -} - -static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - NE2000State *s = opaque; - int offset, page, index; - - addr &= 0xf; -#ifdef DEBUG_NE2000 - printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val); -#endif - if (addr == E8390_CMD) { - /* control register */ - s->cmd = val; - if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */ - s->isr &= ~ENISR_RESET; - /* test specific case: zero length transfert */ - if ((val & (E8390_RREAD | E8390_RWRITE)) && - s->rcnt == 0) { - s->isr |= ENISR_RDC; - ne2000_update_irq(s); - } - if (val & E8390_TRANS) { - index = (s->tpsr << 8); - /* XXX: next 2 lines are a hack to make netware 3.11 work */ - if (index >= NE2000_PMEM_END) - index -= NE2000_PMEM_SIZE; - /* fail safe: check range on the transmitted length */ - if (index + s->tcnt <= NE2000_PMEM_END) { - qemu_send_packet(s->vc, s->mem + index, s->tcnt); - } - /* signal end of transfert */ - s->tsr = ENTSR_PTX; - s->isr |= ENISR_TX; - s->cmd &= ~E8390_TRANS; - ne2000_update_irq(s); - } - } - } else { - page = s->cmd >> 6; - offset = addr | (page << 4); - switch(offset) { - case EN0_STARTPG: - s->start = val << 8; - break; - case EN0_STOPPG: - s->stop = val << 8; - break; - case EN0_BOUNDARY: - s->boundary = val; - break; - case EN0_IMR: - s->imr = val; - ne2000_update_irq(s); - break; - case EN0_TPSR: - s->tpsr = val; - break; - case EN0_TCNTLO: - s->tcnt = (s->tcnt & 0xff00) | val; - break; - case EN0_TCNTHI: - s->tcnt = (s->tcnt & 0x00ff) | (val << 8); - break; - case EN0_RSARLO: - s->rsar = (s->rsar & 0xff00) | val; - break; - case EN0_RSARHI: - s->rsar = (s->rsar & 0x00ff) | (val << 8); - break; - case EN0_RCNTLO: - s->rcnt = (s->rcnt & 0xff00) | val; - break; - case EN0_RCNTHI: - s->rcnt = (s->rcnt & 0x00ff) | (val << 8); - break; - case EN0_RXCR: - s->rxcr = val; - break; - case EN0_DCFG: - s->dcfg = val; - break; - case EN0_ISR: - s->isr &= ~(val & 0x7f); - ne2000_update_irq(s); - break; - case EN1_PHYS ... EN1_PHYS + 5: - s->phys[offset - EN1_PHYS] = val; - break; - case EN1_CURPAG: - s->curpag = val; - break; - case EN1_MULT ... EN1_MULT + 7: - s->mult[offset - EN1_MULT] = val; - break; - } - } -} - -static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) -{ - NE2000State *s = opaque; - int offset, page, ret; - - addr &= 0xf; - if (addr == E8390_CMD) { - ret = s->cmd; - } else { - page = s->cmd >> 6; - offset = addr | (page << 4); - switch(offset) { - case EN0_TSR: - ret = s->tsr; - break; - case EN0_BOUNDARY: - ret = s->boundary; - break; - case EN0_ISR: - ret = s->isr; - break; - case EN0_RSARLO: - ret = s->rsar & 0x00ff; - break; - case EN0_RSARHI: - ret = s->rsar >> 8; - break; - case EN1_PHYS ... EN1_PHYS + 5: - ret = s->phys[offset - EN1_PHYS]; - break; - case EN1_CURPAG: - ret = s->curpag; - break; - case EN1_MULT ... EN1_MULT + 7: - ret = s->mult[offset - EN1_MULT]; - break; - case EN0_RSR: - ret = s->rsr; - break; - case EN2_STARTPG: - ret = s->start >> 8; - break; - case EN2_STOPPG: - ret = s->stop >> 8; - break; - case EN0_RTL8029ID0: - ret = 0x50; - break; - case EN0_RTL8029ID1: - ret = 0x43; - break; - case EN3_CONFIG0: - ret = 0; /* 10baseT media */ - break; - case EN3_CONFIG2: - ret = 0x40; /* 10baseT active */ - break; - case EN3_CONFIG3: - ret = 0x40; /* Full duplex */ - break; - default: - ret = 0x00; - break; - } - } -#ifdef DEBUG_NE2000 - printf("NE2000: read addr=0x%x val=%02x\n", addr, ret); -#endif - return ret; -} - -static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr, - uint32_t val) -{ - if (addr < 32 || - (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { - s->mem[addr] = val; - } -} - -static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr, - uint32_t val) -{ - addr &= ~1; /* XXX: check exact behaviour if not even */ - if (addr < 32 || - (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { - *(uint16_t *)(s->mem + addr) = cpu_to_le16(val); - } -} - -static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr, - uint32_t val) -{ - addr &= ~1; /* XXX: check exact behaviour if not even */ - if (addr < 32 || - (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { - cpu_to_le32wu((uint32_t *)(s->mem + addr), val); - } -} - -static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr) -{ - if (addr < 32 || - (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { - return s->mem[addr]; - } else { - return 0xff; - } -} - -static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr) -{ - addr &= ~1; /* XXX: check exact behaviour if not even */ - if (addr < 32 || - (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { - return le16_to_cpu(*(uint16_t *)(s->mem + addr)); - } else { - return 0xffff; - } -} - -static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr) -{ - addr &= ~1; /* XXX: check exact behaviour if not even */ - if (addr < 32 || - (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { - return le32_to_cpupu((uint32_t *)(s->mem + addr)); - } else { - return 0xffffffff; - } -} - -static inline void ne2000_dma_update(NE2000State *s, int len) -{ - s->rsar += len; - /* wrap */ - /* XXX: check what to do if rsar > stop */ - if (s->rsar == s->stop) - s->rsar = s->start; - - if (s->rcnt <= len) { - s->rcnt = 0; - /* signal end of transfert */ - s->isr |= ENISR_RDC; - ne2000_update_irq(s); - } else { - s->rcnt -= len; - } -} - -static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - NE2000State *s = opaque; - -#ifdef DEBUG_NE2000 - printf("NE2000: asic write val=0x%04x\n", val); -#endif - if (s->rcnt == 0) - return; - if (s->dcfg & 0x01) { - /* 16 bit access */ - ne2000_mem_writew(s, s->rsar, val); - ne2000_dma_update(s, 2); - } else { - /* 8 bit access */ - ne2000_mem_writeb(s, s->rsar, val); - ne2000_dma_update(s, 1); - } -} - -static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr) -{ - NE2000State *s = opaque; - int ret; - - if (s->dcfg & 0x01) { - /* 16 bit access */ - ret = ne2000_mem_readw(s, s->rsar); - ne2000_dma_update(s, 2); - } else { - /* 8 bit access */ - ret = ne2000_mem_readb(s, s->rsar); - ne2000_dma_update(s, 1); - } -#ifdef DEBUG_NE2000 - printf("NE2000: asic read val=0x%04x\n", ret); -#endif - return ret; -} - -static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - NE2000State *s = opaque; - -#ifdef DEBUG_NE2000 - printf("NE2000: asic writel val=0x%04x\n", val); -#endif - if (s->rcnt == 0) - return; - /* 32 bit access */ - ne2000_mem_writel(s, s->rsar, val); - ne2000_dma_update(s, 4); -} - -static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr) -{ - NE2000State *s = opaque; - int ret; - - /* 32 bit access */ - ret = ne2000_mem_readl(s, s->rsar); - ne2000_dma_update(s, 4); -#ifdef DEBUG_NE2000 - printf("NE2000: asic readl val=0x%04x\n", ret); -#endif - return ret; -} - -static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - /* nothing to do (end of reset pulse) */ -} - -static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr) -{ - NE2000State *s = opaque; - ne2000_reset(s); - return 0; -} - -static void ne2000_save(QEMUFile* f,void* opaque) -{ - NE2000State* s=(NE2000State*)opaque; - - qemu_put_8s(f, &s->rxcr); - - qemu_put_8s(f, &s->cmd); - qemu_put_be32s(f, &s->start); - qemu_put_be32s(f, &s->stop); - qemu_put_8s(f, &s->boundary); - qemu_put_8s(f, &s->tsr); - qemu_put_8s(f, &s->tpsr); - qemu_put_be16s(f, &s->tcnt); - qemu_put_be16s(f, &s->rcnt); - qemu_put_be32s(f, &s->rsar); - qemu_put_8s(f, &s->rsr); - qemu_put_8s(f, &s->isr); - qemu_put_8s(f, &s->dcfg); - qemu_put_8s(f, &s->imr); - qemu_put_buffer(f, s->phys, 6); - qemu_put_8s(f, &s->curpag); - qemu_put_buffer(f, s->mult, 8); - qemu_put_be32s(f, &s->irq); - qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE); -} - -static int ne2000_load(QEMUFile* f,void* opaque,int version_id) -{ - NE2000State* s=(NE2000State*)opaque; - - if (version_id == 2) { - qemu_get_8s(f, &s->rxcr); - } else if (version_id == 1) { - s->rxcr = 0x0c; - } else { - return -EINVAL; - } - - qemu_get_8s(f, &s->cmd); - qemu_get_be32s(f, &s->start); - qemu_get_be32s(f, &s->stop); - qemu_get_8s(f, &s->boundary); - qemu_get_8s(f, &s->tsr); - qemu_get_8s(f, &s->tpsr); - qemu_get_be16s(f, &s->tcnt); - qemu_get_be16s(f, &s->rcnt); - qemu_get_be32s(f, &s->rsar); - qemu_get_8s(f, &s->rsr); - qemu_get_8s(f, &s->isr); - qemu_get_8s(f, &s->dcfg); - qemu_get_8s(f, &s->imr); - qemu_get_buffer(f, s->phys, 6); - qemu_get_8s(f, &s->curpag); - qemu_get_buffer(f, s->mult, 8); - qemu_get_be32s(f, &s->irq); - qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE); - - return 0; -} - -void isa_ne2000_init(int base, int irq, NICInfo *nd) -{ - NE2000State *s; - - s = qemu_mallocz(sizeof(NE2000State)); - if (!s) - return; - - register_ioport_write(base, 16, 1, ne2000_ioport_write, s); - register_ioport_read(base, 16, 1, ne2000_ioport_read, s); - - register_ioport_write(base + 0x10, 1, 1, ne2000_asic_ioport_write, s); - register_ioport_read(base + 0x10, 1, 1, ne2000_asic_ioport_read, s); - register_ioport_write(base + 0x10, 2, 2, ne2000_asic_ioport_write, s); - register_ioport_read(base + 0x10, 2, 2, ne2000_asic_ioport_read, s); - - register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); - register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); - s->irq = irq; - memcpy(s->macaddr, nd->macaddr, 6); - - ne2000_reset(s); - - s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, - ne2000_can_receive, s); - - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "ne2000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - s->macaddr[0], - s->macaddr[1], - s->macaddr[2], - s->macaddr[3], - s->macaddr[4], - s->macaddr[5]); - - register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s); -} - -/***********************************************************/ -/* PCI NE2000 definitions */ - -typedef struct PCINE2000State { - PCIDevice dev; - NE2000State ne2000; -} PCINE2000State; - -static void ne2000_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - PCINE2000State *d = (PCINE2000State *)pci_dev; - NE2000State *s = &d->ne2000; - - register_ioport_write(addr, 16, 1, ne2000_ioport_write, s); - register_ioport_read(addr, 16, 1, ne2000_ioport_read, s); - - register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s); - register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s); - register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s); - register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s); - register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s); - register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s); - - register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s); - register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); -} - -void pci_ne2000_init(PCIBus *bus, NICInfo *nd) -{ - PCINE2000State *d; - NE2000State *s; - uint8_t *pci_conf; - - d = (PCINE2000State *)pci_register_device(bus, - "NE2000", sizeof(PCINE2000State), - -1, - NULL, NULL); - pci_conf = d->dev.config; - pci_conf[0x00] = 0xec; // Realtek 8029 - pci_conf[0x01] = 0x10; - pci_conf[0x02] = 0x29; - pci_conf[0x03] = 0x80; - pci_conf[0x0a] = 0x00; // ethernet network controller - pci_conf[0x0b] = 0x02; - pci_conf[0x0e] = 0x00; // header_type - pci_conf[0x3d] = 1; // interrupt pin 0 - - pci_register_io_region(&d->dev, 0, 0x100, - PCI_ADDRESS_SPACE_IO, ne2000_map); - s = &d->ne2000; - s->irq = 16; // PCI interrupt - s->pci_dev = (PCIDevice *)d; - memcpy(s->macaddr, nd->macaddr, 6); - ne2000_reset(s); - s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, - ne2000_can_receive, s); - - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - s->macaddr[0], - s->macaddr[1], - s->macaddr[2], - s->macaddr[3], - s->macaddr[4], - s->macaddr[5]); - - /* XXX: instance number ? */ - register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s); - register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, - &d->dev); -} diff --git a/hw/openpic.c b/hw/openpic.c deleted file mode 100644 index 3177337..0000000 --- a/hw/openpic.c +++ /dev/null @@ -1,1027 +0,0 @@ -/* - * OpenPIC emulation - * - * Copyright (c) 2004 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -/* - * - * Based on OpenPic implementations: - * - Intel GW80314 I/O compagnion chip developper's manual - * - Motorola MPC8245 & MPC8540 user manuals. - * - Motorola MCP750 (aka Raven) programmer manual. - * - Motorola Harrier programmer manuel - * - * Serial interrupts, as implemented in Raven chipset are not supported yet. - * - */ -#include "vl.h" - -//#define DEBUG_OPENPIC - -#ifdef DEBUG_OPENPIC -#define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) -#else -#define DPRINTF(fmt, args...) do { } while (0) -#endif -#define ERROR(fmr, args...) do { printf("ERROR: " fmr , ##args); } while (0) - -#define USE_MPCxxx /* Intel model is broken, for now */ - -#if defined (USE_INTEL_GW80314) -/* Intel GW80314 I/O Companion chip */ - -#define MAX_CPU 4 -#define MAX_IRQ 32 -#define MAX_DBL 4 -#define MAX_MBX 4 -#define MAX_TMR 4 -#define VECTOR_BITS 8 -#define MAX_IPI 0 - -#define VID (0x00000000) - -#define OPENPIC_LITTLE_ENDIAN 1 -#define OPENPIC_BIG_ENDIAN 0 - -#elif defined(USE_MPCxxx) - -#define MAX_CPU 2 -#define MAX_IRQ 64 -#define EXT_IRQ 48 -#define MAX_DBL 0 -#define MAX_MBX 0 -#define MAX_TMR 4 -#define VECTOR_BITS 8 -#define MAX_IPI 4 -#define VID 0x03 /* MPIC version ID */ -#define VENI 0x00000000 /* Vendor ID */ - -enum { - IRQ_IPVP = 0, - IRQ_IDE, -}; - -#define OPENPIC_LITTLE_ENDIAN 1 -#define OPENPIC_BIG_ENDIAN 0 - -#else -#error "Please select which OpenPic implementation is to be emulated" -#endif - -#if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \ - (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN) -#define OPENPIC_SWAP -#endif - -/* Interrupt definitions */ -#define IRQ_FE (EXT_IRQ) /* Internal functional IRQ */ -#define IRQ_ERR (EXT_IRQ + 1) /* Error IRQ */ -#define IRQ_TIM0 (EXT_IRQ + 2) /* First timer IRQ */ -#if MAX_IPI > 0 -#define IRQ_IPI0 (IRQ_TIM0 + MAX_TMR) /* First IPI IRQ */ -#define IRQ_DBL0 (IRQ_IPI0 + (MAX_CPU * MAX_IPI)) /* First doorbell IRQ */ -#else -#define IRQ_DBL0 (IRQ_TIM0 + MAX_TMR) /* First doorbell IRQ */ -#define IRQ_MBX0 (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */ -#endif - -#define BF_WIDTH(_bits_) \ -(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8)) - -static inline void set_bit (uint32_t *field, int bit) -{ - field[bit >> 5] |= 1 << (bit & 0x1F); -} - -static inline void reset_bit (uint32_t *field, int bit) -{ - field[bit >> 5] &= ~(1 << (bit & 0x1F)); -} - -static inline int test_bit (uint32_t *field, int bit) -{ - return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0; -} - -enum { - IRQ_EXTERNAL = 0x01, - IRQ_INTERNAL = 0x02, - IRQ_TIMER = 0x04, - IRQ_SPECIAL = 0x08, -} IRQ_src_type; - -typedef struct IRQ_queue_t { - uint32_t queue[BF_WIDTH(MAX_IRQ)]; - int next; - int priority; -} IRQ_queue_t; - -typedef struct IRQ_src_t { - uint32_t ipvp; /* IRQ vector/priority register */ - uint32_t ide; /* IRQ destination register */ - int type; - int last_cpu; - int pending; /* TRUE if IRQ is pending */ -} IRQ_src_t; - -enum IPVP_bits { - IPVP_MASK = 31, - IPVP_ACTIVITY = 30, - IPVP_MODE = 29, - IPVP_POLARITY = 23, - IPVP_SENSE = 22, -}; -#define IPVP_PRIORITY_MASK (0x1F << 16) -#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) -#define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) -#define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) - -typedef struct IRQ_dst_t { - uint32_t pctp; /* CPU current task priority */ - uint32_t pcsr; /* CPU sensitivity register */ - IRQ_queue_t raised; - IRQ_queue_t servicing; - CPUState *env; -} IRQ_dst_t; - -struct openpic_t { - PCIDevice pci_dev; - int mem_index; - /* Global registers */ - uint32_t frep; /* Feature reporting register */ - uint32_t glbc; /* Global configuration register */ - uint32_t micr; /* MPIC interrupt configuration register */ - uint32_t veni; /* Vendor identification register */ - uint32_t spve; /* Spurious vector register */ - uint32_t tifr; /* Timer frequency reporting register */ - /* Source registers */ - IRQ_src_t src[MAX_IRQ]; - /* Local registers per output pin */ - IRQ_dst_t dst[MAX_CPU]; - int nb_cpus; - /* Timer registers */ - struct { - uint32_t ticc; /* Global timer current count register */ - uint32_t tibc; /* Global timer base count register */ - } timers[MAX_TMR]; -#if MAX_DBL > 0 - /* Doorbell registers */ - uint32_t dar; /* Doorbell activate register */ - struct { - uint32_t dmr; /* Doorbell messaging register */ - } doorbells[MAX_DBL]; -#endif -#if MAX_MBX > 0 - /* Mailbox registers */ - struct { - uint32_t mbr; /* Mailbox register */ - } mailboxes[MAX_MAILBOXES]; -#endif -}; - -static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) -{ - set_bit(q->queue, n_IRQ); -} - -static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ) -{ - reset_bit(q->queue, n_IRQ); -} - -static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ) -{ - return test_bit(q->queue, n_IRQ); -} - -static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) -{ - int next, i; - int priority; - - next = -1; - priority = -1; - for (i = 0; i < MAX_IRQ; i++) { - if (IRQ_testbit(q, i)) { - DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", - i, IPVP_PRIORITY(opp->src[i].ipvp), priority); - if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { - next = i; - priority = IPVP_PRIORITY(opp->src[i].ipvp); - } - } - } - q->next = next; - q->priority = priority; -} - -static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) -{ - if (q->next == -1) { - /* XXX: optimize */ - IRQ_check(opp, q); - } - - return q->next; -} - -static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) -{ - IRQ_dst_t *dst; - IRQ_src_t *src; - int priority; - - dst = &opp->dst[n_CPU]; - src = &opp->src[n_IRQ]; - priority = IPVP_PRIORITY(src->ipvp); - if (priority <= dst->pctp) { - /* Too low priority */ - return; - } - if (IRQ_testbit(&dst->raised, n_IRQ)) { - /* Interrupt miss */ - return; - } - set_bit(&src->ipvp, IPVP_ACTIVITY); - IRQ_setbit(&dst->raised, n_IRQ); - if (priority > dst->raised.priority) { - IRQ_get_next(opp, &dst->raised); - DPRINTF("Raise CPU IRQ\n"); - cpu_interrupt(dst->env, CPU_INTERRUPT_HARD); - } -} - -/* update pic state because registers for n_IRQ have changed value */ -static void openpic_update_irq(openpic_t *opp, int n_IRQ) -{ - IRQ_src_t *src; - int i; - - src = &opp->src[n_IRQ]; - - if (!src->pending) { - /* no irq pending */ - return; - } - if (test_bit(&src->ipvp, IPVP_MASK)) { - /* Interrupt source is disabled */ - return; - } - if (IPVP_PRIORITY(src->ipvp) == 0) { - /* Priority set to zero */ - return; - } - if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { - /* IRQ already active */ - return; - } - if (src->ide == 0x00000000) { - /* No target */ - return; - } - - if (!test_bit(&src->ipvp, IPVP_MODE) || - src->ide == (1 << src->last_cpu)) { - /* Directed delivery mode */ - for (i = 0; i < opp->nb_cpus; i++) { - if (test_bit(&src->ide, i)) - IRQ_local_pipe(opp, i, n_IRQ); - } - } else { - /* Distributed delivery mode */ - /* XXX: incorrect code */ - for (i = src->last_cpu; i < src->last_cpu; i++) { - if (i == MAX_IRQ) - i = 0; - if (test_bit(&src->ide, i)) { - IRQ_local_pipe(opp, i, n_IRQ); - src->last_cpu = i; - break; - } - } - } -} - -void openpic_set_irq(void *opaque, int n_IRQ, int level) -{ - openpic_t *opp = opaque; - IRQ_src_t *src; - - src = &opp->src[n_IRQ]; - DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", - n_IRQ, level, src->ipvp); - if (test_bit(&src->ipvp, IPVP_SENSE)) { - /* level-sensitive irq */ - src->pending = level; - if (!level) - reset_bit(&src->ipvp, IPVP_ACTIVITY); - } else { - /* edge-sensitive irq */ - if (level) - src->pending = 1; - } - openpic_update_irq(opp, n_IRQ); -} - -static void openpic_reset (openpic_t *opp) -{ - int i; - - opp->glbc = 0x80000000; - /* Initialise controller registers */ - opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID; - opp->veni = VENI; - opp->spve = 0x000000FF; - opp->tifr = 0x003F7A00; - /* ? */ - opp->micr = 0x00000000; - /* Initialise IRQ sources */ - for (i = 0; i < MAX_IRQ; i++) { - opp->src[i].ipvp = 0xA0000000; - opp->src[i].ide = 0x00000000; - } - /* Initialise IRQ destinations */ - for (i = 0; i < opp->nb_cpus; i++) { - opp->dst[i].pctp = 0x0000000F; - opp->dst[i].pcsr = 0x00000000; - memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); - memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); - } - /* Initialise timers */ - for (i = 0; i < MAX_TMR; i++) { - opp->timers[i].ticc = 0x00000000; - opp->timers[i].tibc = 0x80000000; - } - /* Initialise doorbells */ -#if MAX_DBL > 0 - opp->dar = 0x00000000; - for (i = 0; i < MAX_DBL; i++) { - opp->doorbells[i].dmr = 0x00000000; - } -#endif - /* Initialise mailboxes */ -#if MAX_MBX > 0 - for (i = 0; i < MAX_MBX; i++) { /* ? */ - opp->mailboxes[i].mbr = 0x00000000; - } -#endif - /* Go out of RESET state */ - opp->glbc = 0x00000000; -} - -static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg) -{ - uint32_t retval; - - switch (reg) { - case IRQ_IPVP: - retval = opp->src[n_IRQ].ipvp; - break; - case IRQ_IDE: - retval = opp->src[n_IRQ].ide; - break; - } - - return retval; -} - -static inline void write_IRQreg (openpic_t *opp, int n_IRQ, - uint32_t reg, uint32_t val) -{ - uint32_t tmp; - - switch (reg) { - case IRQ_IPVP: - /* NOTE: not fully accurate for special IRQs, but simple and - sufficient */ - /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ipvp = - (opp->src[n_IRQ].ipvp & 0x40000000) | - (val & 0x800F00FF); - openpic_update_irq(opp, n_IRQ); - DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", - n_IRQ, val, opp->src[n_IRQ].ipvp); - break; - case IRQ_IDE: - tmp = val & 0xC0000000; - tmp |= val & ((1 << MAX_CPU) - 1); - opp->src[n_IRQ].ide = tmp; - DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); - break; - } -} - -#if 0 // Code provision for Intel model -#if MAX_DBL > 0 -static uint32_t read_doorbell_register (openpic_t *opp, - int n_dbl, uint32_t offset) -{ - uint32_t retval; - - switch (offset) { - case DBL_IPVP_OFFSET: - retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP); - break; - case DBL_IDE_OFFSET: - retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE); - break; - case DBL_DMR_OFFSET: - retval = opp->doorbells[n_dbl].dmr; - break; - } - - return retval; -} - -static void write_doorbell_register (penpic_t *opp, int n_dbl, - uint32_t offset, uint32_t value) -{ - switch (offset) { - case DBL_IVPR_OFFSET: - write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value); - break; - case DBL_IDE_OFFSET: - write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value); - break; - case DBL_DMR_OFFSET: - opp->doorbells[n_dbl].dmr = value; - break; - } -} -#endif - -#if MAX_MBX > 0 -static uint32_t read_mailbox_register (openpic_t *opp, - int n_mbx, uint32_t offset) -{ - uint32_t retval; - - switch (offset) { - case MBX_MBR_OFFSET: - retval = opp->mailboxes[n_mbx].mbr; - break; - case MBX_IVPR_OFFSET: - retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP); - break; - case MBX_DMR_OFFSET: - retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE); - break; - } - - return retval; -} - -static void write_mailbox_register (openpic_t *opp, int n_mbx, - uint32_t address, uint32_t value) -{ - switch (offset) { - case MBX_MBR_OFFSET: - opp->mailboxes[n_mbx].mbr = value; - break; - case MBX_IVPR_OFFSET: - write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value); - break; - case MBX_DMR_OFFSET: - write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value); - break; - } -} -#endif -#endif /* 0 : Code provision for Intel model */ - -static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) -{ - openpic_t *opp = opaque; - - DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; -#if defined OPENPIC_SWAP - val = bswap32(val); -#endif - addr &= 0xFF; - switch (addr) { - case 0x00: /* FREP */ - break; - case 0x20: /* GLBC */ - if (val & 0x80000000) - openpic_reset(opp); - opp->glbc = val & ~0x80000000; - break; - case 0x80: /* VENI */ - break; - case 0x90: /* PINT */ - /* XXX: Should be able to reset any CPU */ - if (val & 1) { - DPRINTF("Reset CPU IRQ\n"); - // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET); - } - break; -#if MAX_IPI > 0 - case 0xA0: /* IPI_IPVP */ - case 0xB0: - case 0xC0: - case 0xD0: - { - int idx; - idx = (addr - 0xA0) >> 4; - write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val); - } - break; -#endif - case 0xE0: /* SPVE */ - opp->spve = val & 0x000000FF; - break; - case 0xF0: /* TIFR */ - opp->tifr = val; - break; - default: - break; - } -} - -static uint32_t openpic_gbl_read (void *opaque, uint32_t addr) -{ - openpic_t *opp = opaque; - uint32_t retval; - - DPRINTF("%s: addr %08x\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; - addr &= 0xFF; - switch (addr) { - case 0x00: /* FREP */ - retval = opp->frep; - break; - case 0x20: /* GLBC */ - retval = opp->glbc; - break; - case 0x80: /* VENI */ - retval = opp->veni; - break; - case 0x90: /* PINT */ - retval = 0x00000000; - break; -#if MAX_IPI > 0 - case 0xA0: /* IPI_IPVP */ - case 0xB0: - case 0xC0: - case 0xD0: - { - int idx; - idx = (addr - 0xA0) >> 4; - retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP); - } - break; -#endif - case 0xE0: /* SPVE */ - retval = opp->spve; - break; - case 0xF0: /* TIFR */ - retval = opp->tifr; - break; - default: - break; - } - DPRINTF("%s: => %08x\n", __func__, retval); -#if defined OPENPIC_SWAP - retval = bswap32(retval); -#endif - - return retval; -} - -static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val) -{ - openpic_t *opp = opaque; - int idx; - - DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; -#if defined OPENPIC_SWAP - val = bswap32(val); -#endif - addr -= 0x1100; - addr &= 0xFFFF; - idx = (addr & 0xFFF0) >> 6; - addr = addr & 0x30; - switch (addr) { - case 0x00: /* TICC */ - break; - case 0x10: /* TIBC */ - if ((opp->timers[idx].ticc & 0x80000000) != 0 && - (val & 0x80000000) == 0 && - (opp->timers[idx].tibc & 0x80000000) != 0) - opp->timers[idx].ticc &= ~0x80000000; - opp->timers[idx].tibc = val; - break; - case 0x20: /* TIVP */ - write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val); - break; - case 0x30: /* TIDE */ - write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val); - break; - } -} - -static uint32_t openpic_timer_read (void *opaque, uint32_t addr) -{ - openpic_t *opp = opaque; - uint32_t retval; - int idx; - - DPRINTF("%s: addr %08x\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; - addr -= 0x1100; - addr &= 0xFFFF; - idx = (addr & 0xFFF0) >> 6; - addr = addr & 0x30; - switch (addr) { - case 0x00: /* TICC */ - retval = opp->timers[idx].ticc; - break; - case 0x10: /* TIBC */ - retval = opp->timers[idx].tibc; - break; - case 0x20: /* TIPV */ - retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP); - break; - case 0x30: /* TIDE */ - retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE); - break; - } - DPRINTF("%s: => %08x\n", __func__, retval); -#if defined OPENPIC_SWAP - retval = bswap32(retval); -#endif - - return retval; -} - -static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val) -{ - openpic_t *opp = opaque; - int idx; - - DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; -#if defined OPENPIC_SWAP - val = tswap32(val); -#endif - addr = addr & 0xFFF0; - idx = addr >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg(opp, idx, IRQ_IDE, val); - } else { - /* EXVP / IFEVP / IEEVP */ - write_IRQreg(opp, idx, IRQ_IPVP, val); - } -} - -static uint32_t openpic_src_read (void *opaque, uint32_t addr) -{ - openpic_t *opp = opaque; - uint32_t retval; - int idx; - - DPRINTF("%s: addr %08x\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; - addr = addr & 0xFFF0; - idx = addr >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg(opp, idx, IRQ_IDE); - } else { - /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg(opp, idx, IRQ_IPVP); - } - DPRINTF("%s: => %08x\n", __func__, retval); -#if defined OPENPIC_SWAP - retval = tswap32(retval); -#endif - - return retval; -} - -static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) -{ - openpic_t *opp = opaque; - IRQ_src_t *src; - IRQ_dst_t *dst; - int idx, n_IRQ; - - DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; -#if defined OPENPIC_SWAP - val = bswap32(val); -#endif - addr &= 0x1FFF0; - idx = addr / 0x1000; - dst = &opp->dst[idx]; - addr &= 0xFF0; - switch (addr) { -#if MAX_IPI > 0 - case 0x40: /* PIPD */ - case 0x50: - case 0x60: - case 0x70: - idx = (addr - 0x40) >> 4; - write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val); - openpic_set_irq(opp, IRQ_IPI0 + idx, 1); - openpic_set_irq(opp, IRQ_IPI0 + idx, 0); - break; -#endif - case 0x80: /* PCTP */ - dst->pctp = val & 0x0000000F; - break; - case 0x90: /* WHOAMI */ - /* Read-only register */ - break; - case 0xA0: /* PIAC */ - /* Read-only register */ - break; - case 0xB0: /* PEOI */ - DPRINTF("PEOI\n"); - n_IRQ = IRQ_get_next(opp, &dst->servicing); - IRQ_resetbit(&dst->servicing, n_IRQ); - dst->servicing.next = -1; - src = &opp->src[n_IRQ]; - /* Set up next servicing IRQ */ - IRQ_get_next(opp, &dst->servicing); - /* Check queued interrupts. */ - n_IRQ = IRQ_get_next(opp, &dst->raised); - if (n_IRQ != -1) { - src = &opp->src[n_IRQ]; - if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) { - DPRINTF("Raise CPU IRQ\n"); - cpu_interrupt(dst->env, CPU_INTERRUPT_HARD); - } - } - break; - default: - break; - } -} - -static uint32_t openpic_cpu_read (void *opaque, uint32_t addr) -{ - openpic_t *opp = opaque; - IRQ_src_t *src; - IRQ_dst_t *dst; - uint32_t retval; - int idx, n_IRQ; - - DPRINTF("%s: addr %08x\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; - addr &= 0x1FFF0; - idx = addr / 0x1000; - dst = &opp->dst[idx]; - addr &= 0xFF0; - switch (addr) { - case 0x80: /* PCTP */ - retval = dst->pctp; - break; - case 0x90: /* WHOAMI */ - retval = idx; - break; - case 0xA0: /* PIAC */ - n_IRQ = IRQ_get_next(opp, &dst->raised); - DPRINTF("PIAC: irq=%d\n", n_IRQ); - if (n_IRQ == -1) { - /* No more interrupt pending */ - retval = opp->spve; - } else { - src = &opp->src[n_IRQ]; - if (!test_bit(&src->ipvp, IPVP_ACTIVITY) || - !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) { - /* - Spurious level-sensitive IRQ - * - Priorities has been changed - * and the pending IRQ isn't allowed anymore - */ - reset_bit(&src->ipvp, IPVP_ACTIVITY); - retval = IPVP_VECTOR(opp->spve); - } else { - /* IRQ enter servicing state */ - IRQ_setbit(&dst->servicing, n_IRQ); - retval = IPVP_VECTOR(src->ipvp); - } - IRQ_resetbit(&dst->raised, n_IRQ); - dst->raised.next = -1; - if (!test_bit(&src->ipvp, IPVP_SENSE)) { - /* edge-sensitive IRQ */ - reset_bit(&src->ipvp, IPVP_ACTIVITY); - src->pending = 0; - } - } - break; - case 0xB0: /* PEOI */ - retval = 0; - break; -#if MAX_IPI > 0 - case 0x40: /* IDE */ - case 0x50: - idx = (addr - 0x40) >> 4; - retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE); - break; -#endif - default: - break; - } - DPRINTF("%s: => %08x\n", __func__, retval); -#if defined OPENPIC_SWAP - retval= bswap32(retval); -#endif - - return retval; -} - -static void openpic_buggy_write (void *opaque, - target_phys_addr_t addr, uint32_t val) -{ - printf("Invalid OPENPIC write access !\n"); -} - -static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr) -{ - printf("Invalid OPENPIC read access !\n"); - - return -1; -} - -static void openpic_writel (void *opaque, - target_phys_addr_t addr, uint32_t val) -{ - openpic_t *opp = opaque; - - addr &= 0x3FFFF; - DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val); - if (addr < 0x1100) { - /* Global registers */ - openpic_gbl_write(opp, addr, val); - } else if (addr < 0x10000) { - /* Timers registers */ - openpic_timer_write(opp, addr, val); - } else if (addr < 0x20000) { - /* Source registers */ - openpic_src_write(opp, addr, val); - } else { - /* CPU registers */ - openpic_cpu_write(opp, addr, val); - } -} - -static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr) -{ - openpic_t *opp = opaque; - uint32_t retval; - - addr &= 0x3FFFF; - DPRINTF("%s: offset %08x\n", __func__, (int)addr); - if (addr < 0x1100) { - /* Global registers */ - retval = openpic_gbl_read(opp, addr); - } else if (addr < 0x10000) { - /* Timers registers */ - retval = openpic_timer_read(opp, addr); - } else if (addr < 0x20000) { - /* Source registers */ - retval = openpic_src_read(opp, addr); - } else { - /* CPU registers */ - retval = openpic_cpu_read(opp, addr); - } - - return retval; -} - -static CPUWriteMemoryFunc *openpic_write[] = { - &openpic_buggy_write, - &openpic_buggy_write, - &openpic_writel, -}; - -static CPUReadMemoryFunc *openpic_read[] = { - &openpic_buggy_read, - &openpic_buggy_read, - &openpic_readl, -}; - -static void openpic_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - openpic_t *opp; - - DPRINTF("Map OpenPIC\n"); - opp = (openpic_t *)pci_dev; - /* Global registers */ - DPRINTF("Register OPENPIC gbl %08x => %08x\n", - addr + 0x1000, addr + 0x1000 + 0x100); - /* Timer registers */ - DPRINTF("Register OPENPIC timer %08x => %08x\n", - addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR); - /* Interrupt source registers */ - DPRINTF("Register OPENPIC src %08x => %08x\n", - addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2)); - /* Per CPU registers */ - DPRINTF("Register OPENPIC dst %08x => %08x\n", - addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU); - cpu_register_physical_memory(addr, 0x40000, opp->mem_index); -#if 0 // Don't implement ISU for now - opp_io_memory = cpu_register_io_memory(0, openpic_src_read, - openpic_src_write); - cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2), - opp_io_memory); -#endif -} - -openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, - CPUPPCState **envp) -{ - openpic_t *opp; - uint8_t *pci_conf; - int i, m; - - /* XXX: for now, only one CPU is supported */ - if (nb_cpus != 1) - return NULL; - if (bus) { - opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t), - -1, NULL, NULL); - if (opp == NULL) - return NULL; - pci_conf = opp->pci_dev.config; - pci_conf[0x00] = 0x14; // IBM MPIC2 - pci_conf[0x01] = 0x10; - pci_conf[0x02] = 0xFF; - pci_conf[0x03] = 0xFF; - pci_conf[0x0a] = 0x80; // PIC - pci_conf[0x0b] = 0x08; - pci_conf[0x0e] = 0x00; // header_type - pci_conf[0x3d] = 0x00; // no interrupt pin - - /* Register I/O spaces */ - pci_register_io_region((PCIDevice *)opp, 0, 0x40000, - PCI_ADDRESS_SPACE_MEM, &openpic_map); - } else { - opp = qemu_mallocz(sizeof(openpic_t)); - } - - opp->mem_index = cpu_register_io_memory(0, openpic_read, - openpic_write, opp); - - // isu_base &= 0xFFFC0000; - opp->nb_cpus = nb_cpus; - /* Set IRQ types */ - for (i = 0; i < EXT_IRQ; i++) { - opp->src[i].type = IRQ_EXTERNAL; - } - for (; i < IRQ_TIM0; i++) { - opp->src[i].type = IRQ_SPECIAL; - } -#if MAX_IPI > 0 - m = IRQ_IPI0; -#else - m = IRQ_DBL0; -#endif - for (; i < m; i++) { - opp->src[i].type = IRQ_TIMER; - } - for (; i < MAX_IRQ; i++) { - opp->src[i].type = IRQ_INTERNAL; - } - for (i = 0; i < nb_cpus; i++) - opp->dst[i].env = envp[i]; - openpic_reset(opp); - if (pmem_index) - *pmem_index = opp->mem_index; - return opp; -} diff --git a/hw/parallel.c b/hw/parallel.c deleted file mode 100644 index cba9561..0000000 --- a/hw/parallel.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * QEMU Parallel PORT emulation - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -//#define DEBUG_PARALLEL - -/* - * These are the definitions for the Printer Status Register - */ -#define PARA_STS_BUSY 0x80 /* Busy complement */ -#define PARA_STS_ACK 0x40 /* Acknowledge */ -#define PARA_STS_PAPER 0x20 /* Out of paper */ -#define PARA_STS_ONLINE 0x10 /* Online */ -#define PARA_STS_ERROR 0x08 /* Error complement */ - -/* - * These are the definitions for the Printer Control Register - */ -#define PARA_CTR_INTEN 0x10 /* IRQ Enable */ -#define PARA_CTR_SELECT 0x08 /* Select In complement */ -#define PARA_CTR_INIT 0x04 /* Initialize Printer complement */ -#define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */ -#define PARA_CTR_STROBE 0x01 /* Strobe complement */ - -struct ParallelState { - uint8_t data; - uint8_t status; /* read only register */ - uint8_t control; - int irq; - int irq_pending; - CharDriverState *chr; - int hw_driver; -}; - -static void parallel_update_irq(ParallelState *s) -{ - if (s->irq_pending) - pic_set_irq(s->irq, 1); - else - pic_set_irq(s->irq, 0); -} - -static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - ParallelState *s = opaque; - - addr &= 7; -#ifdef DEBUG_PARALLEL - printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val); -#endif - switch(addr) { - case 0: - if (s->hw_driver) { - s->data = val; - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &s->data); - } else { - s->data = val; - parallel_update_irq(s); - } - break; - case 2: - if (s->hw_driver) { - s->control = val; - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &s->control); - } else { - if ((val & PARA_CTR_INIT) == 0 ) { - s->status = PARA_STS_BUSY; - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_ONLINE; - s->status |= PARA_STS_ERROR; - } - else if (val & PARA_CTR_SELECT) { - if (val & PARA_CTR_STROBE) { - s->status &= ~PARA_STS_BUSY; - if ((s->control & PARA_CTR_STROBE) == 0) - qemu_chr_write(s->chr, &s->data, 1); - } else { - if (s->control & PARA_CTR_INTEN) { - s->irq_pending = 1; - } - } - } - parallel_update_irq(s); - s->control = val; - } - break; - } -} - -static uint32_t parallel_ioport_read(void *opaque, uint32_t addr) -{ - ParallelState *s = opaque; - uint32_t ret = 0xff; - - addr &= 7; - switch(addr) { - case 0: - if (s->hw_driver) { - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &s->data); - } - ret = s->data; - break; - case 1: - if (s->hw_driver) { - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &s->status); - ret = s->status; - } else { - ret = s->status; - s->irq_pending = 0; - if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { - /* XXX Fixme: wait 5 microseconds */ - if (s->status & PARA_STS_ACK) - s->status &= ~PARA_STS_ACK; - else { - /* XXX Fixme: wait 5 microseconds */ - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_BUSY; - } - } - parallel_update_irq(s); - } - break; - case 2: - if (s->hw_driver) { - qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &s->control); - } - ret = s->control; - break; - } -#ifdef DEBUG_PARALLEL - printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret); -#endif - return ret; -} - -/* If fd is zero, it means that the parallel device uses the console */ -ParallelState *parallel_init(int base, int irq, CharDriverState *chr) -{ - ParallelState *s; - uint8_t dummy; - - s = qemu_mallocz(sizeof(ParallelState)); - if (!s) - return NULL; - s->chr = chr; - s->hw_driver = 0; - if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) - s->hw_driver = 1; - - s->irq = irq; - s->data = 0; - s->status = PARA_STS_BUSY; - s->status |= PARA_STS_ACK; - s->status |= PARA_STS_ONLINE; - s->status |= PARA_STS_ERROR; - s->control = PARA_CTR_SELECT; - s->control |= PARA_CTR_INIT; - - register_ioport_write(base, 8, 1, parallel_ioport_write, s); - register_ioport_read(base, 8, 1, parallel_ioport_read, s); - return s; -} diff --git a/hw/pc.c b/hw/pc.c deleted file mode 100644 index 898d068..0000000 --- a/hw/pc.c +++ /dev/null @@ -1,911 +0,0 @@ -/* - * QEMU PC System Emulator - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* output Bochs bios info messages */ -//#define DEBUG_BIOS - -#define BIOS_FILENAME "bios.bin" -#define VGABIOS_FILENAME "vgabios.bin" -#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin" -#define LINUX_BOOT_FILENAME "linux_boot.bin" - -#define KERNEL_LOAD_ADDR 0x00100000 -#define INITRD_LOAD_ADDR 0x00600000 -#define KERNEL_PARAMS_ADDR 0x00090000 -#define KERNEL_CMDLINE_ADDR 0x00099000 - -static fdctrl_t *floppy_controller; -static RTCState *rtc_state; -static PITState *pit; -static IOAPICState *ioapic; - -static void ioport80_write(void *opaque, uint32_t addr, uint32_t data) -{ -} - -/* MSDOS compatibility mode FPU exception support */ -/* XXX: add IGNNE support */ -void cpu_set_ferr(CPUX86State *s) -{ - pic_set_irq(13, 1); -} - -static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data) -{ - pic_set_irq(13, 0); -} - -/* TSC handling */ -uint64_t cpu_get_tsc(CPUX86State *env) -{ - /* Note: when using kqemu, it is more logical to return the host TSC - because kqemu does not trap the RDTSC instruction for - performance reasons */ -#if USE_KQEMU - if (env->kqemu_enabled) { - return cpu_get_real_ticks(); - } else -#endif - { - return cpu_get_ticks(); - } -} - -/* IRQ handling */ -int cpu_get_pic_interrupt(CPUState *env) -{ - int intno; - - intno = apic_get_interrupt(env); - if (intno >= 0) { - /* set irq request if a PIC irq is still pending */ - /* XXX: improve that */ - pic_update_irq(isa_pic); - return intno; - } - /* read the irq from the PIC */ - intno = pic_read_irq(isa_pic); - return intno; -} - -static void pic_irq_request(void *opaque, int level) -{ - CPUState *env = opaque; - if (level) - cpu_interrupt(env, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(env, CPU_INTERRUPT_HARD); -} - -/* PC cmos mappings */ - -#define REG_EQUIPMENT_BYTE 0x14 -#define REG_IBM_CENTURY_BYTE 0x32 -#define REG_IBM_PS2_CENTURY_BYTE 0x37 - - -static inline int to_bcd(RTCState *s, int a) -{ - return ((a / 10) << 4) | (a % 10); -} - -static int cmos_get_fd_drive_type(int fd0) -{ - int val; - - switch (fd0) { - case 0: - /* 1.44 Mb 3"5 drive */ - val = 4; - break; - case 1: - /* 2.88 Mb 3"5 drive */ - val = 5; - break; - case 2: - /* 1.2 Mb 5"5 drive */ - val = 2; - break; - default: - val = 0; - break; - } - return val; -} - -static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd) -{ - RTCState *s = rtc_state; - int cylinders, heads, sectors; - bdrv_get_geometry_hint(hd, &cylinders, &heads, §ors); - rtc_set_memory(s, type_ofs, 47); - rtc_set_memory(s, info_ofs, cylinders); - rtc_set_memory(s, info_ofs + 1, cylinders >> 8); - rtc_set_memory(s, info_ofs + 2, heads); - rtc_set_memory(s, info_ofs + 3, 0xff); - rtc_set_memory(s, info_ofs + 4, 0xff); - rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3)); - rtc_set_memory(s, info_ofs + 6, cylinders); - rtc_set_memory(s, info_ofs + 7, cylinders >> 8); - rtc_set_memory(s, info_ofs + 8, sectors); -} - -/* hd_table must contain 4 block drivers */ -static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table) -{ - RTCState *s = rtc_state; - int val; - int fd0, fd1, nb; - time_t ti; - struct tm *tm; - int i; - - /* set the CMOS date */ - time(&ti); - if (rtc_utc) - tm = gmtime(&ti); - else - tm = localtime(&ti); - rtc_set_date(s, tm); - - val = to_bcd(s, (tm->tm_year / 100) + 19); - rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val); - rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val); - - /* various important CMOS locations needed by PC/Bochs bios */ - - /* memory size */ - val = 640; /* base memory in K */ - rtc_set_memory(s, 0x15, val); - rtc_set_memory(s, 0x16, val >> 8); - - val = (ram_size / 1024) - 1024; - if (val > 65535) - val = 65535; - rtc_set_memory(s, 0x17, val); - rtc_set_memory(s, 0x18, val >> 8); - rtc_set_memory(s, 0x30, val); - rtc_set_memory(s, 0x31, val >> 8); - - if (ram_size > (16 * 1024 * 1024)) - val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); - else - val = 0; - if (val > 65535) - val = 65535; - rtc_set_memory(s, 0x34, val); - rtc_set_memory(s, 0x35, val >> 8); - - switch(boot_device) { - case 'a': - case 'b': - rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */ - if (!fd_bootchk) - rtc_set_memory(s, 0x38, 0x01); /* disable signature check */ - break; - default: - case 'c': - rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */ - break; - case 'd': - rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */ - break; - } - - /* floppy type */ - - fd0 = fdctrl_get_drive_type(floppy_controller, 0); - fd1 = fdctrl_get_drive_type(floppy_controller, 1); - - val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1); - rtc_set_memory(s, 0x10, val); - - val = 0; - nb = 0; - if (fd0 < 3) - nb++; - if (fd1 < 3) - nb++; - switch (nb) { - case 0: - break; - case 1: - val |= 0x01; /* 1 drive, ready for boot */ - break; - case 2: - val |= 0x41; /* 2 drives, ready for boot */ - break; - } - val |= 0x02; /* FPU is there */ - val |= 0x04; /* PS/2 mouse installed */ - rtc_set_memory(s, REG_EQUIPMENT_BYTE, val); - - /* hard drives */ - - rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0)); - if (hd_table[0]) - cmos_init_hd(0x19, 0x1b, hd_table[0]); - if (hd_table[1]) - cmos_init_hd(0x1a, 0x24, hd_table[1]); - - val = 0; - for (i = 0; i < 4; i++) { - if (hd_table[i]) { - int cylinders, heads, sectors, translation; - /* NOTE: bdrv_get_geometry_hint() returns the physical - geometry. It is always such that: 1 <= sects <= 63, 1 - <= heads <= 16, 1 <= cylinders <= 16383. The BIOS - geometry can be different if a translation is done. */ - translation = bdrv_get_translation_hint(hd_table[i]); - if (translation == BIOS_ATA_TRANSLATION_AUTO) { - bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, §ors); - if (cylinders <= 1024 && heads <= 16 && sectors <= 63) { - /* No translation. */ - translation = 0; - } else { - /* LBA translation. */ - translation = 1; - } - } else { - translation--; - } - val |= translation << (i * 2); - } - } - rtc_set_memory(s, 0x39, val); -} - -void ioport_set_a20(int enable) -{ - /* XXX: send to all CPUs ? */ - cpu_x86_set_a20(first_cpu, enable); -} - -int ioport_get_a20(void) -{ - return ((first_cpu->a20_mask >> 20) & 1); -} - -static void ioport92_write(void *opaque, uint32_t addr, uint32_t val) -{ - ioport_set_a20((val >> 1) & 1); - /* XXX: bit 0 is fast reset */ -} - -static uint32_t ioport92_read(void *opaque, uint32_t addr) -{ - return ioport_get_a20() << 1; -} - -/***********************************************************/ -/* Bochs BIOS debug ports */ - -void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val) -{ - static const char shutdown_str[8] = "Shutdown"; - static int shutdown_index = 0; - - switch(addr) { - /* Bochs BIOS messages */ - case 0x400: - case 0x401: - fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); - exit(1); - case 0x402: - case 0x403: -#ifdef DEBUG_BIOS - fprintf(stderr, "%c", val); -#endif - break; - case 0x8900: - /* same as Bochs power off */ - if (val == shutdown_str[shutdown_index]) { - shutdown_index++; - if (shutdown_index == 8) { - shutdown_index = 0; - qemu_system_shutdown_request(); - } - } else { - shutdown_index = 0; - } - break; - - /* LGPL'ed VGA BIOS messages */ - case 0x501: - case 0x502: - fprintf(stderr, "VGA BIOS panic, line %d\n", val); - exit(1); - case 0x500: - case 0x503: -#ifdef DEBUG_BIOS - fprintf(stderr, "%c", val); -#endif - break; - } -} - -void bochs_bios_init(void) -{ - register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL); - register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL); - register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL); - register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL); - register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL); - - register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL); - register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL); - register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL); - register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL); -} - - -int load_kernel(const char *filename, uint8_t *addr, - uint8_t *real_addr) -{ - int fd, size; - int setup_sects; - - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - return -1; - - /* load 16 bit code */ - if (read(fd, real_addr, 512) != 512) - goto fail; - setup_sects = real_addr[0x1F1]; - if (!setup_sects) - setup_sects = 4; - if (read(fd, real_addr + 512, setup_sects * 512) != - setup_sects * 512) - goto fail; - - /* load 32 bit code */ - size = read(fd, addr, 16 * 1024 * 1024); - if (size < 0) - goto fail; - close(fd); - return size; - fail: - close(fd); - return -1; -} - -static void main_cpu_reset(void *opaque) -{ - CPUState *env = opaque; - cpu_reset(env); -} - -/*************************************************/ - -static void putb(uint8_t **pp, int val) -{ - uint8_t *q; - q = *pp; - *q++ = val; - *pp = q; -} - -static void putstr(uint8_t **pp, const char *str) -{ - uint8_t *q; - q = *pp; - while (*str) - *q++ = *str++; - *pp = q; -} - -static void putle16(uint8_t **pp, int val) -{ - uint8_t *q; - q = *pp; - *q++ = val; - *q++ = val >> 8; - *pp = q; -} - -static void putle32(uint8_t **pp, int val) -{ - uint8_t *q; - q = *pp; - *q++ = val; - *q++ = val >> 8; - *q++ = val >> 16; - *q++ = val >> 24; - *pp = q; -} - -static int mpf_checksum(const uint8_t *data, int len) -{ - int sum, i; - sum = 0; - for(i = 0; i < len; i++) - sum += data[i]; - return sum & 0xff; -} - -/* Build the Multi Processor table in the BIOS. Same values as Bochs. */ -static void bios_add_mptable(uint8_t *bios_data) -{ - uint8_t *mp_config_table, *q, *float_pointer_struct; - int ioapic_id, offset, i, len; - - if (smp_cpus <= 1) - return; - - mp_config_table = bios_data + 0xb000; - q = mp_config_table; - putstr(&q, "PCMP"); /* "PCMP signature */ - putle16(&q, 0); /* table length (patched later) */ - putb(&q, 4); /* spec rev */ - putb(&q, 0); /* checksum (patched later) */ - putstr(&q, "QEMUCPU "); /* OEM id */ - putstr(&q, "0.1 "); /* vendor id */ - putle32(&q, 0); /* OEM table ptr */ - putle16(&q, 0); /* OEM table size */ - putle16(&q, 20); /* entry count */ - putle32(&q, 0xfee00000); /* local APIC addr */ - putle16(&q, 0); /* ext table length */ - putb(&q, 0); /* ext table checksum */ - putb(&q, 0); /* reserved */ - - for(i = 0; i < smp_cpus; i++) { - putb(&q, 0); /* entry type = processor */ - putb(&q, i); /* APIC id */ - putb(&q, 0x11); /* local APIC version number */ - if (i == 0) - putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */ - else - putb(&q, 1); /* cpu flags: enabled */ - putb(&q, 0); /* cpu signature */ - putb(&q, 6); - putb(&q, 0); - putb(&q, 0); - putle16(&q, 0x201); /* feature flags */ - putle16(&q, 0); - - putle16(&q, 0); /* reserved */ - putle16(&q, 0); - putle16(&q, 0); - putle16(&q, 0); - } - - /* isa bus */ - putb(&q, 1); /* entry type = bus */ - putb(&q, 0); /* bus ID */ - putstr(&q, "ISA "); - - /* ioapic */ - ioapic_id = smp_cpus; - putb(&q, 2); /* entry type = I/O APIC */ - putb(&q, ioapic_id); /* apic ID */ - putb(&q, 0x11); /* I/O APIC version number */ - putb(&q, 1); /* enable */ - putle32(&q, 0xfec00000); /* I/O APIC addr */ - - /* irqs */ - for(i = 0; i < 16; i++) { - putb(&q, 3); /* entry type = I/O interrupt */ - putb(&q, 0); /* interrupt type = vectored interrupt */ - putb(&q, 0); /* flags: po=0, el=0 */ - putb(&q, 0); - putb(&q, 0); /* source bus ID = ISA */ - putb(&q, i); /* source bus IRQ */ - putb(&q, ioapic_id); /* dest I/O APIC ID */ - putb(&q, i); /* dest I/O APIC interrupt in */ - } - /* patch length */ - len = q - mp_config_table; - mp_config_table[4] = len; - mp_config_table[5] = len >> 8; - - mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table); - - /* align to 16 */ - offset = q - bios_data; - offset = (offset + 15) & ~15; - float_pointer_struct = bios_data + offset; - - /* floating pointer structure */ - q = float_pointer_struct; - putstr(&q, "_MP_"); - /* pointer to MP config table */ - putle32(&q, mp_config_table - bios_data + 0x000f0000); - - putb(&q, 1); /* length in 16 byte units */ - putb(&q, 4); /* MP spec revision */ - putb(&q, 0); /* checksum (patched later) */ - putb(&q, 0); /* MP feature byte 1 */ - - putb(&q, 0); - putb(&q, 0); - putb(&q, 0); - putb(&q, 0); - float_pointer_struct[10] = - -mpf_checksum(float_pointer_struct, q - float_pointer_struct); -} - - -static const int ide_iobase[2] = { 0x1f0, 0x170 }; -static const int ide_iobase2[2] = { 0x3f6, 0x376 }; -static const int ide_irq[2] = { 14, 15 }; - -#define NE2000_NB_MAX 6 - -static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; -static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; - -static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; -static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; - -static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; -static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; - -#ifdef HAS_AUDIO -static void audio_init (PCIBus *pci_bus) -{ - struct soundhw *c; - int audio_enabled = 0; - - for (c = soundhw; !audio_enabled && c->name; ++c) { - audio_enabled = c->enabled; - } - - if (audio_enabled) { - AudioState *s; - - s = AUD_init (); - if (s) { - for (c = soundhw; c->name; ++c) { - if (c->enabled) { - if (c->isa) { - c->init.init_isa (s); - } - else { - if (pci_bus) { - c->init.init_pci (pci_bus, s); - } - } - } - } - } - } -} -#endif - -static void pc_init_ne2k_isa(NICInfo *nd) -{ - static int nb_ne2k = 0; - - if (nb_ne2k == NE2000_NB_MAX) - return; - isa_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd); - nb_ne2k++; -} - -/* PC hardware initialisation */ -static void pc_init1(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, - int pci_enabled) -{ - char buf[1024]; - int ret, linux_boot, initrd_size, i; - unsigned long bios_offset, vga_bios_offset; - int bios_size, isa_bios_size; - PCIBus *pci_bus; - int piix3_devfn = -1; - CPUState *env; - NICInfo *nd; - - linux_boot = (kernel_filename != NULL); - - /* init CPUs */ - for(i = 0; i < smp_cpus; i++) { - env = cpu_init(); - if (i != 0) - env->hflags |= HF_HALTED_MASK; - if (smp_cpus > 1) { - /* XXX: enable it in all cases */ - env->cpuid_features |= CPUID_APIC; - } - register_savevm("cpu", i, 3, cpu_save, cpu_load, env); - qemu_register_reset(main_cpu_reset, env); - if (pci_enabled) { - apic_init(env); - } - } - - /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, 0); - - /* BIOS load */ - bios_offset = ram_size + vga_ram_size; - vga_bios_offset = bios_offset + 256 * 1024; - - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - bios_size = get_image_size(buf); - if (bios_size <= 0 || - (bios_size % 65536) != 0 || - bios_size > (256 * 1024)) { - goto bios_error; - } - ret = load_image(buf, phys_ram_base + bios_offset); - if (ret != bios_size) { - bios_error: - fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); - exit(1); - } - if (bios_size == 65536) { - bios_add_mptable(phys_ram_base + bios_offset); - } - - /* VGA BIOS load */ - if (cirrus_vga_enabled) { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME); - } else { - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); - } - ret = load_image(buf, phys_ram_base + vga_bios_offset); - - /* setup basic memory access */ - cpu_register_physical_memory(0xc0000, 0x10000, - vga_bios_offset | IO_MEM_ROM); - - /* map the last 128KB of the BIOS in ISA space */ - isa_bios_size = bios_size; - if (isa_bios_size > (128 * 1024)) - isa_bios_size = 128 * 1024; - cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, - IO_MEM_UNASSIGNED); - cpu_register_physical_memory(0x100000 - isa_bios_size, - isa_bios_size, - (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); - /* map all the bios at the top of memory */ - cpu_register_physical_memory((uint32_t)(-bios_size), - bios_size, bios_offset | IO_MEM_ROM); - - bochs_bios_init(); - - if (linux_boot) { - uint8_t bootsect[512]; - uint8_t old_bootsect[512]; - - if (bs_table[0] == NULL) { - fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); - exit(1); - } - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME); - ret = load_image(buf, bootsect); - if (ret != sizeof(bootsect)) { - fprintf(stderr, "qemu: could not load linux boot sector '%s'\n", - buf); - exit(1); - } - - if (bdrv_read(bs_table[0], 0, old_bootsect, 1) >= 0) { - /* copy the MSDOS partition table */ - memcpy(bootsect + 0x1be, old_bootsect + 0x1be, 0x40); - } - - bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); - - /* now we can load the kernel */ - ret = load_kernel(kernel_filename, - phys_ram_base + KERNEL_LOAD_ADDR, - phys_ram_base + KERNEL_PARAMS_ADDR); - if (ret < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - if (initrd_filename) { - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } - if (initrd_size > 0) { - stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR); - stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); - } - pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, - kernel_cmdline); - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F); - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22, - KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR); - /* loader type */ - stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); - } - - if (pci_enabled) { - pci_bus = i440fx_init(); - piix3_devfn = piix3_init(pci_bus); - } else { - pci_bus = NULL; - } - - /* init basic PC hardware */ - register_ioport_write(0x80, 1, 1, ioport80_write, NULL); - - register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); - - if (cirrus_vga_enabled) { - if (pci_enabled) { - pci_cirrus_vga_init(pci_bus, - ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); - } else { - isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size, - vga_ram_size); - } - } else { - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0, 0); - } - - rtc_state = rtc_init(0x70, 8); - - register_ioport_read(0x92, 1, 1, ioport92_read, NULL); - register_ioport_write(0x92, 1, 1, ioport92_write, NULL); - - if (pci_enabled) { - ioapic = ioapic_init(); - } - isa_pic = pic_init(pic_irq_request, first_cpu); - pit = pit_init(0x40, 0); - pcspk_init(pit); - if (pci_enabled) { - pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); - } - - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_init(&pic_set_irq_new, isa_pic, - serial_io[i], serial_irq[i], serial_hds[i]); - } - } - - for(i = 0; i < MAX_PARALLEL_PORTS; i++) { - if (parallel_hds[i]) { - parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]); - } - } - - for(i = 0; i < nb_nics; i++) { - nd = &nd_table[i]; - if (!nd->model) { - if (pci_enabled) { - nd->model = "ne2k_pci"; - } else { - nd->model = "ne2k_isa"; - } - } - if (strcmp(nd->model, "ne2k_isa") == 0) { - pc_init_ne2k_isa(nd); - } else if (pci_enabled) { - pci_nic_init(pci_bus, nd); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); - exit(1); - } - } - - if (pci_enabled) { - pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1); - } else { - for(i = 0; i < 2; i++) { - isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], - bs_table[2 * i], bs_table[2 * i + 1]); - } - } - - kbd_init(); - DMA_init(0); -#ifdef HAS_AUDIO - audio_init(pci_enabled ? pci_bus : NULL); -#endif - - floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); - - cmos_init(ram_size, boot_device, bs_table); - - if (pci_enabled && usb_enabled) { - usb_uhci_init(pci_bus, piix3_devfn + 2); - } - - if (pci_enabled && acpi_enabled) { - piix4_pm_init(pci_bus, piix3_devfn + 3); - } - -#if 0 - /* ??? Need to figure out some way for the user to - specify SCSI devices. */ - if (pci_enabled) { - void *scsi; - BlockDriverState *bdrv; - - scsi = lsi_scsi_init(pci_bus, -1); - bdrv = bdrv_new("scsidisk"); - bdrv_open(bdrv, "scsi_disk.img", 0); - lsi_scsi_attach(scsi, bdrv, -1); - bdrv = bdrv_new("scsicd"); - bdrv_open(bdrv, "scsi_cd.iso", 0); - bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM); - lsi_scsi_attach(scsi, bdrv, -1); - } -#endif - /* must be done after all PCI devices are instanciated */ - /* XXX: should be done in the Bochs BIOS */ - if (pci_enabled) { - pci_bios_init(); - if (acpi_enabled) - acpi_bios_init(); - } -} - -static void pc_init_pci(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename) -{ - pc_init1(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, - initrd_filename, 1); -} - -static void pc_init_isa(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename) -{ - pc_init1(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, - initrd_filename, 0); -} - -QEMUMachine pc_machine = { - "pc", - "Standard PC", - pc_init_pci, -}; - -QEMUMachine isapc_machine = { - "isapc", - "ISA-only PC", - pc_init_isa, -}; @@ -2,7 +2,7 @@ * QEMU PCI bus manager * * Copyright (c) 2004 Fabrice Bellard - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -75,16 +75,16 @@ int generic_pci_load(QEMUFile* f, void *opaque, int version_id) } /* -1 for devfn means auto assign */ -PCIDevice *pci_register_device(PCIBus *bus, const char *name, +PCIDevice *pci_register_device(PCIBus *bus, const char *name, int instance_size, int devfn, - PCIConfigReadFunc *config_read, + PCIConfigReadFunc *config_read, PCIConfigWriteFunc *config_write) { PCIDevice *pci_dev; if (pci_irq_index >= PCI_DEVICES_MAX) return NULL; - + if (devfn < 0) { for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) { if (!bus->devices[devfn]) @@ -111,8 +111,8 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name, return pci_dev; } -void pci_register_io_region(PCIDevice *pci_dev, int region_num, - uint32_t size, int type, +void pci_register_io_region(PCIDevice *pci_dev, int region_num, + uint32_t size, int type, PCIMapIORegionFunc *map_func) { PCIIORegion *r; @@ -143,7 +143,7 @@ static void pci_update_mappings(PCIDevice *d) PCIIORegion *r; int cmd, i; uint32_t last_addr, new_addr, config_ofs; - + cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND)); for(i = 0; i < PCI_NUM_REGIONS; i++) { r = &d->io_regions[i]; @@ -155,7 +155,7 @@ static void pci_update_mappings(PCIDevice *d) if (r->size != 0) { if (r->type & PCI_ADDRESS_SPACE_IO) { if (cmd & PCI_COMMAND_IO) { - new_addr = le32_to_cpu(*(uint32_t *)(d->config + + new_addr = le32_to_cpu(*(uint32_t *)(d->config + config_ofs)); new_addr = new_addr & ~(r->size - 1); last_addr = new_addr + r->size - 1; @@ -169,7 +169,7 @@ static void pci_update_mappings(PCIDevice *d) } } else { if (cmd & PCI_COMMAND_MEMORY) { - new_addr = le32_to_cpu(*(uint32_t *)(d->config + + new_addr = le32_to_cpu(*(uint32_t *)(d->config + config_ofs)); /* the ROM slot has a specific enable bit */ if (i == PCI_ROM_SLOT && !(new_addr & 1)) @@ -204,7 +204,7 @@ static void pci_update_mappings(PCIDevice *d) } } else { cpu_register_physical_memory(pci_to_cpu_addr(r->addr), - r->size, + r->size, IO_MEM_UNASSIGNED); } } @@ -217,7 +217,7 @@ static void pci_update_mappings(PCIDevice *d) } } -uint32_t pci_default_read_config(PCIDevice *d, +uint32_t pci_default_read_config(PCIDevice *d, uint32_t address, int len) { uint32_t val; @@ -236,13 +236,13 @@ uint32_t pci_default_read_config(PCIDevice *d, return val; } -void pci_default_write_config(PCIDevice *d, +void pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, int len) { int can_write, i; uint32_t end, addr; - if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || + if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || (address >= 0x30 && address < 0x34))) { PCIIORegion *r; int reg; @@ -336,7 +336,7 @@ void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len) PCIBus *s = opaque; PCIDevice *pci_dev; int config_addr, bus_num; - + #if defined(DEBUG_PCI) && 0 printf("pci_data_write: addr=%08x val=%08x len=%d\n", addr, val, len); @@ -414,7 +414,7 @@ typedef struct { const char *desc; } pci_class_desc; -static pci_class_desc pci_class_descriptions[] = +static pci_class_desc pci_class_descriptions[] = { { 0x0101, "IDE controller"}, { 0x0200, "Ethernet controller"}, @@ -456,10 +456,10 @@ static void pci_info_device(PCIDevice *d) if (r->size != 0) { term_printf(" BAR%d: ", i); if (r->type & PCI_ADDRESS_SPACE_IO) { - term_printf("I/O at 0x%04x [0x%04x].\n", + term_printf("I/O at 0x%04x [0x%04x].\n", r->addr, r->addr + r->size - 1); } else { - term_printf("32 bit memory at 0x%08x [0x%08x].\n", + term_printf("32 bit memory at 0x%08x [0x%08x].\n", r->addr, r->addr + r->size - 1); } } @@ -471,7 +471,7 @@ void pci_for_each_device(void (*fn)(PCIDevice *d)) PCIBus *bus = first_bus; PCIDevice *d; int devfn; - + if (bus) { for(devfn = 0; devfn < 256; devfn++) { d = bus->devices[devfn]; @@ -489,6 +489,7 @@ void pci_info(void) /* Initialize a PCI NIC. */ void pci_nic_init(PCIBus *bus, NICInfo *nd) { +#if 0 /* ANDROID */ if (strcmp(nd->model, "ne2k_pci") == 0) { pci_ne2000_init(bus, nd); } else if (strcmp(nd->model, "rtl8139") == 0) { @@ -496,6 +497,9 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd) } else if (strcmp(nd->model, "pcnet") == 0) { pci_pcnet_init(bus, nd); } else { +#else + { +#endif fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model); exit (1); } diff --git a/hw/pckbd.c b/hw/pckbd.c deleted file mode 100644 index 3c41e5f..0000000 --- a/hw/pckbd.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * QEMU PC keyboard emulation - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* debug PC keyboard */ -//#define DEBUG_KBD - -/* debug PC keyboard : only mouse */ -//#define DEBUG_MOUSE - -/* Keyboard Controller Commands */ -#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ -#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ -#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ -#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ -#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ -#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ -#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ -#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ -#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ -#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ -#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ -#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ -#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ -#define KBD_CCMD_WRITE_OBUF 0xD2 -#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if - initiated by the auxiliary device */ -#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ -#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */ -#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */ -#define KBD_CCMD_RESET 0xFE - -/* Keyboard Commands */ -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ -#define KBD_CMD_ECHO 0xEE -#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ -#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ -#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ -#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ -#define KBD_CMD_RESET 0xFF /* Reset */ - -/* Keyboard Replies */ -#define KBD_REPLY_POR 0xAA /* Power on reset */ -#define KBD_REPLY_ACK 0xFA /* Command ACK */ -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ - -/* Status Register Bits */ -#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ -#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ -#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ -#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ -#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ -#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ -#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ -#define KBD_STAT_PERR 0x80 /* Parity error */ - -/* Controller Mode Register Bits */ -#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ -#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ -#define KBD_MODE_SYS 0x04 /* The system flag (?) */ -#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ -#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ -#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ -#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ -#define KBD_MODE_RFU 0x80 - -/* Mouse Commands */ -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ -#define AUX_SET_RES 0xE8 /* Set resolution */ -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ -#define AUX_SET_STREAM 0xEA /* Set stream mode */ -#define AUX_POLL 0xEB /* Poll */ -#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ -#define AUX_SET_WRAP 0xEE /* Set wrap mode */ -#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ -#define AUX_GET_TYPE 0xF2 /* Get type */ -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ -#define AUX_SET_DEFAULT 0xF6 -#define AUX_RESET 0xFF /* Reset aux device */ -#define AUX_ACK 0xFA /* Command byte ACK. */ - -#define MOUSE_STATUS_REMOTE 0x40 -#define MOUSE_STATUS_ENABLED 0x20 -#define MOUSE_STATUS_SCALE21 0x10 - -#define KBD_QUEUE_SIZE 256 - -#define KBD_PENDING_KBD 1 -#define KBD_PENDING_AUX 2 - -typedef struct KBDState { - uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ - uint8_t status; - uint8_t mode; - /* Bitmask of devices with data available. */ - uint8_t pending; - void *kbd; - void *mouse; -} KBDState; - -KBDState kbd_state; - -/* update irq and KBD_STAT_[MOUSE_]OBF */ -/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be - incorrect, but it avoids having to simulate exact delays */ -static void kbd_update_irq(KBDState *s) -{ - int irq12_level, irq1_level; - - irq1_level = 0; - irq12_level = 0; - s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); - if (s->pending) { - s->status |= KBD_STAT_OBF; - /* kdb data takes priority over aux data. */ - if (s->pending == KBD_PENDING_AUX) { - s->status |= KBD_STAT_MOUSE_OBF; - if (s->mode & KBD_MODE_MOUSE_INT) - irq12_level = 1; - } else { - if ((s->mode & KBD_MODE_KBD_INT) && - !(s->mode & KBD_MODE_DISABLE_KBD)) - irq1_level = 1; - } - } - pic_set_irq(1, irq1_level); - pic_set_irq(12, irq12_level); -} - -static void kbd_update_kbd_irq(void *opaque, int level) -{ - KBDState *s = (KBDState *)opaque; - - if (level) - s->pending |= KBD_PENDING_KBD; - else - s->pending &= ~KBD_PENDING_KBD; - kbd_update_irq(s); -} - -static void kbd_update_aux_irq(void *opaque, int level) -{ - KBDState *s = (KBDState *)opaque; - - if (level) - s->pending |= KBD_PENDING_AUX; - else - s->pending &= ~KBD_PENDING_AUX; - kbd_update_irq(s); -} - -static uint32_t kbd_read_status(void *opaque, uint32_t addr) -{ - KBDState *s = opaque; - int val; - val = s->status; -#if defined(DEBUG_KBD) - printf("kbd: read status=0x%02x\n", val); -#endif - return val; -} - -static void kbd_queue(KBDState *s, int b, int aux) -{ - if (aux) - ps2_queue(s->mouse, b); - else - ps2_queue(s->kbd, b); -} - -static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) -{ - KBDState *s = opaque; - -#ifdef DEBUG_KBD - printf("kbd: write cmd=0x%02x\n", val); -#endif - switch(val) { - case KBD_CCMD_READ_MODE: - kbd_queue(s, s->mode, 0); - break; - case KBD_CCMD_WRITE_MODE: - case KBD_CCMD_WRITE_OBUF: - case KBD_CCMD_WRITE_AUX_OBUF: - case KBD_CCMD_WRITE_MOUSE: - case KBD_CCMD_WRITE_OUTPORT: - s->write_cmd = val; - break; - case KBD_CCMD_MOUSE_DISABLE: - s->mode |= KBD_MODE_DISABLE_MOUSE; - break; - case KBD_CCMD_MOUSE_ENABLE: - s->mode &= ~KBD_MODE_DISABLE_MOUSE; - break; - case KBD_CCMD_TEST_MOUSE: - kbd_queue(s, 0x00, 0); - break; - case KBD_CCMD_SELF_TEST: - s->status |= KBD_STAT_SELFTEST; - kbd_queue(s, 0x55, 0); - break; - case KBD_CCMD_KBD_TEST: - kbd_queue(s, 0x00, 0); - break; - case KBD_CCMD_KBD_DISABLE: - s->mode |= KBD_MODE_DISABLE_KBD; - kbd_update_irq(s); - break; - case KBD_CCMD_KBD_ENABLE: - s->mode &= ~KBD_MODE_DISABLE_KBD; - kbd_update_irq(s); - break; - case KBD_CCMD_READ_INPORT: - kbd_queue(s, 0x00, 0); - break; - case KBD_CCMD_READ_OUTPORT: - /* XXX: check that */ -#ifdef TARGET_I386 - val = 0x01 | (ioport_get_a20() << 1); -#else - val = 0x01; -#endif - if (s->status & KBD_STAT_OBF) - val |= 0x10; - if (s->status & KBD_STAT_MOUSE_OBF) - val |= 0x20; - kbd_queue(s, val, 0); - break; -#ifdef TARGET_I386 - case KBD_CCMD_ENABLE_A20: - ioport_set_a20(1); - break; - case KBD_CCMD_DISABLE_A20: - ioport_set_a20(0); - break; -#endif - case KBD_CCMD_RESET: - qemu_system_reset_request(); - break; - case 0xff: - /* ignore that - I don't know what is its use */ - break; - default: - fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); - break; - } -} - -static uint32_t kbd_read_data(void *opaque, uint32_t addr) -{ - KBDState *s = opaque; - - if (s->pending == KBD_PENDING_AUX) - return ps2_read_data(s->mouse); - - return ps2_read_data(s->kbd); -} - -void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) -{ - KBDState *s = opaque; - -#ifdef DEBUG_KBD - printf("kbd: write data=0x%02x\n", val); -#endif - - switch(s->write_cmd) { - case 0: - ps2_write_keyboard(s->kbd, val); - break; - case KBD_CCMD_WRITE_MODE: - s->mode = val; - ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0); - /* ??? */ - kbd_update_irq(s); - break; - case KBD_CCMD_WRITE_OBUF: - kbd_queue(s, val, 0); - break; - case KBD_CCMD_WRITE_AUX_OBUF: - kbd_queue(s, val, 1); - break; - case KBD_CCMD_WRITE_OUTPORT: -#ifdef TARGET_I386 - ioport_set_a20((val >> 1) & 1); -#endif - if (!(val & 1)) { - qemu_system_reset_request(); - } - break; - case KBD_CCMD_WRITE_MOUSE: - ps2_write_mouse(s->mouse, val); - break; - default: - break; - } - s->write_cmd = 0; -} - -static void kbd_reset(void *opaque) -{ - KBDState *s = opaque; - - s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; - s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; -} - -static void kbd_save(QEMUFile* f, void* opaque) -{ - KBDState *s = (KBDState*)opaque; - - qemu_put_8s(f, &s->write_cmd); - qemu_put_8s(f, &s->status); - qemu_put_8s(f, &s->mode); - qemu_put_8s(f, &s->pending); -} - -static int kbd_load(QEMUFile* f, void* opaque, int version_id) -{ - KBDState *s = (KBDState*)opaque; - - if (version_id != 3) - return -EINVAL; - qemu_get_8s(f, &s->write_cmd); - qemu_get_8s(f, &s->status); - qemu_get_8s(f, &s->mode); - qemu_get_8s(f, &s->pending); - return 0; -} - -void kbd_init(void) -{ - KBDState *s = &kbd_state; - - kbd_reset(s); - register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s); - register_ioport_read(0x60, 1, 1, kbd_read_data, s); - register_ioport_write(0x60, 1, 1, kbd_write_data, s); - register_ioport_read(0x64, 1, 1, kbd_read_status, s); - register_ioport_write(0x64, 1, 1, kbd_write_command, s); - - s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); - s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); - qemu_register_reset(kbd_reset, s); -} diff --git a/hw/pcnet.c b/hw/pcnet.c deleted file mode 100644 index 0845cdc..0000000 --- a/hw/pcnet.c +++ /dev/null @@ -1,1789 +0,0 @@ -/* - * QEMU AMD PC-Net II (Am79C970A) emulation - * - * Copyright (c) 2004 Antony T Curtis - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* This software was written to be compatible with the specification: - * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet - * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 - */ - -#include "vl.h" - -//#define PCNET_DEBUG -//#define PCNET_DEBUG_IO -//#define PCNET_DEBUG_BCR -//#define PCNET_DEBUG_CSR -//#define PCNET_DEBUG_RMD -//#define PCNET_DEBUG_TMD -//#define PCNET_DEBUG_MATCH - - -#define PCNET_IOPORT_SIZE 0x20 -#define PCNET_PNPMMIO_SIZE 0x20 - - -typedef struct PCNetState_st PCNetState; - -struct PCNetState_st { - PCIDevice dev; - VLANClientState *vc; - NICInfo *nd; - QEMUTimer *poll_timer; - int mmio_io_addr, rap, isr, lnkst; - target_phys_addr_t rdra, tdra; - uint8_t prom[16]; - uint16_t csr[128]; - uint16_t bcr[32]; - uint64_t timer; - int xmit_pos, recv_pos; - uint8_t buffer[4096]; - int tx_busy; -}; - -/* XXX: using bitfields for target memory structures is almost surely - not portable, so it should be suppressed ASAP */ -#ifdef __GNUC__ -#define PACKED_FIELD(A) A __attribute__ ((packed)) -#else -#error FixMe -#endif - -struct qemu_ether_header { - uint8_t ether_dhost[6]; - uint8_t ether_shost[6]; - uint16_t ether_type; -}; - -/* BUS CONFIGURATION REGISTERS */ -#define BCR_MSRDA 0 -#define BCR_MSWRA 1 -#define BCR_MC 2 -#define BCR_LNKST 4 -#define BCR_LED1 5 -#define BCR_LED2 6 -#define BCR_LED3 7 -#define BCR_FDC 9 -#define BCR_BSBC 18 -#define BCR_EECAS 19 -#define BCR_SWS 20 -#define BCR_PLAT 22 - -#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080) -#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100) -#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF) - -#define CSR_INIT(S) !!(((S)->csr[0])&0x0001) -#define CSR_STRT(S) !!(((S)->csr[0])&0x0002) -#define CSR_STOP(S) !!(((S)->csr[0])&0x0004) -#define CSR_TDMD(S) !!(((S)->csr[0])&0x0008) -#define CSR_TXON(S) !!(((S)->csr[0])&0x0010) -#define CSR_RXON(S) !!(((S)->csr[0])&0x0020) -#define CSR_INEA(S) !!(((S)->csr[0])&0x0040) -#define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020) -#define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040) -#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800) -#define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000) -#define CSR_SPND(S) !!(((S)->csr[5])&0x0001) -#define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000) -#define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000) -#define CSR_DRX(S) !!(((S)->csr[15])&0x0001) -#define CSR_DTX(S) !!(((S)->csr[15])&0x0002) -#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004) -#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000) -#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000) -#define CSR_PROM(S) !!(((S)->csr[15])&0x8000) - -#define CSR_CRBC(S) ((S)->csr[40]) -#define CSR_CRST(S) ((S)->csr[41]) -#define CSR_CXBC(S) ((S)->csr[42]) -#define CSR_CXST(S) ((S)->csr[43]) -#define CSR_NRBC(S) ((S)->csr[44]) -#define CSR_NRST(S) ((S)->csr[45]) -#define CSR_POLL(S) ((S)->csr[46]) -#define CSR_PINT(S) ((S)->csr[47]) -#define CSR_RCVRC(S) ((S)->csr[72]) -#define CSR_XMTRC(S) ((S)->csr[74]) -#define CSR_RCVRL(S) ((S)->csr[76]) -#define CSR_XMTRL(S) ((S)->csr[78]) -#define CSR_MISSC(S) ((S)->csr[112]) - -#define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16)) -#define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16)) -#define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16)) -#define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16)) -#define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16)) -#define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16)) -#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16)) -#define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16)) -#define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16)) -#define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16)) -#define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16)) -#define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16)) -#define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16)) -#define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16)) - -#define PHYSADDR(S,A) \ - (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16)) - -struct pcnet_initblk16 { - uint16_t mode; - uint16_t padr1; - uint16_t padr2; - uint16_t padr3; - uint16_t ladrf1; - uint16_t ladrf2; - uint16_t ladrf3; - uint16_t ladrf4; - unsigned PACKED_FIELD(rdra:24); - unsigned PACKED_FIELD(res1:5); - unsigned PACKED_FIELD(rlen:3); - unsigned PACKED_FIELD(tdra:24); - unsigned PACKED_FIELD(res2:5); - unsigned PACKED_FIELD(tlen:3); -}; - -struct pcnet_initblk32 { - uint16_t mode; - unsigned PACKED_FIELD(res1:4); - unsigned PACKED_FIELD(rlen:4); - unsigned PACKED_FIELD(res2:4); - unsigned PACKED_FIELD(tlen:4); - uint16_t padr1; - uint16_t padr2; - uint16_t padr3; - uint16_t _res; - uint16_t ladrf1; - uint16_t ladrf2; - uint16_t ladrf3; - uint16_t ladrf4; - uint32_t rdra; - uint32_t tdra; -}; - -struct pcnet_TMD { - struct { - unsigned tbadr:32; - } tmd0; - struct { - unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:7), PACKED_FIELD(bpe:1); - unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(def:1), PACKED_FIELD(one:1); - unsigned PACKED_FIELD(ltint:1), PACKED_FIELD(nofcs:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); - } tmd1; - struct { - unsigned PACKED_FIELD(trc:4), PACKED_FIELD(res:12); - unsigned PACKED_FIELD(tdr:10), PACKED_FIELD(rtry:1), PACKED_FIELD(lcar:1); - unsigned PACKED_FIELD(lcol:1), PACKED_FIELD(exdef:1), PACKED_FIELD(uflo:1), PACKED_FIELD(buff:1); - } tmd2; - struct { - unsigned res:32; - } tmd3; -}; - -struct pcnet_RMD { - struct { - unsigned rbadr:32; - } rmd0; - struct { - unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:4); - unsigned PACKED_FIELD(bam:1), PACKED_FIELD(lafm:1), PACKED_FIELD(pam:1), PACKED_FIELD(bpe:1); - unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(buff:1), PACKED_FIELD(crc:1); - unsigned PACKED_FIELD(oflo:1), PACKED_FIELD(fram:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1); - } rmd1; - struct { - unsigned PACKED_FIELD(mcnt:12), PACKED_FIELD(zeros:4); - unsigned PACKED_FIELD(rpc:8), PACKED_FIELD(rcc:8); - } rmd2; - struct { - unsigned res:32; - } rmd3; -}; - - -#define PRINT_TMD(T) printf( \ - "TMD0 : TBADR=0x%08x\n" \ - "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \ - "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \ - " BPE=%d, BCNT=%d\n" \ - "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \ - "LCA=%d, RTR=%d,\n" \ - " TDR=%d, TRC=%d\n", \ - (T)->tmd0.tbadr, \ - (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \ - (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \ - (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \ - 4096-(T)->tmd1.bcnt, \ - (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\ - (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \ - (T)->tmd2.tdr, (T)->tmd2.trc) - -#define PRINT_RMD(R) printf( \ - "RMD0 : RBADR=0x%08x\n" \ - "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \ - "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \ - "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \ - "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \ - (R)->rmd0.rbadr, \ - (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \ - (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \ - (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \ - (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \ - (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \ - (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \ - (R)->rmd2.zeros) - -static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) -{ - if (!BCR_SWSTYLE(s)) { - uint16_t xda[4]; - cpu_physical_memory_read(addr, - (void *)&xda[0], sizeof(xda)); - ((uint32_t *)tmd)[0] = (xda[0]&0xffff) | - ((xda[1]&0x00ff) << 16); - ((uint32_t *)tmd)[1] = (xda[2]&0xffff)| - ((xda[1] & 0xff00) << 16); - ((uint32_t *)tmd)[2] = - (xda[3] & 0xffff) << 16; - ((uint32_t *)tmd)[3] = 0; - } - else - if (BCR_SWSTYLE(s) != 3) - cpu_physical_memory_read(addr, (void *)tmd, 16); - else { - uint32_t xda[4]; - cpu_physical_memory_read(addr, - (void *)&xda[0], sizeof(xda)); - ((uint32_t *)tmd)[0] = xda[2]; - ((uint32_t *)tmd)[1] = xda[1]; - ((uint32_t *)tmd)[2] = xda[0]; - ((uint32_t *)tmd)[3] = xda[3]; - } -} - -static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr) -{ - if (!BCR_SWSTYLE(s)) { - uint16_t xda[4]; - xda[0] = ((uint32_t *)tmd)[0] & 0xffff; - xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) | - ((((uint32_t *)tmd)[1]>>16)&0xff00); - xda[2] = ((uint32_t *)tmd)[1] & 0xffff; - xda[3] = ((uint32_t *)tmd)[2] >> 16; - cpu_physical_memory_write(addr, - (void *)&xda[0], sizeof(xda)); - } - else { - if (BCR_SWSTYLE(s) != 3) - cpu_physical_memory_write(addr, (void *)tmd, 16); - else { - uint32_t xda[4]; - xda[0] = ((uint32_t *)tmd)[2]; - xda[1] = ((uint32_t *)tmd)[1]; - xda[2] = ((uint32_t *)tmd)[0]; - xda[3] = ((uint32_t *)tmd)[3]; - cpu_physical_memory_write(addr, - (void *)&xda[0], sizeof(xda)); - } - } -} - -static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) -{ - if (!BCR_SWSTYLE(s)) { - uint16_t rda[4]; - cpu_physical_memory_read(addr, - (void *)&rda[0], sizeof(rda)); - ((uint32_t *)rmd)[0] = (rda[0]&0xffff)| - ((rda[1] & 0x00ff) << 16); - ((uint32_t *)rmd)[1] = (rda[2]&0xffff)| - ((rda[1] & 0xff00) << 16); - ((uint32_t *)rmd)[2] = rda[3] & 0xffff; - ((uint32_t *)rmd)[3] = 0; - } - else - if (BCR_SWSTYLE(s) != 3) - cpu_physical_memory_read(addr, (void *)rmd, 16); - else { - uint32_t rda[4]; - cpu_physical_memory_read(addr, - (void *)&rda[0], sizeof(rda)); - ((uint32_t *)rmd)[0] = rda[2]; - ((uint32_t *)rmd)[1] = rda[1]; - ((uint32_t *)rmd)[2] = rda[0]; - ((uint32_t *)rmd)[3] = rda[3]; - } -} - -static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) -{ - if (!BCR_SWSTYLE(s)) { - uint16_t rda[4]; \ - rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \ - rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\ - ((((uint32_t *)rmd)[1]>>16)&0xff00);\ - rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \ - rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \ - cpu_physical_memory_write(addr, \ - (void *)&rda[0], sizeof(rda)); \ - } - else { - if (BCR_SWSTYLE(s) != 3) - cpu_physical_memory_write(addr, (void *)rmd, 16); - else { - uint32_t rda[4]; - rda[0] = ((uint32_t *)rmd)[2]; - rda[1] = ((uint32_t *)rmd)[1]; - rda[2] = ((uint32_t *)rmd)[0]; - rda[3] = ((uint32_t *)rmd)[3]; - cpu_physical_memory_write(addr, - (void *)&rda[0], sizeof(rda)); - } - } -} - - -#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR) - -#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR) - -#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR) - -#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR) - -#if 1 - -#define CHECK_RMD(ADDR,RES) do { \ - struct pcnet_RMD rmd; \ - RMDLOAD(&rmd,(ADDR)); \ - (RES) |= (rmd.rmd1.ones != 15) \ - || (rmd.rmd2.zeros != 0); \ -} while (0) - -#define CHECK_TMD(ADDR,RES) do { \ - struct pcnet_TMD tmd; \ - TMDLOAD(&tmd,(ADDR)); \ - (RES) |= (tmd.tmd1.ones != 15); \ -} while (0) - -#else - -#define CHECK_RMD(ADDR,RES) do { \ - switch (BCR_SWSTYLE(s)) { \ - case 0x00: \ - do { \ - uint16_t rda[4]; \ - cpu_physical_memory_read((ADDR), \ - (void *)&rda[0], sizeof(rda)); \ - (RES) |= (rda[2] & 0xf000)!=0xf000; \ - (RES) |= (rda[3] & 0xf000)!=0x0000; \ - } while (0); \ - break; \ - case 0x01: \ - case 0x02: \ - do { \ - uint32_t rda[4]; \ - cpu_physical_memory_read((ADDR), \ - (void *)&rda[0], sizeof(rda)); \ - (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ - (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ - } while (0); \ - break; \ - case 0x03: \ - do { \ - uint32_t rda[4]; \ - cpu_physical_memory_read((ADDR), \ - (void *)&rda[0], sizeof(rda)); \ - (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ - (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ - } while (0); \ - break; \ - } \ -} while (0) - -#define CHECK_TMD(ADDR,RES) do { \ - switch (BCR_SWSTYLE(s)) { \ - case 0x00: \ - do { \ - uint16_t xda[4]; \ - cpu_physical_memory_read((ADDR), \ - (void *)&xda[0], sizeof(xda)); \ - (RES) |= (xda[2] & 0xf000)!=0xf000;\ - } while (0); \ - break; \ - case 0x01: \ - case 0x02: \ - case 0x03: \ - do { \ - uint32_t xda[4]; \ - cpu_physical_memory_read((ADDR), \ - (void *)&xda[0], sizeof(xda)); \ - (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ - } while (0); \ - break; \ - } \ -} while (0) - -#endif - -#define PRINT_PKTHDR(BUF) do { \ - struct qemu_ether_header *hdr = (void *)(BUF); \ - printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \ - "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \ - "type=0x%04x (bcast=%d)\n", \ - hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \ - hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \ - hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \ - hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \ - be16_to_cpu(hdr->ether_type), \ - !!ETHER_IS_MULTICAST(hdr->ether_dhost)); \ -} while (0) - -#define MULTICAST_FILTER_LEN 8 - -static inline uint32_t lnc_mchash(const uint8_t *ether_addr) -{ -#define LNC_POLYNOMIAL 0xEDB88320UL - uint32_t crc = 0xFFFFFFFF; - int idx, bit; - uint8_t data; - - for (idx = 0; idx < 6; idx++) { - for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) { - crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0); - data >>= 1; - } - } - return crc; -#undef LNC_POLYNOMIAL -} - -#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff]) - -/* generated using the AUTODIN II polynomial - * x^32 + x^26 + x^23 + x^22 + x^16 + - * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1 - */ -static const uint32_t crctab[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, -}; - -static inline int padr_match(PCNetState *s, const uint8_t *buf, int size) -{ - struct qemu_ether_header *hdr = (void *)buf; - uint8_t padr[6] = { - s->csr[12] & 0xff, s->csr[12] >> 8, - s->csr[13] & 0xff, s->csr[13] >> 8, - s->csr[14] & 0xff, s->csr[14] >> 8 - }; - int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6); -#ifdef PCNET_DEBUG_MATCH - printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " - "padr=%02x:%02x:%02x:%02x:%02x:%02x\n", - hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], - hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], - padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]); - printf("padr_match result=%d\n", result); -#endif - return result; -} - -static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size) -{ - static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct qemu_ether_header *hdr = (void *)buf; - int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6); -#ifdef PCNET_DEBUG_MATCH - printf("padr_bcast result=%d\n", result); -#endif - return result; -} - -static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) -{ - struct qemu_ether_header *hdr = (void *)buf; - if ((*(hdr->ether_dhost)&0x01) && - ((uint64_t *)&s->csr[8])[0] != 0LL) { - uint8_t ladr[8] = { - s->csr[8] & 0xff, s->csr[8] >> 8, - s->csr[9] & 0xff, s->csr[9] >> 8, - s->csr[10] & 0xff, s->csr[10] >> 8, - s->csr[11] & 0xff, s->csr[11] >> 8 - }; - int index = lnc_mchash(hdr->ether_dhost) >> 26; - return !!(ladr[index >> 3] & (1 << (index & 7))); - } - return 0; -} - -static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) -{ - while (idx < 1) idx += CSR_RCVRL(s); - return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8)); -} - -static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time) -{ - int64_t next_time = current_time + - muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)), - ticks_per_sec, 33000000L); - if (next_time <= current_time) - next_time = current_time + 1; - return next_time; -} - -static void pcnet_poll(PCNetState *s); -static void pcnet_poll_timer(void *opaque); - -static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap); -static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value); -static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val); -static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); - -static void pcnet_s_reset(PCNetState *s) -{ -#ifdef PCNET_DEBUG - printf("pcnet_s_reset\n"); -#endif - - s->lnkst = 0x40; - s->rdra = 0; - s->tdra = 0; - s->rap = 0; - - s->bcr[BCR_BSBC] &= ~0x0080; - - s->csr[0] = 0x0004; - s->csr[3] = 0x0000; - s->csr[4] = 0x0115; - s->csr[5] = 0x0000; - s->csr[6] = 0x0000; - s->csr[8] = 0; - s->csr[9] = 0; - s->csr[10] = 0; - s->csr[11] = 0; - s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]); - s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]); - s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]); - s->csr[15] &= 0x21c4; - s->csr[72] = 1; - s->csr[74] = 1; - s->csr[76] = 1; - s->csr[78] = 1; - s->csr[80] = 0x1410; - s->csr[88] = 0x1003; - s->csr[89] = 0x0262; - s->csr[94] = 0x0000; - s->csr[100] = 0x0200; - s->csr[103] = 0x0105; - s->csr[103] = 0x0105; - s->csr[112] = 0x0000; - s->csr[114] = 0x0000; - s->csr[122] = 0x0000; - s->csr[124] = 0x0000; - - s->tx_busy = 0; -} - -static void pcnet_update_irq(PCNetState *s) -{ - int isr = 0; - s->csr[0] &= ~0x0080; - -#if 1 - if (((s->csr[0] & ~s->csr[3]) & 0x5f00) || - (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) || - (((s->csr[5]>>1) & s->csr[5]) & 0x0048)) -#else - if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ || - (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ || - (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ || - (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ || - (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ || - (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ || - (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ || - (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ || - (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ || - (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ || - (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ || - (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */) -#endif - { - - isr = CSR_INEA(s); - s->csr[0] |= 0x0080; - } - - if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */ - s->csr[4] &= ~0x0080; - s->csr[4] |= 0x0040; - s->csr[0] |= 0x0080; - isr = 1; -#ifdef PCNET_DEBUG - printf("pcnet user int\n"); -#endif - } - -#if 1 - if (((s->csr[5]>>1) & s->csr[5]) & 0x0500) -#else - if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ || - (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ ) -#endif - { - isr = 1; - s->csr[0] |= 0x0080; - } - - if (isr != s->isr) { -#ifdef PCNET_DEBUG - printf("pcnet: INTA=%d\n", isr); -#endif - } - pci_set_irq(&s->dev, 0, isr); - s->isr = isr; -} - -static void pcnet_init(PCNetState *s) -{ -#ifdef PCNET_DEBUG - printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s))); -#endif - -#define PCNET_INIT() do { \ - cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \ - (uint8_t *)&initblk, sizeof(initblk)); \ - s->csr[15] = le16_to_cpu(initblk.mode); \ - CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \ - CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \ - s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \ - s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \ - s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \ - s->csr[10] = le16_to_cpu(initblk.ladrf3); \ - s->csr[11] = le16_to_cpu(initblk.ladrf4); \ - s->csr[12] = le16_to_cpu(initblk.padr1); \ - s->csr[13] = le16_to_cpu(initblk.padr2); \ - s->csr[14] = le16_to_cpu(initblk.padr3); \ - s->rdra = PHYSADDR(s,initblk.rdra); \ - s->tdra = PHYSADDR(s,initblk.tdra); \ -} while (0) - - if (BCR_SSIZE32(s)) { - struct pcnet_initblk32 initblk; - PCNET_INIT(); -#ifdef PCNET_DEBUG - printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", - initblk.rlen, initblk.tlen); -#endif - } else { - struct pcnet_initblk16 initblk; - PCNET_INIT(); -#ifdef PCNET_DEBUG - printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", - initblk.rlen, initblk.tlen); -#endif - } - -#undef PCNET_INIT - - CSR_RCVRC(s) = CSR_RCVRL(s); - CSR_XMTRC(s) = CSR_XMTRL(s); - -#ifdef PCNET_DEBUG - printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", - BCR_SSIZE32(s), - s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s)); -#endif - - s->csr[0] |= 0x0101; - s->csr[0] &= ~0x0004; /* clear STOP bit */ -} - -static void pcnet_start(PCNetState *s) -{ -#ifdef PCNET_DEBUG - printf("pcnet_start\n"); -#endif - - if (!CSR_DTX(s)) - s->csr[0] |= 0x0010; /* set TXON */ - - if (!CSR_DRX(s)) - s->csr[0] |= 0x0020; /* set RXON */ - - s->csr[0] &= ~0x0004; /* clear STOP bit */ - s->csr[0] |= 0x0002; -} - -static void pcnet_stop(PCNetState *s) -{ -#ifdef PCNET_DEBUG - printf("pcnet_stop\n"); -#endif - s->csr[0] &= ~0x7feb; - s->csr[0] |= 0x0014; - s->csr[4] &= ~0x02c2; - s->csr[5] &= ~0x0011; - pcnet_poll_timer(s); -} - -static void pcnet_rdte_poll(PCNetState *s) -{ - s->csr[28] = s->csr[29] = 0; - if (s->rdra) { - int bad = 0; -#if 1 - target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); - target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); - target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); -#else - target_phys_addr_t crda = s->rdra + - (CSR_RCVRL(s) - CSR_RCVRC(s)) * - (BCR_SWSTYLE(s) ? 16 : 8 ); - int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; - target_phys_addr_t nrda = s->rdra + - (CSR_RCVRL(s) - nrdc) * - (BCR_SWSTYLE(s) ? 16 : 8 ); - int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; - target_phys_addr_t nnrd = s->rdra + - (CSR_RCVRL(s) - nnrc) * - (BCR_SWSTYLE(s) ? 16 : 8 ); -#endif - - CHECK_RMD(PHYSADDR(s,crda), bad); - if (!bad) { - CHECK_RMD(PHYSADDR(s,nrda), bad); - if (bad || (nrda == crda)) nrda = 0; - CHECK_RMD(PHYSADDR(s,nnrd), bad); - if (bad || (nnrd == crda)) nnrd = 0; - - s->csr[28] = crda & 0xffff; - s->csr[29] = crda >> 16; - s->csr[26] = nrda & 0xffff; - s->csr[27] = nrda >> 16; - s->csr[36] = nnrd & 0xffff; - s->csr[37] = nnrd >> 16; -#ifdef PCNET_DEBUG - if (bad) { - printf("pcnet: BAD RMD RECORDS AFTER 0x%08x\n", - PHYSADDR(s,crda)); - } - } else { - printf("pcnet: BAD RMD RDA=0x%08x\n", PHYSADDR(s,crda)); -#endif - } - } - - if (CSR_CRDA(s)) { - struct pcnet_RMD rmd; - RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s))); - CSR_CRBC(s) = rmd.rmd1.bcnt; - CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16; -#ifdef PCNET_DEBUG_RMD_X - printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n", - PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s), - ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]); - PRINT_RMD(&rmd); -#endif - } else { - CSR_CRBC(s) = CSR_CRST(s) = 0; - } - - if (CSR_NRDA(s)) { - struct pcnet_RMD rmd; - RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s))); - CSR_NRBC(s) = rmd.rmd1.bcnt; - CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16; - } else { - CSR_NRBC(s) = CSR_NRST(s) = 0; - } - -} - -static int pcnet_tdte_poll(PCNetState *s) -{ - s->csr[34] = s->csr[35] = 0; - if (s->tdra) { - target_phys_addr_t cxda = s->tdra + - (CSR_XMTRL(s) - CSR_XMTRC(s)) * - (BCR_SWSTYLE(s) ? 16 : 8 ); - int bad = 0; - CHECK_TMD(PHYSADDR(s, cxda),bad); - if (!bad) { - if (CSR_CXDA(s) != cxda) { - s->csr[60] = s->csr[34]; - s->csr[61] = s->csr[35]; - s->csr[62] = CSR_CXBC(s); - s->csr[63] = CSR_CXST(s); - } - s->csr[34] = cxda & 0xffff; - s->csr[35] = cxda >> 16; -#ifdef PCNET_DEBUG - } else { - printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda)); -#endif - } - } - - if (CSR_CXDA(s)) { - struct pcnet_TMD tmd; - - TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); - - CSR_CXBC(s) = tmd.tmd1.bcnt; - CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16; - } else { - CSR_CXBC(s) = CSR_CXST(s) = 0; - } - - return !!(CSR_CXST(s) & 0x8000); -} - -static int pcnet_can_receive(void *opaque) -{ - PCNetState *s = opaque; - if (CSR_STOP(s) || CSR_SPND(s)) - return 0; - - if (s->recv_pos > 0) - return 0; - - return sizeof(s->buffer)-16; -} - -#define MIN_BUF_SIZE 60 - -static void pcnet_receive(void *opaque, const uint8_t *buf, int size) -{ - PCNetState *s = opaque; - int is_padr = 0, is_bcast = 0, is_ladr = 0; - uint8_t buf1[60]; - - if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) - return; - -#ifdef PCNET_DEBUG - printf("pcnet_receive size=%d\n", size); -#endif - - /* if too small buffer, then expand it */ - if (size < MIN_BUF_SIZE) { - memcpy(buf1, buf, size); - memset(buf1 + size, 0, MIN_BUF_SIZE - size); - buf = buf1; - size = MIN_BUF_SIZE; - } - - if (CSR_PROM(s) - || (is_padr=padr_match(s, buf, size)) - || (is_bcast=padr_bcast(s, buf, size)) - || (is_ladr=ladr_match(s, buf, size))) { - - pcnet_rdte_poll(s); - - if (!(CSR_CRST(s) & 0x8000) && s->rdra) { - struct pcnet_RMD rmd; - int rcvrc = CSR_RCVRC(s)-1,i; - target_phys_addr_t nrda; - for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) { - if (rcvrc <= 1) - rcvrc = CSR_RCVRL(s); - nrda = s->rdra + - (CSR_RCVRL(s) - rcvrc) * - (BCR_SWSTYLE(s) ? 16 : 8 ); - RMDLOAD(&rmd, PHYSADDR(s,nrda)); - if (rmd.rmd1.own) { -#ifdef PCNET_DEBUG_RMD - printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", - rcvrc, CSR_RCVRC(s)); -#endif - CSR_RCVRC(s) = rcvrc; - pcnet_rdte_poll(s); - break; - } - } - } - - if (!(CSR_CRST(s) & 0x8000)) { -#ifdef PCNET_DEBUG_RMD - printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s)); -#endif - s->csr[0] |= 0x1000; /* Set MISS flag */ - CSR_MISSC(s)++; - } else { - uint8_t *src = &s->buffer[8]; - target_phys_addr_t crda = CSR_CRDA(s); - struct pcnet_RMD rmd; - int pktcount = 0; - - memcpy(src, buf, size); - -#if 1 - /* no need to compute the CRC */ - src[size] = 0; - src[size + 1] = 0; - src[size + 2] = 0; - src[size + 3] = 0; - size += 4; -#else - /* XXX: avoid CRC generation */ - if (!CSR_ASTRP_RCV(s)) { - uint32_t fcs = ~0; - uint8_t *p = src; - - while (size < 46) { - src[size++] = 0; - } - - while (p != &src[size]) { - CRC(fcs, *p++); - } - ((uint32_t *)&src[size])[0] = htonl(fcs); - size += 4; /* FCS at end of packet */ - } else size += 4; -#endif - -#ifdef PCNET_DEBUG_MATCH - PRINT_PKTHDR(buf); -#endif - - RMDLOAD(&rmd, PHYSADDR(s,crda)); - /*if (!CSR_LAPPEN(s))*/ - rmd.rmd1.stp = 1; - -#define PCNET_RECV_STORE() do { \ - int count = MIN(4096 - rmd.rmd1.bcnt,size); \ - target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \ - cpu_physical_memory_write(rbadr, src, count); \ - src += count; size -= count; \ - rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \ - RMDSTORE(&rmd, PHYSADDR(s,crda)); \ - pktcount++; \ -} while (0) - - PCNET_RECV_STORE(); - if ((size > 0) && CSR_NRDA(s)) { - target_phys_addr_t nrda = CSR_NRDA(s); - RMDLOAD(&rmd, PHYSADDR(s,nrda)); - if (rmd.rmd1.own) { - crda = nrda; - PCNET_RECV_STORE(); - if ((size > 0) && (nrda=CSR_NNRD(s))) { - RMDLOAD(&rmd, PHYSADDR(s,nrda)); - if (rmd.rmd1.own) { - crda = nrda; - PCNET_RECV_STORE(); - } - } - } - } - -#undef PCNET_RECV_STORE - - RMDLOAD(&rmd, PHYSADDR(s,crda)); - if (size == 0) { - rmd.rmd1.enp = 1; - rmd.rmd1.pam = !CSR_PROM(s) && is_padr; - rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr; - rmd.rmd1.bam = !CSR_PROM(s) && is_bcast; - } else { - rmd.rmd1.oflo = 1; - rmd.rmd1.buff = 1; - rmd.rmd1.err = 1; - } - RMDSTORE(&rmd, PHYSADDR(s,crda)); - s->csr[0] |= 0x0400; - -#ifdef PCNET_DEBUG - printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", - CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount); -#endif -#ifdef PCNET_DEBUG_RMD - PRINT_RMD(&rmd); -#endif - - while (pktcount--) { - if (CSR_RCVRC(s) <= 1) - CSR_RCVRC(s) = CSR_RCVRL(s); - else - CSR_RCVRC(s)--; - } - - pcnet_rdte_poll(s); - - } - } - - pcnet_poll(s); - pcnet_update_irq(s); -} - -static void pcnet_transmit(PCNetState *s) -{ - target_phys_addr_t xmit_cxda = 0; - int count = CSR_XMTRL(s)-1; - s->xmit_pos = -1; - - if (!CSR_TXON(s)) { - s->csr[0] &= ~0x0008; - return; - } - - s->tx_busy = 1; - - txagain: - if (pcnet_tdte_poll(s)) { - struct pcnet_TMD tmd; - - TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s))); - -#ifdef PCNET_DEBUG_TMD - printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s))); - PRINT_TMD(&tmd); -#endif - if (tmd.tmd1.stp) { - s->xmit_pos = 0; - if (!tmd.tmd1.enp) { - cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), - s->buffer, 4096 - tmd.tmd1.bcnt); - s->xmit_pos += 4096 - tmd.tmd1.bcnt; - } - xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); - } - if (tmd.tmd1.enp && (s->xmit_pos >= 0)) { - cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), - s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt); - s->xmit_pos += 4096 - tmd.tmd1.bcnt; -#ifdef PCNET_DEBUG - printf("pcnet_transmit size=%d\n", s->xmit_pos); -#endif - if (CSR_LOOP(s)) - pcnet_receive(s, s->buffer, s->xmit_pos); - else - qemu_send_packet(s->vc, s->buffer, s->xmit_pos); - - s->csr[0] &= ~0x0008; /* clear TDMD */ - s->csr[4] |= 0x0004; /* set TXSTRT */ - s->xmit_pos = -1; - } - - tmd.tmd1.own = 0; - TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); - if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint)) - s->csr[0] |= 0x0200; /* set TINT */ - - if (CSR_XMTRC(s)<=1) - CSR_XMTRC(s) = CSR_XMTRL(s); - else - CSR_XMTRC(s)--; - if (count--) - goto txagain; - - } else - if (s->xmit_pos >= 0) { - struct pcnet_TMD tmd; - TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda)); - tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1; - tmd.tmd1.own = 0; - TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda)); - s->csr[0] |= 0x0200; /* set TINT */ - if (!CSR_DXSUFLO(s)) { - s->csr[0] &= ~0x0010; - } else - if (count--) - goto txagain; - } - - s->tx_busy = 0; -} - -static void pcnet_poll(PCNetState *s) -{ - if (CSR_RXON(s)) { - pcnet_rdte_poll(s); - } - - if (CSR_TDMD(s) || - (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s))) - { - /* prevent recursion */ - if (s->tx_busy) - return; - - pcnet_transmit(s); - } -} - -static void pcnet_poll_timer(void *opaque) -{ - PCNetState *s = opaque; - - qemu_del_timer(s->poll_timer); - - if (CSR_TDMD(s)) { - pcnet_transmit(s); - } - - pcnet_update_irq(s); - - if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) { - uint64_t now = qemu_get_clock(vm_clock) * 33; - if (!s->timer || !now) - s->timer = now; - else { - uint64_t t = now - s->timer + CSR_POLL(s); - if (t > 0xffffLL) { - pcnet_poll(s); - CSR_POLL(s) = CSR_PINT(s); - } else - CSR_POLL(s) = t; - } - qemu_mod_timer(s->poll_timer, - pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock))); - } -} - - -static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value) -{ - uint16_t val = new_value; -#ifdef PCNET_DEBUG_CSR - printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val); -#endif - switch (rap) { - case 0: - s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */ - - s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048); - - val = (val & 0x007f) | (s->csr[0] & 0x7f00); - - /* IFF STOP, STRT and INIT are set, clear STRT and INIT */ - if ((val&7) == 7) - val &= ~3; - - if (!CSR_STOP(s) && (val & 4)) - pcnet_stop(s); - - if (!CSR_INIT(s) && (val & 1)) - pcnet_init(s); - - if (!CSR_STRT(s) && (val & 2)) - pcnet_start(s); - - if (CSR_TDMD(s)) - pcnet_transmit(s); - - return; - case 1: - case 2: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 18: /* CRBAL */ - case 19: /* CRBAU */ - case 20: /* CXBAL */ - case 21: /* CXBAU */ - case 22: /* NRBAU */ - case 23: /* NRBAU */ - case 24: - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 31: - case 32: - case 33: - case 34: - case 35: - case 36: - case 37: - case 38: - case 39: - case 40: /* CRBC */ - case 41: - case 42: /* CXBC */ - case 43: - case 44: - case 45: - case 46: /* POLL */ - case 47: /* POLLINT */ - case 72: - case 74: - case 76: /* RCVRL */ - case 78: /* XMTRL */ - case 112: - if (CSR_STOP(s) || CSR_SPND(s)) - break; - return; - case 3: - break; - case 4: - s->csr[4] &= ~(val & 0x026a); - val &= ~0x026a; val |= s->csr[4] & 0x026a; - break; - case 5: - s->csr[5] &= ~(val & 0x0a90); - val &= ~0x0a90; val |= s->csr[5] & 0x0a90; - break; - case 16: - pcnet_csr_writew(s,1,val); - return; - case 17: - pcnet_csr_writew(s,2,val); - return; - case 58: - pcnet_bcr_writew(s,BCR_SWS,val); - break; - default: - return; - } - s->csr[rap] = val; -} - -static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap) -{ - uint32_t val; - switch (rap) { - case 0: - pcnet_update_irq(s); - val = s->csr[0]; - val |= (val & 0x7800) ? 0x8000 : 0; - break; - case 16: - return pcnet_csr_readw(s,1); - case 17: - return pcnet_csr_readw(s,2); - case 58: - return pcnet_bcr_readw(s,BCR_SWS); - case 88: - val = s->csr[89]; - val <<= 16; - val |= s->csr[88]; - break; - default: - val = s->csr[rap]; - } -#ifdef PCNET_DEBUG_CSR - printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val); -#endif - return val; -} - -static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val) -{ - rap &= 127; -#ifdef PCNET_DEBUG_BCR - printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val); -#endif - switch (rap) { - case BCR_SWS: - if (!(CSR_STOP(s) || CSR_SPND(s))) - return; - val &= ~0x0300; - switch (val & 0x00ff) { - case 0: - val |= 0x0200; - break; - case 1: - val |= 0x0100; - break; - case 2: - case 3: - val |= 0x0300; - break; - default: - printf("Bad SWSTYLE=0x%02x\n", val & 0xff); - val = 0x0200; - break; - } -#ifdef PCNET_DEBUG - printf("BCR_SWS=0x%04x\n", val); -#endif - case BCR_LNKST: - case BCR_LED1: - case BCR_LED2: - case BCR_LED3: - case BCR_MC: - case BCR_FDC: - case BCR_BSBC: - case BCR_EECAS: - case BCR_PLAT: - s->bcr[rap] = val; - break; - default: - break; - } -} - -static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) -{ - uint32_t val; - rap &= 127; - switch (rap) { - case BCR_LNKST: - case BCR_LED1: - case BCR_LED2: - case BCR_LED3: - val = s->bcr[rap] & ~0x8000; - val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0; - break; - default: - val = rap < 32 ? s->bcr[rap] : 0; - break; - } -#ifdef PCNET_DEBUG_BCR - printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val); -#endif - return val; -} - -static void pcnet_h_reset(PCNetState *s) -{ - int i; - uint16_t checksum; - - /* Initialize the PROM */ - - memcpy(s->prom, s->nd->macaddr, 6); - s->prom[12] = s->prom[13] = 0x00; - s->prom[14] = s->prom[15] = 0x57; - - for (i = 0,checksum = 0; i < 16; i++) - checksum += s->prom[i]; - *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum); - - - s->bcr[BCR_MSRDA] = 0x0005; - s->bcr[BCR_MSWRA] = 0x0005; - s->bcr[BCR_MC ] = 0x0002; - s->bcr[BCR_LNKST] = 0x00c0; - s->bcr[BCR_LED1 ] = 0x0084; - s->bcr[BCR_LED2 ] = 0x0088; - s->bcr[BCR_LED3 ] = 0x0090; - s->bcr[BCR_FDC ] = 0x0000; - s->bcr[BCR_BSBC ] = 0x9001; - s->bcr[BCR_EECAS] = 0x0002; - s->bcr[BCR_SWS ] = 0x0200; - s->bcr[BCR_PLAT ] = 0xff06; - - pcnet_s_reset(s); -} - -static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - PCNetState *s = opaque; -#ifdef PCNET_DEBUG - printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); -#endif - /* Check APROMWE bit to enable write access */ - if (pcnet_bcr_readw(s,2) & 0x80) - s->prom[addr & 15] = val; -} - -static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) -{ - PCNetState *s = opaque; - uint32_t val = s->prom[addr &= 15]; -#ifdef PCNET_DEBUG - printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val); -#endif - return val; -} - -static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val) -{ - PCNetState *s = opaque; - pcnet_poll_timer(s); -#ifdef PCNET_DEBUG_IO - printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val); -#endif - if (!BCR_DWIO(s)) { - switch (addr & 0x0f) { - case 0x00: /* RDP */ - pcnet_csr_writew(s, s->rap, val); - break; - case 0x02: - s->rap = val & 0x7f; - break; - case 0x06: - pcnet_bcr_writew(s, s->rap, val); - break; - } - } - pcnet_update_irq(s); -} - -static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr) -{ - PCNetState *s = opaque; - uint32_t val = -1; - pcnet_poll_timer(s); - if (!BCR_DWIO(s)) { - switch (addr & 0x0f) { - case 0x00: /* RDP */ - val = pcnet_csr_readw(s, s->rap); - break; - case 0x02: - val = s->rap; - break; - case 0x04: - pcnet_s_reset(s); - val = 0; - break; - case 0x06: - val = pcnet_bcr_readw(s, s->rap); - break; - } - } - pcnet_update_irq(s); -#ifdef PCNET_DEBUG_IO - printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff); -#endif - return val; -} - -static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - PCNetState *s = opaque; - pcnet_poll_timer(s); -#ifdef PCNET_DEBUG_IO - printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val); -#endif - if (BCR_DWIO(s)) { - switch (addr & 0x0f) { - case 0x00: /* RDP */ - pcnet_csr_writew(s, s->rap, val & 0xffff); - break; - case 0x04: - s->rap = val & 0x7f; - break; - case 0x0c: - pcnet_bcr_writew(s, s->rap, val & 0xffff); - break; - } - } else - if ((addr & 0x0f) == 0) { - /* switch device to dword i/o mode */ - pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080); -#ifdef PCNET_DEBUG_IO - printf("device switched into dword i/o mode\n"); -#endif - } - pcnet_update_irq(s); -} - -static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) -{ - PCNetState *s = opaque; - uint32_t val = -1; - pcnet_poll_timer(s); - if (BCR_DWIO(s)) { - switch (addr & 0x0f) { - case 0x00: /* RDP */ - val = pcnet_csr_readw(s, s->rap); - break; - case 0x04: - val = s->rap; - break; - case 0x08: - pcnet_s_reset(s); - val = 0; - break; - case 0x0c: - val = pcnet_bcr_readw(s, s->rap); - break; - } - } - pcnet_update_irq(s); -#ifdef PCNET_DEBUG_IO - printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val); -#endif - return val; -} - -static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - PCNetState *d = (PCNetState *)pci_dev; - -#ifdef PCNET_DEBUG_IO - printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size); -#endif - - register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); - register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); - - register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); - register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); - register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); - register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d); -} - -static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writeb addr=0x%08x val=0x%02x\n", addr, val); -#endif - if (!(addr & 0x10)) - pcnet_aprom_writeb(d, addr & 0x0f, val); -} - -static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) -{ - PCNetState *d = opaque; - uint32_t val = -1; - if (!(addr & 0x10)) - val = pcnet_aprom_readb(d, addr & 0x0f); -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readb addr=0x%08x val=0x%02x\n", addr, val & 0xff); -#endif - return val; -} - -static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writew addr=0x%08x val=0x%04x\n", addr, val); -#endif - if (addr & 0x10) - pcnet_ioport_writew(d, addr & 0x0f, val); - else { - addr &= 0x0f; - pcnet_aprom_writeb(d, addr, val & 0xff); - pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); - } -} - -static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) -{ - PCNetState *d = opaque; - uint32_t val = -1; - if (addr & 0x10) - val = pcnet_ioport_readw(d, addr & 0x0f); - else { - addr &= 0x0f; - val = pcnet_aprom_readb(d, addr+1); - val <<= 8; - val |= pcnet_aprom_readb(d, addr); - } -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readw addr=0x%08x val = 0x%04x\n", addr, val & 0xffff); -#endif - return val; -} - -static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writel addr=0x%08x val=0x%08x\n", addr, val); -#endif - if (addr & 0x10) - pcnet_ioport_writel(d, addr & 0x0f, val); - else { - addr &= 0x0f; - pcnet_aprom_writeb(d, addr, val & 0xff); - pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); - pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); - pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); - } -} - -static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) -{ - PCNetState *d = opaque; - uint32_t val; - if (addr & 0x10) - val = pcnet_ioport_readl(d, addr & 0x0f); - else { - addr &= 0x0f; - val = pcnet_aprom_readb(d, addr+3); - val <<= 8; - val |= pcnet_aprom_readb(d, addr+2); - val <<= 8; - val |= pcnet_aprom_readb(d, addr+1); - val <<= 8; - val |= pcnet_aprom_readb(d, addr); - } -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readl addr=0x%08x val=0x%08x\n", addr, val); -#endif - return val; -} - - -static CPUWriteMemoryFunc *pcnet_mmio_write[] = { - (CPUWriteMemoryFunc *)&pcnet_mmio_writeb, - (CPUWriteMemoryFunc *)&pcnet_mmio_writew, - (CPUWriteMemoryFunc *)&pcnet_mmio_writel -}; - -static CPUReadMemoryFunc *pcnet_mmio_read[] = { - (CPUReadMemoryFunc *)&pcnet_mmio_readb, - (CPUReadMemoryFunc *)&pcnet_mmio_readw, - (CPUReadMemoryFunc *)&pcnet_mmio_readl -}; - -static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - PCNetState *d = (PCNetState *)pci_dev; - -#ifdef PCNET_DEBUG_IO - printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size); -#endif - - cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr); -} - -void pci_pcnet_init(PCIBus *bus, NICInfo *nd) -{ - PCNetState *d; - uint8_t *pci_conf; - -#if 0 - printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", - sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); -#endif - - d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), - -1, NULL, NULL); - - pci_conf = d->dev.config; - - *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022); - *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000); - *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); - *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280); - pci_conf[0x08] = 0x10; - pci_conf[0x09] = 0x00; - pci_conf[0x0a] = 0x00; // ethernet network controller - pci_conf[0x0b] = 0x02; - pci_conf[0x0e] = 0x00; // header_type - - *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001); - *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000); - - pci_conf[0x3d] = 1; // interrupt pin 0 - pci_conf[0x3e] = 0x06; - pci_conf[0x3f] = 0xff; - - /* Handler for memory-mapped I/O */ - d->mmio_io_addr = - cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d); - - pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, - PCI_ADDRESS_SPACE_IO, pcnet_ioport_map); - - pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, - PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); - - d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); - - d->nd = nd; - - d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, - pcnet_can_receive, d); - - snprintf(d->vc->info_str, sizeof(d->vc->info_str), - "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - d->nd->macaddr[0], - d->nd->macaddr[1], - d->nd->macaddr[2], - d->nd->macaddr[3], - d->nd->macaddr[4], - d->nd->macaddr[5]); - - pcnet_h_reset(d); -} diff --git a/hw/pcspk.c b/hw/pcspk.c deleted file mode 100644 index 0d52b31..0000000 --- a/hw/pcspk.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * QEMU PC speaker emulation - * - * Copyright (c) 2006 Joachim Henke - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "vl.h" - -#define PCSPK_BUF_LEN 1792 -#define PCSPK_SAMPLE_RATE 32000 -#define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1) -#define PCSPK_MIN_COUNT ((PIT_FREQ + PCSPK_MAX_FREQ - 1) / PCSPK_MAX_FREQ) - -typedef struct { - uint8_t sample_buf[PCSPK_BUF_LEN]; - QEMUSoundCard card; - SWVoiceOut *voice; - PITState *pit; - unsigned int pit_count; - unsigned int samples; - unsigned int play_pos; - int data_on; - int dummy_refresh_clock; -} PCSpkState; - -static const char *s_spk = "pcspk"; -static PCSpkState pcspk_state; - -static inline void generate_samples(PCSpkState *s) -{ - unsigned int i; - - if (s->pit_count) { - const uint32_t m = PCSPK_SAMPLE_RATE * s->pit_count; - const uint32_t n = ((uint64_t)PIT_FREQ << 32) / m; - - /* multiple of wavelength for gapless looping */ - s->samples = (PCSPK_BUF_LEN * PIT_FREQ / m * m / (PIT_FREQ >> 1) + 1) >> 1; - for (i = 0; i < s->samples; ++i) - s->sample_buf[i] = (64 & (n * i >> 25)) - 32; - } else { - s->samples = PCSPK_BUF_LEN; - for (i = 0; i < PCSPK_BUF_LEN; ++i) - s->sample_buf[i] = 128; /* silence */ - } -} - -static void pcspk_callback(void *opaque, int free) -{ - PCSpkState *s = opaque; - unsigned int n; - - if (pit_get_mode(s->pit, 2) != 3) - return; - - n = pit_get_initial_count(s->pit, 2); - /* avoid frequencies that are not reproducible with sample rate */ - if (n < PCSPK_MIN_COUNT) - n = 0; - - if (s->pit_count != n) { - s->pit_count = n; - s->play_pos = 0; - generate_samples(s); - } - - while (free > 0) { - n = audio_MIN(s->samples - s->play_pos, (unsigned int)free); - n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n); - if (!n) - break; - s->play_pos = (s->play_pos + n) % s->samples; - free -= n; - } -} - -int pcspk_audio_init(AudioState *audio) -{ - PCSpkState *s = &pcspk_state; - audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0}; - - if (!audio) { - AUD_log(s_spk, "No audio state\n"); - return -1; - } - AUD_register_card(audio, s_spk, &s->card); - - s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as); - if (!s->voice) { - AUD_log(s_spk, "Could not open voice\n"); - return -1; - } - - return 0; -} - -static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr) -{ - PCSpkState *s = opaque; - int out; - - s->dummy_refresh_clock ^= (1 << 4); - out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5; - - return pit_get_gate(s->pit, 2) | (s->data_on << 1) | s->dummy_refresh_clock | out; -} - -static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - PCSpkState *s = opaque; - const int gate = val & 1; - - s->data_on = (val >> 1) & 1; - pit_set_gate(s->pit, 2, gate); - if (s->voice) { - if (gate) /* restart */ - s->play_pos = 0; - AUD_set_active_out(s->voice, gate & s->data_on); - } -} - -void pcspk_init(PITState *pit) -{ - PCSpkState *s = &pcspk_state; - - s->pit = pit; - register_ioport_read(0x61, 1, 1, pcspk_ioport_read, s); - register_ioport_write(0x61, 1, 1, pcspk_ioport_write, s); -} diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c deleted file mode 100644 index ee2f63a..0000000 --- a/hw/pflash_cfi02.c +++ /dev/null @@ -1,624 +0,0 @@ -/* - * CFI parallel flash with AMD command set emulation - * - * Copyright (c) 2005 Jocelyn Mayer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * For now, this code can emulate flashes of 1, 2 or 4 bytes width. - * Supported commands/modes are: - * - flash read - * - flash write - * - flash ID read - * - sector erase - * - chip erase - * - unlock bypass command - * - CFI queries - * - * It does not support flash interleaving. - * It does not implement boot blocs with reduced size - * It does not implement software data protection as found in many real chips - * It does not implement erase suspend/resume commands - * It does not implement multiple sectors erase - */ - -#include "vl.h" - -//#define PFLASH_DEBUG -#ifdef PFLASH_DEBUG -#define DPRINTF(fmt, args...) \ -do { \ - printf("PFLASH: " fmt , ##args); \ -} while (0) -#else -#define DPRINTF(fmt, args...) do { } while (0) -#endif - -struct pflash_t { - BlockDriverState *bs; - target_ulong base; - target_ulong sector_len; - target_ulong total_len; - int width; - int wcycle; /* if 0, the flash is read normally */ - int bypass; - int ro; - uint8_t cmd; - uint8_t status; - uint16_t ident[4]; - uint8_t cfi_len; - uint8_t cfi_table[0x52]; - QEMUTimer *timer; - ram_addr_t off; - int fl_mem; - void *storage; -}; - -static void pflash_timer (void *opaque) -{ - pflash_t *pfl = opaque; - - DPRINTF("%s: command %02x done\n", __func__, pfl->cmd); - /* Reset flash */ - pfl->status ^= 0x80; - if (pfl->bypass) { - pfl->wcycle = 2; - } else { - cpu_register_physical_memory(pfl->base, pfl->total_len, - pfl->off | IO_MEM_ROMD | pfl->fl_mem); - pfl->wcycle = 0; - } - pfl->cmd = 0; -} - -static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width) -{ - target_ulong boff; - uint32_t ret; - uint8_t *p; - - DPRINTF("%s: offset %08x\n", __func__, offset); - ret = -1; - offset -= pfl->base; - boff = offset & 0xFF; - if (pfl->width == 2) - boff = boff >> 1; - else if (pfl->width == 4) - boff = boff >> 2; - switch (pfl->cmd) { - default: - /* This should never happen : reset state & treat it as a read*/ - DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); - pfl->wcycle = 0; - pfl->cmd = 0; - case 0x80: - /* We accept reads during second unlock sequence... */ - case 0x00: - flash_read: - /* Flash area read */ - p = pfl->storage; - switch (width) { - case 1: - ret = p[offset]; -// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret); - break; - case 2: -#if defined(TARGET_WORDS_BIGENDIAN) - ret = p[offset] << 8; - ret |= p[offset + 1]; -#else - ret = p[offset]; - ret |= p[offset + 1] << 8; -#endif -// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret); - break; - case 4: -#if defined(TARGET_WORDS_BIGENDIAN) - ret = p[offset] << 24; - ret |= p[offset + 1] << 16; - ret |= p[offset + 2] << 8; - ret |= p[offset + 3]; -#else - ret = p[offset]; - ret |= p[offset + 1] << 8; - ret |= p[offset + 1] << 8; - ret |= p[offset + 2] << 16; - ret |= p[offset + 3] << 24; -#endif -// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret); - break; - } - break; - case 0x90: - /* flash ID read */ - switch (boff) { - case 0x00: - case 0x01: - ret = pfl->ident[boff & 0x01]; - break; - case 0x02: - ret = 0x00; /* Pretend all sectors are unprotected */ - break; - case 0x0E: - case 0x0F: - if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1) - goto flash_read; - ret = pfl->ident[2 + (boff & 0x01)]; - break; - default: - goto flash_read; - } - DPRINTF("%s: ID %d %x\n", __func__, boff, ret); - break; - case 0xA0: - case 0x10: - case 0x30: - /* Status register read */ - ret = pfl->status; - DPRINTF("%s: status %x\n", __func__, ret); - /* Toggle bit 6 */ - pfl->status ^= 0x40; - break; - case 0x98: - /* CFI query mode */ - if (boff > pfl->cfi_len) - ret = 0; - else - ret = pfl->cfi_table[boff]; - break; - } - - return ret; -} - -/* update flash content on disk */ -static void pflash_update(pflash_t *pfl, int offset, - int size) -{ - int offset_end; - if (pfl->bs) { - offset_end = offset + size; - /* round to sectors */ - offset = offset >> 9; - offset_end = (offset_end + 511) >> 9; - bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9), - offset_end - offset); - } -} - -static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value, - int width) -{ - target_ulong boff; - uint8_t *p; - uint8_t cmd; - - /* WARNING: when the memory area is in ROMD mode, the offset is a - ram offset, not a physical address */ - if (pfl->wcycle == 0) - offset -= (target_ulong)(long)pfl->storage; - else - offset -= pfl->base; - - cmd = value; - DPRINTF("%s: offset %08x %08x %d\n", __func__, offset, value, width); - if (pfl->cmd != 0xA0 && cmd == 0xF0) { - DPRINTF("%s: flash reset asked (%02x %02x)\n", - __func__, pfl->cmd, cmd); - goto reset_flash; - } - /* Set the device in I/O access mode */ - cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem); - boff = offset & (pfl->sector_len - 1); - if (pfl->width == 2) - boff = boff >> 1; - else if (pfl->width == 4) - boff = boff >> 2; - switch (pfl->wcycle) { - case 0: - /* We're in read mode */ - check_unlock0: - if (boff == 0x55 && cmd == 0x98) { - enter_CFI_mode: - /* Enter CFI query mode */ - pfl->wcycle = 7; - pfl->cmd = 0x98; - return; - } - if (boff != 0x555 || cmd != 0xAA) { - DPRINTF("%s: unlock0 failed %04x %02x %04x\n", - __func__, boff, cmd, 0x555); - goto reset_flash; - } - DPRINTF("%s: unlock sequence started\n", __func__); - break; - case 1: - /* We started an unlock sequence */ - check_unlock1: - if (boff != 0x2AA || cmd != 0x55) { - DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd); - goto reset_flash; - } - DPRINTF("%s: unlock sequence done\n", __func__); - break; - case 2: - /* We finished an unlock sequence */ - if (!pfl->bypass && boff != 0x555) { - DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd); - goto reset_flash; - } - switch (cmd) { - case 0x20: - pfl->bypass = 1; - goto do_bypass; - case 0x80: - case 0x90: - case 0xA0: - pfl->cmd = cmd; - DPRINTF("%s: starting command %02x\n", __func__, cmd); - break; - default: - DPRINTF("%s: unknown command %02x\n", __func__, cmd); - goto reset_flash; - } - break; - case 3: - switch (pfl->cmd) { - case 0x80: - /* We need another unlock sequence */ - goto check_unlock0; - case 0xA0: - DPRINTF("%s: write data offset %08x %08x %d\n", - __func__, offset, value, width); - p = pfl->storage; - switch (width) { - case 1: - p[offset] &= value; - pflash_update(pfl, offset, 1); - break; - case 2: -#if defined(TARGET_WORDS_BIGENDIAN) - p[offset] &= value >> 8; - p[offset + 1] &= value; -#else - p[offset] &= value; - p[offset + 1] &= value >> 8; -#endif - pflash_update(pfl, offset, 2); - break; - case 4: -#if defined(TARGET_WORDS_BIGENDIAN) - p[offset] &= value >> 24; - p[offset + 1] &= value >> 16; - p[offset + 2] &= value >> 8; - p[offset + 3] &= value; -#else - p[offset] &= value; - p[offset + 1] &= value >> 8; - p[offset + 2] &= value >> 16; - p[offset + 3] &= value >> 24; -#endif - pflash_update(pfl, offset, 4); - break; - } - pfl->status = 0x00 | ~(value & 0x80); - /* Let's pretend write is immediate */ - if (pfl->bypass) - goto do_bypass; - goto reset_flash; - case 0x90: - if (pfl->bypass && cmd == 0x00) { - /* Unlock bypass reset */ - goto reset_flash; - } - /* We can enter CFI query mode from autoselect mode */ - if (boff == 0x55 && cmd == 0x98) - goto enter_CFI_mode; - /* No break here */ - default: - DPRINTF("%s: invalid write for command %02x\n", - __func__, pfl->cmd); - goto reset_flash; - } - case 4: - switch (pfl->cmd) { - case 0xA0: - /* Ignore writes while flash data write is occuring */ - /* As we suppose write is immediate, this should never happen */ - return; - case 0x80: - goto check_unlock1; - default: - /* Should never happen */ - DPRINTF("%s: invalid command state %02x (wc 4)\n", - __func__, pfl->cmd); - goto reset_flash; - } - break; - case 5: - switch (cmd) { - case 0x10: - if (boff != 0x555) { - DPRINTF("%s: chip erase: invalid address %04x\n", - __func__, offset); - goto reset_flash; - } - /* Chip erase */ - DPRINTF("%s: start chip erase\n", __func__); - memset(pfl->storage, 0xFF, pfl->total_len); - pfl->status = 0x00; - pflash_update(pfl, 0, pfl->total_len); - /* Let's wait 5 seconds before chip erase is done */ - qemu_mod_timer(pfl->timer, - qemu_get_clock(vm_clock) + (ticks_per_sec * 5)); - break; - case 0x30: - /* Sector erase */ - p = pfl->storage; - offset &= ~(pfl->sector_len - 1); - DPRINTF("%s: start sector erase at %08x\n", __func__, offset); - memset(p + offset, 0xFF, pfl->sector_len); - pflash_update(pfl, offset, pfl->sector_len); - pfl->status = 0x00; - /* Let's wait 1/2 second before sector erase is done */ - qemu_mod_timer(pfl->timer, - qemu_get_clock(vm_clock) + (ticks_per_sec / 2)); - break; - default: - DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd); - goto reset_flash; - } - pfl->cmd = cmd; - break; - case 6: - switch (pfl->cmd) { - case 0x10: - /* Ignore writes during chip erase */ - return; - case 0x30: - /* Ignore writes during sector erase */ - return; - default: - /* Should never happen */ - DPRINTF("%s: invalid command state %02x (wc 6)\n", - __func__, pfl->cmd); - goto reset_flash; - } - break; - case 7: /* Special value for CFI queries */ - DPRINTF("%s: invalid write in CFI query mode\n", __func__); - goto reset_flash; - default: - /* Should never happen */ - DPRINTF("%s: invalid write state (wc 7)\n", __func__); - goto reset_flash; - } - pfl->wcycle++; - - return; - - /* Reset flash */ - reset_flash: - if (pfl->wcycle != 0) { - cpu_register_physical_memory(pfl->base, pfl->total_len, - pfl->off | IO_MEM_ROMD | pfl->fl_mem); - } - pfl->bypass = 0; - pfl->wcycle = 0; - pfl->cmd = 0; - return; - - do_bypass: - pfl->wcycle = 2; - pfl->cmd = 0; - return; -} - - -static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr) -{ - return pflash_read(opaque, addr, 1); -} - -static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr) -{ - pflash_t *pfl = opaque; - - return pflash_read(pfl, addr, 2); -} - -static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr) -{ - pflash_t *pfl = opaque; - - return pflash_read(pfl, addr, 4); -} - -static void pflash_writeb (void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - pflash_write(opaque, addr, value, 1); -} - -static void pflash_writew (void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - pflash_t *pfl = opaque; - - pflash_write(pfl, addr, value, 2); -} - -static void pflash_writel (void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - pflash_t *pfl = opaque; - - pflash_write(pfl, addr, value, 4); -} - -static CPUWriteMemoryFunc *pflash_write_ops[] = { - &pflash_writeb, - &pflash_writew, - &pflash_writel, -}; - -static CPUReadMemoryFunc *pflash_read_ops[] = { - &pflash_readb, - &pflash_readw, - &pflash_readl, -}; - -/* Count trailing zeroes of a 32 bits quantity */ -static int ctz32 (uint32_t n) -{ - int ret; - - ret = 0; - if (!(n & 0xFFFF)) { - ret += 16; - n = n >> 16; - } - if (!(n & 0xFF)) { - ret += 8; - n = n >> 8; - } - if (!(n & 0xF)) { - ret += 4; - n = n >> 4; - } - if (!(n & 0x3)) { - ret += 2; - n = n >> 2; - } - if (!(n & 0x1)) { - ret++; - n = n >> 1; - } -#if 0 /* This is not necessary as n is never 0 */ - if (!n) - ret++; -#endif - - return ret; -} - -pflash_t *pflash_register (target_ulong base, ram_addr_t off, - BlockDriverState *bs, - target_ulong sector_len, int nb_blocs, int width, - uint16_t id0, uint16_t id1, - uint16_t id2, uint16_t id3) -{ - pflash_t *pfl; - target_long total_len; - - total_len = sector_len * nb_blocs; - /* XXX: to be fixed */ - if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) && - total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024)) - return NULL; - pfl = qemu_mallocz(sizeof(pflash_t)); - if (pfl == NULL) - return NULL; - pfl->storage = phys_ram_base + off; - pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl); - pfl->off = off; - cpu_register_physical_memory(base, total_len, - off | pfl->fl_mem | IO_MEM_ROMD); - pfl->bs = bs; - if (pfl->bs) { - /* read the initial flash content */ - bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9); - } -#if 0 /* XXX: there should be a bit to set up read-only, - * the same way the hardware does (with WP pin). - */ - pfl->ro = 1; -#else - pfl->ro = 0; -#endif - pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl); - pfl->base = base; - pfl->sector_len = sector_len; - pfl->total_len = total_len; - pfl->width = width; - pfl->wcycle = 0; - pfl->cmd = 0; - pfl->status = 0; - pfl->ident[0] = id0; - pfl->ident[1] = id1; - pfl->ident[2] = id2; - pfl->ident[3] = id3; - /* Hardcoded CFI table (mostly from SG29 Spansion flash) */ - pfl->cfi_len = 0x52; - /* Standard "QRY" string */ - pfl->cfi_table[0x10] = 'Q'; - pfl->cfi_table[0x11] = 'R'; - pfl->cfi_table[0x12] = 'Y'; - /* Command set (AMD/Fujitsu) */ - pfl->cfi_table[0x13] = 0x02; - pfl->cfi_table[0x14] = 0x00; - /* Primary extended table address (none) */ - pfl->cfi_table[0x15] = 0x00; - pfl->cfi_table[0x16] = 0x00; - /* Alternate command set (none) */ - pfl->cfi_table[0x17] = 0x00; - pfl->cfi_table[0x18] = 0x00; - /* Alternate extended table (none) */ - pfl->cfi_table[0x19] = 0x00; - pfl->cfi_table[0x1A] = 0x00; - /* Vcc min */ - pfl->cfi_table[0x1B] = 0x27; - /* Vcc max */ - pfl->cfi_table[0x1C] = 0x36; - /* Vpp min (no Vpp pin) */ - pfl->cfi_table[0x1D] = 0x00; - /* Vpp max (no Vpp pin) */ - pfl->cfi_table[0x1E] = 0x00; - /* Reserved */ - pfl->cfi_table[0x1F] = 0x07; - /* Timeout for min size buffer write (16 µs) */ - pfl->cfi_table[0x20] = 0x04; - /* Typical timeout for block erase (512 ms) */ - pfl->cfi_table[0x21] = 0x09; - /* Typical timeout for full chip erase (4096 ms) */ - pfl->cfi_table[0x22] = 0x0C; - /* Reserved */ - pfl->cfi_table[0x23] = 0x01; - /* Max timeout for buffer write */ - pfl->cfi_table[0x24] = 0x04; - /* Max timeout for block erase */ - pfl->cfi_table[0x25] = 0x0A; - /* Max timeout for chip erase */ - pfl->cfi_table[0x26] = 0x0D; - /* Device size */ - pfl->cfi_table[0x27] = ctz32(total_len) + 1; - /* Flash device interface (8 & 16 bits) */ - pfl->cfi_table[0x28] = 0x02; - pfl->cfi_table[0x29] = 0x00; - /* Max number of bytes in multi-bytes write */ - pfl->cfi_table[0x2A] = 0x05; - pfl->cfi_table[0x2B] = 0x00; - /* Number of erase block regions (uniform) */ - pfl->cfi_table[0x2C] = 0x01; - /* Erase block region 1 */ - pfl->cfi_table[0x2D] = nb_blocs - 1; - pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8; - pfl->cfi_table[0x2F] = sector_len >> 8; - pfl->cfi_table[0x30] = sector_len >> 16; - - return pfl; -} diff --git a/hw/piix_pci.c b/hw/piix_pci.c deleted file mode 100644 index 1f7ad94..0000000 --- a/hw/piix_pci.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * QEMU i440FX/PIIX3 PCI Bridge Emulation - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "vl.h" -typedef uint32_t pci_addr_t; -#include "pci_host.h" - -typedef PCIHostState I440FXState; - -static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val) -{ - I440FXState *s = opaque; - s->config_reg = val; -} - -static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr) -{ - I440FXState *s = opaque; - return s->config_reg; -} - -static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level); - -PCIBus *i440fx_init(void) -{ - PCIBus *b; - PCIDevice *d; - I440FXState *s; - - s = qemu_mallocz(sizeof(I440FXState)); - b = pci_register_bus(piix3_set_irq, NULL, 0); - s->bus = b; - - register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s); - register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s); - - register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s); - register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s); - register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s); - register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s); - register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); - register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); - - d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0, - NULL, NULL); - - d->config[0x00] = 0x86; // vendor_id - d->config[0x01] = 0x80; - d->config[0x02] = 0x37; // device_id - d->config[0x03] = 0x12; - d->config[0x08] = 0x02; // revision - d->config[0x0a] = 0x00; // class_sub = host2pci - d->config[0x0b] = 0x06; // class_base = PCI_bridge - d->config[0x0e] = 0x00; // header_type - return b; -} - -/* PIIX3 PCI to ISA bridge */ - -static PCIDevice *piix3_dev; - -/* just used for simpler irq handling. */ -#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) - -static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS]; - -/* return the global irq number corresponding to a given device irq - pin. We could also use the bus number to have a more precise - mapping. */ -static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) -{ - int slot_addend; - slot_addend = (pci_dev->devfn >> 3) - 1; - return (irq_num + slot_addend) & 3; -} - -static inline int get_pci_irq_level(int irq_num) -{ - int pic_level; -#if (PCI_IRQ_WORDS == 2) - pic_level = ((pci_irq_levels[irq_num][0] | - pci_irq_levels[irq_num][1]) != 0); -#else - { - int i; - pic_level = 0; - for(i = 0; i < PCI_IRQ_WORDS; i++) { - if (pci_irq_levels[irq_num][i]) { - pic_level = 1; - break; - } - } - } -#endif - return pic_level; -} - -static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level) -{ - int irq_index, shift, pic_irq, pic_level; - uint32_t *p; - - irq_num = pci_slot_get_pirq(pci_dev, irq_num); - irq_index = pci_dev->irq_index; - p = &pci_irq_levels[irq_num][irq_index >> 5]; - shift = (irq_index & 0x1f); - *p = (*p & ~(1 << shift)) | (level << shift); - - /* now we change the pic irq level according to the piix irq mappings */ - /* XXX: optimize */ - pic_irq = piix3_dev->config[0x60 + irq_num]; - if (pic_irq < 16) { - /* the pic level is the logical OR of all the PCI irqs mapped - to it */ - pic_level = 0; - if (pic_irq == piix3_dev->config[0x60]) - pic_level |= get_pci_irq_level(0); - if (pic_irq == piix3_dev->config[0x61]) - pic_level |= get_pci_irq_level(1); - if (pic_irq == piix3_dev->config[0x62]) - pic_level |= get_pci_irq_level(2); - if (pic_irq == piix3_dev->config[0x63]) - pic_level |= get_pci_irq_level(3); - pic_set_irq(pic_irq, pic_level); - } -} - -static void piix3_reset(PCIDevice *d) -{ - uint8_t *pci_conf = d->config; - - pci_conf[0x04] = 0x07; // master, memory and I/O - pci_conf[0x05] = 0x00; - pci_conf[0x06] = 0x00; - pci_conf[0x07] = 0x02; // PCI_status_devsel_medium - pci_conf[0x4c] = 0x4d; - pci_conf[0x4e] = 0x03; - pci_conf[0x4f] = 0x00; - pci_conf[0x60] = 0x80; - pci_conf[0x69] = 0x02; - pci_conf[0x70] = 0x80; - pci_conf[0x76] = 0x0c; - pci_conf[0x77] = 0x0c; - pci_conf[0x78] = 0x02; - pci_conf[0x79] = 0x00; - pci_conf[0x80] = 0x00; - pci_conf[0x82] = 0x00; - pci_conf[0xa0] = 0x08; - pci_conf[0xa0] = 0x08; - pci_conf[0xa2] = 0x00; - pci_conf[0xa3] = 0x00; - pci_conf[0xa4] = 0x00; - pci_conf[0xa5] = 0x00; - pci_conf[0xa6] = 0x00; - pci_conf[0xa7] = 0x00; - pci_conf[0xa8] = 0x0f; - pci_conf[0xaa] = 0x00; - pci_conf[0xab] = 0x00; - pci_conf[0xac] = 0x00; - pci_conf[0xae] = 0x00; -} - -int piix3_init(PCIBus *bus) -{ - PCIDevice *d; - uint8_t *pci_conf; - - d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice), - -1, NULL, NULL); - register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); - - piix3_dev = d; - pci_conf = d->config; - - pci_conf[0x00] = 0x86; // Intel - pci_conf[0x01] = 0x80; - pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) - pci_conf[0x03] = 0x70; - pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA - pci_conf[0x0b] = 0x06; // class_base = PCI_bridge - pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic - - piix3_reset(d); - return d->devfn; -} - -/***********************************************************/ -/* XXX: the following should be moved to the PC BIOS */ - -static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) -{ - return cpu_inb(NULL, addr); -} - -static void isa_outb(uint32_t val, uint32_t addr) -{ - cpu_outb(NULL, addr, val); -} - -static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) -{ - return cpu_inw(NULL, addr); -} - -static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) -{ - cpu_outw(NULL, addr, val); -} - -static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) -{ - return cpu_inl(NULL, addr); -} - -static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) -{ - cpu_outl(NULL, addr, val); -} - -static uint32_t pci_bios_io_addr; -static uint32_t pci_bios_mem_addr; -/* host irqs corresponding to PCI irqs A-D */ -static uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; - -static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - pci_data_write(s, addr, val, 4); -} - -static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - pci_data_write(s, addr, val, 2); -} - -static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - pci_data_write(s, addr, val, 1); -} - -static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - return pci_data_read(s, addr, 4); -} - -static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - return pci_data_read(s, addr, 2); -} - -static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) -{ - PCIBus *s = d->bus; - addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); - return pci_data_read(s, addr, 1); -} - -static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) -{ - PCIIORegion *r; - uint16_t cmd; - uint32_t ofs; - - if ( region_num == PCI_ROM_SLOT ) { - ofs = 0x30; - }else{ - ofs = 0x10 + region_num * 4; - } - - pci_config_writel(d, ofs, addr); - r = &d->io_regions[region_num]; - - /* enable memory mappings */ - cmd = pci_config_readw(d, PCI_COMMAND); - if ( region_num == PCI_ROM_SLOT ) - cmd |= 2; - else if (r->type & PCI_ADDRESS_SPACE_IO) - cmd |= 1; - else - cmd |= 2; - pci_config_writew(d, PCI_COMMAND, cmd); -} - -static void pci_bios_init_device(PCIDevice *d) -{ - int class; - PCIIORegion *r; - uint32_t *paddr; - int i, pin, pic_irq, vendor_id, device_id; - - class = pci_config_readw(d, PCI_CLASS_DEVICE); - vendor_id = pci_config_readw(d, PCI_VENDOR_ID); - device_id = pci_config_readw(d, PCI_DEVICE_ID); - switch(class) { - case 0x0101: - if (vendor_id == 0x8086 && device_id == 0x7010) { - /* PIIX3 IDE */ - pci_config_writew(d, 0x40, 0x8000); // enable IDE0 - pci_config_writew(d, 0x42, 0x8000); // enable IDE1 - goto default_map; - } else { - /* IDE: we map it as in ISA mode */ - pci_set_io_region_addr(d, 0, 0x1f0); - pci_set_io_region_addr(d, 1, 0x3f4); - pci_set_io_region_addr(d, 2, 0x170); - pci_set_io_region_addr(d, 3, 0x374); - } - break; - case 0x0300: - if (vendor_id != 0x1234) - goto default_map; - /* VGA: map frame buffer to default Bochs VBE address */ - pci_set_io_region_addr(d, 0, 0xE0000000); - break; - case 0x0800: - /* PIC */ - vendor_id = pci_config_readw(d, PCI_VENDOR_ID); - device_id = pci_config_readw(d, PCI_DEVICE_ID); - if (vendor_id == 0x1014) { - /* IBM */ - if (device_id == 0x0046 || device_id == 0xFFFF) { - /* MPIC & MPIC2 */ - pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); - } - } - break; - case 0xff00: - if (vendor_id == 0x0106b && - (device_id == 0x0017 || device_id == 0x0022)) { - /* macio bridge */ - pci_set_io_region_addr(d, 0, 0x80800000); - } - break; - default: - default_map: - /* default memory mappings */ - for(i = 0; i < PCI_NUM_REGIONS; i++) { - r = &d->io_regions[i]; - if (r->size) { - if (r->type & PCI_ADDRESS_SPACE_IO) - paddr = &pci_bios_io_addr; - else - paddr = &pci_bios_mem_addr; - *paddr = (*paddr + r->size - 1) & ~(r->size - 1); - pci_set_io_region_addr(d, i, *paddr); - *paddr += r->size; - } - } - break; - } - - /* map the interrupt */ - pin = pci_config_readb(d, PCI_INTERRUPT_PIN); - if (pin != 0) { - pin = pci_slot_get_pirq(d, pin - 1); - pic_irq = pci_irqs[pin]; - pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); - } -} - -/* - * This function initializes the PCI devices as a normal PCI BIOS - * would do. It is provided just in case the BIOS has no support for - * PCI. - */ -void pci_bios_init(void) -{ - int i, irq; - uint8_t elcr[2]; - - pci_bios_io_addr = 0xc000; - pci_bios_mem_addr = 0xf0000000; - - /* activate IRQ mappings */ - elcr[0] = 0x00; - elcr[1] = 0x00; - for(i = 0; i < 4; i++) { - irq = pci_irqs[i]; - /* set to trigger level */ - elcr[irq >> 3] |= (1 << (irq & 7)); - /* activate irq remapping in PIIX */ - pci_config_writeb(piix3_dev, 0x60 + i, irq); - } - isa_outb(elcr[0], 0x4d0); - isa_outb(elcr[1], 0x4d1); - - pci_for_each_device(pci_bios_init_device); -} - diff --git a/hw/pl011.c b/hw/pl011.c deleted file mode 100644 index 657f03b..0000000 --- a/hw/pl011.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Arm PrimeCell PL011 UART - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the GPL. - */ - -#include "vl.h" - -typedef struct { - uint32_t base; - uint32_t readbuff; - uint32_t flags; - uint32_t lcr; - uint32_t cr; - uint32_t dmacr; - uint32_t int_enabled; - uint32_t int_level; - uint32_t read_fifo[16]; - uint32_t ilpr; - uint32_t ibrd; - uint32_t fbrd; - uint32_t ifl; - int read_pos; - int read_count; - int read_trigger; - CharDriverState *chr; - void *pic; - int irq; -} pl011_state; - -#define PL011_INT_TX 0x20 -#define PL011_INT_RX 0x10 - -#define PL011_FLAG_TXFE 0x80 -#define PL011_FLAG_RXFF 0x40 -#define PL011_FLAG_TXFF 0x20 -#define PL011_FLAG_RXFE 0x10 - -static const unsigned char pl011_id[] = -{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; - -static void pl011_update(pl011_state *s) -{ - uint32_t flags; - - flags = s->int_level & s->int_enabled; - pic_set_irq_new(s->pic, s->irq, flags != 0); -} - -static uint32_t pl011_read(void *opaque, target_phys_addr_t offset) -{ - pl011_state *s = (pl011_state *)opaque; - uint32_t c; - - offset -= s->base; - if (offset >= 0xfe0 && offset < 0x1000) { - return pl011_id[(offset - 0xfe0) >> 2]; - } - switch (offset >> 2) { - case 0: /* UARTDR */ - s->flags &= ~PL011_FLAG_RXFF; - c = s->read_fifo[s->read_pos]; - if (s->read_count > 0) { - s->read_count--; - if (++s->read_pos == 16) - s->read_pos = 0; - } - if (s->read_count == 0) { - s->flags |= PL011_FLAG_RXFE; - } - if (s->read_count == s->read_trigger - 1) - s->int_level &= ~ PL011_INT_RX; - pl011_update(s); - return c; - case 1: /* UARTCR */ - return 0; - case 6: /* UARTFR */ - return s->flags; - case 8: /* UARTILPR */ - return s->ilpr; - case 9: /* UARTIBRD */ - return s->ibrd; - case 10: /* UARTFBRD */ - return s->fbrd; - case 11: /* UARTLCR_H */ - return s->lcr; - case 12: /* UARTCR */ - return s->cr; - case 13: /* UARTIFLS */ - return s->ifl; - case 14: /* UARTIMSC */ - return s->int_enabled; - case 15: /* UARTRIS */ - return s->int_level; - case 16: /* UARTMIS */ - return s->int_level & s->int_enabled; - case 18: /* UARTDMACR */ - return s->dmacr; - default: - cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset); - return 0; - } -} - -static void pl011_set_read_trigger(pl011_state *s) -{ -#if 0 - /* The docs say the RX interrupt is triggered when the FIFO exceeds - the threshold. However linux only reads the FIFO in response to an - interrupt. Triggering the interrupt when the FIFO is non-empty seems - to make things work. */ - if (s->lcr & 0x10) - s->read_trigger = (s->ifl >> 1) & 0x1c; - else -#endif - s->read_trigger = 1; -} - -static void pl011_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - pl011_state *s = (pl011_state *)opaque; - unsigned char ch; - - offset -= s->base; - switch (offset >> 2) { - case 0: /* UARTDR */ - /* ??? Check if transmitter is enabled. */ - ch = value; - if (s->chr) - qemu_chr_write(s->chr, &ch, 1); - s->int_level |= PL011_INT_TX; - pl011_update(s); - break; - case 1: /* UARTCR */ - s->cr = value; - break; - case 8: /* UARTUARTILPR */ - s->ilpr = value; - break; - case 9: /* UARTIBRD */ - s->ibrd = value; - break; - case 10: /* UARTFBRD */ - s->fbrd = value; - break; - case 11: /* UARTLCR_H */ - s->lcr = value; - pl011_set_read_trigger(s); - break; - case 12: /* UARTCR */ - /* ??? Need to implement the enable and loopback bits. */ - s->cr = value; - break; - case 13: /* UARTIFS */ - s->ifl = value; - pl011_set_read_trigger(s); - break; - case 14: /* UARTIMSC */ - s->int_enabled = value; - pl011_update(s); - break; - case 17: /* UARTICR */ - s->int_level &= ~value; - pl011_update(s); - break; - case 18: /* UARTDMACR */ - s->dmacr = value; - if (value & 3) - cpu_abort(cpu_single_env, "PL011: DMA not implemented\n"); - break; - default: - cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset); - } -} - -static int pl011_can_recieve(void *opaque) -{ - pl011_state *s = (pl011_state *)opaque; - - if (s->lcr & 0x10) - return s->read_count < 16; - else - return s->read_count < 1; -} - -static void pl011_recieve(void *opaque, const uint8_t *buf, int size) -{ - pl011_state *s = (pl011_state *)opaque; - int slot; - - slot = s->read_pos + s->read_count; - if (slot >= 16) - slot -= 16; - s->read_fifo[slot] = *buf; - s->read_count++; - s->flags &= ~PL011_FLAG_RXFE; - if (s->cr & 0x10 || s->read_count == 16) { - s->flags |= PL011_FLAG_RXFF; - } - if (s->read_count == s->read_trigger) { - s->int_level |= PL011_INT_RX; - pl011_update(s); - } -} - -static void pl011_event(void *opaque, int event) -{ - /* ??? Should probably implement break. */ -} - -static CPUReadMemoryFunc *pl011_readfn[] = { - pl011_read, - pl011_read, - pl011_read -}; - -static CPUWriteMemoryFunc *pl011_writefn[] = { - pl011_write, - pl011_write, - pl011_write -}; - -void pl011_init(uint32_t base, void *pic, int irq, - CharDriverState *chr) -{ - int iomemtype; - pl011_state *s; - - s = (pl011_state *)qemu_mallocz(sizeof(pl011_state)); - iomemtype = cpu_register_io_memory(0, pl011_readfn, - pl011_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - s->base = base; - s->pic = pic; - s->irq = irq; - s->chr = chr; - s->read_trigger = 1; - s->ifl = 0x12; - s->cr = 0x300; - s->flags = 0x90; - if (chr){ - qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s); - qemu_chr_add_event_handler(chr, pl011_event); - } - /* ??? Save/restore. */ -} - diff --git a/hw/pl050.c b/hw/pl050.c deleted file mode 100644 index 20451e5..0000000 --- a/hw/pl050.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Arm PrimeCell PL050 Keyboard / Mouse Interface - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the GPL. - */ - -#include "vl.h" - -typedef struct { - void *dev; - uint32_t base; - uint32_t cr; - uint32_t clk; - uint32_t last; - void *pic; - int pending; - int irq; - int is_mouse; -} pl050_state; - -static const unsigned char pl050_id[] = -{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; - -static void pl050_update(void *opaque, int level) -{ - pl050_state *s = (pl050_state *)opaque; - int raise; - - s->pending = level; - raise = (s->pending && (s->cr & 0x10) != 0) - || (s->cr & 0x08) != 0; - pic_set_irq_new(s->pic, s->irq, raise); -} - -static uint32_t pl050_read(void *opaque, target_phys_addr_t offset) -{ - pl050_state *s = (pl050_state *)opaque; - offset -= s->base; - if (offset >= 0xfe0 && offset < 0x1000) - return pl050_id[(offset - 0xfe0) >> 2]; - - switch (offset >> 2) { - case 0: /* KMICR */ - return s->cr; - case 1: /* KMISTAT */ - /* KMIC and KMID bits not implemented. */ - if (s->pending) { - return 0x10; - } else { - return 0; - } - case 2: /* KMIDATA */ - if (s->pending) - s->last = ps2_read_data(s->dev); - return s->last; - case 3: /* KMICLKDIV */ - return s->clk; - case 4: /* KMIIR */ - return s->pending | 2; - default: - cpu_abort (cpu_single_env, "pl050_read: Bad offset %x\n", offset); - return 0; - } -} - -static void pl050_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - pl050_state *s = (pl050_state *)opaque; - offset -= s->base; - switch (offset >> 2) { - case 0: /* KMICR */ - s->cr = value; - pl050_update(s, s->pending); - /* ??? Need to implement the enable/disable bit. */ - break; - case 2: /* KMIDATA */ - /* ??? This should toggle the TX interrupt line. */ - /* ??? This means kbd/mouse can block each other. */ - if (s->is_mouse) { - ps2_write_mouse(s->dev, value); - } else { - ps2_write_keyboard(s->dev, value); - } - break; - case 3: /* KMICLKDIV */ - s->clk = value; - return; - default: - cpu_abort (cpu_single_env, "pl050_write: Bad offset %x\n", offset); - } -} -static CPUReadMemoryFunc *pl050_readfn[] = { - pl050_read, - pl050_read, - pl050_read -}; - -static CPUWriteMemoryFunc *pl050_writefn[] = { - pl050_write, - pl050_write, - pl050_write -}; - -void pl050_init(uint32_t base, void *pic, int irq, int is_mouse) -{ - int iomemtype; - pl050_state *s; - - s = (pl050_state *)qemu_mallocz(sizeof(pl050_state)); - iomemtype = cpu_register_io_memory(0, pl050_readfn, - pl050_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - s->base = base; - s->pic = pic; - s->irq = irq; - s->is_mouse = is_mouse; - if (is_mouse) - s->dev = ps2_mouse_init(pl050_update, s); - else - s->dev = ps2_kbd_init(pl050_update, s); - /* ??? Save/restore. */ -} - diff --git a/hw/pl080.c b/hw/pl080.c deleted file mode 100644 index 49996ca..0000000 --- a/hw/pl080.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Arm PrimeCell PL080 DMA controller - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the GPL. - */ - -#include "vl.h" - -#define PL080_NUM_CHANNELS 8 -#define PL080_CONF_E 0x1 -#define PL080_CONF_M1 0x2 -#define PL080_CONF_M2 0x4 - -#define PL080_CCONF_H 0x40000 -#define PL080_CCONF_A 0x20000 -#define PL080_CCONF_L 0x10000 -#define PL080_CCONF_ITC 0x08000 -#define PL080_CCONF_IE 0x04000 -#define PL080_CCONF_E 0x00001 - -#define PL080_CCTRL_I 0x80000000 -#define PL080_CCTRL_DI 0x08000000 -#define PL080_CCTRL_SI 0x04000000 -#define PL080_CCTRL_D 0x02000000 -#define PL080_CCTRL_S 0x01000000 - -typedef struct { - uint32_t src; - uint32_t dest; - uint32_t lli; - uint32_t ctrl; - uint32_t conf; -} pl080_channel; - -typedef struct { - uint32_t base; - uint8_t tc_int; - uint8_t tc_mask; - uint8_t err_int; - uint8_t err_mask; - uint32_t conf; - uint32_t sync; - uint32_t req_single; - uint32_t req_burst; - pl080_channel chan[PL080_NUM_CHANNELS]; - /* Flag to avoid recursive DMA invocations. */ - int running; - void *pic; - int irq; -} pl080_state; - -static const unsigned char pl080_id[] = -{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 }; - -static void pl080_update(pl080_state *s) -{ - if ((s->tc_int & s->tc_mask) - || (s->err_int & s->err_mask)) - pic_set_irq_new(s->pic, s->irq, 1); - else - pic_set_irq_new(s->pic, s->irq, 1); -} - -static void pl080_run(pl080_state *s) -{ - int c; - int flow; - pl080_channel *ch; - int swidth; - int dwidth; - int xsize; - int n; - int src_id; - int dest_id; - int size; - char buff[4]; - uint32_t req; - - s->tc_mask = 0; - for (c = 0; c < PL080_NUM_CHANNELS; c++) { - if (s->chan[c].conf & PL080_CCONF_ITC) - s->tc_mask |= 1 << c; - if (s->chan[c].conf & PL080_CCONF_IE) - s->err_mask |= 1 << c; - } - - if ((s->conf & PL080_CONF_E) == 0) - return; - -cpu_abort(cpu_single_env, "DMA active\n"); - /* If we are already in the middle of a DMA operation then indicate that - there may be new DMA requests and return immediately. */ - if (s->running) { - s->running++; - return; - } - s->running = 1; - while (s->running) { - for (c = 0; c < PL080_NUM_CHANNELS; c++) { - ch = &s->chan[c]; -again: - /* Test if thiws channel has any pending DMA requests. */ - if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E)) - != PL080_CCONF_E) - continue; - flow = (ch->conf >> 11) & 7; - if (flow >= 4) { - cpu_abort(cpu_single_env, - "pl080_run: Peripheral flow control not implemented\n"); - } - src_id = (ch->conf >> 1) & 0x1f; - dest_id = (ch->conf >> 6) & 0x1f; - size = ch->ctrl & 0xfff; - req = s->req_single | s->req_burst; - switch (flow) { - case 0: - break; - case 1: - if ((req & (1u << dest_id)) == 0) - size = 0; - break; - case 2: - if ((req & (1u << src_id)) == 0) - size = 0; - break; - case 3: - if ((req & (1u << src_id)) == 0 - || (req & (1u << dest_id)) == 0) - size = 0; - break; - } - if (!size) - continue; - - /* Transfer one element. */ - /* ??? Should transfer multiple elements for a burst request. */ - /* ??? Unclear what the proper behavior is when source and - destination widths are different. */ - swidth = 1 << ((ch->ctrl >> 18) & 7); - dwidth = 1 << ((ch->ctrl >> 21) & 7); - for (n = 0; n < dwidth; n+= swidth) { - cpu_physical_memory_read(ch->src, buff + n, swidth); - if (ch->ctrl & PL080_CCTRL_SI) - ch->src += swidth; - } - xsize = (dwidth < swidth) ? swidth : dwidth; - /* ??? This may pad the value incorrectly for dwidth < 32. */ - for (n = 0; n < xsize; n += dwidth) { - cpu_physical_memory_write(ch->dest + n, buff + n, dwidth); - if (ch->ctrl & PL080_CCTRL_DI) - ch->dest += swidth; - } - - size--; - ch->ctrl = (ch->ctrl & 0xfffff000) | size; - if (size == 0) { - /* Transfer complete. */ - if (ch->lli) { - ch->src = ldl_phys(ch->lli); - ch->dest = ldl_phys(ch->lli + 4); - ch->ctrl = ldl_phys(ch->lli + 12); - ch->lli = ldl_phys(ch->lli + 8); - } else { - ch->conf &= ~PL080_CCONF_E; - } - if (ch->ctrl & PL080_CCTRL_I) { - s->tc_int |= 1 << c; - } - } - goto again; - } - if (--s->running) - s->running = 1; - } -} - -static uint32_t pl080_read(void *opaque, target_phys_addr_t offset) -{ - pl080_state *s = (pl080_state *)opaque; - uint32_t i; - uint32_t mask; - - offset -= s->base; - if (offset >= 0xfe0 && offset < 0x1000) { - return pl080_id[(offset - 0xfe0) >> 2]; - } - if (offset >= 0x100 && offset < 0x200) { - i = (offset & 0xe0) >> 5; - switch (offset >> 2) { - case 0: /* SrcAddr */ - return s->chan[i].src; - case 1: /* DestAddr */ - return s->chan[i].dest; - case 2: /* LLI */ - return s->chan[i].lli; - case 3: /* Control */ - return s->chan[i].ctrl; - case 4: /* Configuration */ - return s->chan[i].conf; - default: - goto bad_offset; - } - } - switch (offset >> 2) { - case 0: /* IntStatus */ - return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask); - case 1: /* IntTCStatus */ - return (s->tc_int & s->tc_mask); - case 3: /* IntErrorStatus */ - return (s->err_int & s->err_mask); - case 5: /* RawIntTCStatus */ - return s->tc_int; - case 6: /* RawIntErrorStatus */ - return s->err_int; - case 7: /* EnbldChns */ - mask = 0; - for (i = 0; i < PL080_NUM_CHANNELS; i++) { - if (s->chan[i].conf & PL080_CCONF_E) - mask |= 1 << i; - } - return mask; - case 8: /* SoftBReq */ - case 9: /* SoftSReq */ - case 10: /* SoftLBReq */ - case 11: /* SoftLSReq */ - /* ??? Implement these. */ - return 0; - case 12: /* Configuration */ - return s->conf; - case 13: /* Sync */ - return s->sync; - default: - bad_offset: - cpu_abort(cpu_single_env, "pl080_read: Bad offset %x\n", offset); - return 0; - } -} - -static void pl080_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - pl080_state *s = (pl080_state *)opaque; - int i; - - offset -= s->base; - if (offset >= 0x100 && offset < 0x200) { - i = (offset & 0xe0) >> 5; - switch (offset >> 2) { - case 0: /* SrcAddr */ - s->chan[i].src = value; - break; - case 1: /* DestAddr */ - s->chan[i].dest = value; - break; - case 2: /* LLI */ - s->chan[i].lli = value; - break; - case 3: /* Control */ - s->chan[i].ctrl = value; - break; - case 4: /* Configuration */ - s->chan[i].conf = value; - pl080_run(s); - break; - } - } - switch (offset >> 2) { - case 2: /* IntTCClear */ - s->tc_int &= ~value; - break; - case 4: /* IntErrorClear */ - s->err_int &= ~value; - break; - case 8: /* SoftBReq */ - case 9: /* SoftSReq */ - case 10: /* SoftLBReq */ - case 11: /* SoftLSReq */ - /* ??? Implement these. */ - cpu_abort(cpu_single_env, "pl080_write: Soft DMA not implemented\n"); - break; - case 12: /* Configuration */ - s->conf = value; - if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) { - cpu_abort(cpu_single_env, - "pl080_write: Big-endian DMA not implemented\n"); - } - pl080_run(s); - break; - case 13: /* Sync */ - s->sync = value; - break; - default: - cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", offset); - } - pl080_update(s); -} - -static CPUReadMemoryFunc *pl080_readfn[] = { - pl080_read, - pl080_read, - pl080_read -}; - -static CPUWriteMemoryFunc *pl080_writefn[] = { - pl080_write, - pl080_write, - pl080_write -}; - -void *pl080_init(uint32_t base, void *pic, int irq) -{ - int iomemtype; - pl080_state *s; - - s = (pl080_state *)qemu_mallocz(sizeof(pl080_state)); - iomemtype = cpu_register_io_memory(0, pl080_readfn, - pl080_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - s->base = base; - s->pic = pic; - s->irq = irq; - /* ??? Save/restore. */ - return s; -} - diff --git a/hw/pl110.c b/hw/pl110.c deleted file mode 100644 index ecebe35..0000000 --- a/hw/pl110.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Arm PrimeCell PL110 Color LCD Controller - * - * Copyright (c) 2005-2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the GNU LGPL - */ - -#include "vl.h" - -#define PL110_CR_EN 0x001 -#define PL110_CR_BEBO 0x200 -#define PL110_CR_BEPO 0x400 -#define PL110_CR_PWR 0x800 - -enum pl110_bppmode -{ - BPP_1, - BPP_2, - BPP_4, - BPP_8, - BPP_16, - BPP_32 -}; - -typedef struct { - uint32_t base; - DisplayState *ds; - /* The Versatile/PB uses a slightly modified PL110 controller. */ - int versatile; - void *pic; - uint32_t timing[4]; - uint32_t cr; - uint32_t upbase; - uint32_t lpbase; - uint32_t int_status; - uint32_t int_mask; - int cols; - int rows; - enum pl110_bppmode bpp; - int invalidate; - uint32_t pallette[256]; - uint32_t raw_pallette[128]; - int irq; -} pl110_state; - -static const unsigned char pl110_id[] = -{ 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; - -/* The Arm documentation (DDI0224C) says the CLDC on the Versatile board - has a different ID. However Linux only looks for the normal ID. */ -#if 0 -static const unsigned char pl110_versatile_id[] = -{ 0x93, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; -#else -#define pl110_versatile_id pl110_id -#endif - -static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); -} - -static inline uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); -} - -static inline uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); -} - -static inline uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b) -{ - return (r << 16) | (g << 8) | b; -} - -static inline uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) -{ - return (r << 16) | (g << 8) | b; -} - -typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int); - -#define BITS 8 -#include "pl110_template.h" -#define BITS 15 -#include "pl110_template.h" -#define BITS 16 -#include "pl110_template.h" -#define BITS 24 -#include "pl110_template.h" -#define BITS 32 -#include "pl110_template.h" - -static int pl110_enabled(pl110_state *s) -{ - return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR); -} - -static void pl110_update_display(void *opaque) -{ - pl110_state *s = (pl110_state *)opaque; - drawfn* fntable; - drawfn fn; - uint32_t *pallette; - uint32_t addr; - uint32_t base; - int dest_width; - int src_width; - uint8_t *dest; - uint8_t *src; - int first, last = 0; - int dirty, new_dirty; - int i; - - if (!pl110_enabled(s)) - return; - - switch (s->ds->depth) { - case 0: - return; - case 8: - fntable = pl110_draw_fn_8; - dest_width = 1; - break; - case 15: - fntable = pl110_draw_fn_15; - dest_width = 2; - break; - case 16: - fntable = pl110_draw_fn_16; - dest_width = 2; - break; - case 24: - fntable = pl110_draw_fn_24; - dest_width = 3; - break; - case 32: - fntable = pl110_draw_fn_32; - dest_width = 4; - break; - default: - fprintf(stderr, "pl110: Bad color depth\n"); - exit(1); - } - if (s->cr & PL110_CR_BEBO) - fn = fntable[s->bpp + 6]; - else if (s->cr & PL110_CR_BEPO) - fn = fntable[s->bpp + 12]; - else - fn = fntable[s->bpp]; - - src_width = s->cols; - switch (s->bpp) { - case BPP_1: - src_width >>= 3; - break; - case BPP_2: - src_width >>= 2; - break; - case BPP_4: - src_width >>= 1; - break; - case BPP_8: - break; - case BPP_16: - src_width <<= 1; - break; - case BPP_32: - src_width <<= 2; - break; - } - dest_width *= s->cols; - pallette = s->pallette; - base = s->upbase; - /* HACK: Arm aliases physical memory at 0x80000000. */ - if (base > 0x80000000) - base -= 0x80000000; - src = phys_ram_base + base; - dest = s->ds->data; - first = -1; - addr = base; - - dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG); - for (i = 0; i < s->rows; i++) { - new_dirty = 0; - if ((addr & TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) { - uint32_t tmp; - for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) { - new_dirty |= cpu_physical_memory_get_dirty(addr + tmp, - VGA_DIRTY_FLAG); - } - } - - if (dirty || new_dirty || s->invalidate) { - fn(pallette, dest, src, s->cols); - if (first == -1) - first = i; - last = i; - } - dirty = new_dirty; - addr += src_width; - dest += dest_width; - src += src_width; - } - if (first < 0) - return; - - s->invalidate = 0; - cpu_physical_memory_reset_dirty(base + first * src_width, - base + (last + 1) * src_width, - VGA_DIRTY_FLAG); - dpy_update(s->ds, 0, first, s->cols, last - first + 1); -} - -static void pl110_invalidate_display(void * opaque) -{ - pl110_state *s = (pl110_state *)opaque; - s->invalidate = 1; -} - -static void pl110_update_pallette(pl110_state *s, int n) -{ - int i; - uint32_t raw; - unsigned int r, g, b; - - raw = s->raw_pallette[n]; - n <<= 1; - for (i = 0; i < 2; i++) { - r = (raw & 0x1f) << 3; - raw >>= 5; - g = (raw & 0x1f) << 3; - raw >>= 5; - b = (raw & 0x1f) << 3; - /* The I bit is ignored. */ - raw >>= 6; - switch (s->ds->depth) { - case 8: - s->pallette[n] = rgb_to_pixel8(r, g, b); - break; - case 15: - s->pallette[n] = rgb_to_pixel15(r, g, b); - break; - case 16: - s->pallette[n] = rgb_to_pixel16(r, g, b); - break; - case 24: - case 32: - s->pallette[n] = rgb_to_pixel32(r, g, b); - break; - } - n++; - } -} - -static void pl110_resize(pl110_state *s, int width, int height) -{ - if (width != s->cols || height != s->rows) { - if (pl110_enabled(s)) { - dpy_resize(s->ds, width, height); - } - } - s->cols = width; - s->rows = height; -} - -/* Update interrupts. */ -static void pl110_update(pl110_state *s) -{ - /* TODO: Implement interrupts. */ -} - -static uint32_t pl110_read(void *opaque, target_phys_addr_t offset) -{ - pl110_state *s = (pl110_state *)opaque; - - offset -= s->base; - if (offset >= 0xfe0 && offset < 0x1000) { - if (s->versatile) - return pl110_versatile_id[(offset - 0xfe0) >> 2]; - else - return pl110_id[(offset - 0xfe0) >> 2]; - } - if (offset >= 0x200 && offset < 0x400) { - return s->raw_pallette[(offset - 0x200) >> 2]; - } - switch (offset >> 2) { - case 0: /* LCDTiming0 */ - return s->timing[0]; - case 1: /* LCDTiming1 */ - return s->timing[1]; - case 2: /* LCDTiming2 */ - return s->timing[2]; - case 3: /* LCDTiming3 */ - return s->timing[3]; - case 4: /* LCDUPBASE */ - return s->upbase; - case 5: /* LCDLPBASE */ - return s->lpbase; - case 6: /* LCDIMSC */ - return s->int_mask; - case 7: /* LCDControl */ - return s->cr; - case 8: /* LCDRIS */ - return s->int_status; - case 9: /* LCDMIS */ - return s->int_status & s->int_mask; - case 11: /* LCDUPCURR */ - /* TODO: Implement vertical refresh. */ - return s->upbase; - case 12: /* LCDLPCURR */ - return s->lpbase; - default: - cpu_abort (cpu_single_env, "pl110_read: Bad offset %x\n", offset); - return 0; - } -} - -static void pl110_write(void *opaque, target_phys_addr_t offset, - uint32_t val) -{ - pl110_state *s = (pl110_state *)opaque; - int n; - - /* For simplicity invalidate the display whenever a control register - is writen to. */ - s->invalidate = 1; - offset -= s->base; - if (offset >= 0x200 && offset < 0x400) { - /* Pallette. */ - n = (offset - 0x200) >> 2; - s->raw_pallette[(offset - 0x200) >> 2] = val; - pl110_update_pallette(s, n); - return; - } - switch (offset >> 2) { - case 0: /* LCDTiming0 */ - s->timing[0] = val; - n = ((val & 0xfc) + 4) * 4; - pl110_resize(s, n, s->rows); - break; - case 1: /* LCDTiming1 */ - s->timing[1] = val; - n = (val & 0x3ff) + 1; - pl110_resize(s, s->cols, n); - break; - case 2: /* LCDTiming2 */ - s->timing[2] = val; - break; - case 3: /* LCDTiming3 */ - s->timing[3] = val; - break; - case 4: /* LCDUPBASE */ - s->upbase = val; - break; - case 5: /* LCDLPBASE */ - s->lpbase = val; - break; - case 6: /* LCDIMSC */ - if (s->versatile) - goto control; - imsc: - s->int_mask = val; - pl110_update(s); - break; - case 7: /* LCDControl */ - if (s->versatile) - goto imsc; - control: - s->cr = val; - s->bpp = (val >> 1) & 7; - if (pl110_enabled(s)) { - dpy_resize(s->ds, s->cols, s->rows); - } - break; - case 10: /* LCDICR */ - s->int_status &= ~val; - pl110_update(s); - break; - default: - cpu_abort (cpu_single_env, "pl110_write: Bad offset %x\n", offset); - } -} - -static CPUReadMemoryFunc *pl110_readfn[] = { - pl110_read, - pl110_read, - pl110_read -}; - -static CPUWriteMemoryFunc *pl110_writefn[] = { - pl110_write, - pl110_write, - pl110_write -}; - -void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, - int versatile) -{ - pl110_state *s; - int iomemtype; - - s = (pl110_state *)qemu_mallocz(sizeof(pl110_state)); - iomemtype = cpu_register_io_memory(0, pl110_readfn, - pl110_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - s->base = base; - s->ds = ds; - s->versatile = versatile; - s->pic = pic; - s->irq = irq; - graphic_console_init(ds, pl110_update_display, pl110_invalidate_display, - NULL, s); - /* ??? Save/restore. */ - return s; -} diff --git a/hw/pl110_template.h b/hw/pl110_template.h deleted file mode 100644 index db05035..0000000 --- a/hw/pl110_template.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Arm PrimeCell PL110 Color LCD Controller - * - * Copyright (c) 2005 CodeSourcery, LLC. - * Written by Paul Brook - * - * This code is licenced under the GNU LGPL - * - * Framebuffer format conversion routines. - */ - -#ifndef ORDER - -#if BITS == 8 -#define COPY_PIXEL(to, from) *(to++) = from -#elif BITS == 15 || BITS == 16 -#define COPY_PIXEL(to, from) *(uint16_t *)to = from; to += 2; -#elif BITS == 24 -#define COPY_PIXEL(to, from) \ - *(to++) = from; *(to++) = (from) >> 8; *(to++) = (from) >> 16 -#elif BITS == 32 -#define COPY_PIXEL(to, from) *(uint32_t *)to = from; to += 4; -#else -#error unknown bit depth -#endif - -#define ORDER 0 -#include "pl110_template.h" -#define ORDER 1 -#include "pl110_template.h" -#define ORDER 2 -#include "pl110_template.h" - -static drawfn glue(pl110_draw_fn_,BITS)[18] = -{ - glue(pl110_draw_line1_lblp,BITS), - glue(pl110_draw_line2_lblp,BITS), - glue(pl110_draw_line4_lblp,BITS), - glue(pl110_draw_line8_lblp,BITS), - glue(pl110_draw_line16_lblp,BITS), - glue(pl110_draw_line32_lblp,BITS), - - glue(pl110_draw_line1_bbbp,BITS), - glue(pl110_draw_line2_bbbp,BITS), - glue(pl110_draw_line4_bbbp,BITS), - glue(pl110_draw_line8_bbbp,BITS), - glue(pl110_draw_line16_bbbp,BITS), - glue(pl110_draw_line32_bbbp,BITS), - - glue(pl110_draw_line1_lbbp,BITS), - glue(pl110_draw_line2_lbbp,BITS), - glue(pl110_draw_line4_lbbp,BITS), - glue(pl110_draw_line8_lbbp,BITS), - glue(pl110_draw_line16_lbbp,BITS), - glue(pl110_draw_line32_lbbp,BITS) -}; - -#undef BITS -#undef COPY_PIXEL - -#else - -#if ORDER == 0 -#define NAME glue(lblp, BITS) -#ifdef WORDS_BIGENDIAN -#define SWAP_WORDS 1 -#endif -#elif ORDER == 1 -#define NAME glue(bbbp, BITS) -#ifndef WORDS_BIGENDIAN -#define SWAP_WORDS 1 -#endif -#else -#define SWAP_PIXELS 1 -#define NAME glue(lbbp, BITS) -#ifdef WORDS_BIGENDIAN -#define SWAP_WORDS 1 -#endif -#endif - -#define FN_2(x, y) FN(x, y) FN(x+1, y) -#define FN_4(x, y) FN_2(x, y) FN_2(x+1, y) -#define FN_8(y) FN_4(0, y) FN_4(4, y) - -static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) -{ - uint32_t data; - while (width > 0) { - data = *(uint32_t *)src; -#ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 7 - (x))) & 1]); -#else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x) + y)) & 1]); -#endif -#ifdef SWAP_WORDS - FN_8(24) - FN_8(16) - FN_8(8) - FN_8(0) -#else - FN_8(0) - FN_8(8) - FN_8(16) - FN_8(24) -#endif -#undef FN - width -= 32; - src += 4; - } -} - -static void glue(pl110_draw_line2_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) -{ - uint32_t data; - while (width > 0) { - data = *(uint32_t *)src; -#ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 6 - (x)*2)) & 3]); -#else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*2 + y)) & 3]); -#endif -#ifdef SWAP_WORDS - FN_4(0, 24) - FN_4(0, 16) - FN_4(0, 8) - FN_4(0, 0) -#else - FN_4(0, 0) - FN_4(0, 8) - FN_4(0, 16) - FN_4(0, 24) -#endif -#undef FN - width -= 16; - src += 4; - } -} - -static void glue(pl110_draw_line4_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) -{ - uint32_t data; - while (width > 0) { - data = *(uint32_t *)src; -#ifdef SWAP_PIXELS -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 4 - (x)*4)) & 0xf]); -#else -#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*4 + y)) & 0xf]); -#endif -#ifdef SWAP_WORDS - FN_2(0, 24) - FN_2(0, 16) - FN_2(0, 8) - FN_2(0, 0) -#else - FN_2(0, 0) - FN_2(0, 8) - FN_2(0, 16) - FN_2(0, 24) -#endif -#undef FN - width -= 8; - src += 4; - } -} - -static void glue(pl110_draw_line8_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) -{ - uint32_t data; - while (width > 0) { - data = *(uint32_t *)src; -#define FN(x) COPY_PIXEL(d, pallette[(data >> (x)) & 0xff]); -#ifdef SWAP_WORDS - FN(24) - FN(16) - FN(8) - FN(0) -#else - FN(0) - FN(8) - FN(16) - FN(24) -#endif -#undef FN - width -= 4; - src += 4; - } -} - -static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) -{ - uint32_t data; - unsigned int r, g, b; - while (width > 0) { - data = *(uint32_t *)src; -#ifdef SWAP_WORDS - data = bswap32(data); -#endif -#if 0 - r = data & 0x1f; - data >>= 5; - g = data & 0x3f; - data >>= 6; - b = data & 0x1f; - data >>= 5; -#else - r = (data & 0x1f) << 3; - data >>= 5; - g = (data & 0x3f) << 2; - data >>= 6; - b = (data & 0x1f) << 3; - data >>= 5; -#endif - COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); - r = (data & 0x1f) << 3; - data >>= 5; - g = (data & 0x3f) << 2; - data >>= 6; - b = (data & 0x1f) << 3; - data >>= 5; - COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); - width -= 2; - src += 4; - } -} - -static void glue(pl110_draw_line32_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width) -{ - uint32_t data; - unsigned int r, g, b; - while (width > 0) { - data = *(uint32_t *)src; -#ifdef SWAP_WORDS - r = data & 0xff; - g = (data >> 8) & 0xff; - b = (data >> 16) & 0xff; -#else - r = (data >> 24) & 0xff; - g = (data >> 16) & 0xff; - b = (data >> 8) & 0xff; -#endif - COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b)); - width--; - src += 4; - } -} - -#undef SWAP_PIXELS -#undef NAME -#undef SWAP_WORDS -#undef ORDER - -#endif diff --git a/hw/pl190.c b/hw/pl190.c deleted file mode 100644 index 55c7180..0000000 --- a/hw/pl190.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Arm PrimeCell PL190 Vector Interrupt Controller - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the GPL. - */ - -#include "vl.h" -#include "arm_pic.h" - -/* The number of virtual priority levels. 16 user vectors plus the - unvectored IRQ. Chained interrupts would require an additional level - if implemented. */ - -#define PL190_NUM_PRIO 17 - -typedef struct { - arm_pic_handler handler; - uint32_t base; - DisplayState *ds; - uint32_t level; - uint32_t soft_level; - uint32_t irq_enable; - uint32_t fiq_select; - uint32_t default_addr; - uint8_t vect_control[16]; - uint32_t vect_addr[PL190_NUM_PRIO]; - /* Mask containing interrupts with higher priority than this one. */ - uint32_t prio_mask[PL190_NUM_PRIO + 1]; - int protected; - /* Current priority level. */ - int priority; - int prev_prio[PL190_NUM_PRIO]; - void *parent; - int irq; - int fiq; -} pl190_state; - -static const unsigned char pl190_id[] = -{ 0x90, 0x11, 0x04, 0x00, 0x0D, 0xf0, 0x05, 0xb1 }; - -static inline uint32_t pl190_irq_level(pl190_state *s) -{ - return (s->level | s->soft_level) & s->irq_enable & ~s->fiq_select; -} - -/* Update interrupts. */ -static void pl190_update(pl190_state *s) -{ - uint32_t level = pl190_irq_level(s); - int set; - - set = (level & s->prio_mask[s->priority]) != 0; - pic_set_irq_new(s->parent, s->irq, set); - set = ((s->level | s->soft_level) & s->fiq_select) != 0; - pic_set_irq_new(s->parent, s->fiq, set); -} - -static void pl190_set_irq(void *opaque, int irq, int level) -{ - pl190_state *s = (pl190_state *)opaque; - - if (level) - s->level |= 1u << irq; - else - s->level &= ~(1u << irq); - pl190_update(s); -} - -static void pl190_update_vectors(pl190_state *s) -{ - uint32_t mask; - int i; - int n; - - mask = 0; - for (i = 0; i < 16; i++) - { - s->prio_mask[i] = mask; - if (s->vect_control[i] & 0x20) - { - n = s->vect_control[i] & 0x1f; - mask |= 1 << n; - } - } - s->prio_mask[16] = mask; - pl190_update(s); -} - -static uint32_t pl190_read(void *opaque, target_phys_addr_t offset) -{ - pl190_state *s = (pl190_state *)opaque; - int i; - - offset -= s->base; - if (offset >= 0xfe0 && offset < 0x1000) { - return pl190_id[(offset - 0xfe0) >> 2]; - } - if (offset >= 0x100 && offset < 0x140) { - return s->vect_addr[(offset - 0x100) >> 2]; - } - if (offset >= 0x200 && offset < 0x240) { - return s->vect_control[(offset - 0x200) >> 2]; - } - switch (offset >> 2) { - case 0: /* IRQSTATUS */ - return pl190_irq_level(s); - case 1: /* FIQSATUS */ - return (s->level | s->soft_level) & s->fiq_select; - case 2: /* RAWINTR */ - return s->level | s->soft_level; - case 3: /* INTSELECT */ - return s->fiq_select; - case 4: /* INTENABLE */ - return s->irq_enable; - case 6: /* SOFTINT */ - return s->soft_level; - case 8: /* PROTECTION */ - return s->protected; - case 12: /* VECTADDR */ - /* Read vector address at the start of an ISR. Increases the - current priority level to that of the current interrupt. */ - for (i = 0; i < s->priority; i++) - { - if ((s->level | s->soft_level) & s->prio_mask[i]) - break; - } - /* Reading this value with no pending interrupts is undefined. - We return the default address. */ - if (i == PL190_NUM_PRIO) - return s->vect_addr[16]; - if (i < s->priority) - { - s->prev_prio[i] = s->priority; - s->priority = i; - pl190_update(s); - } - return s->vect_addr[s->priority]; - case 13: /* DEFVECTADDR */ - return s->vect_addr[16]; - default: - cpu_abort (cpu_single_env, "pl190_read: Bad offset %x\n", offset); - return 0; - } -} - -static void pl190_write(void *opaque, target_phys_addr_t offset, uint32_t val) -{ - pl190_state *s = (pl190_state *)opaque; - - offset -= s->base; - if (offset >= 0x100 && offset < 0x140) { - s->vect_addr[(offset - 0x100) >> 2] = val; - pl190_update_vectors(s); - return; - } - if (offset >= 0x200 && offset < 0x240) { - s->vect_control[(offset - 0x200) >> 2] = val; - pl190_update_vectors(s); - return; - } - switch (offset >> 2) { - case 0: /* SELECT */ - /* This is a readonly register, but linux tries to write to it - anyway. Ignore the write. */ - break; - case 3: /* INTSELECT */ - s->fiq_select = val; - break; - case 4: /* INTENABLE */ - s->irq_enable |= val; - break; - case 5: /* INTENCLEAR */ - s->irq_enable &= ~val; - break; - case 6: /* SOFTINT */ - s->soft_level |= val; - break; - case 7: /* SOFTINTCLEAR */ - s->soft_level &= ~val; - break; - case 8: /* PROTECTION */ - /* TODO: Protection (supervisor only access) is not implemented. */ - s->protected = val & 1; - break; - case 12: /* VECTADDR */ - /* Restore the previous priority level. The value written is - ignored. */ - if (s->priority < PL190_NUM_PRIO) - s->priority = s->prev_prio[s->priority]; - break; - case 13: /* DEFVECTADDR */ - s->default_addr = val; - break; - case 0xc0: /* ITCR */ - if (val) - cpu_abort(cpu_single_env, "pl190: Test mode not implemented\n"); - break; - default: - cpu_abort(cpu_single_env, "pl190_write: Bad offset %x\n", offset); - return; - } - pl190_update(s); -} - -static CPUReadMemoryFunc *pl190_readfn[] = { - pl190_read, - pl190_read, - pl190_read -}; - -static CPUWriteMemoryFunc *pl190_writefn[] = { - pl190_write, - pl190_write, - pl190_write -}; - -void pl190_reset(pl190_state *s) -{ - int i; - - for (i = 0; i < 16; i++) - { - s->vect_addr[i] = 0; - s->vect_control[i] = 0; - } - s->vect_addr[16] = 0; - s->prio_mask[17] = 0xffffffff; - s->priority = PL190_NUM_PRIO; - pl190_update_vectors(s); -} - -void *pl190_init(uint32_t base, void *parent, int irq, int fiq) -{ - pl190_state *s; - int iomemtype; - - s = (pl190_state *)qemu_mallocz(sizeof(pl190_state)); - iomemtype = cpu_register_io_memory(0, pl190_readfn, - pl190_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - s->handler = pl190_set_irq; - s->base = base; - s->parent = parent; - s->irq = irq; - s->fiq = fiq; - pl190_reset(s); - /* ??? Save/restore. */ - return s; -} diff --git a/hw/power_supply.h b/hw/power_supply.h new file mode 100644 index 0000000..b85edc7 --- /dev/null +++ b/hw/power_supply.h @@ -0,0 +1,109 @@ +/* + * Universal power supply monitor class + * + * Copyright © 2007 Anton Vorontsov <cbou@mail.ru> + * Copyright © 2004 Szabolcs Gyurko + * Copyright © 2003 Ian Molton <spyro@f2s.com> + * + * Modified: 2004, Oct Szabolcs Gyurko + * + * You may use this code as per GPL version 2 + */ + +#ifndef __LINUX_POWER_SUPPLY_H__ +#define __LINUX_POWER_SUPPLY_H__ + +/* + * All voltages, currents, charges, energies, time and temperatures in uV, + * µA, µAh, µWh, seconds and tenths of degree Celsius unless otherwise + * stated. It's driver's job to convert its raw values to units in which + * this class operates. + */ + +/* + * For systems where the charger determines the maximum battery capacity + * the min and max fields should be used to present these values to user + * space. Unused/unknown fields will not appear in sysfs. + */ + +enum { + POWER_SUPPLY_STATUS_UNKNOWN = 0, + POWER_SUPPLY_STATUS_CHARGING, + POWER_SUPPLY_STATUS_DISCHARGING, + POWER_SUPPLY_STATUS_NOT_CHARGING, + POWER_SUPPLY_STATUS_FULL, +}; + +enum { + POWER_SUPPLY_HEALTH_UNKNOWN = 0, + POWER_SUPPLY_HEALTH_GOOD, + POWER_SUPPLY_HEALTH_OVERHEAT, + POWER_SUPPLY_HEALTH_DEAD, + POWER_SUPPLY_HEALTH_OVERVOLTAGE, + POWER_SUPPLY_HEALTH_UNSPEC_FAILURE, +}; + +enum { + POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0, + POWER_SUPPLY_TECHNOLOGY_NiMH, + POWER_SUPPLY_TECHNOLOGY_LION, + POWER_SUPPLY_TECHNOLOGY_LIPO, + POWER_SUPPLY_TECHNOLOGY_LiFe, + POWER_SUPPLY_TECHNOLOGY_NiCd, +}; + +enum { + POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0, + POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL, + POWER_SUPPLY_CAPACITY_LEVEL_LOW, + POWER_SUPPLY_CAPACITY_LEVEL_NORMAL, + POWER_SUPPLY_CAPACITY_LEVEL_HIGH, + POWER_SUPPLY_CAPACITY_LEVEL_FULL, +}; + +enum power_supply_property { + /* Properties of type `int' */ + POWER_SUPPLY_PROP_STATUS = 0, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_AVG, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CURRENT_AVG, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_EMPTY, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_AVG, + POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, + POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, + POWER_SUPPLY_PROP_ENERGY_FULL, + POWER_SUPPLY_PROP_ENERGY_EMPTY, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_ENERGY_AVG, + POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TEMP_AMBIENT, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, + /* Properties of type `const char *' */ + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +enum power_supply_type { + POWER_SUPPLY_TYPE_BATTERY = 0, + POWER_SUPPLY_TYPE_UPS, + POWER_SUPPLY_TYPE_MAINS, + POWER_SUPPLY_TYPE_USB, +}; + +#endif /* __LINUX_POWER_SUPPLY_H__ */ diff --git a/hw/ppc.c b/hw/ppc.c deleted file mode 100644 index 3743ad7..0000000 --- a/hw/ppc.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * QEMU generic PPC hardware System Emulator - * - * Copyright (c) 2003-2004 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -#include "m48t59.h" - -/*****************************************************************************/ -/* PPC time base and decrementer emulation */ -//#define DEBUG_TB - -struct ppc_tb_t { - /* Time base management */ - int64_t tb_offset; /* Compensation */ - uint32_t tb_freq; /* TB frequency */ - /* Decrementer management */ - uint64_t decr_next; /* Tick for next decr interrupt */ - struct QEMUTimer *decr_timer; -}; - -static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env) -{ - /* TB time in tb periods */ - return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset, - tb_env->tb_freq, ticks_per_sec); -} - -uint32_t cpu_ppc_load_tbl (CPUState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb; - - tb = cpu_ppc_get_tb(tb_env); -#ifdef DEBUG_TB - { - static int last_time; - int now; - now = time(NULL); - if (last_time != now) { - last_time = now; - printf("%s: tb=0x%016lx %d %08lx\n", - __func__, tb, now, tb_env->tb_offset); - } - } -#endif - - return tb & 0xFFFFFFFF; -} - -uint32_t cpu_ppc_load_tbu (CPUState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t tb; - - tb = cpu_ppc_get_tb(tb_env); -#ifdef DEBUG_TB - printf("%s: tb=0x%016lx\n", __func__, tb); -#endif - return tb >> 32; -} - -static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value) -{ - tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq) - - qemu_get_clock(vm_clock); -#ifdef DEBUG_TB - printf("%s: tb=0x%016lx offset=%08x\n", __func__, value); -#endif -} - -void cpu_ppc_store_tbu (CPUState *env, uint32_t value) -{ - ppc_tb_t *tb_env = env->tb_env; - - cpu_ppc_store_tb(tb_env, - ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); -} - -void cpu_ppc_store_tbl (CPUState *env, uint32_t value) -{ - ppc_tb_t *tb_env = env->tb_env; - - cpu_ppc_store_tb(tb_env, - ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value); -} - -uint32_t cpu_ppc_load_decr (CPUState *env) -{ - ppc_tb_t *tb_env = env->tb_env; - uint32_t decr; - int64_t diff; - - diff = tb_env->decr_next - qemu_get_clock(vm_clock); - if (diff >= 0) - decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec); - else - decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec); -#if defined(DEBUG_TB) - printf("%s: 0x%08x\n", __func__, decr); -#endif - return decr; -} - -/* When decrementer expires, - * all we need to do is generate or queue a CPU exception - */ -static inline void cpu_ppc_decr_excp (CPUState *env) -{ - /* Raise it */ -#ifdef DEBUG_TB - printf("raise decrementer exception\n"); -#endif - cpu_interrupt(env, CPU_INTERRUPT_TIMER); -} - -static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, - uint32_t value, int is_excp) -{ - ppc_tb_t *tb_env = env->tb_env; - uint64_t now, next; - -#ifdef DEBUG_TB - printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value); -#endif - now = qemu_get_clock(vm_clock); - next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); - if (is_excp) - next += tb_env->decr_next - now; - if (next == now) - next++; - tb_env->decr_next = next; - /* Adjust timer */ - qemu_mod_timer(tb_env->decr_timer, next); - /* If we set a negative value and the decrementer was positive, - * raise an exception. - */ - if ((value & 0x80000000) && !(decr & 0x80000000)) - cpu_ppc_decr_excp(env); -} - -void cpu_ppc_store_decr (CPUState *env, uint32_t value) -{ - _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0); -} - -static void cpu_ppc_decr_cb (void *opaque) -{ - _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); -} - -/* Set up (once) timebase frequency (in Hz) */ -ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq) -{ - ppc_tb_t *tb_env; - - tb_env = qemu_mallocz(sizeof(ppc_tb_t)); - if (tb_env == NULL) - return NULL; - env->tb_env = tb_env; - if (tb_env->tb_freq == 0 || 1) { - tb_env->tb_freq = freq; - /* Create new timer */ - tb_env->decr_timer = - qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); - /* There is a bug in 2.4 kernels: - * if a decrementer exception is pending when it enables msr_ee, - * it's not ready to handle it... - */ - _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); - } - - return tb_env; -} - -#if 0 -/*****************************************************************************/ -/* Handle system reset (for now, just stop emulation) */ -void cpu_ppc_reset (CPUState *env) -{ - printf("Reset asked... Stop emulation\n"); - abort(); -} -#endif - -static void PPC_io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - cpu_outb(NULL, addr & 0xffff, value); -} - -static uint32_t PPC_io_readb (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inb(NULL, addr & 0xffff); - return ret; -} - -static void PPC_io_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap16(value); -#endif - cpu_outw(NULL, addr & 0xffff, value); -} - -static uint32_t PPC_io_readw (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inw(NULL, addr & 0xffff); -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap16(ret); -#endif - return ret; -} - -static void PPC_io_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap32(value); -#endif - cpu_outl(NULL, addr & 0xffff, value); -} - -static uint32_t PPC_io_readl (void *opaque, target_phys_addr_t addr) -{ - uint32_t ret = cpu_inl(NULL, addr & 0xffff); - -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap32(ret); -#endif - return ret; -} - -CPUWriteMemoryFunc *PPC_io_write[] = { - &PPC_io_writeb, - &PPC_io_writew, - &PPC_io_writel, -}; - -CPUReadMemoryFunc *PPC_io_read[] = { - &PPC_io_readb, - &PPC_io_readw, - &PPC_io_readl, -}; - -/*****************************************************************************/ -/* Debug port */ -void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val) -{ - addr &= 0xF; - switch (addr) { - case 0: - printf("%c", val); - break; - case 1: - printf("\n"); - fflush(stdout); - break; - case 2: - printf("Set loglevel to %04x\n", val); - cpu_set_log(val | 0x100); - break; - } -} - -/*****************************************************************************/ -/* NVRAM helpers */ -void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) -{ - m48t59_write(nvram, addr, value); -} - -uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) -{ - return m48t59_read(nvram, addr); -} - -void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) -{ - m48t59_write(nvram, addr, value >> 8); - m48t59_write(nvram, addr + 1, value & 0xFF); -} - -uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) -{ - uint16_t tmp; - - tmp = m48t59_read(nvram, addr) << 8; - tmp |= m48t59_read(nvram, addr + 1); - return tmp; -} - -void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) -{ - m48t59_write(nvram, addr, value >> 24); - m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF); - m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF); - m48t59_write(nvram, addr + 3, value & 0xFF); -} - -uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) -{ - uint32_t tmp; - - tmp = m48t59_read(nvram, addr) << 24; - tmp |= m48t59_read(nvram, addr + 1) << 16; - tmp |= m48t59_read(nvram, addr + 2) << 8; - tmp |= m48t59_read(nvram, addr + 3); - return tmp; -} - -void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, - const unsigned char *str, uint32_t max) -{ - int i; - - for (i = 0; i < max && str[i] != '\0'; i++) { - m48t59_write(nvram, addr + i, str[i]); - } - m48t59_write(nvram, addr + max - 1, '\0'); -} - -int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max) -{ - int i; - - memset(dst, 0, max); - for (i = 0; i < max; i++) { - dst[i] = NVRAM_get_byte(nvram, addr + i); - if (dst[i] == '\0') - break; - } - - return i; -} - -static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) -{ - uint16_t tmp; - uint16_t pd, pd1, pd2; - - tmp = prev >> 8; - pd = prev ^ value; - pd1 = pd & 0x000F; - pd2 = ((pd >> 4) & 0x000F) ^ pd1; - tmp ^= (pd1 << 3) | (pd1 << 8); - tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); - - return tmp; -} - -uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) -{ - uint32_t i; - uint16_t crc = 0xFFFF; - int odd; - - odd = count & 1; - count &= ~1; - for (i = 0; i != count; i++) { - crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); - } - if (odd) { - crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); - } - - return crc; -} - -#define CMDLINE_ADDR 0x017ff000 - -int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, - const unsigned char *arch, - uint32_t RAM_size, int boot_device, - uint32_t kernel_image, uint32_t kernel_size, - const char *cmdline, - uint32_t initrd_image, uint32_t initrd_size, - uint32_t NVRAM_image, - int width, int height, int depth) -{ - uint16_t crc; - - /* Set parameters for Open Hack'Ware BIOS */ - NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16); - NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */ - NVRAM_set_word(nvram, 0x14, NVRAM_size); - NVRAM_set_string(nvram, 0x20, arch, 16); - NVRAM_set_lword(nvram, 0x30, RAM_size); - NVRAM_set_byte(nvram, 0x34, boot_device); - NVRAM_set_lword(nvram, 0x38, kernel_image); - NVRAM_set_lword(nvram, 0x3C, kernel_size); - if (cmdline) { - /* XXX: put the cmdline in NVRAM too ? */ - strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); - NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR); - NVRAM_set_lword(nvram, 0x44, strlen(cmdline)); - } else { - NVRAM_set_lword(nvram, 0x40, 0); - NVRAM_set_lword(nvram, 0x44, 0); - } - NVRAM_set_lword(nvram, 0x48, initrd_image); - NVRAM_set_lword(nvram, 0x4C, initrd_size); - NVRAM_set_lword(nvram, 0x50, NVRAM_image); - - NVRAM_set_word(nvram, 0x54, width); - NVRAM_set_word(nvram, 0x56, height); - NVRAM_set_word(nvram, 0x58, depth); - crc = NVRAM_compute_crc(nvram, 0x00, 0xF8); - NVRAM_set_word(nvram, 0xFC, crc); - - return 0; -} diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c deleted file mode 100644 index 42d5995..0000000 --- a/hw/ppc_chrp.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * QEMU PPC CHRP/PMAC hardware System Emulator - * - * Copyright (c) 2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -#define BIOS_FILENAME "ppc_rom.bin" -#define VGABIOS_FILENAME "video.x" -#define NVRAM_SIZE 0x2000 - -#define KERNEL_LOAD_ADDR 0x01000000 -#define INITRD_LOAD_ADDR 0x01800000 - -/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA, - NVRAM */ - -static int dbdma_mem_index; -static int cuda_mem_index; -static int ide0_mem_index = -1; -static int ide1_mem_index = -1; -static int openpic_mem_index = -1; -static int heathrow_pic_mem_index = -1; -static int macio_nvram_mem_index = -1; - -/* DBDMA: currently no op - should suffice right now */ - -static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - printf("%s: 0x%08x <= 0x%08x\n", __func__, addr, value); -} - -static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -} - -static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -} - -static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr) -{ - printf("%s: 0x%08x => 0x00000000\n", __func__, addr); - return 0; -} - -static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr) -{ - return 0; -} - -static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr) -{ - return 0; -} - -static CPUWriteMemoryFunc *dbdma_write[] = { - &dbdma_writeb, - &dbdma_writew, - &dbdma_writel, -}; - -static CPUReadMemoryFunc *dbdma_read[] = { - &dbdma_readb, - &dbdma_readw, - &dbdma_readl, -}; - -/* macio style NVRAM device */ -typedef struct MacIONVRAMState { - uint8_t data[0x2000]; -} MacIONVRAMState; - -static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - MacIONVRAMState *s = opaque; - addr = (addr >> 4) & 0x1fff; - s->data[addr] = value; - // printf("macio_nvram_writeb %04x = %02x\n", addr, value); -} - -static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr) -{ - MacIONVRAMState *s = opaque; - uint32_t value; - - addr = (addr >> 4) & 0x1fff; - value = s->data[addr]; - // printf("macio_nvram_readb %04x = %02x\n", addr, value); - return value; -} - -static CPUWriteMemoryFunc *macio_nvram_write[] = { - &macio_nvram_writeb, - &macio_nvram_writeb, - &macio_nvram_writeb, -}; - -static CPUReadMemoryFunc *macio_nvram_read[] = { - &macio_nvram_readb, - &macio_nvram_readb, - &macio_nvram_readb, -}; - -static MacIONVRAMState *macio_nvram_init(void) -{ - MacIONVRAMState *s; - s = qemu_mallocz(sizeof(MacIONVRAMState)); - if (!s) - return NULL; - macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read, - macio_nvram_write, s); - return s; -} - -static void macio_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - if (heathrow_pic_mem_index >= 0) { - cpu_register_physical_memory(addr + 0x00000, 0x1000, - heathrow_pic_mem_index); - } - cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index); - cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index); - if (ide0_mem_index >= 0) - cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index); - if (ide1_mem_index >= 0) - cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index); - if (openpic_mem_index >= 0) { - cpu_register_physical_memory(addr + 0x40000, 0x40000, - openpic_mem_index); - } - if (macio_nvram_mem_index >= 0) - cpu_register_physical_memory(addr + 0x60000, 0x20000, macio_nvram_mem_index); -} - -static void macio_init(PCIBus *bus, int device_id) -{ - PCIDevice *d; - - d = pci_register_device(bus, "macio", sizeof(PCIDevice), - -1, NULL, NULL); - /* Note: this code is strongly inspirated from the corresponding code - in PearPC */ - d->config[0x00] = 0x6b; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = device_id; - d->config[0x03] = device_id >> 8; - - d->config[0x0a] = 0x00; // class_sub = pci2pci - d->config[0x0b] = 0xff; // class_base = bridge - d->config[0x0e] = 0x00; // header_type - - d->config[0x3d] = 0x01; // interrupt on pin 1 - - dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL); - - pci_register_io_region(d, 0, 0x80000, - PCI_ADDRESS_SPACE_MEM, macio_map); -} - -/* UniN device */ -static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -} - -static uint32_t unin_readl (void *opaque, target_phys_addr_t addr) -{ - return 0; -} - -static CPUWriteMemoryFunc *unin_write[] = { - &unin_writel, - &unin_writel, - &unin_writel, -}; - -static CPUReadMemoryFunc *unin_read[] = { - &unin_readl, - &unin_readl, - &unin_readl, -}; - -/* temporary frame buffer OSI calls for the video.x driver. The right - solution is to modify the driver to use VGA PCI I/Os */ -static int vga_osi_call(CPUState *env) -{ - static int vga_vbl_enabled; - int linesize; - - // printf("osi_call R5=%d\n", env->gpr[5]); - - /* same handler as PearPC, coming from the original MOL video - driver. */ - switch(env->gpr[5]) { - case 4: - break; - case 28: /* set_vmode */ - if (env->gpr[6] != 1 || env->gpr[7] != 0) - env->gpr[3] = 1; - else - env->gpr[3] = 0; - break; - case 29: /* get_vmode_info */ - if (env->gpr[6] != 0) { - if (env->gpr[6] != 1 || env->gpr[7] != 0) { - env->gpr[3] = 1; - break; - } - } - env->gpr[3] = 0; - env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */ - env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */ - env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */ - env->gpr[7] = 85 << 16; /* refresh rate */ - env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */ - linesize = ((graphic_depth + 7) >> 3) * graphic_width; - linesize = (linesize + 3) & ~3; - env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */ - break; - case 31: /* set_video power */ - env->gpr[3] = 0; - break; - case 39: /* video_ctrl */ - if (env->gpr[6] == 0 || env->gpr[6] == 1) - vga_vbl_enabled = env->gpr[6]; - env->gpr[3] = 0; - break; - case 47: - break; - case 59: /* set_color */ - /* R6 = index, R7 = RGB */ - env->gpr[3] = 0; - break; - case 64: /* get color */ - /* R6 = index */ - env->gpr[3] = 0; - break; - case 116: /* set hwcursor */ - /* R6 = x, R7 = y, R8 = visible, R9 = data */ - break; - default: - fprintf(stderr, "unsupported OSI call R5=%08x\n", env->gpr[5]); - break; - } - return 1; /* osi_call handled */ -} - -/* XXX: suppress that */ -static void pic_irq_request(void *opaque, int level) -{ -} - -static uint8_t nvram_chksum(const uint8_t *buf, int n) -{ - int sum, i; - sum = 0; - for(i = 0; i < n; i++) - sum += buf[i]; - return (sum & 0xff) + (sum >> 8); -} - -/* set a free Mac OS NVRAM partition */ -void pmac_format_nvram_partition(uint8_t *buf, int len) -{ - char partition_name[12] = "wwwwwwwwwwww"; - - buf[0] = 0x7f; /* free partition magic */ - buf[1] = 0; /* checksum */ - buf[2] = len >> 8; - buf[3] = len; - memcpy(buf + 4, partition_name, 12); - buf[1] = nvram_chksum(buf, 16); -} - -/* PowerPC CHRP hardware initialisation */ -static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - int is_heathrow) -{ - CPUState *env; - char buf[1024]; - SetIRQFunc *set_irq; - void *pic; - m48t59_t *nvram; - int PPC_io_memory, unin_memory; - int linux_boot, i; - unsigned long bios_offset, vga_bios_offset; - uint32_t kernel_base, kernel_size, initrd_base, initrd_size; - ppc_def_t *def; - PCIBus *pci_bus; - const char *arch_name; - int vga_bios_size, bios_size; - - linux_boot = (kernel_filename != NULL); - - /* init CPUs */ - env = cpu_init(); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - - /* Register CPU as a 74x/75x */ - /* XXX: CPU model (or PVR) should be provided on command line */ - // ppc_find_by_name("750gx", &def); // Linux boot OK - // ppc_find_by_name("750fx", &def); // Linux boot OK - /* Linux does not boot on 750cxe (and probably other 750cx based) - * because it assumes it has 8 IBAT & DBAT pairs as it only have 4. - */ - // ppc_find_by_name("750cxe", &def); - // ppc_find_by_name("750p", &def); - // ppc_find_by_name("740p", &def); - ppc_find_by_name("750", &def); - // ppc_find_by_name("740", &def); - // ppc_find_by_name("G3", &def); - // ppc_find_by_name("604r", &def); - // ppc_find_by_name("604e", &def); - // ppc_find_by_name("604", &def); - if (def == NULL) { - cpu_abort(env, "Unable to find PowerPC CPU definition\n"); - } - cpu_ppc_register(env, def); - - /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); - - env->osi_call = vga_osi_call; - - /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); - - /* allocate and load BIOS */ - bios_offset = ram_size + vga_ram_size; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - bios_size = load_image(buf, phys_ram_base + bios_offset); - if (bios_size < 0 || bios_size > BIOS_SIZE) { - fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf); - exit(1); - } - bios_size = (bios_size + 0xfff) & ~0xfff; - cpu_register_physical_memory((uint32_t)(-bios_size), - bios_size, bios_offset | IO_MEM_ROM); - - /* allocate and load VGA BIOS */ - vga_bios_offset = bios_offset + bios_size; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); - vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8); - if (vga_bios_size < 0) { - /* if no bios is present, we can still work */ - fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf); - vga_bios_size = 0; - } else { - /* set a specific header (XXX: find real Apple format for NDRV - drivers) */ - phys_ram_base[vga_bios_offset] = 'N'; - phys_ram_base[vga_bios_offset + 1] = 'D'; - phys_ram_base[vga_bios_offset + 2] = 'R'; - phys_ram_base[vga_bios_offset + 3] = 'V'; - cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4), - vga_bios_size); - vga_bios_size += 8; - } - vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff; - - if (linux_boot) { - kernel_base = KERNEL_LOAD_ADDR; - /* now we can load the kernel */ - kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - /* load initrd */ - if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; - initrd_size = load_image(initrd_filename, - phys_ram_base + initrd_base); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } else { - initrd_base = 0; - initrd_size = 0; - } - boot_device = 'm'; - } else { - kernel_base = 0; - kernel_size = 0; - initrd_base = 0; - initrd_size = 0; - } - - if (is_heathrow) { - isa_mem_base = 0x80000000; - - /* Register 2 MB of ISA IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); - cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory); - - /* init basic PC hardware */ - pic = heathrow_pic_init(&heathrow_pic_mem_index); - set_irq = heathrow_pic_set_irq; - pci_bus = pci_grackle_init(0xfec00000, pic); - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, - ram_size, vga_ram_size, - vga_bios_offset, vga_bios_size); - - /* XXX: suppress that */ - isa_pic = pic_init(pic_irq_request, NULL); - - /* XXX: use Mac Serial port */ - serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); - - for(i = 0; i < nb_nics; i++) { - if (!nd_table[i].model) - nd_table[i].model = "ne2k_pci"; - pci_nic_init(pci_bus, &nd_table[i]); - } - - pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); - - /* cuda also initialize ADB */ - cuda_mem_index = cuda_init(set_irq, pic, 0x12); - - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); - - { - MacIONVRAMState *nvr; - nvr = macio_nvram_init(); - pmac_format_nvram_partition(nvr->data, 0x2000); - } - - macio_init(pci_bus, 0x0017); - - nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59); - - arch_name = "HEATHROW"; - } else { - isa_mem_base = 0x80000000; - - /* Register 8 MB of ISA IO space */ - PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL); - cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory); - - /* UniN init */ - unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL); - cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory); - - pic = openpic_init(NULL, &openpic_mem_index, 1, &env); - set_irq = openpic_set_irq; - pci_bus = pci_pmac_init(pic); - /* init basic PC hardware */ - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, - ram_size, vga_ram_size, - vga_bios_offset, vga_bios_size); - - /* XXX: suppress that */ - isa_pic = pic_init(pic_irq_request, NULL); - - /* XXX: use Mac Serial port */ - serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); - - for(i = 0; i < nb_nics; i++) { - pci_ne2000_init(pci_bus, &nd_table[i]); - } - -#if 1 - ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13); - ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14); -#else - pci_cmd646_ide_init(pci_bus, &bs_table[0], 0); -#endif - /* cuda also initialize ADB */ - cuda_mem_index = cuda_init(set_irq, pic, 0x19); - - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); - - macio_init(pci_bus, 0x0022); - - nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59); - - arch_name = "MAC99"; - } - - if (usb_enabled) { - usb_ohci_init(pci_bus, 3, -1); - } - - if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) - graphic_depth = 15; - - PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device, - kernel_base, kernel_size, - kernel_cmdline, - initrd_base, initrd_size, - /* XXX: need an option to load a NVRAM image */ - 0, - graphic_width, graphic_height, graphic_depth); - /* No PCI init: the BIOS will do it */ - - /* Special port to get debug messages from Open-Firmware */ - register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); -} - -static void ppc_core99_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename) -{ - ppc_chrp_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, - initrd_filename, 0); -} - -static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, - int snapshot, - const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename) -{ - ppc_chrp_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, - initrd_filename, 1); -} - -QEMUMachine core99_machine = { - "mac99", - "Mac99 based PowerMAC", - ppc_core99_init, -}; - -QEMUMachine heathrow_machine = { - "g3bw", - "Heathrow based PowerMAC", - ppc_heathrow_init, -}; diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c deleted file mode 100644 index a4d7ddf..0000000 --- a/hw/ppc_prep.c +++ /dev/null @@ -1,694 +0,0 @@ -/* - * QEMU PPC PREP hardware System Emulator - * - * Copyright (c) 2003-2004 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -//#define HARD_DEBUG_PPC_IO -//#define DEBUG_PPC_IO - -#define BIOS_FILENAME "ppc_rom.bin" -#define KERNEL_LOAD_ADDR 0x01000000 -#define INITRD_LOAD_ADDR 0x01800000 - -extern int loglevel; -extern FILE *logfile; - -#if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO) -#define DEBUG_PPC_IO -#endif - -#if defined (HARD_DEBUG_PPC_IO) -#define PPC_IO_DPRINTF(fmt, args...) \ -do { \ - if (loglevel & CPU_LOG_IOPORT) { \ - fprintf(logfile, "%s: " fmt, __func__ , ##args); \ - } else { \ - printf("%s : " fmt, __func__ , ##args); \ - } \ -} while (0) -#elif defined (DEBUG_PPC_IO) -#define PPC_IO_DPRINTF(fmt, args...) \ -do { \ - if (loglevel & CPU_LOG_IOPORT) { \ - fprintf(logfile, "%s: " fmt, __func__ , ##args); \ - } \ -} while (0) -#else -#define PPC_IO_DPRINTF(fmt, args...) do { } while (0) -#endif - -/* Constants for devices init */ -static const int ide_iobase[2] = { 0x1f0, 0x170 }; -static const int ide_iobase2[2] = { 0x3f6, 0x376 }; -static const int ide_irq[2] = { 13, 13 }; - -#define NE2000_NB_MAX 6 - -static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 }; -static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; - -//static PITState *pit; - -/* ISA IO ports bridge */ -#define PPC_IO_BASE 0x80000000 - -/* Speaker port 0x61 */ -int speaker_data_on; -int dummy_refresh_clock; - -static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ -#if 0 - speaker_data_on = (val >> 1) & 1; - pit_set_gate(pit, 2, val & 1); -#endif -} - -static uint32_t speaker_ioport_read(void *opaque, uint32_t addr) -{ -#if 0 - int out; - out = pit_get_out(pit, 2, qemu_get_clock(vm_clock)); - dummy_refresh_clock ^= 1; - return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) | - (dummy_refresh_clock << 4); -#endif - return 0; -} - -static void pic_irq_request(void *opaque, int level) -{ - if (level) - cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD); - else - cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD); -} - -/* PCI intack register */ -/* Read-only register (?) */ -static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value); -} - -static inline uint32_t _PPC_intack_read (target_phys_addr_t addr) -{ - uint32_t retval = 0; - - if (addr == 0xBFFFFFF0) - retval = pic_intack_read(isa_pic); - // printf("%s: 0x%08x <= %d\n", __func__, addr, retval); - - return retval; -} - -static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr) -{ - return _PPC_intack_read(addr); -} - -static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr) -{ -#ifdef TARGET_WORDS_BIGENDIAN - return bswap16(_PPC_intack_read(addr)); -#else - return _PPC_intack_read(addr); -#endif -} - -static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr) -{ -#ifdef TARGET_WORDS_BIGENDIAN - return bswap32(_PPC_intack_read(addr)); -#else - return _PPC_intack_read(addr); -#endif -} - -static CPUWriteMemoryFunc *PPC_intack_write[] = { - &_PPC_intack_write, - &_PPC_intack_write, - &_PPC_intack_write, -}; - -static CPUReadMemoryFunc *PPC_intack_read[] = { - &PPC_intack_readb, - &PPC_intack_readw, - &PPC_intack_readl, -}; - -/* PowerPC control and status registers */ -#if 0 // Not used -static struct { - /* IDs */ - uint32_t veni_devi; - uint32_t revi; - /* Control and status */ - uint32_t gcsr; - uint32_t xcfr; - uint32_t ct32; - uint32_t mcsr; - /* General purpose registers */ - uint32_t gprg[6]; - /* Exceptions */ - uint32_t feen; - uint32_t fest; - uint32_t fema; - uint32_t fecl; - uint32_t eeen; - uint32_t eest; - uint32_t eecl; - uint32_t eeint; - uint32_t eemck0; - uint32_t eemck1; - /* Error diagnostic */ -} XCSR; - -static void PPC_XCSR_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) -{ - printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); -} - -static void PPC_XCSR_writew (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap16(value); -#endif - printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); -} - -static void PPC_XCSR_writel (void *opaque, target_phys_addr_t addr, uint32_t value) -{ -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap32(value); -#endif - printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value); -} - -static uint32_t PPC_XCSR_readb (void *opaque, target_phys_addr_t addr) -{ - uint32_t retval = 0; - - printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); - - return retval; -} - -static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr) -{ - uint32_t retval = 0; - - printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); -#ifdef TARGET_WORDS_BIGENDIAN - retval = bswap16(retval); -#endif - - return retval; -} - -static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr) -{ - uint32_t retval = 0; - - printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval); -#ifdef TARGET_WORDS_BIGENDIAN - retval = bswap32(retval); -#endif - - return retval; -} - -static CPUWriteMemoryFunc *PPC_XCSR_write[] = { - &PPC_XCSR_writeb, - &PPC_XCSR_writew, - &PPC_XCSR_writel, -}; - -static CPUReadMemoryFunc *PPC_XCSR_read[] = { - &PPC_XCSR_readb, - &PPC_XCSR_readw, - &PPC_XCSR_readl, -}; -#endif - -/* Fake super-io ports for PREP platform (Intel 82378ZB) */ -typedef struct sysctrl_t { - m48t59_t *nvram; - uint8_t state; - uint8_t syscontrol; - uint8_t fake_io[2]; - int contiguous_map; - int endian; -} sysctrl_t; - -enum { - STATE_HARDFILE = 0x01, -}; - -static sysctrl_t *sysctrl; - -static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val) -{ - sysctrl_t *sysctrl = opaque; - - PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val); - sysctrl->fake_io[addr - 0x0398] = val; -} - -static uint32_t PREP_io_read (void *opaque, uint32_t addr) -{ - sysctrl_t *sysctrl = opaque; - - PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, - sysctrl->fake_io[addr - 0x0398]); - return sysctrl->fake_io[addr - 0x0398]; -} - -static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val) -{ - sysctrl_t *sysctrl = opaque; - - PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val); - switch (addr) { - case 0x0092: - /* Special port 92 */ - /* Check soft reset asked */ - if (val & 0x01) { - // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET); - } - /* Check LE mode */ - if (val & 0x02) { - sysctrl->endian = 1; - } else { - sysctrl->endian = 0; - } - break; - case 0x0800: - /* Motorola CPU configuration register : read-only */ - break; - case 0x0802: - /* Motorola base module feature register : read-only */ - break; - case 0x0803: - /* Motorola base module status register : read-only */ - break; - case 0x0808: - /* Hardfile light register */ - if (val & 1) - sysctrl->state |= STATE_HARDFILE; - else - sysctrl->state &= ~STATE_HARDFILE; - break; - case 0x0810: - /* Password protect 1 register */ - if (sysctrl->nvram != NULL) - m48t59_toggle_lock(sysctrl->nvram, 1); - break; - case 0x0812: - /* Password protect 2 register */ - if (sysctrl->nvram != NULL) - m48t59_toggle_lock(sysctrl->nvram, 2); - break; - case 0x0814: - /* L2 invalidate register */ - // tlb_flush(first_cpu, 1); - break; - case 0x081C: - /* system control register */ - sysctrl->syscontrol = val & 0x0F; - break; - case 0x0850: - /* I/O map type register */ - sysctrl->contiguous_map = val & 0x01; - break; - default: - printf("ERROR: unaffected IO port write: %04lx => %02x\n", - (long)addr, val); - break; - } -} - -static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr) -{ - sysctrl_t *sysctrl = opaque; - uint32_t retval = 0xFF; - - switch (addr) { - case 0x0092: - /* Special port 92 */ - retval = 0x00; - break; - case 0x0800: - /* Motorola CPU configuration register */ - retval = 0xEF; /* MPC750 */ - break; - case 0x0802: - /* Motorola Base module feature register */ - retval = 0xAD; /* No ESCC, PMC slot neither ethernet */ - break; - case 0x0803: - /* Motorola base module status register */ - retval = 0xE0; /* Standard MPC750 */ - break; - case 0x080C: - /* Equipment present register: - * no L2 cache - * no upgrade processor - * no cards in PCI slots - * SCSI fuse is bad - */ - retval = 0x3C; - break; - case 0x0810: - /* Motorola base module extended feature register */ - retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */ - break; - case 0x0814: - /* L2 invalidate: don't care */ - break; - case 0x0818: - /* Keylock */ - retval = 0x00; - break; - case 0x081C: - /* system control register - * 7 - 6 / 1 - 0: L2 cache enable - */ - retval = sysctrl->syscontrol; - break; - case 0x0823: - /* */ - retval = 0x03; /* no L2 cache */ - break; - case 0x0850: - /* I/O map type register */ - retval = sysctrl->contiguous_map; - break; - default: - printf("ERROR: unaffected IO port: %04lx read\n", (long)addr); - break; - } - PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, retval); - - return retval; -} - -static inline target_phys_addr_t prep_IO_address (sysctrl_t *sysctrl, - target_phys_addr_t addr) -{ - if (sysctrl->contiguous_map == 0) { - /* 64 KB contiguous space for IOs */ - addr &= 0xFFFF; - } else { - /* 8 MB non-contiguous space for IOs */ - addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7); - } - - return addr; -} - -static void PPC_prep_io_writeb (void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - sysctrl_t *sysctrl = opaque; - - addr = prep_IO_address(sysctrl, addr); - cpu_outb(NULL, addr, value); -} - -static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr) -{ - sysctrl_t *sysctrl = opaque; - uint32_t ret; - - addr = prep_IO_address(sysctrl, addr); - ret = cpu_inb(NULL, addr); - - return ret; -} - -static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - sysctrl_t *sysctrl = opaque; - - addr = prep_IO_address(sysctrl, addr); -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap16(value); -#endif - PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value); - cpu_outw(NULL, addr, value); -} - -static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr) -{ - sysctrl_t *sysctrl = opaque; - uint32_t ret; - - addr = prep_IO_address(sysctrl, addr); - ret = cpu_inw(NULL, addr); -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap16(ret); -#endif - PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret); - - return ret; -} - -static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr, - uint32_t value) -{ - sysctrl_t *sysctrl = opaque; - - addr = prep_IO_address(sysctrl, addr); -#ifdef TARGET_WORDS_BIGENDIAN - value = bswap32(value); -#endif - PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value); - cpu_outl(NULL, addr, value); -} - -static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr) -{ - sysctrl_t *sysctrl = opaque; - uint32_t ret; - - addr = prep_IO_address(sysctrl, addr); - ret = cpu_inl(NULL, addr); -#ifdef TARGET_WORDS_BIGENDIAN - ret = bswap32(ret); -#endif - PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret); - - return ret; -} - -CPUWriteMemoryFunc *PPC_prep_io_write[] = { - &PPC_prep_io_writeb, - &PPC_prep_io_writew, - &PPC_prep_io_writel, -}; - -CPUReadMemoryFunc *PPC_prep_io_read[] = { - &PPC_prep_io_readb, - &PPC_prep_io_readw, - &PPC_prep_io_readl, -}; - -#define NVRAM_SIZE 0x2000 - -/* PowerPC PREP hardware initialisation */ -static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) -{ - CPUState *env; - char buf[1024]; - SetIRQFunc *set_irq; - m48t59_t *nvram; - int PPC_io_memory; - int linux_boot, i, nb_nics1, bios_size; - unsigned long bios_offset; - uint32_t kernel_base, kernel_size, initrd_base, initrd_size; - ppc_def_t *def; - PCIBus *pci_bus; - - sysctrl = qemu_mallocz(sizeof(sysctrl_t)); - if (sysctrl == NULL) - return; - - linux_boot = (kernel_filename != NULL); - - /* init CPUs */ - - env = cpu_init(); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - - /* Register CPU as a 604 */ - /* XXX: CPU model (or PVR) should be provided on command line */ - // ppc_find_by_name("604r", &def); - // ppc_find_by_name("604e", &def); - ppc_find_by_name("604", &def); - if (def == NULL) { - cpu_abort(env, "Unable to find PowerPC CPU definition\n"); - } - cpu_ppc_register(env, def); - /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); - - /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); - - /* allocate and load BIOS */ - bios_offset = ram_size + vga_ram_size; - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); - bios_size = load_image(buf, phys_ram_base + bios_offset); - if (bios_size < 0 || bios_size > BIOS_SIZE) { - fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf); - exit(1); - } - bios_size = (bios_size + 0xfff) & ~0xfff; - cpu_register_physical_memory((uint32_t)(-bios_size), - bios_size, bios_offset | IO_MEM_ROM); - - if (linux_boot) { - kernel_base = KERNEL_LOAD_ADDR; - /* now we can load the kernel */ - kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - /* load initrd */ - if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; - initrd_size = load_image(initrd_filename, - phys_ram_base + initrd_base); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } else { - initrd_base = 0; - initrd_size = 0; - } - boot_device = 'm'; - } else { - kernel_base = 0; - kernel_size = 0; - initrd_base = 0; - initrd_size = 0; - } - - isa_mem_base = 0xc0000000; - pci_bus = pci_prep_init(); - // pci_bus = i440fx_init(); - /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ - PPC_io_memory = cpu_register_io_memory(0, PPC_prep_io_read, - PPC_prep_io_write, sysctrl); - cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory); - - /* init basic PC hardware */ - vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size, - vga_ram_size, 0, 0); - rtc_init(0x70, 8); - // openpic = openpic_init(0x00000000, 0xF0000000, 1); - isa_pic = pic_init(pic_irq_request, first_cpu); - // pit = pit_init(0x40, 0); - - serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]); - nb_nics1 = nb_nics; - if (nb_nics1 > NE2000_NB_MAX) - nb_nics1 = NE2000_NB_MAX; - for(i = 0; i < nb_nics1; i++) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "ne2k_isa") == 0) { - isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } - } - - for(i = 0; i < 2; i++) { - isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], - bs_table[2 * i], bs_table[2 * i + 1]); - } - kbd_init(); - DMA_init(1); - // AUD_init(); - // SB16_init(); - - fdctrl_init(6, 2, 0, 0x3f0, fd_table); - - /* Register speaker port */ - register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); - register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL); - /* Register fake IO ports for PREP */ - register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl); - register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl); - /* System control ports */ - register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl); - register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl); - register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl); - register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl); - /* PCI intack location */ - PPC_io_memory = cpu_register_io_memory(0, PPC_intack_read, - PPC_intack_write, NULL); - cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory); - /* PowerPC control and status register group */ -#if 0 - PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, NULL); - cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory); -#endif - - if (usb_enabled) { - usb_ohci_init(pci_bus, 3, -1); - } - - nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); - if (nvram == NULL) - return; - sysctrl->nvram = nvram; - - /* Initialise NVRAM */ - PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device, - kernel_base, kernel_size, - kernel_cmdline, - initrd_base, initrd_size, - /* XXX: need an option to load a NVRAM image */ - 0, - graphic_width, graphic_height, graphic_depth); - - /* Special port to get debug messages from Open-Firmware */ - register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL); -} - -QEMUMachine prep_machine = { - "prep", - "PowerPC PREP platform", - ppc_prep_init, -}; diff --git a/hw/prep_pci.c b/hw/prep_pci.c deleted file mode 100644 index a31b74c..0000000 --- a/hw/prep_pci.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * QEMU PREP PCI host - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "vl.h" -typedef uint32_t pci_addr_t; -#include "pci_host.h" - -typedef PCIHostState PREPPCIState; - -static void pci_prep_addr_writel(void* opaque, uint32_t addr, uint32_t val) -{ - PREPPCIState *s = opaque; - s->config_reg = val; -} - -static uint32_t pci_prep_addr_readl(void* opaque, uint32_t addr) -{ - PREPPCIState *s = opaque; - return s->config_reg; -} - -static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr) -{ - int i; - - for(i = 0; i < 11; i++) { - if ((addr & (1 << (11 + i))) != 0) - break; - } - return (addr & 0x7ff) | (i << 11); -} - -static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PREPPCIState *s = opaque; - pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1); -} - -static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PREPPCIState *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2); -} - -static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PREPPCIState *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4); -} - -static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr) -{ - PREPPCIState *s = opaque; - uint32_t val; - val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1); - return val; -} - -static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr) -{ - PREPPCIState *s = opaque; - uint32_t val; - val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr) -{ - PREPPCIState *s = opaque; - uint32_t val; - val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *PPC_PCIIO_write[] = { - &PPC_PCIIO_writeb, - &PPC_PCIIO_writew, - &PPC_PCIIO_writel, -}; - -static CPUReadMemoryFunc *PPC_PCIIO_read[] = { - &PPC_PCIIO_readb, - &PPC_PCIIO_readw, - &PPC_PCIIO_readl, -}; - -static void prep_set_irq(PCIDevice *d, void *pic, int irq_num, int level) -{ - /* XXX: we do not simulate the hardware - we rely on the BIOS to - set correctly for irq line field */ - pic_set_irq(d->config[PCI_INTERRUPT_LINE], level); -} - -PCIBus *pci_prep_init(void) -{ - PREPPCIState *s; - PCIDevice *d; - int PPC_io_memory; - - s = qemu_mallocz(sizeof(PREPPCIState)); - s->bus = pci_register_bus(prep_set_irq, NULL, 0); - - register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s); - register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s); - - register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s); - register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s); - register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s); - register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s); - register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); - register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); - - PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, - PPC_PCIIO_write, s); - cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory); - - /* PCI host bridge */ - d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven", - sizeof(PCIDevice), 0, NULL, NULL); - d->config[0x00] = 0x57; // vendor_id : Motorola - d->config[0x01] = 0x10; - d->config[0x02] = 0x01; // device_id : Raven - d->config[0x03] = 0x48; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer - - return s->bus; -} - diff --git a/hw/ps2.c b/hw/ps2.c deleted file mode 100644 index 8438a5e..0000000 --- a/hw/ps2.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * QEMU PS/2 keyboard/mouse emulation - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -/* debug PC keyboard */ -//#define DEBUG_KBD - -/* debug PC keyboard : only mouse */ -//#define DEBUG_MOUSE - -/* Keyboard Commands */ -#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ -#define KBD_CMD_ECHO 0xEE -#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ -#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ -#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ -#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ -#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ -#define KBD_CMD_RESET 0xFF /* Reset */ - -/* Keyboard Replies */ -#define KBD_REPLY_POR 0xAA /* Power on reset */ -#define KBD_REPLY_ACK 0xFA /* Command ACK */ -#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ - -/* Mouse Commands */ -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ -#define AUX_SET_RES 0xE8 /* Set resolution */ -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ -#define AUX_SET_STREAM 0xEA /* Set stream mode */ -#define AUX_POLL 0xEB /* Poll */ -#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ -#define AUX_SET_WRAP 0xEE /* Set wrap mode */ -#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ -#define AUX_GET_TYPE 0xF2 /* Get type */ -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ -#define AUX_SET_DEFAULT 0xF6 -#define AUX_RESET 0xFF /* Reset aux device */ -#define AUX_ACK 0xFA /* Command byte ACK. */ - -#define MOUSE_STATUS_REMOTE 0x40 -#define MOUSE_STATUS_ENABLED 0x20 -#define MOUSE_STATUS_SCALE21 0x10 - -#define PS2_QUEUE_SIZE 256 - -typedef struct { - uint8_t data[PS2_QUEUE_SIZE]; - int rptr, wptr, count; -} PS2Queue; - -typedef struct { - PS2Queue queue; - int32_t write_cmd; - void (*update_irq)(void *, int); - void *update_arg; -} PS2State; - -typedef struct { - PS2State common; - int scan_enabled; - /* Qemu uses translated PC scancodes internally. To avoid multiple - conversions we do the translation (if any) in the PS/2 emulation - not the keyboard controller. */ - int translate; -} PS2KbdState; - -typedef struct { - PS2State common; - uint8_t mouse_status; - uint8_t mouse_resolution; - uint8_t mouse_sample_rate; - uint8_t mouse_wrap; - uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ - uint8_t mouse_detect_state; - int mouse_dx; /* current values, needed for 'poll' mode */ - int mouse_dy; - int mouse_dz; - uint8_t mouse_buttons; -} PS2MouseState; - -/* Table to convert from PC scancodes to raw scancodes. */ -static const unsigned char ps2_raw_keycode[128] = { - 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, - 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, - 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, - 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 -}; - -void ps2_queue(void *opaque, int b) -{ - PS2State *s = (PS2State *)opaque; - PS2Queue *q = &s->queue; - - if (q->count >= PS2_QUEUE_SIZE) - return; - q->data[q->wptr] = b; - if (++q->wptr == PS2_QUEUE_SIZE) - q->wptr = 0; - q->count++; - s->update_irq(s->update_arg, 1); -} - -static void ps2_put_keycode(void *opaque, int keycode) -{ - PS2KbdState *s = opaque; - if (!s->translate && keycode < 0xe0) - { - if (keycode & 0x80) - ps2_queue(&s->common, 0xf0); - keycode = ps2_raw_keycode[keycode & 0x7f]; - } - ps2_queue(&s->common, keycode); -} - -uint32_t ps2_read_data(void *opaque) -{ - PS2State *s = (PS2State *)opaque; - PS2Queue *q; - int val, index; - - q = &s->queue; - if (q->count == 0) { - /* NOTE: if no data left, we return the last keyboard one - (needed for EMM386) */ - /* XXX: need a timer to do things correctly */ - index = q->rptr - 1; - if (index < 0) - index = PS2_QUEUE_SIZE - 1; - val = q->data[index]; - } else { - val = q->data[q->rptr]; - if (++q->rptr == PS2_QUEUE_SIZE) - q->rptr = 0; - q->count--; - /* reading deasserts IRQ */ - s->update_irq(s->update_arg, 0); - /* reassert IRQs if data left */ - s->update_irq(s->update_arg, q->count != 0); - } - return val; -} - -static void ps2_reset_keyboard(PS2KbdState *s) -{ - s->scan_enabled = 1; -} - -void ps2_write_keyboard(void *opaque, int val) -{ - PS2KbdState *s = (PS2KbdState *)opaque; - - switch(s->common.write_cmd) { - default: - case -1: - switch(val) { - case 0x00: - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - case 0x05: - ps2_queue(&s->common, KBD_REPLY_RESEND); - break; - case KBD_CMD_GET_ID: - ps2_queue(&s->common, KBD_REPLY_ACK); - ps2_queue(&s->common, 0xab); - ps2_queue(&s->common, 0x83); - break; - case KBD_CMD_ECHO: - ps2_queue(&s->common, KBD_CMD_ECHO); - break; - case KBD_CMD_ENABLE: - s->scan_enabled = 1; - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - case KBD_CMD_SET_LEDS: - case KBD_CMD_SET_RATE: - s->common.write_cmd = val; - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - case KBD_CMD_RESET_DISABLE: - ps2_reset_keyboard(s); - s->scan_enabled = 0; - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - case KBD_CMD_RESET_ENABLE: - ps2_reset_keyboard(s); - s->scan_enabled = 1; - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - case KBD_CMD_RESET: - ps2_reset_keyboard(s); - ps2_queue(&s->common, KBD_REPLY_ACK); - ps2_queue(&s->common, KBD_REPLY_POR); - break; - default: - ps2_queue(&s->common, KBD_REPLY_ACK); - break; - } - break; - case KBD_CMD_SET_LEDS: - ps2_queue(&s->common, KBD_REPLY_ACK); - s->common.write_cmd = -1; - break; - case KBD_CMD_SET_RATE: - ps2_queue(&s->common, KBD_REPLY_ACK); - s->common.write_cmd = -1; - break; - } -} - -/* Set the scancode translation mode. - 0 = raw scancodes. - 1 = translated scancodes (used by qemu internally). */ - -void ps2_keyboard_set_translation(void *opaque, int mode) -{ - PS2KbdState *s = (PS2KbdState *)opaque; - s->translate = mode; -} - -static void ps2_mouse_send_packet(PS2MouseState *s) -{ - unsigned int b; - int dx1, dy1, dz1; - - dx1 = s->mouse_dx; - dy1 = s->mouse_dy; - dz1 = s->mouse_dz; - /* XXX: increase range to 8 bits ? */ - if (dx1 > 127) - dx1 = 127; - else if (dx1 < -127) - dx1 = -127; - if (dy1 > 127) - dy1 = 127; - else if (dy1 < -127) - dy1 = -127; - b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); - ps2_queue(&s->common, b); - ps2_queue(&s->common, dx1 & 0xff); - ps2_queue(&s->common, dy1 & 0xff); - /* extra byte for IMPS/2 or IMEX */ - switch(s->mouse_type) { - default: - break; - case 3: - if (dz1 > 127) - dz1 = 127; - else if (dz1 < -127) - dz1 = -127; - ps2_queue(&s->common, dz1 & 0xff); - break; - case 4: - if (dz1 > 7) - dz1 = 7; - else if (dz1 < -7) - dz1 = -7; - b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); - ps2_queue(&s->common, b); - break; - } - - /* update deltas */ - s->mouse_dx -= dx1; - s->mouse_dy -= dy1; - s->mouse_dz -= dz1; -} - -static void ps2_mouse_event(void *opaque, - int dx, int dy, int dz, int buttons_state) -{ - PS2MouseState *s = opaque; - - /* check if deltas are recorded when disabled */ - if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) - return; - - s->mouse_dx += dx; - s->mouse_dy -= dy; - s->mouse_dz += dz; - /* XXX: SDL sometimes generates nul events: we delete them */ - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && - s->mouse_buttons == buttons_state) - return; - s->mouse_buttons = buttons_state; - - if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && - (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) { - for(;;) { - /* if not remote, send event. Multiple events are sent if - too big deltas */ - ps2_mouse_send_packet(s); - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) - break; - } - } -} - -void ps2_write_mouse(void *opaque, int val) -{ - PS2MouseState *s = (PS2MouseState *)opaque; -#ifdef DEBUG_MOUSE - printf("kbd: write mouse 0x%02x\n", val); -#endif - switch(s->common.write_cmd) { - default: - case -1: - /* mouse command */ - if (s->mouse_wrap) { - if (val == AUX_RESET_WRAP) { - s->mouse_wrap = 0; - ps2_queue(&s->common, AUX_ACK); - return; - } else if (val != AUX_RESET) { - ps2_queue(&s->common, val); - return; - } - } - switch(val) { - case AUX_SET_SCALE11: - s->mouse_status &= ~MOUSE_STATUS_SCALE21; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_SET_SCALE21: - s->mouse_status |= MOUSE_STATUS_SCALE21; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_SET_STREAM: - s->mouse_status &= ~MOUSE_STATUS_REMOTE; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_SET_WRAP: - s->mouse_wrap = 1; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_SET_REMOTE: - s->mouse_status |= MOUSE_STATUS_REMOTE; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_GET_TYPE: - ps2_queue(&s->common, AUX_ACK); - ps2_queue(&s->common, s->mouse_type); - break; - case AUX_SET_RES: - case AUX_SET_SAMPLE: - s->common.write_cmd = val; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_GET_SCALE: - ps2_queue(&s->common, AUX_ACK); - ps2_queue(&s->common, s->mouse_status); - ps2_queue(&s->common, s->mouse_resolution); - ps2_queue(&s->common, s->mouse_sample_rate); - break; - case AUX_POLL: - ps2_queue(&s->common, AUX_ACK); - ps2_mouse_send_packet(s); - break; - case AUX_ENABLE_DEV: - s->mouse_status |= MOUSE_STATUS_ENABLED; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_DISABLE_DEV: - s->mouse_status &= ~MOUSE_STATUS_ENABLED; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_SET_DEFAULT: - s->mouse_sample_rate = 100; - s->mouse_resolution = 2; - s->mouse_status = 0; - ps2_queue(&s->common, AUX_ACK); - break; - case AUX_RESET: - s->mouse_sample_rate = 100; - s->mouse_resolution = 2; - s->mouse_status = 0; - s->mouse_type = 0; - ps2_queue(&s->common, AUX_ACK); - ps2_queue(&s->common, 0xaa); - ps2_queue(&s->common, s->mouse_type); - break; - default: - break; - } - break; - case AUX_SET_SAMPLE: - s->mouse_sample_rate = val; - /* detect IMPS/2 or IMEX */ - switch(s->mouse_detect_state) { - default: - case 0: - if (val == 200) - s->mouse_detect_state = 1; - break; - case 1: - if (val == 100) - s->mouse_detect_state = 2; - else if (val == 200) - s->mouse_detect_state = 3; - else - s->mouse_detect_state = 0; - break; - case 2: - if (val == 80) - s->mouse_type = 3; /* IMPS/2 */ - s->mouse_detect_state = 0; - break; - case 3: - if (val == 80) - s->mouse_type = 4; /* IMEX */ - s->mouse_detect_state = 0; - break; - } - ps2_queue(&s->common, AUX_ACK); - s->common.write_cmd = -1; - break; - case AUX_SET_RES: - s->mouse_resolution = val; - ps2_queue(&s->common, AUX_ACK); - s->common.write_cmd = -1; - break; - } -} - -static void ps2_reset(void *opaque) -{ - PS2State *s = (PS2State *)opaque; - PS2Queue *q; - s->write_cmd = -1; - q = &s->queue; - q->rptr = 0; - q->wptr = 0; - q->count = 0; -} - -static void ps2_common_save (QEMUFile *f, PS2State *s) -{ - qemu_put_be32s (f, &s->write_cmd); - qemu_put_be32s (f, &s->queue.rptr); - qemu_put_be32s (f, &s->queue.wptr); - qemu_put_be32s (f, &s->queue.count); - qemu_put_buffer (f, s->queue.data, sizeof (s->queue.data)); -} - -static void ps2_common_load (QEMUFile *f, PS2State *s) -{ - qemu_get_be32s (f, &s->write_cmd); - qemu_get_be32s (f, &s->queue.rptr); - qemu_get_be32s (f, &s->queue.wptr); - qemu_get_be32s (f, &s->queue.count); - qemu_get_buffer (f, s->queue.data, sizeof (s->queue.data)); -} - -static void ps2_kbd_save(QEMUFile* f, void* opaque) -{ - PS2KbdState *s = (PS2KbdState*)opaque; - - ps2_common_save (f, &s->common); - qemu_put_be32s(f, &s->scan_enabled); - qemu_put_be32s(f, &s->translate); -} - -static void ps2_mouse_save(QEMUFile* f, void* opaque) -{ - PS2MouseState *s = (PS2MouseState*)opaque; - - ps2_common_save (f, &s->common); - qemu_put_8s(f, &s->mouse_status); - qemu_put_8s(f, &s->mouse_resolution); - qemu_put_8s(f, &s->mouse_sample_rate); - qemu_put_8s(f, &s->mouse_wrap); - qemu_put_8s(f, &s->mouse_type); - qemu_put_8s(f, &s->mouse_detect_state); - qemu_put_be32s(f, &s->mouse_dx); - qemu_put_be32s(f, &s->mouse_dy); - qemu_put_be32s(f, &s->mouse_dz); - qemu_put_8s(f, &s->mouse_buttons); -} - -static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id) -{ - PS2KbdState *s = (PS2KbdState*)opaque; - - if (version_id != 2) - return -EINVAL; - - ps2_common_load (f, &s->common); - qemu_get_be32s(f, &s->scan_enabled); - qemu_get_be32s(f, &s->translate); - return 0; -} - -static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id) -{ - PS2MouseState *s = (PS2MouseState*)opaque; - - if (version_id != 2) - return -EINVAL; - - ps2_common_load (f, &s->common); - qemu_get_8s(f, &s->mouse_status); - qemu_get_8s(f, &s->mouse_resolution); - qemu_get_8s(f, &s->mouse_sample_rate); - qemu_get_8s(f, &s->mouse_wrap); - qemu_get_8s(f, &s->mouse_type); - qemu_get_8s(f, &s->mouse_detect_state); - qemu_get_be32s(f, &s->mouse_dx); - qemu_get_be32s(f, &s->mouse_dy); - qemu_get_be32s(f, &s->mouse_dz); - qemu_get_8s(f, &s->mouse_buttons); - return 0; -} - -void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) -{ - PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState)); - - s->common.update_irq = update_irq; - s->common.update_arg = update_arg; - ps2_reset(&s->common); - register_savevm("ps2kbd", 0, 2, ps2_kbd_save, ps2_kbd_load, s); - qemu_add_kbd_event_handler(ps2_put_keycode, s); - qemu_register_reset(ps2_reset, &s->common); - return s; -} - -void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) -{ - PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState)); - - s->common.update_irq = update_irq; - s->common.update_arg = update_arg; - ps2_reset(&s->common); - register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s); - qemu_add_mouse_event_handler(ps2_mouse_event, s, 0); - qemu_register_reset(ps2_reset, &s->common); - return s; -} diff --git a/hw/rtl8139.c b/hw/rtl8139.c deleted file mode 100644 index 9c613a8..0000000 --- a/hw/rtl8139.c +++ /dev/null @@ -1,3471 +0,0 @@ -/** - * QEMU RTL8139 emulation - * - * Copyright (c) 2006 Igor Kovalenko - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - - * Modifications: - * 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver) - * - * 2006-Apr-28 Juergen Lock : EEPROM emulation changes for FreeBSD driver - * HW revision ID changes for FreeBSD driver - * - * 2006-Jul-01 Igor Kovalenko : Implemented loopback mode for FreeBSD driver - * Corrected packet transfer reassembly routine for 8139C+ mode - * Rearranged debugging print statements - * Implemented PCI timer interrupt (disabled by default) - * Implemented Tally Counters, increased VM load/save version - * Implemented IP/TCP/UDP checksum task offloading - * - * 2006-Jul-04 Igor Kovalenko : Implemented TCP segmentation offloading - * Fixed MTU=1500 for produced ethernet frames - * - * 2006-Jul-09 Igor Kovalenko : Fixed TCP header length calculation while processing - * segmentation offloading - * Removed slirp.h dependency - * Added rx/tx buffer reset when enabling rx/tx operation - */ - -#include "vl.h" - -/* debug RTL8139 card */ -//#define DEBUG_RTL8139 1 - -#define PCI_FREQUENCY 33000000L - -/* debug RTL8139 card C+ mode only */ -//#define DEBUG_RTL8139CP 1 - -/* RTL8139 provides frame CRC with received packet, this feature seems to be - ignored by most drivers, disabled by default */ -//#define RTL8139_CALCULATE_RXCRC 1 - -/* Uncomment to enable on-board timer interrupts */ -//#define RTL8139_ONBOARD_TIMER 1 - -#if defined(RTL8139_CALCULATE_RXCRC) -/* For crc32 */ -#include <zlib.h> -#endif - -#define SET_MASKED(input, mask, curr) \ - ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) ) - -/* arg % size for size which is a power of 2 */ -#define MOD2(input, size) \ - ( ( input ) & ( size - 1 ) ) - -#if defined (DEBUG_RTL8139) -# define DEBUG_PRINT(x) do { printf x ; } while (0) -#else -# define DEBUG_PRINT(x) -#endif - -/* Symbolic offsets to registers. */ -enum RTL8139_registers { - MAC0 = 0, /* Ethernet hardware address. */ - MAR0 = 8, /* Multicast filter. */ - TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */ - /* Dump Tally Conter control register(64bit). C+ mode only */ - TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */ - RxBuf = 0x30, - ChipCmd = 0x37, - RxBufPtr = 0x38, - RxBufAddr = 0x3A, - IntrMask = 0x3C, - IntrStatus = 0x3E, - TxConfig = 0x40, - RxConfig = 0x44, - Timer = 0x48, /* A general-purpose counter. */ - RxMissed = 0x4C, /* 24 bits valid, write clears. */ - Cfg9346 = 0x50, - Config0 = 0x51, - Config1 = 0x52, - FlashReg = 0x54, - MediaStatus = 0x58, - Config3 = 0x59, - Config4 = 0x5A, /* absent on RTL-8139A */ - HltClk = 0x5B, - MultiIntr = 0x5C, - PCIRevisionID = 0x5E, - TxSummary = 0x60, /* TSAD register. Transmit Status of All Descriptors*/ - BasicModeCtrl = 0x62, - BasicModeStatus = 0x64, - NWayAdvert = 0x66, - NWayLPAR = 0x68, - NWayExpansion = 0x6A, - /* Undocumented registers, but required for proper operation. */ - FIFOTMS = 0x70, /* FIFO Control and test. */ - CSCR = 0x74, /* Chip Status and Configuration Register. */ - PARA78 = 0x78, - PARA7c = 0x7c, /* Magic transceiver parameter register. */ - Config5 = 0xD8, /* absent on RTL-8139A */ - /* C+ mode */ - TxPoll = 0xD9, /* Tell chip to check Tx descriptors for work */ - RxMaxSize = 0xDA, /* Max size of an Rx packet (8169 only) */ - CpCmd = 0xE0, /* C+ Command register (C+ mode only) */ - IntrMitigate = 0xE2, /* rx/tx interrupt mitigation control */ - RxRingAddrLO = 0xE4, /* 64-bit start addr of Rx ring */ - RxRingAddrHI = 0xE8, /* 64-bit start addr of Rx ring */ - TxThresh = 0xEC, /* Early Tx threshold */ -}; - -enum ClearBitMasks { - MultiIntrClear = 0xF000, - ChipCmdClear = 0xE2, - Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1), -}; - -enum ChipCmdBits { - CmdReset = 0x10, - CmdRxEnb = 0x08, - CmdTxEnb = 0x04, - RxBufEmpty = 0x01, -}; - -/* C+ mode */ -enum CplusCmdBits { - CPlusRxVLAN = 0x0040, /* enable receive VLAN detagging */ - CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */ - CPlusRxEnb = 0x0002, - CPlusTxEnb = 0x0001, -}; - -/* Interrupt register bits, using my own meaningful names. */ -enum IntrStatusBits { - PCIErr = 0x8000, - PCSTimeout = 0x4000, - RxFIFOOver = 0x40, - RxUnderrun = 0x20, - RxOverflow = 0x10, - TxErr = 0x08, - TxOK = 0x04, - RxErr = 0x02, - RxOK = 0x01, - - RxAckBits = RxFIFOOver | RxOverflow | RxOK, -}; - -enum TxStatusBits { - TxHostOwns = 0x2000, - TxUnderrun = 0x4000, - TxStatOK = 0x8000, - TxOutOfWindow = 0x20000000, - TxAborted = 0x40000000, - TxCarrierLost = 0x80000000, -}; -enum RxStatusBits { - RxMulticast = 0x8000, - RxPhysical = 0x4000, - RxBroadcast = 0x2000, - RxBadSymbol = 0x0020, - RxRunt = 0x0010, - RxTooLong = 0x0008, - RxCRCErr = 0x0004, - RxBadAlign = 0x0002, - RxStatusOK = 0x0001, -}; - -/* Bits in RxConfig. */ -enum rx_mode_bits { - AcceptErr = 0x20, - AcceptRunt = 0x10, - AcceptBroadcast = 0x08, - AcceptMulticast = 0x04, - AcceptMyPhys = 0x02, - AcceptAllPhys = 0x01, -}; - -/* Bits in TxConfig. */ -enum tx_config_bits { - - /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */ - TxIFGShift = 24, - TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */ - TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */ - TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */ - TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */ - - TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */ - TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */ - TxClearAbt = (1 << 0), /* Clear abort (WO) */ - TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */ - TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */ - - TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */ -}; - - -/* Transmit Status of All Descriptors (TSAD) Register */ -enum TSAD_bits { - TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3 - TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2 - TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1 - TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0 - TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3 - TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2 - TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1 - TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0 - TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3 - TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2 - TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1 - TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0 - TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3 - TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2 - TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1 - TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0 -}; - - -/* Bits in Config1 */ -enum Config1Bits { - Cfg1_PM_Enable = 0x01, - Cfg1_VPD_Enable = 0x02, - Cfg1_PIO = 0x04, - Cfg1_MMIO = 0x08, - LWAKE = 0x10, /* not on 8139, 8139A */ - Cfg1_Driver_Load = 0x20, - Cfg1_LED0 = 0x40, - Cfg1_LED1 = 0x80, - SLEEP = (1 << 1), /* only on 8139, 8139A */ - PWRDN = (1 << 0), /* only on 8139, 8139A */ -}; - -/* Bits in Config3 */ -enum Config3Bits { - Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */ - Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */ - Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */ - Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */ - Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */ - Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */ - Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */ - Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */ -}; - -/* Bits in Config4 */ -enum Config4Bits { - LWPTN = (1 << 2), /* not on 8139, 8139A */ -}; - -/* Bits in Config5 */ -enum Config5Bits { - Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */ - Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */ - Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */ - Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */ - Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */ - Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */ - Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */ -}; - -enum RxConfigBits { - /* rx fifo threshold */ - RxCfgFIFOShift = 13, - RxCfgFIFONone = (7 << RxCfgFIFOShift), - - /* Max DMA burst */ - RxCfgDMAShift = 8, - RxCfgDMAUnlimited = (7 << RxCfgDMAShift), - - /* rx ring buffer length */ - RxCfgRcv8K = 0, - RxCfgRcv16K = (1 << 11), - RxCfgRcv32K = (1 << 12), - RxCfgRcv64K = (1 << 11) | (1 << 12), - - /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */ - RxNoWrap = (1 << 7), -}; - -/* Twister tuning parameters from RealTek. - Completely undocumented, but required to tune bad links on some boards. */ -/* -enum CSCRBits { - CSCR_LinkOKBit = 0x0400, - CSCR_LinkChangeBit = 0x0800, - CSCR_LinkStatusBits = 0x0f000, - CSCR_LinkDownOffCmd = 0x003c0, - CSCR_LinkDownCmd = 0x0f3c0, -*/ -enum CSCRBits { - CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */ - CSCR_LD = 1<<9, /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/ - CSCR_HEART_BIT = 1<<8, /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/ - CSCR_JBEN = 1<<7, /* 1 = enable jabber function. 0 = disable jabber function, def 1*/ - CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/ - CSCR_F_Connect = 1<<5, /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/ - CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/ - CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/ - CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/ -}; - -enum Cfg9346Bits { - Cfg9346_Lock = 0x00, - Cfg9346_Unlock = 0xC0, -}; - -typedef enum { - CH_8139 = 0, - CH_8139_K, - CH_8139A, - CH_8139A_G, - CH_8139B, - CH_8130, - CH_8139C, - CH_8100, - CH_8100B_8139D, - CH_8101, -} chip_t; - -enum chip_flags { - HasHltClk = (1 << 0), - HasLWake = (1 << 1), -}; - -#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \ - (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22) -#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1) - -#define RTL8139_PCI_REVID_8139 0x10 -#define RTL8139_PCI_REVID_8139CPLUS 0x20 - -#define RTL8139_PCI_REVID RTL8139_PCI_REVID_8139CPLUS - -/* Size is 64 * 16bit words */ -#define EEPROM_9346_ADDR_BITS 6 -#define EEPROM_9346_SIZE (1 << EEPROM_9346_ADDR_BITS) -#define EEPROM_9346_ADDR_MASK (EEPROM_9346_SIZE - 1) - -enum Chip9346Operation -{ - Chip9346_op_mask = 0xc0, /* 10 zzzzzz */ - Chip9346_op_read = 0x80, /* 10 AAAAAA */ - Chip9346_op_write = 0x40, /* 01 AAAAAA D(15)..D(0) */ - Chip9346_op_ext_mask = 0xf0, /* 11 zzzzzz */ - Chip9346_op_write_enable = 0x30, /* 00 11zzzz */ - Chip9346_op_write_all = 0x10, /* 00 01zzzz */ - Chip9346_op_write_disable = 0x00, /* 00 00zzzz */ -}; - -enum Chip9346Mode -{ - Chip9346_none = 0, - Chip9346_enter_command_mode, - Chip9346_read_command, - Chip9346_data_read, /* from output register */ - Chip9346_data_write, /* to input register, then to contents at specified address */ - Chip9346_data_write_all, /* to input register, then filling contents */ -}; - -typedef struct EEprom9346 -{ - uint16_t contents[EEPROM_9346_SIZE]; - int mode; - uint32_t tick; - uint8_t address; - uint16_t input; - uint16_t output; - - uint8_t eecs; - uint8_t eesk; - uint8_t eedi; - uint8_t eedo; -} EEprom9346; - -typedef struct RTL8139TallyCounters -{ - /* Tally counters */ - uint64_t TxOk; - uint64_t RxOk; - uint64_t TxERR; - uint32_t RxERR; - uint16_t MissPkt; - uint16_t FAE; - uint32_t Tx1Col; - uint32_t TxMCol; - uint64_t RxOkPhy; - uint64_t RxOkBrd; - uint32_t RxOkMul; - uint16_t TxAbt; - uint16_t TxUndrn; -} RTL8139TallyCounters; - -/* Clears all tally counters */ -static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters); - -/* Writes tally counters to specified physical memory address */ -static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* counters); - -/* Loads values of tally counters from VM state file */ -static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters); - -/* Saves values of tally counters to VM state file */ -static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters); - -typedef struct RTL8139State { - uint8_t phys[8]; /* mac address */ - uint8_t mult[8]; /* multicast mask array */ - - uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */ - uint32_t TxAddr[4]; /* TxAddr0 */ - uint32_t RxBuf; /* Receive buffer */ - uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */ - uint32_t RxBufPtr; - uint32_t RxBufAddr; - - uint16_t IntrStatus; - uint16_t IntrMask; - - uint32_t TxConfig; - uint32_t RxConfig; - uint32_t RxMissed; - - uint16_t CSCR; - - uint8_t Cfg9346; - uint8_t Config0; - uint8_t Config1; - uint8_t Config3; - uint8_t Config4; - uint8_t Config5; - - uint8_t clock_enabled; - uint8_t bChipCmdState; - - uint16_t MultiIntr; - - uint16_t BasicModeCtrl; - uint16_t BasicModeStatus; - uint16_t NWayAdvert; - uint16_t NWayLPAR; - uint16_t NWayExpansion; - - uint16_t CpCmd; - uint8_t TxThresh; - - int irq; - PCIDevice *pci_dev; - VLANClientState *vc; - uint8_t macaddr[6]; - int rtl8139_mmio_io_addr; - - /* C ring mode */ - uint32_t currTxDesc; - - /* C+ mode */ - uint32_t currCPlusRxDesc; - uint32_t currCPlusTxDesc; - - uint32_t RxRingAddrLO; - uint32_t RxRingAddrHI; - - EEprom9346 eeprom; - - uint32_t TCTR; - uint32_t TimerInt; - int64_t TCTR_base; - - /* Tally counters */ - RTL8139TallyCounters tally_counters; - - /* Non-persistent data */ - uint8_t *cplus_txbuffer; - int cplus_txbuffer_len; - int cplus_txbuffer_offset; - - /* PCI interrupt timer */ - QEMUTimer *timer; - -} RTL8139State; - -void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command) -{ - DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command)); - - switch (command & Chip9346_op_mask) - { - case Chip9346_op_read: - { - eeprom->address = command & EEPROM_9346_ADDR_MASK; - eeprom->output = eeprom->contents[eeprom->address]; - eeprom->eedo = 0; - eeprom->tick = 0; - eeprom->mode = Chip9346_data_read; - DEBUG_PRINT(("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->output)); - } - break; - - case Chip9346_op_write: - { - eeprom->address = command & EEPROM_9346_ADDR_MASK; - eeprom->input = 0; - eeprom->tick = 0; - eeprom->mode = Chip9346_none; /* Chip9346_data_write */ - DEBUG_PRINT(("RTL8139: eeprom begin write to address 0x%02x\n", - eeprom->address)); - } - break; - default: - eeprom->mode = Chip9346_none; - switch (command & Chip9346_op_ext_mask) - { - case Chip9346_op_write_enable: - DEBUG_PRINT(("RTL8139: eeprom write enabled\n")); - break; - case Chip9346_op_write_all: - DEBUG_PRINT(("RTL8139: eeprom begin write all\n")); - break; - case Chip9346_op_write_disable: - DEBUG_PRINT(("RTL8139: eeprom write disabled\n")); - break; - } - break; - } -} - -void prom9346_shift_clock(EEprom9346 *eeprom) -{ - int bit = eeprom->eedi?1:0; - - ++ eeprom->tick; - - DEBUG_PRINT(("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo)); - - switch (eeprom->mode) - { - case Chip9346_enter_command_mode: - if (bit) - { - eeprom->mode = Chip9346_read_command; - eeprom->tick = 0; - eeprom->input = 0; - DEBUG_PRINT(("eeprom: +++ synchronized, begin command read\n")); - } - break; - - case Chip9346_read_command: - eeprom->input = (eeprom->input << 1) | (bit & 1); - if (eeprom->tick == 8) - { - prom9346_decode_command(eeprom, eeprom->input & 0xff); - } - break; - - case Chip9346_data_read: - eeprom->eedo = (eeprom->output & 0x8000)?1:0; - eeprom->output <<= 1; - if (eeprom->tick == 16) - { -#if 1 - // the FreeBSD drivers (rl and re) don't explicitly toggle - // CS between reads (or does setting Cfg9346 to 0 count too?), - // so we need to enter wait-for-command state here - eeprom->mode = Chip9346_enter_command_mode; - eeprom->input = 0; - eeprom->tick = 0; - - DEBUG_PRINT(("eeprom: +++ end of read, awaiting next command\n")); -#else - // original behaviour - ++eeprom->address; - eeprom->address &= EEPROM_9346_ADDR_MASK; - eeprom->output = eeprom->contents[eeprom->address]; - eeprom->tick = 0; - - DEBUG_PRINT(("eeprom: +++ read next address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->output)); -#endif - } - break; - - case Chip9346_data_write: - eeprom->input = (eeprom->input << 1) | (bit & 1); - if (eeprom->tick == 16) - { - DEBUG_PRINT(("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", - eeprom->address, eeprom->input)); - - eeprom->contents[eeprom->address] = eeprom->input; - eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */ - eeprom->tick = 0; - eeprom->input = 0; - } - break; - - case Chip9346_data_write_all: - eeprom->input = (eeprom->input << 1) | (bit & 1); - if (eeprom->tick == 16) - { - int i; - for (i = 0; i < EEPROM_9346_SIZE; i++) - { - eeprom->contents[i] = eeprom->input; - } - DEBUG_PRINT(("RTL8139: eeprom filled with data=0x%04x\n", - eeprom->input)); - - eeprom->mode = Chip9346_enter_command_mode; - eeprom->tick = 0; - eeprom->input = 0; - } - break; - - default: - break; - } -} - -int prom9346_get_wire(RTL8139State *s) -{ - EEprom9346 *eeprom = &s->eeprom; - if (!eeprom->eecs) - return 0; - - return eeprom->eedo; -} - -void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi) -{ - EEprom9346 *eeprom = &s->eeprom; - uint8_t old_eecs = eeprom->eecs; - uint8_t old_eesk = eeprom->eesk; - - eeprom->eecs = eecs; - eeprom->eesk = eesk; - eeprom->eedi = eedi; - - DEBUG_PRINT(("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", - eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo)); - - if (!old_eecs && eecs) - { - /* Synchronize start */ - eeprom->tick = 0; - eeprom->input = 0; - eeprom->output = 0; - eeprom->mode = Chip9346_enter_command_mode; - - DEBUG_PRINT(("=== eeprom: begin access, enter command mode\n")); - } - - if (!eecs) - { - DEBUG_PRINT(("=== eeprom: end access\n")); - return; - } - - if (!old_eesk && eesk) - { - /* SK front rules */ - prom9346_shift_clock(eeprom); - } -} - -static void rtl8139_update_irq(RTL8139State *s) -{ - int isr; - isr = (s->IntrStatus & s->IntrMask) & 0xffff; - - DEBUG_PRINT(("RTL8139: Set IRQ line %d to %d (%04x %04x)\n", - s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask)); - - if (s->irq == 16) { - /* PCI irq */ - pci_set_irq(s->pci_dev, 0, (isr != 0)); - } else { - /* ISA irq */ - pic_set_irq(s->irq, (isr != 0)); - } -} - -#define POLYNOMIAL 0x04c11db6 - -/* From FreeBSD */ -/* XXX: optimize */ -static int compute_mcast_idx(const uint8_t *ep) -{ - uint32_t crc; - int carry, i, j; - uint8_t b; - - crc = 0xffffffff; - for (i = 0; i < 6; i++) { - b = *ep++; - for (j = 0; j < 8; j++) { - carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); - crc <<= 1; - b >>= 1; - if (carry) - crc = ((crc ^ POLYNOMIAL) | carry); - } - } - return (crc >> 26); -} - -static int rtl8139_RxWrap(RTL8139State *s) -{ - /* wrapping enabled; assume 1.5k more buffer space if size < 65536 */ - return (s->RxConfig & (1 << 7)); -} - -static int rtl8139_receiver_enabled(RTL8139State *s) -{ - return s->bChipCmdState & CmdRxEnb; -} - -static int rtl8139_transmitter_enabled(RTL8139State *s) -{ - return s->bChipCmdState & CmdTxEnb; -} - -static int rtl8139_cp_receiver_enabled(RTL8139State *s) -{ - return s->CpCmd & CPlusRxEnb; -} - -static int rtl8139_cp_transmitter_enabled(RTL8139State *s) -{ - return s->CpCmd & CPlusTxEnb; -} - -static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size) -{ - if (s->RxBufAddr + size > s->RxBufferSize) - { - int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize); - - /* write packet data */ - if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s)) - { - DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped)); - - if (size > wrapped) - { - cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, - buf, size-wrapped ); - } - - /* reset buffer pointer */ - s->RxBufAddr = 0; - - cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, - buf + (size-wrapped), wrapped ); - - s->RxBufAddr = wrapped; - - return; - } - } - - /* non-wrapping path or overwrapping enabled */ - cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, buf, size ); - - s->RxBufAddr += size; -} - -#define MIN_BUF_SIZE 60 -static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high) -{ -#if TARGET_PHYS_ADDR_BITS > 32 - return low | ((target_phys_addr_t)high << 32); -#else - return low; -#endif -} - -static int rtl8139_can_receive(void *opaque) -{ - RTL8139State *s = opaque; - int avail; - - /* Recieve (drop) packets if card is disabled. */ - if (!s->clock_enabled) - return 1; - if (!rtl8139_receiver_enabled(s)) - return 1; - - if (rtl8139_cp_receiver_enabled(s)) { - /* ??? Flow control not implemented in c+ mode. - This is a hack to work around slirp deficiencies anyway. */ - return 1; - } else { - avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, - s->RxBufferSize); - return (avail == 0 || avail >= 1514); - } -} - -static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int do_interrupt) -{ - RTL8139State *s = opaque; - - uint32_t packet_header = 0; - - uint8_t buf1[60]; - static const uint8_t broadcast_macaddr[6] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - - DEBUG_PRINT((">>> RTL8139: received len=%d\n", size)); - - /* test if board clock is stopped */ - if (!s->clock_enabled) - { - DEBUG_PRINT(("RTL8139: stopped ==========================\n")); - return; - } - - /* first check if receiver is enabled */ - - if (!rtl8139_receiver_enabled(s)) - { - DEBUG_PRINT(("RTL8139: receiver disabled ================\n")); - return; - } - - /* XXX: check this */ - if (s->RxConfig & AcceptAllPhys) { - /* promiscuous: receive all */ - DEBUG_PRINT((">>> RTL8139: packet received in promiscuous mode\n")); - - } else { - if (!memcmp(buf, broadcast_macaddr, 6)) { - /* broadcast address */ - if (!(s->RxConfig & AcceptBroadcast)) - { - DEBUG_PRINT((">>> RTL8139: broadcast packet rejected\n")); - - /* update tally counter */ - ++s->tally_counters.RxERR; - - return; - } - - packet_header |= RxBroadcast; - - DEBUG_PRINT((">>> RTL8139: broadcast packet received\n")); - - /* update tally counter */ - ++s->tally_counters.RxOkBrd; - - } else if (buf[0] & 0x01) { - /* multicast */ - if (!(s->RxConfig & AcceptMulticast)) - { - DEBUG_PRINT((">>> RTL8139: multicast packet rejected\n")); - - /* update tally counter */ - ++s->tally_counters.RxERR; - - return; - } - - int mcast_idx = compute_mcast_idx(buf); - - if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) - { - DEBUG_PRINT((">>> RTL8139: multicast address mismatch\n")); - - /* update tally counter */ - ++s->tally_counters.RxERR; - - return; - } - - packet_header |= RxMulticast; - - DEBUG_PRINT((">>> RTL8139: multicast packet received\n")); - - /* update tally counter */ - ++s->tally_counters.RxOkMul; - - } else if (s->phys[0] == buf[0] && - s->phys[1] == buf[1] && - s->phys[2] == buf[2] && - s->phys[3] == buf[3] && - s->phys[4] == buf[4] && - s->phys[5] == buf[5]) { - /* match */ - if (!(s->RxConfig & AcceptMyPhys)) - { - DEBUG_PRINT((">>> RTL8139: rejecting physical address matching packet\n")); - - /* update tally counter */ - ++s->tally_counters.RxERR; - - return; - } - - packet_header |= RxPhysical; - - DEBUG_PRINT((">>> RTL8139: physical address matching packet received\n")); - - /* update tally counter */ - ++s->tally_counters.RxOkPhy; - - } else { - - DEBUG_PRINT((">>> RTL8139: unknown packet\n")); - - /* update tally counter */ - ++s->tally_counters.RxERR; - - return; - } - } - - /* if too small buffer, then expand it */ - if (size < MIN_BUF_SIZE) { - memcpy(buf1, buf, size); - memset(buf1 + size, 0, MIN_BUF_SIZE - size); - buf = buf1; - size = MIN_BUF_SIZE; - } - - if (rtl8139_cp_receiver_enabled(s)) - { - DEBUG_PRINT(("RTL8139: in C+ Rx mode ================\n")); - - /* begin C+ receiver mode */ - -/* w0 ownership flag */ -#define CP_RX_OWN (1<<31) -/* w0 end of ring flag */ -#define CP_RX_EOR (1<<30) -/* w0 bits 0...12 : buffer size */ -#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1) -/* w1 tag available flag */ -#define CP_RX_TAVA (1<<16) -/* w1 bits 0...15 : VLAN tag */ -#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1) -/* w2 low 32bit of Rx buffer ptr */ -/* w3 high 32bit of Rx buffer ptr */ - - int descriptor = s->currCPlusRxDesc; - target_phys_addr_t cplus_rx_ring_desc; - - cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI); - cplus_rx_ring_desc += 16 * descriptor; - - DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = %016" PRIx64 "\n", - descriptor, s->RxRingAddrHI, s->RxRingAddrLO, (uint64_t)cplus_rx_ring_desc)); - - uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI; - - cpu_physical_memory_read(cplus_rx_ring_desc, (uint8_t *)&val, 4); - rxdw0 = le32_to_cpu(val); - cpu_physical_memory_read(cplus_rx_ring_desc+4, (uint8_t *)&val, 4); - rxdw1 = le32_to_cpu(val); - cpu_physical_memory_read(cplus_rx_ring_desc+8, (uint8_t *)&val, 4); - rxbufLO = le32_to_cpu(val); - cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4); - rxbufHI = le32_to_cpu(val); - - DEBUG_PRINT(("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n", - descriptor, - rxdw0, rxdw1, rxbufLO, rxbufHI)); - - if (!(rxdw0 & CP_RX_OWN)) - { - DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor)); - - s->IntrStatus |= RxOverflow; - ++s->RxMissed; - - /* update tally counter */ - ++s->tally_counters.RxERR; - ++s->tally_counters.MissPkt; - - rtl8139_update_irq(s); - return; - } - - uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; - - /* TODO: scatter the packet over available receive ring descriptors space */ - - if (size+4 > rx_space) - { - DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n", - descriptor, rx_space, size)); - - s->IntrStatus |= RxOverflow; - ++s->RxMissed; - - /* update tally counter */ - ++s->tally_counters.RxERR; - ++s->tally_counters.MissPkt; - - rtl8139_update_irq(s); - return; - } - - target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI); - - /* receive/copy to target memory */ - cpu_physical_memory_write( rx_addr, buf, size ); - - if (s->CpCmd & CPlusRxChkSum) - { - /* do some packet checksumming */ - } - - /* write checksum */ -#if defined (RTL8139_CALCULATE_RXCRC) - val = cpu_to_le32(crc32(~0, buf, size)); -#else - val = 0; -#endif - cpu_physical_memory_write( rx_addr+size, (uint8_t *)&val, 4); - -/* first segment of received packet flag */ -#define CP_RX_STATUS_FS (1<<29) -/* last segment of received packet flag */ -#define CP_RX_STATUS_LS (1<<28) -/* multicast packet flag */ -#define CP_RX_STATUS_MAR (1<<26) -/* physical-matching packet flag */ -#define CP_RX_STATUS_PAM (1<<25) -/* broadcast packet flag */ -#define CP_RX_STATUS_BAR (1<<24) -/* runt packet flag */ -#define CP_RX_STATUS_RUNT (1<<19) -/* crc error flag */ -#define CP_RX_STATUS_CRC (1<<18) -/* IP checksum error flag */ -#define CP_RX_STATUS_IPF (1<<15) -/* UDP checksum error flag */ -#define CP_RX_STATUS_UDPF (1<<14) -/* TCP checksum error flag */ -#define CP_RX_STATUS_TCPF (1<<13) - - /* transfer ownership to target */ - rxdw0 &= ~CP_RX_OWN; - - /* set first segment bit */ - rxdw0 |= CP_RX_STATUS_FS; - - /* set last segment bit */ - rxdw0 |= CP_RX_STATUS_LS; - - /* set received packet type flags */ - if (packet_header & RxBroadcast) - rxdw0 |= CP_RX_STATUS_BAR; - if (packet_header & RxMulticast) - rxdw0 |= CP_RX_STATUS_MAR; - if (packet_header & RxPhysical) - rxdw0 |= CP_RX_STATUS_PAM; - - /* set received size */ - rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK; - rxdw0 |= (size+4); - - /* reset VLAN tag flag */ - rxdw1 &= ~CP_RX_TAVA; - - /* update ring data */ - val = cpu_to_le32(rxdw0); - cpu_physical_memory_write(cplus_rx_ring_desc, (uint8_t *)&val, 4); - val = cpu_to_le32(rxdw1); - cpu_physical_memory_write(cplus_rx_ring_desc+4, (uint8_t *)&val, 4); - - /* update tally counter */ - ++s->tally_counters.RxOk; - - /* seek to next Rx descriptor */ - if (rxdw0 & CP_RX_EOR) - { - s->currCPlusRxDesc = 0; - } - else - { - ++s->currCPlusRxDesc; - } - - DEBUG_PRINT(("RTL8139: done C+ Rx mode ----------------\n")); - - } - else - { - DEBUG_PRINT(("RTL8139: in ring Rx mode ================\n")); - - /* begin ring receiver mode */ - int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize); - - /* if receiver buffer is empty then avail == 0 */ - - if (avail != 0 && size + 8 >= avail) - { - DEBUG_PRINT(("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8)); - - s->IntrStatus |= RxOverflow; - ++s->RxMissed; - rtl8139_update_irq(s); - return; - } - - packet_header |= RxStatusOK; - - packet_header |= (((size+4) << 16) & 0xffff0000); - - /* write header */ - uint32_t val = cpu_to_le32(packet_header); - - rtl8139_write_buffer(s, (uint8_t *)&val, 4); - - rtl8139_write_buffer(s, buf, size); - - /* write checksum */ -#if defined (RTL8139_CALCULATE_RXCRC) - val = cpu_to_le32(crc32(~0, buf, size)); -#else - val = 0; -#endif - - rtl8139_write_buffer(s, (uint8_t *)&val, 4); - - /* correct buffer write pointer */ - s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize); - - /* now we can signal we have received something */ - - DEBUG_PRINT((" received: rx buffer length %d head 0x%04x read 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr)); - } - - s->IntrStatus |= RxOK; - - if (do_interrupt) - { - rtl8139_update_irq(s); - } -} - -static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) -{ - rtl8139_do_receive(opaque, buf, size, 1); -} - -static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) -{ - s->RxBufferSize = bufferSize; - s->RxBufPtr = 0; - s->RxBufAddr = 0; -} - -static void rtl8139_reset(RTL8139State *s) -{ - int i; - - /* restore MAC address */ - memcpy(s->phys, s->macaddr, 6); - - /* reset interrupt mask */ - s->IntrStatus = 0; - s->IntrMask = 0; - - rtl8139_update_irq(s); - - /* prepare eeprom */ - s->eeprom.contents[0] = 0x8129; -#if 1 - // PCI vendor and device ID should be mirrored here - s->eeprom.contents[1] = 0x10ec; - s->eeprom.contents[2] = 0x8139; -#endif - memcpy(&s->eeprom.contents[7], s->macaddr, 6); - - /* mark all status registers as owned by host */ - for (i = 0; i < 4; ++i) - { - s->TxStatus[i] = TxHostOwns; - } - - s->currTxDesc = 0; - s->currCPlusRxDesc = 0; - s->currCPlusTxDesc = 0; - - s->RxRingAddrLO = 0; - s->RxRingAddrHI = 0; - - s->RxBuf = 0; - - rtl8139_reset_rxring(s, 8192); - - /* ACK the reset */ - s->TxConfig = 0; - -#if 0 -// s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139 HasHltClk - s->clock_enabled = 0; -#else - s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake - s->clock_enabled = 1; -#endif - - s->bChipCmdState = CmdReset; /* RxBufEmpty bit is calculated on read from ChipCmd */; - - /* set initial state data */ - s->Config0 = 0x0; /* No boot ROM */ - s->Config1 = 0xC; /* IO mapped and MEM mapped registers available */ - s->Config3 = 0x1; /* fast back-to-back compatible */ - s->Config5 = 0x0; - - s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; - - s->CpCmd = 0x0; /* reset C+ mode */ - -// s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation -// s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex - s->BasicModeCtrl = 0x1000; // autonegotiation - - s->BasicModeStatus = 0x7809; - //s->BasicModeStatus |= 0x0040; /* UTP medium */ - s->BasicModeStatus |= 0x0020; /* autonegotiation completed */ - s->BasicModeStatus |= 0x0004; /* link is up */ - - s->NWayAdvert = 0x05e1; /* all modes, full duplex */ - s->NWayLPAR = 0x05e1; /* all modes, full duplex */ - s->NWayExpansion = 0x0001; /* autonegotiation supported */ - - /* also reset timer and disable timer interrupt */ - s->TCTR = 0; - s->TimerInt = 0; - s->TCTR_base = 0; - - /* reset tally counters */ - RTL8139TallyCounters_clear(&s->tally_counters); -} - -void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters) -{ - counters->TxOk = 0; - counters->RxOk = 0; - counters->TxERR = 0; - counters->RxERR = 0; - counters->MissPkt = 0; - counters->FAE = 0; - counters->Tx1Col = 0; - counters->TxMCol = 0; - counters->RxOkPhy = 0; - counters->RxOkBrd = 0; - counters->RxOkMul = 0; - counters->TxAbt = 0; - counters->TxUndrn = 0; -} - -static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* tally_counters) -{ - uint16_t val16; - uint32_t val32; - uint64_t val64; - - val64 = cpu_to_le64(tally_counters->TxOk); - cpu_physical_memory_write(tc_addr + 0, (uint8_t *)&val64, 8); - - val64 = cpu_to_le64(tally_counters->RxOk); - cpu_physical_memory_write(tc_addr + 8, (uint8_t *)&val64, 8); - - val64 = cpu_to_le64(tally_counters->TxERR); - cpu_physical_memory_write(tc_addr + 16, (uint8_t *)&val64, 8); - - val32 = cpu_to_le32(tally_counters->RxERR); - cpu_physical_memory_write(tc_addr + 24, (uint8_t *)&val32, 4); - - val16 = cpu_to_le16(tally_counters->MissPkt); - cpu_physical_memory_write(tc_addr + 28, (uint8_t *)&val16, 2); - - val16 = cpu_to_le16(tally_counters->FAE); - cpu_physical_memory_write(tc_addr + 30, (uint8_t *)&val16, 2); - - val32 = cpu_to_le32(tally_counters->Tx1Col); - cpu_physical_memory_write(tc_addr + 32, (uint8_t *)&val32, 4); - - val32 = cpu_to_le32(tally_counters->TxMCol); - cpu_physical_memory_write(tc_addr + 36, (uint8_t *)&val32, 4); - - val64 = cpu_to_le64(tally_counters->RxOkPhy); - cpu_physical_memory_write(tc_addr + 40, (uint8_t *)&val64, 8); - - val64 = cpu_to_le64(tally_counters->RxOkBrd); - cpu_physical_memory_write(tc_addr + 48, (uint8_t *)&val64, 8); - - val32 = cpu_to_le32(tally_counters->RxOkMul); - cpu_physical_memory_write(tc_addr + 56, (uint8_t *)&val32, 4); - - val16 = cpu_to_le16(tally_counters->TxAbt); - cpu_physical_memory_write(tc_addr + 60, (uint8_t *)&val16, 2); - - val16 = cpu_to_le16(tally_counters->TxUndrn); - cpu_physical_memory_write(tc_addr + 62, (uint8_t *)&val16, 2); -} - -/* Loads values of tally counters from VM state file */ -static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters) -{ - qemu_get_be64s(f, &tally_counters->TxOk); - qemu_get_be64s(f, &tally_counters->RxOk); - qemu_get_be64s(f, &tally_counters->TxERR); - qemu_get_be32s(f, &tally_counters->RxERR); - qemu_get_be16s(f, &tally_counters->MissPkt); - qemu_get_be16s(f, &tally_counters->FAE); - qemu_get_be32s(f, &tally_counters->Tx1Col); - qemu_get_be32s(f, &tally_counters->TxMCol); - qemu_get_be64s(f, &tally_counters->RxOkPhy); - qemu_get_be64s(f, &tally_counters->RxOkBrd); - qemu_get_be32s(f, &tally_counters->RxOkMul); - qemu_get_be16s(f, &tally_counters->TxAbt); - qemu_get_be16s(f, &tally_counters->TxUndrn); -} - -/* Saves values of tally counters to VM state file */ -static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters) -{ - qemu_put_be64s(f, &tally_counters->TxOk); - qemu_put_be64s(f, &tally_counters->RxOk); - qemu_put_be64s(f, &tally_counters->TxERR); - qemu_put_be32s(f, &tally_counters->RxERR); - qemu_put_be16s(f, &tally_counters->MissPkt); - qemu_put_be16s(f, &tally_counters->FAE); - qemu_put_be32s(f, &tally_counters->Tx1Col); - qemu_put_be32s(f, &tally_counters->TxMCol); - qemu_put_be64s(f, &tally_counters->RxOkPhy); - qemu_put_be64s(f, &tally_counters->RxOkBrd); - qemu_put_be32s(f, &tally_counters->RxOkMul); - qemu_put_be16s(f, &tally_counters->TxAbt); - qemu_put_be16s(f, &tally_counters->TxUndrn); -} - -static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val) -{ - val &= 0xff; - - DEBUG_PRINT(("RTL8139: ChipCmd write val=0x%08x\n", val)); - - if (val & CmdReset) - { - DEBUG_PRINT(("RTL8139: ChipCmd reset\n")); - rtl8139_reset(s); - } - if (val & CmdRxEnb) - { - DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n")); - - s->currCPlusRxDesc = 0; - } - if (val & CmdTxEnb) - { - DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n")); - - s->currCPlusTxDesc = 0; - } - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0xe3, s->bChipCmdState); - - /* Deassert reset pin before next read */ - val &= ~CmdReset; - - s->bChipCmdState = val; -} - -static int rtl8139_RxBufferEmpty(RTL8139State *s) -{ - int unread = MOD2(s->RxBufferSize + s->RxBufAddr - s->RxBufPtr, s->RxBufferSize); - - if (unread != 0) - { - DEBUG_PRINT(("RTL8139: receiver buffer data available 0x%04x\n", unread)); - return 0; - } - - DEBUG_PRINT(("RTL8139: receiver buffer is empty\n")); - - return 1; -} - -static uint32_t rtl8139_ChipCmd_read(RTL8139State *s) -{ - uint32_t ret = s->bChipCmdState; - - if (rtl8139_RxBufferEmpty(s)) - ret |= RxBufEmpty; - - DEBUG_PRINT(("RTL8139: ChipCmd read val=0x%04x\n", ret)); - - return ret; -} - -static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val) -{ - val &= 0xffff; - - DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val)); - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0xff84, s->CpCmd); - - s->CpCmd = val; -} - -static uint32_t rtl8139_CpCmd_read(RTL8139State *s) -{ - uint32_t ret = s->CpCmd; - - DEBUG_PRINT(("RTL8139C+ command register read(w) val=0x%04x\n", ret)); - - return ret; -} - -static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val) -{ - DEBUG_PRINT(("RTL8139C+ IntrMitigate register write(w) val=0x%04x\n", val)); -} - -static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s) -{ - uint32_t ret = 0; - - DEBUG_PRINT(("RTL8139C+ IntrMitigate register read(w) val=0x%04x\n", ret)); - - return ret; -} - -int rtl8139_config_writeable(RTL8139State *s) -{ - if (s->Cfg9346 & Cfg9346_Unlock) - { - return 1; - } - - DEBUG_PRINT(("RTL8139: Configuration registers are write-protected\n")); - - return 0; -} - -static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val) -{ - val &= 0xffff; - - DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val)); - - /* mask unwriteable bits */ - uint32 mask = 0x4cff; - - if (1 || !rtl8139_config_writeable(s)) - { - /* Speed setting and autonegotiation enable bits are read-only */ - mask |= 0x3000; - /* Duplex mode setting is read-only */ - mask |= 0x0100; - } - - val = SET_MASKED(val, mask, s->BasicModeCtrl); - - s->BasicModeCtrl = val; -} - -static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s) -{ - uint32_t ret = s->BasicModeCtrl; - - DEBUG_PRINT(("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret)); - - return ret; -} - -static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val) -{ - val &= 0xffff; - - DEBUG_PRINT(("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val)); - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0xff3f, s->BasicModeStatus); - - s->BasicModeStatus = val; -} - -static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s) -{ - uint32_t ret = s->BasicModeStatus; - - DEBUG_PRINT(("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret)); - - return ret; -} - -static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val) -{ - val &= 0xff; - - DEBUG_PRINT(("RTL8139: Cfg9346 write val=0x%02x\n", val)); - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0x31, s->Cfg9346); - - uint32_t opmode = val & 0xc0; - uint32_t eeprom_val = val & 0xf; - - if (opmode == 0x80) { - /* eeprom access */ - int eecs = (eeprom_val & 0x08)?1:0; - int eesk = (eeprom_val & 0x04)?1:0; - int eedi = (eeprom_val & 0x02)?1:0; - prom9346_set_wire(s, eecs, eesk, eedi); - } else if (opmode == 0x40) { - /* Reset. */ - val = 0; - rtl8139_reset(s); - } - - s->Cfg9346 = val; -} - -static uint32_t rtl8139_Cfg9346_read(RTL8139State *s) -{ - uint32_t ret = s->Cfg9346; - - uint32_t opmode = ret & 0xc0; - - if (opmode == 0x80) - { - /* eeprom access */ - int eedo = prom9346_get_wire(s); - if (eedo) - { - ret |= 0x01; - } - else - { - ret &= ~0x01; - } - } - - DEBUG_PRINT(("RTL8139: Cfg9346 read val=0x%02x\n", ret)); - - return ret; -} - -static void rtl8139_Config0_write(RTL8139State *s, uint32_t val) -{ - val &= 0xff; - - DEBUG_PRINT(("RTL8139: Config0 write val=0x%02x\n", val)); - - if (!rtl8139_config_writeable(s)) - return; - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0xf8, s->Config0); - - s->Config0 = val; -} - -static uint32_t rtl8139_Config0_read(RTL8139State *s) -{ - uint32_t ret = s->Config0; - - DEBUG_PRINT(("RTL8139: Config0 read val=0x%02x\n", ret)); - - return ret; -} - -static void rtl8139_Config1_write(RTL8139State *s, uint32_t val) -{ - val &= 0xff; - - DEBUG_PRINT(("RTL8139: Config1 write val=0x%02x\n", val)); - - if (!rtl8139_config_writeable(s)) - return; - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0xC, s->Config1); - - s->Config1 = val; -} - -static uint32_t rtl8139_Config1_read(RTL8139State *s) -{ - uint32_t ret = s->Config1; - - DEBUG_PRINT(("RTL8139: Config1 read val=0x%02x\n", ret)); - - return ret; -} - -static void rtl8139_Config3_write(RTL8139State *s, uint32_t val) -{ - val &= 0xff; - - DEBUG_PRINT(("RTL8139: Config3 write val=0x%02x\n", val)); - - if (!rtl8139_config_writeable(s)) - return; - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0x8F, s->Config3); - - s->Config3 = val; -} - -static uint32_t rtl8139_Config3_read(RTL8139State *s) -{ - uint32_t ret = s->Config3; - - DEBUG_PRINT(("RTL8139: Config3 read val=0x%02x\n", ret)); - - return ret; -} - -static void rtl8139_Config4_write(RTL8139State *s, uint32_t val) -{ - val &= 0xff; - - DEBUG_PRINT(("RTL8139: Config4 write val=0x%02x\n", val)); - - if (!rtl8139_config_writeable(s)) - return; - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0x0a, s->Config4); - - s->Config4 = val; -} - -static uint32_t rtl8139_Config4_read(RTL8139State *s) -{ - uint32_t ret = s->Config4; - - DEBUG_PRINT(("RTL8139: Config4 read val=0x%02x\n", ret)); - - return ret; -} - -static void rtl8139_Config5_write(RTL8139State *s, uint32_t val) -{ - val &= 0xff; - - DEBUG_PRINT(("RTL8139: Config5 write val=0x%02x\n", val)); - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0x80, s->Config5); - - s->Config5 = val; -} - -static uint32_t rtl8139_Config5_read(RTL8139State *s) -{ - uint32_t ret = s->Config5; - - DEBUG_PRINT(("RTL8139: Config5 read val=0x%02x\n", ret)); - - return ret; -} - -static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val) -{ - if (!rtl8139_transmitter_enabled(s)) - { - DEBUG_PRINT(("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val)); - return; - } - - DEBUG_PRINT(("RTL8139: TxConfig write val=0x%08x\n", val)); - - val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig); - - s->TxConfig = val; -} - -static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val) -{ - DEBUG_PRINT(("RTL8139C TxConfig via write(b) val=0x%02x\n", val)); - - uint32_t tc = s->TxConfig; - tc &= 0xFFFFFF00; - tc |= (val & 0x000000FF); - rtl8139_TxConfig_write(s, tc); -} - -static uint32_t rtl8139_TxConfig_read(RTL8139State *s) -{ - uint32_t ret = s->TxConfig; - - DEBUG_PRINT(("RTL8139: TxConfig read val=0x%04x\n", ret)); - - return ret; -} - -static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val) -{ - DEBUG_PRINT(("RTL8139: RxConfig write val=0x%08x\n", val)); - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0xf0fc0040, s->RxConfig); - - s->RxConfig = val; - - /* reset buffer size and read/write pointers */ - rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3)); - - DEBUG_PRINT(("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize)); -} - -static uint32_t rtl8139_RxConfig_read(RTL8139State *s) -{ - uint32_t ret = s->RxConfig; - - DEBUG_PRINT(("RTL8139: RxConfig read val=0x%08x\n", ret)); - - return ret; -} - -static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size, int do_interrupt) -{ - if (!size) - { - DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n")); - return; - } - - if (TxLoopBack == (s->TxConfig & TxLoopBack)) - { - DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); - rtl8139_do_receive(s, buf, size, do_interrupt); - } - else - { - qemu_send_packet(s->vc, buf, size); - } -} - -static int rtl8139_transmit_one(RTL8139State *s, int descriptor) -{ - if (!rtl8139_transmitter_enabled(s)) - { - DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n", - descriptor)); - return 0; - } - - if (s->TxStatus[descriptor] & TxHostOwns) - { - DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n", - descriptor, s->TxStatus[descriptor])); - return 0; - } - - DEBUG_PRINT(("RTL8139: +++ transmitting from descriptor %d\n", descriptor)); - - int txsize = s->TxStatus[descriptor] & 0x1fff; - uint8_t txbuffer[0x2000]; - - DEBUG_PRINT(("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n", - txsize, s->TxAddr[descriptor])); - - cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize); - - /* Mark descriptor as transferred */ - s->TxStatus[descriptor] |= TxHostOwns; - s->TxStatus[descriptor] |= TxStatOK; - - rtl8139_transfer_frame(s, txbuffer, txsize, 0); - - DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor)); - - /* update interrupt */ - s->IntrStatus |= TxOK; - rtl8139_update_irq(s); - - return 1; -} - -/* structures and macros for task offloading */ -typedef struct ip_header -{ - uint8_t ip_ver_len; /* version and header length */ - uint8_t ip_tos; /* type of service */ - uint16_t ip_len; /* total length */ - uint16_t ip_id; /* identification */ - uint16_t ip_off; /* fragment offset field */ - uint8_t ip_ttl; /* time to live */ - uint8_t ip_p; /* protocol */ - uint16_t ip_sum; /* checksum */ - uint32_t ip_src,ip_dst; /* source and dest address */ -} ip_header; - -#define IP_HEADER_VERSION_4 4 -#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf) -#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2) - -typedef struct tcp_header -{ - uint16_t th_sport; /* source port */ - uint16_t th_dport; /* destination port */ - uint32_t th_seq; /* sequence number */ - uint32_t th_ack; /* acknowledgement number */ - uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */ - uint16_t th_win; /* window */ - uint16_t th_sum; /* checksum */ - uint16_t th_urp; /* urgent pointer */ -} tcp_header; - -typedef struct udp_header -{ - uint16_t uh_sport; /* source port */ - uint16_t uh_dport; /* destination port */ - uint16_t uh_ulen; /* udp length */ - uint16_t uh_sum; /* udp checksum */ -} udp_header; - -typedef struct ip_pseudo_header -{ - uint32_t ip_src; - uint32_t ip_dst; - uint8_t zeros; - uint8_t ip_proto; - uint16_t ip_payload; -} ip_pseudo_header; - -#define IP_PROTO_TCP 6 -#define IP_PROTO_UDP 17 - -#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2) -#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f) -#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags)) - -#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off))) - -#define TCP_FLAG_FIN 0x01 -#define TCP_FLAG_PUSH 0x08 - -/* produces ones' complement sum of data */ -static uint16_t ones_complement_sum(uint8_t *data, size_t len) -{ - uint32_t result = 0; - - for (; len > 1; data+=2, len-=2) - { - result += *(uint16_t*)data; - } - - /* add the remainder byte */ - if (len) - { - uint8_t odd[2] = {*data, 0}; - result += *(uint16_t*)odd; - } - - while (result>>16) - result = (result & 0xffff) + (result >> 16); - - return result; -} - -static uint16_t ip_checksum(void *data, size_t len) -{ - return ~ones_complement_sum((uint8_t*)data, len); -} - -static int rtl8139_cplus_transmit_one(RTL8139State *s) -{ - if (!rtl8139_transmitter_enabled(s)) - { - DEBUG_PRINT(("RTL8139: +++ C+ mode: transmitter disabled\n")); - return 0; - } - - if (!rtl8139_cp_transmitter_enabled(s)) - { - DEBUG_PRINT(("RTL8139: +++ C+ mode: C+ transmitter disabled\n")); - return 0 ; - } - - int descriptor = s->currCPlusTxDesc; - - target_phys_addr_t cplus_tx_ring_desc = - rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]); - - /* Normal priority ring */ - cplus_tx_ring_desc += 16 * descriptor; - - DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n", - descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc)); - - uint32_t val, txdw0,txdw1,txbufLO,txbufHI; - - cpu_physical_memory_read(cplus_tx_ring_desc, (uint8_t *)&val, 4); - txdw0 = le32_to_cpu(val); - cpu_physical_memory_read(cplus_tx_ring_desc+4, (uint8_t *)&val, 4); - txdw1 = le32_to_cpu(val); - cpu_physical_memory_read(cplus_tx_ring_desc+8, (uint8_t *)&val, 4); - txbufLO = le32_to_cpu(val); - cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4); - txbufHI = le32_to_cpu(val); - - DEBUG_PRINT(("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", - descriptor, - txdw0, txdw1, txbufLO, txbufHI)); - -/* w0 ownership flag */ -#define CP_TX_OWN (1<<31) -/* w0 end of ring flag */ -#define CP_TX_EOR (1<<30) -/* first segment of received packet flag */ -#define CP_TX_FS (1<<29) -/* last segment of received packet flag */ -#define CP_TX_LS (1<<28) -/* large send packet flag */ -#define CP_TX_LGSEN (1<<27) -/* large send MSS mask, bits 16...25 */ -#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1) - -/* IP checksum offload flag */ -#define CP_TX_IPCS (1<<18) -/* UDP checksum offload flag */ -#define CP_TX_UDPCS (1<<17) -/* TCP checksum offload flag */ -#define CP_TX_TCPCS (1<<16) - -/* w0 bits 0...15 : buffer size */ -#define CP_TX_BUFFER_SIZE (1<<16) -#define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1) -/* w1 tag available flag */ -#define CP_RX_TAGC (1<<17) -/* w1 bits 0...15 : VLAN tag */ -#define CP_TX_VLAN_TAG_MASK ((1<<16) - 1) -/* w2 low 32bit of Rx buffer ptr */ -/* w3 high 32bit of Rx buffer ptr */ - -/* set after transmission */ -/* FIFO underrun flag */ -#define CP_TX_STATUS_UNF (1<<25) -/* transmit error summary flag, valid if set any of three below */ -#define CP_TX_STATUS_TES (1<<23) -/* out-of-window collision flag */ -#define CP_TX_STATUS_OWC (1<<22) -/* link failure flag */ -#define CP_TX_STATUS_LNKF (1<<21) -/* excessive collisions flag */ -#define CP_TX_STATUS_EXC (1<<20) - - if (!(txdw0 & CP_TX_OWN)) - { - DEBUG_PRINT(("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor)); - return 0 ; - } - - DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor)); - - if (txdw0 & CP_TX_FS) - { - DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is first segment descriptor\n", descriptor)); - - /* reset internal buffer offset */ - s->cplus_txbuffer_offset = 0; - } - - int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK; - target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI); - - /* make sure we have enough space to assemble the packet */ - if (!s->cplus_txbuffer) - { - s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE; - s->cplus_txbuffer = malloc(s->cplus_txbuffer_len); - s->cplus_txbuffer_offset = 0; - - DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len)); - } - - while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) - { - s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE; - s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len); - - DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len)); - } - - if (!s->cplus_txbuffer) - { - /* out of memory */ - - DEBUG_PRINT(("RTL8139: +++ C+ mode transmiter failed to reallocate %d bytes\n", s->cplus_txbuffer_len)); - - /* update tally counter */ - ++s->tally_counters.TxERR; - ++s->tally_counters.TxAbt; - - return 0; - } - - /* append more data to the packet */ - - DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at %016" PRIx64 " to offset %d\n", - txsize, (uint64_t)tx_addr, s->cplus_txbuffer_offset)); - - cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize); - s->cplus_txbuffer_offset += txsize; - - /* seek to next Rx descriptor */ - if (txdw0 & CP_TX_EOR) - { - s->currCPlusTxDesc = 0; - } - else - { - ++s->currCPlusTxDesc; - if (s->currCPlusTxDesc >= 64) - s->currCPlusTxDesc = 0; - } - - /* transfer ownership to target */ - txdw0 &= ~CP_RX_OWN; - - /* reset error indicator bits */ - txdw0 &= ~CP_TX_STATUS_UNF; - txdw0 &= ~CP_TX_STATUS_TES; - txdw0 &= ~CP_TX_STATUS_OWC; - txdw0 &= ~CP_TX_STATUS_LNKF; - txdw0 &= ~CP_TX_STATUS_EXC; - - /* update ring data */ - val = cpu_to_le32(txdw0); - cpu_physical_memory_write(cplus_tx_ring_desc, (uint8_t *)&val, 4); -// val = cpu_to_le32(txdw1); -// cpu_physical_memory_write(cplus_tx_ring_desc+4, &val, 4); - - /* Now decide if descriptor being processed is holding the last segment of packet */ - if (txdw0 & CP_TX_LS) - { - DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is last segment descriptor\n", descriptor)); - - /* can transfer fully assembled packet */ - - uint8_t *saved_buffer = s->cplus_txbuffer; - int saved_size = s->cplus_txbuffer_offset; - int saved_buffer_len = s->cplus_txbuffer_len; - - /* reset the card space to protect from recursive call */ - s->cplus_txbuffer = NULL; - s->cplus_txbuffer_offset = 0; - s->cplus_txbuffer_len = 0; - - if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN)) - { - DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n")); - - #define ETH_P_IP 0x0800 /* Internet Protocol packet */ - #define ETH_HLEN 14 - #define ETH_MTU 1500 - - /* ip packet header */ - ip_header *ip = 0; - int hlen = 0; - uint8_t ip_protocol = 0; - uint16_t ip_data_len = 0; - - uint8_t *eth_payload_data = 0; - size_t eth_payload_len = 0; - - int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12)); - if (proto == ETH_P_IP) - { - DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n")); - - /* not aligned */ - eth_payload_data = saved_buffer + ETH_HLEN; - eth_payload_len = saved_size - ETH_HLEN; - - ip = (ip_header*)eth_payload_data; - - if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) { - DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", IP_HEADER_VERSION(ip), IP_HEADER_VERSION_4)); - ip = NULL; - } else { - hlen = IP_HEADER_LENGTH(ip); - ip_protocol = ip->ip_p; - ip_data_len = be16_to_cpu(ip->ip_len) - hlen; - } - } - - if (ip) - { - if (txdw0 & CP_TX_IPCS) - { - DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n")); - - if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */ - /* bad packet header len */ - /* or packet too short */ - } - else - { - ip->ip_sum = 0; - ip->ip_sum = ip_checksum(ip, hlen); - DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); - } - } - - if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP) - { -#if defined (DEBUG_RTL8139) - int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK; -#endif - DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task TSO MTU=%d IP data %d frame data %d specified MSS=%d\n", - ETH_MTU, ip_data_len, saved_size - ETH_HLEN, large_send_mss)); - - int tcp_send_offset = 0; - int send_count = 0; - - /* maximum IP header length is 60 bytes */ - uint8_t saved_ip_header[60]; - - /* save IP header template; data area is used in tcp checksum calculation */ - memcpy(saved_ip_header, eth_payload_data, hlen); - - /* a placeholder for checksum calculation routine in tcp case */ - uint8_t *data_to_checksum = eth_payload_data + hlen - 12; - // size_t data_to_checksum_len = eth_payload_len - hlen + 12; - - /* pointer to TCP header */ - tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen); - - int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr); - - /* ETH_MTU = ip header len + tcp header len + payload */ - int tcp_data_len = ip_data_len - tcp_hlen; - int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen; - - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP data len %d TCP hlen %d TCP data len %d TCP chunk size %d\n", - ip_data_len, tcp_hlen, tcp_data_len, tcp_chunk_size)); - - /* note the cycle below overwrites IP header data, - but restores it from saved_ip_header before sending packet */ - - int is_last_frame = 0; - - for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size) - { - uint16_t chunk_size = tcp_chunk_size; - - /* check if this is the last frame */ - if (tcp_send_offset + tcp_chunk_size >= tcp_data_len) - { - is_last_frame = 1; - chunk_size = tcp_data_len - tcp_send_offset; - } - - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq))); - - /* add 4 TCP pseudoheader fields */ - /* copy IP source and destination fields */ - memcpy(data_to_checksum, saved_ip_header + 12, 8); - - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size)); - - if (tcp_send_offset) - { - memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size); - } - - /* keep PUSH and FIN flags only for the last frame */ - if (!is_last_frame) - { - TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN); - } - - /* recalculate TCP checksum */ - ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; - p_tcpip_hdr->zeros = 0; - p_tcpip_hdr->ip_proto = IP_PROTO_TCP; - p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size); - - p_tcp_hdr->th_sum = 0; - - int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12); - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum)); - - p_tcp_hdr->th_sum = tcp_checksum; - - /* restore IP header */ - memcpy(eth_payload_data, saved_ip_header, hlen); - - /* set IP data length and recalculate IP checksum */ - ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size); - - /* increment IP id for subsequent frames */ - ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id)); - - ip->ip_sum = 0; - ip->ip_sum = ip_checksum(eth_payload_data, hlen); - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP header len=%d checksum=%04x\n", hlen, ip->ip_sum)); - - int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size; - DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size)); - rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0); - - /* add transferred count to TCP sequence number */ - p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq)); - ++send_count; - } - - /* Stop sending this frame */ - saved_size = 0; - } - else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS)) - { - DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n")); - - /* maximum IP header length is 60 bytes */ - uint8_t saved_ip_header[60]; - memcpy(saved_ip_header, eth_payload_data, hlen); - - uint8_t *data_to_checksum = eth_payload_data + hlen - 12; - // size_t data_to_checksum_len = eth_payload_len - hlen + 12; - - /* add 4 TCP pseudoheader fields */ - /* copy IP source and destination fields */ - memcpy(data_to_checksum, saved_ip_header + 12, 8); - - if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP) - { - DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len)); - - ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum; - p_tcpip_hdr->zeros = 0; - p_tcpip_hdr->ip_proto = IP_PROTO_TCP; - p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len); - - tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12); - - p_tcp_hdr->th_sum = 0; - - int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); - DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum)); - - p_tcp_hdr->th_sum = tcp_checksum; - } - else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP) - { - DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len)); - - ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum; - p_udpip_hdr->zeros = 0; - p_udpip_hdr->ip_proto = IP_PROTO_UDP; - p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len); - - udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12); - - p_udp_hdr->uh_sum = 0; - - int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12); - DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum)); - - p_udp_hdr->uh_sum = udp_checksum; - } - - /* restore IP header */ - memcpy(eth_payload_data, saved_ip_header, hlen); - } - } - } - - /* update tally counter */ - ++s->tally_counters.TxOk; - - DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size)); - - rtl8139_transfer_frame(s, saved_buffer, saved_size, 1); - - /* restore card space if there was no recursion and reset offset */ - if (!s->cplus_txbuffer) - { - s->cplus_txbuffer = saved_buffer; - s->cplus_txbuffer_len = saved_buffer_len; - s->cplus_txbuffer_offset = 0; - } - else - { - free(saved_buffer); - } - } - else - { - DEBUG_PRINT(("RTL8139: +++ C+ mode transmission continue to next descriptor\n")); - } - - return 1; -} - -static void rtl8139_cplus_transmit(RTL8139State *s) -{ - int txcount = 0; - - while (rtl8139_cplus_transmit_one(s)) - { - ++txcount; - } - - /* Mark transfer completed */ - if (!txcount) - { - DEBUG_PRINT(("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n", - s->currCPlusTxDesc)); - } - else - { - /* update interrupt status */ - s->IntrStatus |= TxOK; - rtl8139_update_irq(s); - } -} - -static void rtl8139_transmit(RTL8139State *s) -{ - int descriptor = s->currTxDesc, txcount = 0; - - /*while*/ - if (rtl8139_transmit_one(s, descriptor)) - { - ++s->currTxDesc; - s->currTxDesc %= 4; - ++txcount; - } - - /* Mark transfer completed */ - if (!txcount) - { - DEBUG_PRINT(("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc)); - } -} - -static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32_t val) -{ - - int descriptor = txRegOffset/4; - - /* handle C+ transmit mode register configuration */ - - if (rtl8139_cp_transmitter_enabled(s)) - { - DEBUG_PRINT(("RTL8139C+ DTCCR write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); - - /* handle Dump Tally Counters command */ - s->TxStatus[descriptor] = val; - - if (descriptor == 0 && (val & 0x8)) - { - target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]); - - /* dump tally counters to specified memory location */ - RTL8139TallyCounters_physical_memory_write( tc_addr, &s->tally_counters); - - /* mark dump completed */ - s->TxStatus[0] &= ~0x8; - } - - return; - } - - DEBUG_PRINT(("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor)); - - /* mask only reserved bits */ - val &= ~0xff00c000; /* these bits are reset on write */ - val = SET_MASKED(val, 0x00c00000, s->TxStatus[descriptor]); - - s->TxStatus[descriptor] = val; - - /* attempt to start transmission */ - rtl8139_transmit(s); -} - -static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint32_t txRegOffset) -{ - uint32_t ret = s->TxStatus[txRegOffset/4]; - - DEBUG_PRINT(("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret)); - - return ret; -} - -static uint16_t rtl8139_TSAD_read(RTL8139State *s) -{ - uint16_t ret = 0; - - /* Simulate TSAD, it is read only anyway */ - - ret = ((s->TxStatus[3] & TxStatOK )?TSAD_TOK3:0) - |((s->TxStatus[2] & TxStatOK )?TSAD_TOK2:0) - |((s->TxStatus[1] & TxStatOK )?TSAD_TOK1:0) - |((s->TxStatus[0] & TxStatOK )?TSAD_TOK0:0) - - |((s->TxStatus[3] & TxUnderrun)?TSAD_TUN3:0) - |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0) - |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0) - |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0) - - |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0) - |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0) - |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0) - |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0) - - |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0) - |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0) - |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0) - |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ; - - - DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret)); - - return ret; -} - -static uint16_t rtl8139_CSCR_read(RTL8139State *s) -{ - uint16_t ret = s->CSCR; - - DEBUG_PRINT(("RTL8139: CSCR read val=0x%04x\n", ret)); - - return ret; -} - -static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val) -{ - DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val)); - - s->TxAddr[txAddrOffset/4] = le32_to_cpu(val); -} - -static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset) -{ - uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]); - - DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret)); - - return ret; -} - -static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val) -{ - DEBUG_PRINT(("RTL8139: RxBufPtr write val=0x%04x\n", val)); - - /* this value is off by 16 */ - s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize); - - DEBUG_PRINT((" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n", - s->RxBufferSize, s->RxBufAddr, s->RxBufPtr)); -} - -static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s) -{ - /* this value is off by 16 */ - uint32_t ret = s->RxBufPtr - 0x10; - - DEBUG_PRINT(("RTL8139: RxBufPtr read val=0x%04x\n", ret)); - - return ret; -} - -static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s) -{ - /* this value is NOT off by 16 */ - uint32_t ret = s->RxBufAddr; - - DEBUG_PRINT(("RTL8139: RxBufAddr read val=0x%04x\n", ret)); - - return ret; -} - -static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val) -{ - DEBUG_PRINT(("RTL8139: RxBuf write val=0x%08x\n", val)); - - s->RxBuf = val; - - /* may need to reset rxring here */ -} - -static uint32_t rtl8139_RxBuf_read(RTL8139State *s) -{ - uint32_t ret = s->RxBuf; - - DEBUG_PRINT(("RTL8139: RxBuf read val=0x%08x\n", ret)); - - return ret; -} - -static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val) -{ - DEBUG_PRINT(("RTL8139: IntrMask write(w) val=0x%04x\n", val)); - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0x1e00, s->IntrMask); - - s->IntrMask = val; - - rtl8139_update_irq(s); -} - -static uint32_t rtl8139_IntrMask_read(RTL8139State *s) -{ - uint32_t ret = s->IntrMask; - - DEBUG_PRINT(("RTL8139: IntrMask read(w) val=0x%04x\n", ret)); - - return ret; -} - -static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val) -{ - DEBUG_PRINT(("RTL8139: IntrStatus write(w) val=0x%04x\n", val)); - -#if 0 - - /* writing to ISR has no effect */ - - return; - -#else - uint16_t newStatus = s->IntrStatus & ~val; - - /* mask unwriteable bits */ - newStatus = SET_MASKED(newStatus, 0x1e00, s->IntrStatus); - - /* writing 1 to interrupt status register bit clears it */ - s->IntrStatus = 0; - rtl8139_update_irq(s); - - s->IntrStatus = newStatus; - rtl8139_update_irq(s); -#endif -} - -static uint32_t rtl8139_IntrStatus_read(RTL8139State *s) -{ - uint32_t ret = s->IntrStatus; - - DEBUG_PRINT(("RTL8139: IntrStatus read(w) val=0x%04x\n", ret)); - -#if 0 - - /* reading ISR clears all interrupts */ - s->IntrStatus = 0; - - rtl8139_update_irq(s); - -#endif - - return ret; -} - -static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val) -{ - DEBUG_PRINT(("RTL8139: MultiIntr write(w) val=0x%04x\n", val)); - - /* mask unwriteable bits */ - val = SET_MASKED(val, 0xf000, s->MultiIntr); - - s->MultiIntr = val; -} - -static uint32_t rtl8139_MultiIntr_read(RTL8139State *s) -{ - uint32_t ret = s->MultiIntr; - - DEBUG_PRINT(("RTL8139: MultiIntr read(w) val=0x%04x\n", ret)); - - return ret; -} - -static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val) -{ - RTL8139State *s = opaque; - - addr &= 0xff; - - switch (addr) - { - case MAC0 ... MAC0+5: - s->phys[addr - MAC0] = val; - break; - case MAC0+6 ... MAC0+7: - /* reserved */ - break; - case MAR0 ... MAR0+7: - s->mult[addr - MAR0] = val; - break; - case ChipCmd: - rtl8139_ChipCmd_write(s, val); - break; - case Cfg9346: - rtl8139_Cfg9346_write(s, val); - break; - case TxConfig: /* windows driver sometimes writes using byte-lenth call */ - rtl8139_TxConfig_writeb(s, val); - break; - case Config0: - rtl8139_Config0_write(s, val); - break; - case Config1: - rtl8139_Config1_write(s, val); - break; - case Config3: - rtl8139_Config3_write(s, val); - break; - case Config4: - rtl8139_Config4_write(s, val); - break; - case Config5: - rtl8139_Config5_write(s, val); - break; - case MediaStatus: - /* ignore */ - DEBUG_PRINT(("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val)); - break; - - case HltClk: - DEBUG_PRINT(("RTL8139: HltClk write val=0x%08x\n", val)); - if (val == 'R') - { - s->clock_enabled = 1; - } - else if (val == 'H') - { - s->clock_enabled = 0; - } - break; - - case TxThresh: - DEBUG_PRINT(("RTL8139C+ TxThresh write(b) val=0x%02x\n", val)); - s->TxThresh = val; - break; - - case TxPoll: - DEBUG_PRINT(("RTL8139C+ TxPoll write(b) val=0x%02x\n", val)); - if (val & (1 << 7)) - { - DEBUG_PRINT(("RTL8139C+ TxPoll high priority transmission (not implemented)\n")); - //rtl8139_cplus_transmit(s); - } - if (val & (1 << 6)) - { - DEBUG_PRINT(("RTL8139C+ TxPoll normal priority transmission\n")); - rtl8139_cplus_transmit(s); - } - - break; - - default: - DEBUG_PRINT(("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val)); - break; - } -} - -static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val) -{ - RTL8139State *s = opaque; - - addr &= 0xfe; - - switch (addr) - { - case IntrMask: - rtl8139_IntrMask_write(s, val); - break; - - case IntrStatus: - rtl8139_IntrStatus_write(s, val); - break; - - case MultiIntr: - rtl8139_MultiIntr_write(s, val); - break; - - case RxBufPtr: - rtl8139_RxBufPtr_write(s, val); - break; - - case BasicModeCtrl: - rtl8139_BasicModeCtrl_write(s, val); - break; - case BasicModeStatus: - rtl8139_BasicModeStatus_write(s, val); - break; - case NWayAdvert: - DEBUG_PRINT(("RTL8139: NWayAdvert write(w) val=0x%04x\n", val)); - s->NWayAdvert = val; - break; - case NWayLPAR: - DEBUG_PRINT(("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val)); - break; - case NWayExpansion: - DEBUG_PRINT(("RTL8139: NWayExpansion write(w) val=0x%04x\n", val)); - s->NWayExpansion = val; - break; - - case CpCmd: - rtl8139_CpCmd_write(s, val); - break; - - case IntrMitigate: - rtl8139_IntrMitigate_write(s, val); - break; - - default: - DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val)); - -#ifdef TARGET_WORDS_BIGENDIAN - rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff); - rtl8139_io_writeb(opaque, addr + 1, val & 0xff); -#else - rtl8139_io_writeb(opaque, addr, val & 0xff); - rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif - break; - } -} - -static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val) -{ - RTL8139State *s = opaque; - - addr &= 0xfc; - - switch (addr) - { - case RxMissed: - DEBUG_PRINT(("RTL8139: RxMissed clearing on write\n")); - s->RxMissed = 0; - break; - - case TxConfig: - rtl8139_TxConfig_write(s, val); - break; - - case RxConfig: - rtl8139_RxConfig_write(s, val); - break; - - case TxStatus0 ... TxStatus0+4*4-1: - rtl8139_TxStatus_write(s, addr-TxStatus0, val); - break; - - case TxAddr0 ... TxAddr0+4*4-1: - rtl8139_TxAddr_write(s, addr-TxAddr0, val); - break; - - case RxBuf: - rtl8139_RxBuf_write(s, val); - break; - - case RxRingAddrLO: - DEBUG_PRINT(("RTL8139: C+ RxRing low bits write val=0x%08x\n", val)); - s->RxRingAddrLO = val; - break; - - case RxRingAddrHI: - DEBUG_PRINT(("RTL8139: C+ RxRing high bits write val=0x%08x\n", val)); - s->RxRingAddrHI = val; - break; - - case Timer: - DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n")); - s->TCTR = 0; - s->TCTR_base = qemu_get_clock(vm_clock); - break; - - case FlashReg: - DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", val)); - s->TimerInt = val; - break; - - default: - DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val)); -#ifdef TARGET_WORDS_BIGENDIAN - rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff); - rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff); - rtl8139_io_writeb(opaque, addr + 2, (val >> 8) & 0xff); - rtl8139_io_writeb(opaque, addr + 3, val & 0xff); -#else - rtl8139_io_writeb(opaque, addr, val & 0xff); - rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff); - rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff); - rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif - break; - } -} - -static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr) -{ - RTL8139State *s = opaque; - int ret; - - addr &= 0xff; - - switch (addr) - { - case MAC0 ... MAC0+5: - ret = s->phys[addr - MAC0]; - break; - case MAC0+6 ... MAC0+7: - ret = 0; - break; - case MAR0 ... MAR0+7: - ret = s->mult[addr - MAR0]; - break; - case ChipCmd: - ret = rtl8139_ChipCmd_read(s); - break; - case Cfg9346: - ret = rtl8139_Cfg9346_read(s); - break; - case Config0: - ret = rtl8139_Config0_read(s); - break; - case Config1: - ret = rtl8139_Config1_read(s); - break; - case Config3: - ret = rtl8139_Config3_read(s); - break; - case Config4: - ret = rtl8139_Config4_read(s); - break; - case Config5: - ret = rtl8139_Config5_read(s); - break; - - case MediaStatus: - ret = 0xd0; - DEBUG_PRINT(("RTL8139: MediaStatus read 0x%x\n", ret)); - break; - - case HltClk: - ret = s->clock_enabled; - DEBUG_PRINT(("RTL8139: HltClk read 0x%x\n", ret)); - break; - - case PCIRevisionID: - ret = RTL8139_PCI_REVID; - DEBUG_PRINT(("RTL8139: PCI Revision ID read 0x%x\n", ret)); - break; - - case TxThresh: - ret = s->TxThresh; - DEBUG_PRINT(("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret)); - break; - - case 0x43: /* Part of TxConfig register. Windows driver tries to read it */ - ret = s->TxConfig >> 24; - DEBUG_PRINT(("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret)); - break; - - default: - DEBUG_PRINT(("RTL8139: not implemented read(b) addr=0x%x\n", addr)); - ret = 0; - break; - } - - return ret; -} - -static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr) -{ - RTL8139State *s = opaque; - uint32_t ret; - - addr &= 0xfe; /* mask lower bit */ - - switch (addr) - { - case IntrMask: - ret = rtl8139_IntrMask_read(s); - break; - - case IntrStatus: - ret = rtl8139_IntrStatus_read(s); - break; - - case MultiIntr: - ret = rtl8139_MultiIntr_read(s); - break; - - case RxBufPtr: - ret = rtl8139_RxBufPtr_read(s); - break; - - case RxBufAddr: - ret = rtl8139_RxBufAddr_read(s); - break; - - case BasicModeCtrl: - ret = rtl8139_BasicModeCtrl_read(s); - break; - case BasicModeStatus: - ret = rtl8139_BasicModeStatus_read(s); - break; - case NWayAdvert: - ret = s->NWayAdvert; - DEBUG_PRINT(("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret)); - break; - case NWayLPAR: - ret = s->NWayLPAR; - DEBUG_PRINT(("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret)); - break; - case NWayExpansion: - ret = s->NWayExpansion; - DEBUG_PRINT(("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret)); - break; - - case CpCmd: - ret = rtl8139_CpCmd_read(s); - break; - - case IntrMitigate: - ret = rtl8139_IntrMitigate_read(s); - break; - - case TxSummary: - ret = rtl8139_TSAD_read(s); - break; - - case CSCR: - ret = rtl8139_CSCR_read(s); - break; - - default: - DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr)); - -#ifdef TARGET_WORDS_BIGENDIAN - ret = rtl8139_io_readb(opaque, addr) << 8; - ret |= rtl8139_io_readb(opaque, addr + 1); -#else - ret = rtl8139_io_readb(opaque, addr); - ret |= rtl8139_io_readb(opaque, addr + 1) << 8; -#endif - - DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret)); - break; - } - - return ret; -} - -static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr) -{ - RTL8139State *s = opaque; - uint32_t ret; - - addr &= 0xfc; /* also mask low 2 bits */ - - switch (addr) - { - case RxMissed: - ret = s->RxMissed; - - DEBUG_PRINT(("RTL8139: RxMissed read val=0x%08x\n", ret)); - break; - - case TxConfig: - ret = rtl8139_TxConfig_read(s); - break; - - case RxConfig: - ret = rtl8139_RxConfig_read(s); - break; - - case TxStatus0 ... TxStatus0+4*4-1: - ret = rtl8139_TxStatus_read(s, addr-TxStatus0); - break; - - case TxAddr0 ... TxAddr0+4*4-1: - ret = rtl8139_TxAddr_read(s, addr-TxAddr0); - break; - - case RxBuf: - ret = rtl8139_RxBuf_read(s); - break; - - case RxRingAddrLO: - ret = s->RxRingAddrLO; - DEBUG_PRINT(("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret)); - break; - - case RxRingAddrHI: - ret = s->RxRingAddrHI; - DEBUG_PRINT(("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret)); - break; - - case Timer: - ret = s->TCTR; - DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret)); - break; - - case FlashReg: - ret = s->TimerInt; - DEBUG_PRINT(("RTL8139: FlashReg TimerInt read val=0x%08x\n", ret)); - break; - - default: - DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr)); - -#ifdef TARGET_WORDS_BIGENDIAN - ret = rtl8139_io_readb(opaque, addr) << 24; - ret |= rtl8139_io_readb(opaque, addr + 1) << 16; - ret |= rtl8139_io_readb(opaque, addr + 2) << 8; - ret |= rtl8139_io_readb(opaque, addr + 3); -#else - ret = rtl8139_io_readb(opaque, addr); - ret |= rtl8139_io_readb(opaque, addr + 1) << 8; - ret |= rtl8139_io_readb(opaque, addr + 2) << 16; - ret |= rtl8139_io_readb(opaque, addr + 3) << 24; -#endif - - DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret)); - break; - } - - return ret; -} - -/* */ - -static void rtl8139_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - rtl8139_io_writeb(opaque, addr & 0xFF, val); -} - -static void rtl8139_ioport_writew(void *opaque, uint32_t addr, uint32_t val) -{ - rtl8139_io_writew(opaque, addr & 0xFF, val); -} - -static void rtl8139_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - rtl8139_io_writel(opaque, addr & 0xFF, val); -} - -static uint32_t rtl8139_ioport_readb(void *opaque, uint32_t addr) -{ - return rtl8139_io_readb(opaque, addr & 0xFF); -} - -static uint32_t rtl8139_ioport_readw(void *opaque, uint32_t addr) -{ - return rtl8139_io_readw(opaque, addr & 0xFF); -} - -static uint32_t rtl8139_ioport_readl(void *opaque, uint32_t addr) -{ - return rtl8139_io_readl(opaque, addr & 0xFF); -} - -/* */ - -static void rtl8139_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - rtl8139_io_writeb(opaque, addr & 0xFF, val); -} - -static void rtl8139_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - rtl8139_io_writew(opaque, addr & 0xFF, val); -} - -static void rtl8139_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - rtl8139_io_writel(opaque, addr & 0xFF, val); -} - -static uint32_t rtl8139_mmio_readb(void *opaque, target_phys_addr_t addr) -{ - return rtl8139_io_readb(opaque, addr & 0xFF); -} - -static uint32_t rtl8139_mmio_readw(void *opaque, target_phys_addr_t addr) -{ - return rtl8139_io_readw(opaque, addr & 0xFF); -} - -static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr) -{ - return rtl8139_io_readl(opaque, addr & 0xFF); -} - -/* */ - -static void rtl8139_save(QEMUFile* f,void* opaque) -{ - RTL8139State* s=(RTL8139State*)opaque; - int i; - - qemu_put_buffer(f, s->phys, 6); - qemu_put_buffer(f, s->mult, 8); - - for (i=0; i<4; ++i) - { - qemu_put_be32s(f, &s->TxStatus[i]); /* TxStatus0 */ - } - for (i=0; i<4; ++i) - { - qemu_put_be32s(f, &s->TxAddr[i]); /* TxAddr0 */ - } - - qemu_put_be32s(f, &s->RxBuf); /* Receive buffer */ - qemu_put_be32s(f, &s->RxBufferSize);/* internal variable, receive ring buffer size in C mode */ - qemu_put_be32s(f, &s->RxBufPtr); - qemu_put_be32s(f, &s->RxBufAddr); - - qemu_put_be16s(f, &s->IntrStatus); - qemu_put_be16s(f, &s->IntrMask); - - qemu_put_be32s(f, &s->TxConfig); - qemu_put_be32s(f, &s->RxConfig); - qemu_put_be32s(f, &s->RxMissed); - qemu_put_be16s(f, &s->CSCR); - - qemu_put_8s(f, &s->Cfg9346); - qemu_put_8s(f, &s->Config0); - qemu_put_8s(f, &s->Config1); - qemu_put_8s(f, &s->Config3); - qemu_put_8s(f, &s->Config4); - qemu_put_8s(f, &s->Config5); - - qemu_put_8s(f, &s->clock_enabled); - qemu_put_8s(f, &s->bChipCmdState); - - qemu_put_be16s(f, &s->MultiIntr); - - qemu_put_be16s(f, &s->BasicModeCtrl); - qemu_put_be16s(f, &s->BasicModeStatus); - qemu_put_be16s(f, &s->NWayAdvert); - qemu_put_be16s(f, &s->NWayLPAR); - qemu_put_be16s(f, &s->NWayExpansion); - - qemu_put_be16s(f, &s->CpCmd); - qemu_put_8s(f, &s->TxThresh); - - qemu_put_be32s(f, &s->irq); - qemu_put_buffer(f, s->macaddr, 6); - qemu_put_be32s(f, &s->rtl8139_mmio_io_addr); - - qemu_put_be32s(f, &s->currTxDesc); - qemu_put_be32s(f, &s->currCPlusRxDesc); - qemu_put_be32s(f, &s->currCPlusTxDesc); - qemu_put_be32s(f, &s->RxRingAddrLO); - qemu_put_be32s(f, &s->RxRingAddrHI); - - for (i=0; i<EEPROM_9346_SIZE; ++i) - { - qemu_put_be16s(f, &s->eeprom.contents[i]); - } - qemu_put_be32s(f, &s->eeprom.mode); - qemu_put_be32s(f, &s->eeprom.tick); - qemu_put_8s(f, &s->eeprom.address); - qemu_put_be16s(f, &s->eeprom.input); - qemu_put_be16s(f, &s->eeprom.output); - - qemu_put_8s(f, &s->eeprom.eecs); - qemu_put_8s(f, &s->eeprom.eesk); - qemu_put_8s(f, &s->eeprom.eedi); - qemu_put_8s(f, &s->eeprom.eedo); - - qemu_put_be32s(f, &s->TCTR); - qemu_put_be32s(f, &s->TimerInt); - qemu_put_be64s(f, &s->TCTR_base); - - RTL8139TallyCounters_save(f, &s->tally_counters); -} - -static int rtl8139_load(QEMUFile* f,void* opaque,int version_id) -{ - RTL8139State* s=(RTL8139State*)opaque; - int i; - - /* just 2 versions for now */ - if (version_id > 2) - return -EINVAL; - - /* saved since version 1 */ - qemu_get_buffer(f, s->phys, 6); - qemu_get_buffer(f, s->mult, 8); - - for (i=0; i<4; ++i) - { - qemu_get_be32s(f, &s->TxStatus[i]); /* TxStatus0 */ - } - for (i=0; i<4; ++i) - { - qemu_get_be32s(f, &s->TxAddr[i]); /* TxAddr0 */ - } - - qemu_get_be32s(f, &s->RxBuf); /* Receive buffer */ - qemu_get_be32s(f, &s->RxBufferSize);/* internal variable, receive ring buffer size in C mode */ - qemu_get_be32s(f, &s->RxBufPtr); - qemu_get_be32s(f, &s->RxBufAddr); - - qemu_get_be16s(f, &s->IntrStatus); - qemu_get_be16s(f, &s->IntrMask); - - qemu_get_be32s(f, &s->TxConfig); - qemu_get_be32s(f, &s->RxConfig); - qemu_get_be32s(f, &s->RxMissed); - qemu_get_be16s(f, &s->CSCR); - - qemu_get_8s(f, &s->Cfg9346); - qemu_get_8s(f, &s->Config0); - qemu_get_8s(f, &s->Config1); - qemu_get_8s(f, &s->Config3); - qemu_get_8s(f, &s->Config4); - qemu_get_8s(f, &s->Config5); - - qemu_get_8s(f, &s->clock_enabled); - qemu_get_8s(f, &s->bChipCmdState); - - qemu_get_be16s(f, &s->MultiIntr); - - qemu_get_be16s(f, &s->BasicModeCtrl); - qemu_get_be16s(f, &s->BasicModeStatus); - qemu_get_be16s(f, &s->NWayAdvert); - qemu_get_be16s(f, &s->NWayLPAR); - qemu_get_be16s(f, &s->NWayExpansion); - - qemu_get_be16s(f, &s->CpCmd); - qemu_get_8s(f, &s->TxThresh); - - qemu_get_be32s(f, &s->irq); - qemu_get_buffer(f, s->macaddr, 6); - qemu_get_be32s(f, &s->rtl8139_mmio_io_addr); - - qemu_get_be32s(f, &s->currTxDesc); - qemu_get_be32s(f, &s->currCPlusRxDesc); - qemu_get_be32s(f, &s->currCPlusTxDesc); - qemu_get_be32s(f, &s->RxRingAddrLO); - qemu_get_be32s(f, &s->RxRingAddrHI); - - for (i=0; i<EEPROM_9346_SIZE; ++i) - { - qemu_get_be16s(f, &s->eeprom.contents[i]); - } - qemu_get_be32s(f, &s->eeprom.mode); - qemu_get_be32s(f, &s->eeprom.tick); - qemu_get_8s(f, &s->eeprom.address); - qemu_get_be16s(f, &s->eeprom.input); - qemu_get_be16s(f, &s->eeprom.output); - - qemu_get_8s(f, &s->eeprom.eecs); - qemu_get_8s(f, &s->eeprom.eesk); - qemu_get_8s(f, &s->eeprom.eedi); - qemu_get_8s(f, &s->eeprom.eedo); - - /* saved since version 2 */ - if (version_id >= 2) - { - qemu_get_be32s(f, &s->TCTR); - qemu_get_be32s(f, &s->TimerInt); - qemu_get_be64s(f, &s->TCTR_base); - - RTL8139TallyCounters_load(f, &s->tally_counters); - } - else - { - /* not saved, use default */ - s->TCTR = 0; - s->TimerInt = 0; - s->TCTR_base = 0; - - RTL8139TallyCounters_clear(&s->tally_counters); - } - - return 0; -} - -/***********************************************************/ -/* PCI RTL8139 definitions */ - -typedef struct PCIRTL8139State { - PCIDevice dev; - RTL8139State rtl8139; -} PCIRTL8139State; - -static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - PCIRTL8139State *d = (PCIRTL8139State *)pci_dev; - RTL8139State *s = &d->rtl8139; - - cpu_register_physical_memory(addr + 0, 0x100, s->rtl8139_mmio_io_addr); -} - -static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - PCIRTL8139State *d = (PCIRTL8139State *)pci_dev; - RTL8139State *s = &d->rtl8139; - - register_ioport_write(addr, 0x100, 1, rtl8139_ioport_writeb, s); - register_ioport_read( addr, 0x100, 1, rtl8139_ioport_readb, s); - - register_ioport_write(addr, 0x100, 2, rtl8139_ioport_writew, s); - register_ioport_read( addr, 0x100, 2, rtl8139_ioport_readw, s); - - register_ioport_write(addr, 0x100, 4, rtl8139_ioport_writel, s); - register_ioport_read( addr, 0x100, 4, rtl8139_ioport_readl, s); -} - -static CPUReadMemoryFunc *rtl8139_mmio_read[3] = { - rtl8139_mmio_readb, - rtl8139_mmio_readw, - rtl8139_mmio_readl, -}; - -static CPUWriteMemoryFunc *rtl8139_mmio_write[3] = { - rtl8139_mmio_writeb, - rtl8139_mmio_writew, - rtl8139_mmio_writel, -}; - -static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t current_time) -{ - int64_t next_time = current_time + - muldiv64(1, ticks_per_sec, PCI_FREQUENCY); - if (next_time <= current_time) - next_time = current_time + 1; - return next_time; -} - -#if RTL8139_ONBOARD_TIMER -static void rtl8139_timer(void *opaque) -{ - RTL8139State *s = opaque; - - int is_timeout = 0; - - int64_t curr_time; - uint32_t curr_tick; - - if (!s->clock_enabled) - { - DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n")); - return; - } - - curr_time = qemu_get_clock(vm_clock); - - curr_tick = muldiv64(curr_time - s->TCTR_base, PCI_FREQUENCY, ticks_per_sec); - - if (s->TimerInt && curr_tick >= s->TimerInt) - { - if (s->TCTR < s->TimerInt || curr_tick < s->TCTR) - { - is_timeout = 1; - } - } - - s->TCTR = curr_tick; - -// DEBUG_PRINT(("RTL8139: >>> timer: tick=%08u\n", s->TCTR)); - - if (is_timeout) - { - DEBUG_PRINT(("RTL8139: >>> timer: timeout tick=%08u\n", s->TCTR)); - s->IntrStatus |= PCSTimeout; - rtl8139_update_irq(s); - } - - qemu_mod_timer(s->timer, - rtl8139_get_next_tctr_time(s,curr_time)); -} -#endif /* RTL8139_ONBOARD_TIMER */ - -void pci_rtl8139_init(PCIBus *bus, NICInfo *nd) -{ - PCIRTL8139State *d; - RTL8139State *s; - uint8_t *pci_conf; - - d = (PCIRTL8139State *)pci_register_device(bus, - "RTL8139", sizeof(PCIRTL8139State), - -1, - NULL, NULL); - pci_conf = d->dev.config; - pci_conf[0x00] = 0xec; /* Realtek 8139 */ - pci_conf[0x01] = 0x10; - pci_conf[0x02] = 0x39; - pci_conf[0x03] = 0x81; - pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */ - pci_conf[0x08] = RTL8139_PCI_REVID; /* PCI revision ID; >=0x20 is for 8139C+ */ - pci_conf[0x0a] = 0x00; /* ethernet network controller */ - pci_conf[0x0b] = 0x02; - pci_conf[0x0e] = 0x00; /* header_type */ - pci_conf[0x3d] = 1; /* interrupt pin 0 */ - pci_conf[0x34] = 0xdc; - - s = &d->rtl8139; - - /* I/O handler for memory-mapped I/O */ - s->rtl8139_mmio_io_addr = - cpu_register_io_memory(0, rtl8139_mmio_read, rtl8139_mmio_write, s); - - pci_register_io_region(&d->dev, 0, 0x100, - PCI_ADDRESS_SPACE_IO, rtl8139_ioport_map); - - pci_register_io_region(&d->dev, 1, 0x100, - PCI_ADDRESS_SPACE_MEM, rtl8139_mmio_map); - - s->irq = 16; /* PCI interrupt */ - s->pci_dev = (PCIDevice *)d; - memcpy(s->macaddr, nd->macaddr, 6); - rtl8139_reset(s); - s->vc = qemu_new_vlan_client(nd->vlan, rtl8139_receive, - rtl8139_can_receive, s); - - snprintf(s->vc->info_str, sizeof(s->vc->info_str), - "rtl8139 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - s->macaddr[0], - s->macaddr[1], - s->macaddr[2], - s->macaddr[3], - s->macaddr[4], - s->macaddr[5]); - - s->cplus_txbuffer = NULL; - s->cplus_txbuffer_len = 0; - s->cplus_txbuffer_offset = 0; - - /* XXX: instance number ? */ - register_savevm("rtl8139", 0, 2, rtl8139_save, rtl8139_load, s); - register_savevm("rtl8139_pci", 0, 1, generic_pci_save, generic_pci_load, - &d->dev); - -#if RTL8139_ONBOARD_TIMER - s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s); - - qemu_mod_timer(s->timer, - rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock))); -#endif /* RTL8139_ONBOARD_TIMER */ -} - diff --git a/hw/sb16.c b/hw/sb16.c deleted file mode 100644 index 04325ac..0000000 --- a/hw/sb16.c +++ /dev/null @@ -1,1451 +0,0 @@ -/* - * QEMU Soundblaster 16 emulation - * - * Copyright (c) 2003-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0]))) - -#define dolog(...) AUD_log ("sb16", __VA_ARGS__) - -/* #define DEBUG */ -/* #define DEBUG_SB16_MOST */ - -#ifdef DEBUG -#define ldebug(...) dolog (__VA_ARGS__) -#else -#define ldebug(...) -#endif - -#define IO_READ_PROTO(name) \ - uint32_t name (void *opaque, uint32_t nport) -#define IO_WRITE_PROTO(name) \ - void name (void *opaque, uint32_t nport, uint32_t val) - -static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; - -static struct { - int ver_lo; - int ver_hi; - int irq; - int dma; - int hdma; - int port; -} conf = {5, 4, 5, 1, 5, 0x220}; - -typedef struct SB16State { - QEMUSoundCard card; - int irq; - int dma; - int hdma; - int port; - int ver; - - int in_index; - int out_data_len; - int fmt_stereo; - int fmt_signed; - int fmt_bits; - audfmt_e fmt; - int dma_auto; - int block_size; - int fifo; - int freq; - int time_const; - int speaker; - int needed_bytes; - int cmd; - int use_hdma; - int highspeed; - int can_write; - - int v2x6; - - uint8_t csp_param; - uint8_t csp_value; - uint8_t csp_mode; - uint8_t csp_regs[256]; - uint8_t csp_index; - uint8_t csp_reg83[4]; - int csp_reg83r; - int csp_reg83w; - - uint8_t in2_data[10]; - uint8_t out_data[50]; - uint8_t test_reg; - uint8_t last_read_byte; - int nzero; - - int left_till_irq; - - int dma_running; - int bytes_per_second; - int align; - int audio_free; - SWVoiceOut *voice; - - QEMUTimer *aux_ts; - /* mixer state */ - int mixer_nreg; - uint8_t mixer_regs[256]; -} SB16State; - -static void SB_audio_callback (void *opaque, int free); - -static int magic_of_irq (int irq) -{ - switch (irq) { - case 5: - return 2; - case 7: - return 4; - case 9: - return 1; - case 10: - return 8; - default: - dolog ("bad irq %d\n", irq); - return 2; - } -} - -static int irq_of_magic (int magic) -{ - switch (magic) { - case 1: - return 9; - case 2: - return 5; - case 4: - return 7; - case 8: - return 10; - default: - dolog ("bad irq magic %d\n", magic); - return -1; - } -} - -#if 0 -static void log_dsp (SB16State *dsp) -{ - ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n", - dsp->fmt_stereo ? "Stereo" : "Mono", - dsp->fmt_signed ? "Signed" : "Unsigned", - dsp->fmt_bits, - dsp->dma_auto ? "Auto" : "Single", - dsp->block_size, - dsp->freq, - dsp->time_const, - dsp->speaker); -} -#endif - -static void speaker (SB16State *s, int on) -{ - s->speaker = on; - /* AUD_enable (s->voice, on); */ -} - -static void control (SB16State *s, int hold) -{ - int dma = s->use_hdma ? s->hdma : s->dma; - s->dma_running = hold; - - ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma); - - if (hold) { - DMA_hold_DREQ (dma); - AUD_set_active_out (s->voice, 1); - } - else { - DMA_release_DREQ (dma); - AUD_set_active_out (s->voice, 0); - } -} - -static void aux_timer (void *opaque) -{ - SB16State *s = opaque; - s->can_write = 1; - pic_set_irq (s->irq, 1); -} - -#define DMA8_AUTO 1 -#define DMA8_HIGH 2 - -static void continue_dma8 (SB16State *s) -{ - if (s->freq > 0) { - audsettings_t as; - - s->audio_free = 0; - - as.freq = s->freq; - as.nchannels = 1 << s->fmt_stereo; - as.fmt = s->fmt; - as.endianness = 0; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as - ); - } - - control (s, 1); -} - -static void dma_cmd8 (SB16State *s, int mask, int dma_len) -{ - s->fmt = AUD_FMT_U8; - s->use_hdma = 0; - s->fmt_bits = 8; - s->fmt_signed = 0; - s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0; - if (-1 == s->time_const) { - if (s->freq <= 0) - s->freq = 11025; - } - else { - int tmp = (256 - s->time_const); - s->freq = (1000000 + (tmp / 2)) / tmp; - } - - if (dma_len != -1) { - s->block_size = dma_len << s->fmt_stereo; - } - else { - /* This is apparently the only way to make both Act1/PL - and SecondReality/FC work - - Act1 sets block size via command 0x48 and it's an odd number - SR does the same with even number - Both use stereo, and Creatives own documentation states that - 0x48 sets block size in bytes less one.. go figure */ - s->block_size &= ~s->fmt_stereo; - } - - s->freq >>= s->fmt_stereo; - s->left_till_irq = s->block_size; - s->bytes_per_second = (s->freq << s->fmt_stereo); - /* s->highspeed = (mask & DMA8_HIGH) != 0; */ - s->dma_auto = (mask & DMA8_AUTO) != 0; - s->align = (1 << s->fmt_stereo) - 1; - - if (s->block_size & s->align) { - dolog ("warning: misaligned block size %d, alignment %d\n", - s->block_size, s->align + 1); - } - - ldebug ("freq %d, stereo %d, sign %d, bits %d, " - "dma %d, auto %d, fifo %d, high %d\n", - s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, - s->block_size, s->dma_auto, s->fifo, s->highspeed); - - continue_dma8 (s); - speaker (s, 1); -} - -static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len) -{ - s->use_hdma = cmd < 0xc0; - s->fifo = (cmd >> 1) & 1; - s->dma_auto = (cmd >> 2) & 1; - s->fmt_signed = (d0 >> 4) & 1; - s->fmt_stereo = (d0 >> 5) & 1; - - switch (cmd >> 4) { - case 11: - s->fmt_bits = 16; - break; - - case 12: - s->fmt_bits = 8; - break; - } - - if (-1 != s->time_const) { -#if 1 - int tmp = 256 - s->time_const; - s->freq = (1000000 + (tmp / 2)) / tmp; -#else - /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */ - s->freq = 1000000 / ((255 - s->time_const)); -#endif - s->time_const = -1; - } - - s->block_size = dma_len + 1; - s->block_size <<= (s->fmt_bits == 16); - if (!s->dma_auto) { - /* It is clear that for DOOM and auto-init this value - shouldn't take stereo into account, while Miles Sound Systems - setsound.exe with single transfer mode wouldn't work without it - wonders of SB16 yet again */ - s->block_size <<= s->fmt_stereo; - } - - ldebug ("freq %d, stereo %d, sign %d, bits %d, " - "dma %d, auto %d, fifo %d, high %d\n", - s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits, - s->block_size, s->dma_auto, s->fifo, s->highspeed); - - if (16 == s->fmt_bits) { - if (s->fmt_signed) { - s->fmt = AUD_FMT_S16; - } - else { - s->fmt = AUD_FMT_U16; - } - } - else { - if (s->fmt_signed) { - s->fmt = AUD_FMT_S8; - } - else { - s->fmt = AUD_FMT_U8; - } - } - - s->left_till_irq = s->block_size; - - s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16); - s->highspeed = 0; - s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1; - if (s->block_size & s->align) { - dolog ("warning: misaligned block size %d, alignment %d\n", - s->block_size, s->align + 1); - } - - if (s->freq) { - audsettings_t as; - - s->audio_free = 0; - - as.freq = s->freq; - as.nchannels = 1 << s->fmt_stereo; - as.fmt = s->fmt; - as.endianness = 0; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as - ); - } - - control (s, 1); - speaker (s, 1); -} - -static inline void dsp_out_data (SB16State *s, uint8_t val) -{ - ldebug ("outdata %#x\n", val); - if ((size_t) s->out_data_len < sizeof (s->out_data)) { - s->out_data[s->out_data_len++] = val; - } -} - -static inline uint8_t dsp_get_data (SB16State *s) -{ - if (s->in_index) { - return s->in2_data[--s->in_index]; - } - else { - dolog ("buffer underflow\n"); - return 0; - } -} - -static void command (SB16State *s, uint8_t cmd) -{ - ldebug ("command %#x\n", cmd); - - if (cmd > 0xaf && cmd < 0xd0) { - if (cmd & 8) { - dolog ("ADC not yet supported (command %#x)\n", cmd); - } - - switch (cmd >> 4) { - case 11: - case 12: - break; - default: - dolog ("%#x wrong bits\n", cmd); - } - s->needed_bytes = 3; - } - else { - s->needed_bytes = 0; - - switch (cmd) { - case 0x03: - dsp_out_data (s, 0x10); /* s->csp_param); */ - goto warn; - - case 0x04: - s->needed_bytes = 1; - goto warn; - - case 0x05: - s->needed_bytes = 2; - goto warn; - - case 0x08: - /* __asm__ ("int3"); */ - goto warn; - - case 0x0e: - s->needed_bytes = 2; - goto warn; - - case 0x09: - dsp_out_data (s, 0xf8); - goto warn; - - case 0x0f: - s->needed_bytes = 1; - goto warn; - - case 0x10: - s->needed_bytes = 1; - goto warn; - - case 0x14: - s->needed_bytes = 2; - s->block_size = 0; - break; - - case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */ - dma_cmd8 (s, DMA8_AUTO, -1); - break; - - case 0x20: /* Direct ADC, Juice/PL */ - dsp_out_data (s, 0xff); - goto warn; - - case 0x35: - dolog ("0x35 - MIDI command not implemented\n"); - break; - - case 0x40: - s->freq = -1; - s->time_const = -1; - s->needed_bytes = 1; - break; - - case 0x41: - s->freq = -1; - s->time_const = -1; - s->needed_bytes = 2; - break; - - case 0x42: - s->freq = -1; - s->time_const = -1; - s->needed_bytes = 2; - goto warn; - - case 0x45: - dsp_out_data (s, 0xaa); - goto warn; - - case 0x47: /* Continue Auto-Initialize DMA 16bit */ - break; - - case 0x48: - s->needed_bytes = 2; - break; - - case 0x74: - s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */ - dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"); - break; - - case 0x75: /* DMA DAC, 4-bit ADPCM Reference */ - s->needed_bytes = 2; - dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"); - break; - - case 0x76: /* DMA DAC, 2.6-bit ADPCM */ - s->needed_bytes = 2; - dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"); - break; - - case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */ - s->needed_bytes = 2; - dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"); - break; - - case 0x7d: - dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"); - dolog ("not implemented\n"); - break; - - case 0x7f: - dolog ( - "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n" - ); - dolog ("not implemented\n"); - break; - - case 0x80: - s->needed_bytes = 2; - break; - - case 0x90: - case 0x91: - dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1); - break; - - case 0xd0: /* halt DMA operation. 8bit */ - control (s, 0); - break; - - case 0xd1: /* speaker on */ - speaker (s, 1); - break; - - case 0xd3: /* speaker off */ - speaker (s, 0); - break; - - case 0xd4: /* continue DMA operation. 8bit */ - /* KQ6 (or maybe Sierras audblst.drv in general) resets - the frequency between halt/continue */ - continue_dma8 (s); - break; - - case 0xd5: /* halt DMA operation. 16bit */ - control (s, 0); - break; - - case 0xd6: /* continue DMA operation. 16bit */ - control (s, 1); - break; - - case 0xd9: /* exit auto-init DMA after this block. 16bit */ - s->dma_auto = 0; - break; - - case 0xda: /* exit auto-init DMA after this block. 8bit */ - s->dma_auto = 0; - break; - - case 0xe0: /* DSP identification */ - s->needed_bytes = 1; - break; - - case 0xe1: - dsp_out_data (s, s->ver & 0xff); - dsp_out_data (s, s->ver >> 8); - break; - - case 0xe2: - s->needed_bytes = 1; - goto warn; - - case 0xe3: - { - int i; - for (i = sizeof (e3) - 1; i >= 0; --i) - dsp_out_data (s, e3[i]); - } - break; - - case 0xe4: /* write test reg */ - s->needed_bytes = 1; - break; - - case 0xe7: - dolog ("Attempt to probe for ESS (0xe7)?\n"); - break; - - case 0xe8: /* read test reg */ - dsp_out_data (s, s->test_reg); - break; - - case 0xf2: - case 0xf3: - dsp_out_data (s, 0xaa); - s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2; - pic_set_irq (s->irq, 1); - break; - - case 0xf9: - s->needed_bytes = 1; - goto warn; - - case 0xfa: - dsp_out_data (s, 0); - goto warn; - - case 0xfc: /* FIXME */ - dsp_out_data (s, 0); - goto warn; - - default: - dolog ("Unrecognized command %#x\n", cmd); - break; - } - } - - if (!s->needed_bytes) { - ldebug ("\n"); - } - - exit: - if (!s->needed_bytes) { - s->cmd = -1; - } - else { - s->cmd = cmd; - } - return; - - warn: - dolog ("warning: command %#x,%d is not truly understood yet\n", - cmd, s->needed_bytes); - goto exit; - -} - -static uint16_t dsp_get_lohi (SB16State *s) -{ - uint8_t hi = dsp_get_data (s); - uint8_t lo = dsp_get_data (s); - return (hi << 8) | lo; -} - -static uint16_t dsp_get_hilo (SB16State *s) -{ - uint8_t lo = dsp_get_data (s); - uint8_t hi = dsp_get_data (s); - return (hi << 8) | lo; -} - -static void complete (SB16State *s) -{ - int d0, d1, d2; - ldebug ("complete command %#x, in_index %d, needed_bytes %d\n", - s->cmd, s->in_index, s->needed_bytes); - - if (s->cmd > 0xaf && s->cmd < 0xd0) { - d2 = dsp_get_data (s); - d1 = dsp_get_data (s); - d0 = dsp_get_data (s); - - if (s->cmd & 8) { - dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", - s->cmd, d0, d1, d2); - } - else { - ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", - s->cmd, d0, d1, d2); - dma_cmd (s, s->cmd, d0, d1 + (d2 << 8)); - } - } - else { - switch (s->cmd) { - case 0x04: - s->csp_mode = dsp_get_data (s); - s->csp_reg83r = 0; - s->csp_reg83w = 0; - ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode); - break; - - case 0x05: - s->csp_param = dsp_get_data (s); - s->csp_value = dsp_get_data (s); - ldebug ("CSP command 0x05: param=%#x value=%#x\n", - s->csp_param, - s->csp_value); - break; - - case 0x0e: - d0 = dsp_get_data (s); - d1 = dsp_get_data (s); - ldebug ("write CSP register %d <- %#x\n", d1, d0); - if (d1 == 0x83) { - ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0); - s->csp_reg83[s->csp_reg83r % 4] = d0; - s->csp_reg83r += 1; - } - else { - s->csp_regs[d1] = d0; - } - break; - - case 0x0f: - d0 = dsp_get_data (s); - ldebug ("read CSP register %#x -> %#x, mode=%#x\n", - d0, s->csp_regs[d0], s->csp_mode); - if (d0 == 0x83) { - ldebug ("0x83[%d] -> %#x\n", - s->csp_reg83w, - s->csp_reg83[s->csp_reg83w % 4]); - dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]); - s->csp_reg83w += 1; - } - else { - dsp_out_data (s, s->csp_regs[d0]); - } - break; - - case 0x10: - d0 = dsp_get_data (s); - dolog ("cmd 0x10 d0=%#x\n", d0); - break; - - case 0x14: - dma_cmd8 (s, 0, dsp_get_lohi (s) + 1); - break; - - case 0x40: - s->time_const = dsp_get_data (s); - ldebug ("set time const %d\n", s->time_const); - break; - - case 0x42: /* FT2 sets output freq with this, go figure */ -#if 0 - dolog ("cmd 0x42 might not do what it think it should\n"); -#endif - case 0x41: - s->freq = dsp_get_hilo (s); - ldebug ("set freq %d\n", s->freq); - break; - - case 0x48: - s->block_size = dsp_get_lohi (s) + 1; - ldebug ("set dma block len %d\n", s->block_size); - break; - - case 0x74: - case 0x75: - case 0x76: - case 0x77: - /* ADPCM stuff, ignore */ - break; - - case 0x80: - { - int freq, samples, bytes; - int64_t ticks; - - freq = s->freq > 0 ? s->freq : 11025; - samples = dsp_get_lohi (s) + 1; - bytes = samples << s->fmt_stereo << (s->fmt_bits == 16); - ticks = (bytes * ticks_per_sec) / freq; - if (ticks < ticks_per_sec / 1024) { - pic_set_irq (s->irq, 1); - } - else { - if (s->aux_ts) { - qemu_mod_timer ( - s->aux_ts, - qemu_get_clock (vm_clock) + ticks - ); - } - } - ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks); - } - break; - - case 0xe0: - d0 = dsp_get_data (s); - s->out_data_len = 0; - ldebug ("E0 data = %#x\n", d0); - dsp_out_data (s, ~d0); - break; - - case 0xe2: - d0 = dsp_get_data (s); - ldebug ("E2 = %#x\n", d0); - break; - - case 0xe4: - s->test_reg = dsp_get_data (s); - break; - - case 0xf9: - d0 = dsp_get_data (s); - ldebug ("command 0xf9 with %#x\n", d0); - switch (d0) { - case 0x0e: - dsp_out_data (s, 0xff); - break; - - case 0x0f: - dsp_out_data (s, 0x07); - break; - - case 0x37: - dsp_out_data (s, 0x38); - break; - - default: - dsp_out_data (s, 0x00); - break; - } - break; - - default: - dolog ("complete: unrecognized command %#x\n", s->cmd); - return; - } - } - - ldebug ("\n"); - s->cmd = -1; - return; -} - -static void legacy_reset (SB16State *s) -{ - audsettings_t as; - - s->freq = 11025; - s->fmt_signed = 0; - s->fmt_bits = 8; - s->fmt_stereo = 0; - - as.freq = s->freq; - as.nchannels = 1; - as.fmt = AUD_FMT_U8; - as.endianness = 0; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as - ); - - /* Not sure about that... */ - /* AUD_set_active_out (s->voice, 1); */ -} - -static void reset (SB16State *s) -{ - pic_set_irq (s->irq, 0); - if (s->dma_auto) { - pic_set_irq (s->irq, 1); - pic_set_irq (s->irq, 0); - } - - s->mixer_regs[0x82] = 0; - s->dma_auto = 0; - s->in_index = 0; - s->out_data_len = 0; - s->left_till_irq = 0; - s->needed_bytes = 0; - s->block_size = -1; - s->nzero = 0; - s->highspeed = 0; - s->v2x6 = 0; - s->cmd = -1; - - dsp_out_data(s, 0xaa); - speaker (s, 0); - control (s, 0); - legacy_reset (s); -} - -static IO_WRITE_PROTO (dsp_write) -{ - SB16State *s = opaque; - int iport; - - iport = nport - s->port; - - ldebug ("write %#x <- %#x\n", nport, val); - switch (iport) { - case 0x06: - switch (val) { - case 0x00: - if (s->v2x6 == 1) { - if (0 && s->highspeed) { - s->highspeed = 0; - pic_set_irq (s->irq, 0); - control (s, 0); - } - else { - reset (s); - } - } - s->v2x6 = 0; - break; - - case 0x01: - case 0x03: /* FreeBSD kludge */ - s->v2x6 = 1; - break; - - case 0xc6: - s->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */ - break; - - case 0xb8: /* Panic */ - reset (s); - break; - - case 0x39: - dsp_out_data (s, 0x38); - reset (s); - s->v2x6 = 0x39; - break; - - default: - s->v2x6 = val; - break; - } - break; - - case 0x0c: /* write data or command | write status */ -/* if (s->highspeed) */ -/* break; */ - - if (0 == s->needed_bytes) { - command (s, val); -#if 0 - if (0 == s->needed_bytes) { - log_dsp (s); - } -#endif - } - else { - if (s->in_index == sizeof (s->in2_data)) { - dolog ("in data overrun\n"); - } - else { - s->in2_data[s->in_index++] = val; - if (s->in_index == s->needed_bytes) { - s->needed_bytes = 0; - complete (s); -#if 0 - log_dsp (s); -#endif - } - } - } - break; - - default: - ldebug ("(nport=%#x, val=%#x)\n", nport, val); - break; - } -} - -static IO_READ_PROTO (dsp_read) -{ - SB16State *s = opaque; - int iport, retval, ack = 0; - - iport = nport - s->port; - - switch (iport) { - case 0x06: /* reset */ - retval = 0xff; - break; - - case 0x0a: /* read data */ - if (s->out_data_len) { - retval = s->out_data[--s->out_data_len]; - s->last_read_byte = retval; - } - else { - if (s->cmd != -1) { - dolog ("empty output buffer for command %#x\n", - s->cmd); - } - retval = s->last_read_byte; - /* goto error; */ - } - break; - - case 0x0c: /* 0 can write */ - retval = s->can_write ? 0 : 0x80; - break; - - case 0x0d: /* timer interrupt clear */ - /* dolog ("timer interrupt clear\n"); */ - retval = 0; - break; - - case 0x0e: /* data available status | irq 8 ack */ - retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80; - if (s->mixer_regs[0x82] & 1) { - ack = 1; - s->mixer_regs[0x82] &= 1; - pic_set_irq (s->irq, 0); - } - break; - - case 0x0f: /* irq 16 ack */ - retval = 0xff; - if (s->mixer_regs[0x82] & 2) { - ack = 1; - s->mixer_regs[0x82] &= 2; - pic_set_irq (s->irq, 0); - } - break; - - default: - goto error; - } - - if (!ack) { - ldebug ("read %#x -> %#x\n", nport, retval); - } - - return retval; - - error: - dolog ("warning: dsp_read %#x error\n", nport); - return 0xff; -} - -static void reset_mixer (SB16State *s) -{ - int i; - - memset (s->mixer_regs, 0xff, 0x7f); - memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83); - - s->mixer_regs[0x02] = 4; /* master volume 3bits */ - s->mixer_regs[0x06] = 4; /* MIDI volume 3bits */ - s->mixer_regs[0x08] = 0; /* CD volume 3bits */ - s->mixer_regs[0x0a] = 0; /* voice volume 2bits */ - - /* d5=input filt, d3=lowpass filt, d1,d2=input source */ - s->mixer_regs[0x0c] = 0; - - /* d5=output filt, d1=stereo switch */ - s->mixer_regs[0x0e] = 0; - - /* voice volume L d5,d7, R d1,d3 */ - s->mixer_regs[0x04] = (4 << 5) | (4 << 1); - /* master ... */ - s->mixer_regs[0x22] = (4 << 5) | (4 << 1); - /* MIDI ... */ - s->mixer_regs[0x26] = (4 << 5) | (4 << 1); - - for (i = 0x30; i < 0x48; i++) { - s->mixer_regs[i] = 0x20; - } -} - -static IO_WRITE_PROTO(mixer_write_indexb) -{ - SB16State *s = opaque; - (void) nport; - s->mixer_nreg = val; -} - -static IO_WRITE_PROTO(mixer_write_datab) -{ - SB16State *s = opaque; - - (void) nport; - ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val); - - switch (s->mixer_nreg) { - case 0x00: - reset_mixer (s); - break; - - case 0x80: - { - int irq = irq_of_magic (val); - ldebug ("setting irq to %d (val=%#x)\n", irq, val); - if (irq > 0) { - s->irq = irq; - } - } - break; - - case 0x81: - { - int dma, hdma; - - dma = lsbindex (val & 0xf); - hdma = lsbindex (val & 0xf0); - if (dma != s->dma || hdma != s->hdma) { - dolog ( - "attempt to change DMA " - "8bit %d(%d), 16bit %d(%d) (val=%#x)\n", - dma, s->dma, hdma, s->hdma, val); - } -#if 0 - s->dma = dma; - s->hdma = hdma; -#endif - } - break; - - case 0x82: - dolog ("attempt to write into IRQ status register (val=%#x)\n", - val); - return; - - default: - if (s->mixer_nreg >= 0x80) { - ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val); - } - break; - } - - s->mixer_regs[s->mixer_nreg] = val; -} - -static IO_WRITE_PROTO(mixer_write_indexw) -{ - mixer_write_indexb (opaque, nport, val & 0xff); - mixer_write_datab (opaque, nport, (val >> 8) & 0xff); -} - -static IO_READ_PROTO(mixer_read) -{ - SB16State *s = opaque; - - (void) nport; -#ifndef DEBUG_SB16_MOST - if (s->mixer_nreg != 0x82) { - ldebug ("mixer_read[%#x] -> %#x\n", - s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); - } -#else - ldebug ("mixer_read[%#x] -> %#x\n", - s->mixer_nreg, s->mixer_regs[s->mixer_nreg]); -#endif - return s->mixer_regs[s->mixer_nreg]; -} - -static int write_audio (SB16State *s, int nchan, int dma_pos, - int dma_len, int len) -{ - int temp, net; - uint8_t tmpbuf[4096]; - - temp = len; - net = 0; - - while (temp) { - int left = dma_len - dma_pos; - int copied; - size_t to_copy; - - to_copy = audio_MIN (temp, left); - if (to_copy > sizeof (tmpbuf)) { - to_copy = sizeof (tmpbuf); - } - - copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy); - copied = AUD_write (s->voice, tmpbuf, copied); - - temp -= copied; - dma_pos = (dma_pos + copied) % dma_len; - net += copied; - - if (!copied) { - break; - } - } - - return net; -} - -static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len) -{ - SB16State *s = opaque; - int till, copy, written, free; - - if (s->left_till_irq < 0) { - s->left_till_irq = s->block_size; - } - - if (s->voice) { - free = s->audio_free & ~s->align; - if ((free <= 0) || !dma_len) { - return dma_pos; - } - } - else { - free = dma_len; - } - - copy = free; - till = s->left_till_irq; - -#ifdef DEBUG_SB16_MOST - dolog ("pos:%06d %d till:%d len:%d\n", - dma_pos, free, till, dma_len); -#endif - - if (till <= copy) { - if (0 == s->dma_auto) { - copy = till; - } - } - - written = write_audio (s, nchan, dma_pos, dma_len, copy); - dma_pos = (dma_pos + written) % dma_len; - s->left_till_irq -= written; - - if (s->left_till_irq <= 0) { - s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1; - pic_set_irq (s->irq, 1); - if (0 == s->dma_auto) { - control (s, 0); - speaker (s, 0); - } - } - -#ifdef DEBUG_SB16_MOST - ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n", - dma_pos, free, dma_len, s->left_till_irq, copy, written, - s->block_size); -#endif - - while (s->left_till_irq <= 0) { - s->left_till_irq = s->block_size + s->left_till_irq; - } - - return dma_pos; -} - -static void SB_audio_callback (void *opaque, int free) -{ - SB16State *s = opaque; - s->audio_free = free; -} - -static void SB_save (QEMUFile *f, void *opaque) -{ - SB16State *s = opaque; - - qemu_put_be32s (f, &s->irq); - qemu_put_be32s (f, &s->dma); - qemu_put_be32s (f, &s->hdma); - qemu_put_be32s (f, &s->port); - qemu_put_be32s (f, &s->ver); - qemu_put_be32s (f, &s->in_index); - qemu_put_be32s (f, &s->out_data_len); - qemu_put_be32s (f, &s->fmt_stereo); - qemu_put_be32s (f, &s->fmt_signed); - qemu_put_be32s (f, &s->fmt_bits); - qemu_put_be32s (f, &s->fmt); - qemu_put_be32s (f, &s->dma_auto); - qemu_put_be32s (f, &s->block_size); - qemu_put_be32s (f, &s->fifo); - qemu_put_be32s (f, &s->freq); - qemu_put_be32s (f, &s->time_const); - qemu_put_be32s (f, &s->speaker); - qemu_put_be32s (f, &s->needed_bytes); - qemu_put_be32s (f, &s->cmd); - qemu_put_be32s (f, &s->use_hdma); - qemu_put_be32s (f, &s->highspeed); - qemu_put_be32s (f, &s->can_write); - qemu_put_be32s (f, &s->v2x6); - - qemu_put_8s (f, &s->csp_param); - qemu_put_8s (f, &s->csp_value); - qemu_put_8s (f, &s->csp_mode); - qemu_put_8s (f, &s->csp_param); - qemu_put_buffer (f, s->csp_regs, 256); - qemu_put_8s (f, &s->csp_index); - qemu_put_buffer (f, s->csp_reg83, 4); - qemu_put_be32s (f, &s->csp_reg83r); - qemu_put_be32s (f, &s->csp_reg83w); - - qemu_put_buffer (f, s->in2_data, sizeof (s->in2_data)); - qemu_put_buffer (f, s->out_data, sizeof (s->out_data)); - qemu_put_8s (f, &s->test_reg); - qemu_put_8s (f, &s->last_read_byte); - - qemu_put_be32s (f, &s->nzero); - qemu_put_be32s (f, &s->left_till_irq); - qemu_put_be32s (f, &s->dma_running); - qemu_put_be32s (f, &s->bytes_per_second); - qemu_put_be32s (f, &s->align); - - qemu_put_be32s (f, &s->mixer_nreg); - qemu_put_buffer (f, s->mixer_regs, 256); -} - -static int SB_load (QEMUFile *f, void *opaque, int version_id) -{ - SB16State *s = opaque; - - if (version_id != 1) { - return -EINVAL; - } - - qemu_get_be32s (f, &s->irq); - qemu_get_be32s (f, &s->dma); - qemu_get_be32s (f, &s->hdma); - qemu_get_be32s (f, &s->port); - qemu_get_be32s (f, &s->ver); - qemu_get_be32s (f, &s->in_index); - qemu_get_be32s (f, &s->out_data_len); - qemu_get_be32s (f, &s->fmt_stereo); - qemu_get_be32s (f, &s->fmt_signed); - qemu_get_be32s (f, &s->fmt_bits); - qemu_get_be32s (f, &s->fmt); - qemu_get_be32s (f, &s->dma_auto); - qemu_get_be32s (f, &s->block_size); - qemu_get_be32s (f, &s->fifo); - qemu_get_be32s (f, &s->freq); - qemu_get_be32s (f, &s->time_const); - qemu_get_be32s (f, &s->speaker); - qemu_get_be32s (f, &s->needed_bytes); - qemu_get_be32s (f, &s->cmd); - qemu_get_be32s (f, &s->use_hdma); - qemu_get_be32s (f, &s->highspeed); - qemu_get_be32s (f, &s->can_write); - qemu_get_be32s (f, &s->v2x6); - - qemu_get_8s (f, &s->csp_param); - qemu_get_8s (f, &s->csp_value); - qemu_get_8s (f, &s->csp_mode); - qemu_get_8s (f, &s->csp_param); - qemu_get_buffer (f, s->csp_regs, 256); - qemu_get_8s (f, &s->csp_index); - qemu_get_buffer (f, s->csp_reg83, 4); - qemu_get_be32s (f, &s->csp_reg83r); - qemu_get_be32s (f, &s->csp_reg83w); - - qemu_get_buffer (f, s->in2_data, sizeof (s->in2_data)); - qemu_get_buffer (f, s->out_data, sizeof (s->out_data)); - qemu_get_8s (f, &s->test_reg); - qemu_get_8s (f, &s->last_read_byte); - - qemu_get_be32s (f, &s->nzero); - qemu_get_be32s (f, &s->left_till_irq); - qemu_get_be32s (f, &s->dma_running); - qemu_get_be32s (f, &s->bytes_per_second); - qemu_get_be32s (f, &s->align); - - qemu_get_be32s (f, &s->mixer_nreg); - qemu_get_buffer (f, s->mixer_regs, 256); - - if (s->voice) { - AUD_close_out (&s->card, s->voice); - s->voice = NULL; - } - - if (s->dma_running) { - if (s->freq) { - audsettings_t as; - - s->audio_free = 0; - - as.freq = s->freq; - as.nchannels = 1 << s->fmt_stereo; - as.fmt = s->fmt; - as.endianness = 0; - - s->voice = AUD_open_out ( - &s->card, - s->voice, - "sb16", - s, - SB_audio_callback, - &as - ); - } - - control (s, 1); - speaker (s, s->speaker); - } - return 0; -} - -int SB16_init (AudioState *audio) -{ - SB16State *s; - int i; - static const uint8_t dsp_write_ports[] = {0x6, 0xc}; - static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf}; - - if (!audio) { - dolog ("No audio state\n"); - return -1; - } - - s = qemu_mallocz (sizeof (*s)); - if (!s) { - dolog ("Could not allocate memory for SB16 (%zu bytes)\n", - sizeof (*s)); - return -1; - } - - s->cmd = -1; - s->irq = conf.irq; - s->dma = conf.dma; - s->hdma = conf.hdma; - s->port = conf.port; - s->ver = conf.ver_lo | (conf.ver_hi << 8); - - s->mixer_regs[0x80] = magic_of_irq (s->irq); - s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma); - s->mixer_regs[0x82] = 2 << 5; - - s->csp_regs[5] = 1; - s->csp_regs[9] = 0xf8; - - reset_mixer (s); - s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s); - if (!s->aux_ts) { - dolog ("warning: Could not create auxiliary timer\n"); - } - - for (i = 0; i < LENOFA (dsp_write_ports); i++) { - register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s); - } - - for (i = 0; i < LENOFA (dsp_read_ports); i++) { - register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s); - } - - register_ioport_write (s->port + 0x4, 1, 1, mixer_write_indexb, s); - register_ioport_write (s->port + 0x4, 1, 2, mixer_write_indexw, s); - register_ioport_read (s->port + 0x5, 1, 1, mixer_read, s); - register_ioport_write (s->port + 0x5, 1, 1, mixer_write_datab, s); - - DMA_register_channel (s->hdma, SB_read_DMA, s); - DMA_register_channel (s->dma, SB_read_DMA, s); - s->can_write = 1; - - register_savevm ("sb16", 0, 1, SB_save, SB_load, s); - AUD_register_card (audio, "sb16", &s->card); - return 0; -} @@ -0,0 +1,83 @@ +/* + * include/linux/mmc/sd.h + * + * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#ifndef MMC_SD_H +#define MMC_SD_H + +/* SD commands type argument response */ + /* class 0 */ +/* This is basically the same command as for MMC with some quirks. */ +#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ +#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ + + /* class 10 */ +#define SD_SWITCH 6 /* adtc [31:0] See below R1 */ + + /* Application commands */ +#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ +#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */ +#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ +#define SD_APP_SEND_SCR 51 /* adtc R1 */ + +/* + * SD_SWITCH argument format: + * + * [31] Check (0) or switch (1) + * [30:24] Reserved (0) + * [23:20] Function group 6 + * [19:16] Function group 5 + * [15:12] Function group 4 + * [11:8] Function group 3 + * [7:4] Function group 2 + * [3:0] Function group 1 + */ + +/* + * SD_SEND_IF_COND argument format: + * + * [31:12] Reserved (0) + * [11:8] Host Voltage Supply Flags + * [7:0] Check Pattern (0xAA) + */ + +/* + * SCR field definitions + */ + +#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ +#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ +#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */ + +/* + * SD bus widths + */ +#define SD_BUS_WIDTH_1 0 +#define SD_BUS_WIDTH_4 2 + +/* + * SD_SWITCH mode + */ +#define SD_SWITCH_CHECK 0 +#define SD_SWITCH_SET 1 + +/* + * SD_SWITCH function groups + */ +#define SD_SWITCH_GRP_ACCESS 0 + +/* + * SD_SWITCH access modes + */ +#define SD_SWITCH_ACCESS_DEF 0 +#define SD_SWITCH_ACCESS_HS 1 + +#endif + diff --git a/hw/serial.c b/hw/serial.c deleted file mode 100644 index f36beb2..0000000 --- a/hw/serial.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - * QEMU 16450 UART emulation - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -//#define DEBUG_SERIAL - -#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ - -#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ -#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ -#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ -#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ - -#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ -#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ - -#define UART_IIR_MSI 0x00 /* Modem status interrupt */ -#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ -#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ -#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ - -/* - * These are the definitions for the Modem Control Register - */ -#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ -#define UART_MCR_OUT2 0x08 /* Out2 complement */ -#define UART_MCR_OUT1 0x04 /* Out1 complement */ -#define UART_MCR_RTS 0x02 /* RTS complement */ -#define UART_MCR_DTR 0x01 /* DTR complement */ - -/* - * These are the definitions for the Modem Status Register - */ -#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ -#define UART_MSR_RI 0x40 /* Ring Indicator */ -#define UART_MSR_DSR 0x20 /* Data Set Ready */ -#define UART_MSR_CTS 0x10 /* Clear to Send */ -#define UART_MSR_DDCD 0x08 /* Delta DCD */ -#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ -#define UART_MSR_DDSR 0x02 /* Delta DSR */ -#define UART_MSR_DCTS 0x01 /* Delta CTS */ -#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ - -#define UART_LSR_TEMT 0x40 /* Transmitter empty */ -#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ -#define UART_LSR_BI 0x10 /* Break interrupt indicator */ -#define UART_LSR_FE 0x08 /* Frame error indicator */ -#define UART_LSR_PE 0x04 /* Parity error indicator */ -#define UART_LSR_OE 0x02 /* Overrun error indicator */ -#define UART_LSR_DR 0x01 /* Receiver data ready */ - -struct SerialState { - uint8_t divider; - uint8_t rbr; /* receive register */ - uint8_t ier; - uint8_t iir; /* read only */ - uint8_t lcr; - uint8_t mcr; - uint8_t lsr; /* read only */ - uint8_t msr; /* read only */ - uint8_t scr; - /* NOTE: this hidden state is necessary for tx irq generation as - it can be reset while reading iir */ - int thr_ipending; - SetIRQFunc *set_irq; - void *irq_opaque; - int irq; - CharDriverState *chr; - int last_break_enable; - target_ulong base; - int it_shift; -}; - -static void serial_update_irq(SerialState *s) -{ - if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { - s->iir = UART_IIR_RDI; - } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { - s->iir = UART_IIR_THRI; - } else { - s->iir = UART_IIR_NO_INT; - } - if (s->iir != UART_IIR_NO_INT) { - s->set_irq(s->irq_opaque, s->irq, 1); - } else { - s->set_irq(s->irq_opaque, s->irq, 0); - } -} - -static void serial_update_parameters(SerialState *s) -{ - int speed, parity, data_bits, stop_bits; - QEMUSerialSetParams ssp; - - if (s->lcr & 0x08) { - if (s->lcr & 0x10) - parity = 'E'; - else - parity = 'O'; - } else { - parity = 'N'; - } - if (s->lcr & 0x04) - stop_bits = 2; - else - stop_bits = 1; - data_bits = (s->lcr & 0x03) + 5; - if (s->divider == 0) - return; - speed = 115200 / s->divider; - ssp.speed = speed; - ssp.parity = parity; - ssp.data_bits = data_bits; - ssp.stop_bits = stop_bits; - qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); -#if 0 - printf("speed=%d parity=%c data=%d stop=%d\n", - speed, parity, data_bits, stop_bits); -#endif -} - -static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - SerialState *s = opaque; - unsigned char ch; - - addr &= 7; -#ifdef DEBUG_SERIAL - printf("serial: write addr=0x%02x val=0x%02x\n", addr, val); -#endif - switch(addr) { - default: - case 0: - if (s->lcr & UART_LCR_DLAB) { - s->divider = (s->divider & 0xff00) | val; - serial_update_parameters(s); - } else { - s->thr_ipending = 0; - s->lsr &= ~UART_LSR_THRE; - serial_update_irq(s); - ch = val; - qemu_chr_write(s->chr, &ch, 1); - s->thr_ipending = 1; - s->lsr |= UART_LSR_THRE; - s->lsr |= UART_LSR_TEMT; - serial_update_irq(s); - } - break; - case 1: - if (s->lcr & UART_LCR_DLAB) { - s->divider = (s->divider & 0x00ff) | (val << 8); - serial_update_parameters(s); - } else { - s->ier = val & 0x0f; - if (s->lsr & UART_LSR_THRE) { - s->thr_ipending = 1; - } - serial_update_irq(s); - } - break; - case 2: - break; - case 3: - { - int break_enable; - s->lcr = val; - serial_update_parameters(s); - break_enable = (val >> 6) & 1; - if (break_enable != s->last_break_enable) { - s->last_break_enable = break_enable; - qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, - &break_enable); - } - } - break; - case 4: - s->mcr = val & 0x1f; - break; - case 5: - break; - case 6: - break; - case 7: - s->scr = val; - break; - } -} - -static uint32_t serial_ioport_read(void *opaque, uint32_t addr) -{ - SerialState *s = opaque; - uint32_t ret; - - addr &= 7; - switch(addr) { - default: - case 0: - if (s->lcr & UART_LCR_DLAB) { - ret = s->divider & 0xff; - } else { - ret = s->rbr; - s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); - serial_update_irq(s); - } - break; - case 1: - if (s->lcr & UART_LCR_DLAB) { - ret = (s->divider >> 8) & 0xff; - } else { - ret = s->ier; - } - break; - case 2: - ret = s->iir; - /* reset THR pending bit */ - if ((ret & 0x7) == UART_IIR_THRI) - s->thr_ipending = 0; - serial_update_irq(s); - break; - case 3: - ret = s->lcr; - break; - case 4: - ret = s->mcr; - break; - case 5: - ret = s->lsr; - break; - case 6: - if (s->mcr & UART_MCR_LOOP) { - /* in loopback, the modem output pins are connected to the - inputs */ - ret = (s->mcr & 0x0c) << 4; - ret |= (s->mcr & 0x02) << 3; - ret |= (s->mcr & 0x01) << 5; - } else { - ret = s->msr; - } - break; - case 7: - ret = s->scr; - break; - } -#ifdef DEBUG_SERIAL - printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret); -#endif - return ret; -} - -static int serial_can_receive(SerialState *s) -{ - return !(s->lsr & UART_LSR_DR); -} - -static void serial_receive_byte(SerialState *s, int ch) -{ - s->rbr = ch; - s->lsr |= UART_LSR_DR; - serial_update_irq(s); -} - -static void serial_receive_break(SerialState *s) -{ - s->rbr = 0; - s->lsr |= UART_LSR_BI | UART_LSR_DR; - serial_update_irq(s); -} - -static int serial_can_receive1(void *opaque) -{ - SerialState *s = opaque; - return serial_can_receive(s); -} - -static void serial_receive1(void *opaque, const uint8_t *buf, int size) -{ - SerialState *s = opaque; - serial_receive_byte(s, buf[0]); -} - -static void serial_event(void *opaque, int event) -{ - SerialState *s = opaque; - if (event == CHR_EVENT_BREAK) - serial_receive_break(s); -} - -static void serial_save(QEMUFile *f, void *opaque) -{ - SerialState *s = opaque; - - qemu_put_8s(f,&s->divider); - qemu_put_8s(f,&s->rbr); - qemu_put_8s(f,&s->ier); - qemu_put_8s(f,&s->iir); - qemu_put_8s(f,&s->lcr); - qemu_put_8s(f,&s->mcr); - qemu_put_8s(f,&s->lsr); - qemu_put_8s(f,&s->msr); - qemu_put_8s(f,&s->scr); -} - -static int serial_load(QEMUFile *f, void *opaque, int version_id) -{ - SerialState *s = opaque; - - if(version_id != 1) - return -EINVAL; - - qemu_get_8s(f,&s->divider); - qemu_get_8s(f,&s->rbr); - qemu_get_8s(f,&s->ier); - qemu_get_8s(f,&s->iir); - qemu_get_8s(f,&s->lcr); - qemu_get_8s(f,&s->mcr); - qemu_get_8s(f,&s->lsr); - qemu_get_8s(f,&s->msr); - qemu_get_8s(f,&s->scr); - - return 0; -} - -/* If fd is zero, it means that the serial device uses the console */ -SerialState *serial_init(SetIRQFunc *set_irq, void *opaque, - int base, int irq, CharDriverState *chr) -{ - SerialState *s; - - s = qemu_mallocz(sizeof(SerialState)); - if (!s) - return NULL; - s->set_irq = set_irq; - s->irq_opaque = opaque; - s->irq = irq; - s->lsr = UART_LSR_TEMT | UART_LSR_THRE; - s->iir = UART_IIR_NO_INT; - s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; - - register_savevm("serial", base, 1, serial_save, serial_load, s); - - register_ioport_write(base, 8, 1, serial_ioport_write, s); - register_ioport_read(base, 8, 1, serial_ioport_read, s); - s->chr = chr; - qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s); - qemu_chr_add_event_handler(chr, serial_event); - return s; -} - -/* Memory mapped interface */ -static uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr) -{ - SerialState *s = opaque; - - return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF; -} - -static void serial_mm_writeb (void *opaque, - target_phys_addr_t addr, uint32_t value) -{ - SerialState *s = opaque; - - serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF); -} - -static uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr) -{ - SerialState *s = opaque; - - return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF; -} - -static void serial_mm_writew (void *opaque, - target_phys_addr_t addr, uint32_t value) -{ - SerialState *s = opaque; - - serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF); -} - -static uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr) -{ - SerialState *s = opaque; - - return serial_ioport_read(s, (addr - s->base) >> s->it_shift); -} - -static void serial_mm_writel (void *opaque, - target_phys_addr_t addr, uint32_t value) -{ - SerialState *s = opaque; - - serial_ioport_write(s, (addr - s->base) >> s->it_shift, value); -} - -static CPUReadMemoryFunc *serial_mm_read[] = { - &serial_mm_readb, - &serial_mm_readw, - &serial_mm_readl, -}; - -static CPUWriteMemoryFunc *serial_mm_write[] = { - &serial_mm_writeb, - &serial_mm_writew, - &serial_mm_writel, -}; - -SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque, - target_ulong base, int it_shift, - int irq, CharDriverState *chr) -{ - SerialState *s; - int s_io_memory; - - s = qemu_mallocz(sizeof(SerialState)); - if (!s) - return NULL; - s->set_irq = set_irq; - s->irq_opaque = opaque; - s->irq = irq; - s->lsr = UART_LSR_TEMT | UART_LSR_THRE; - s->iir = UART_IIR_NO_INT; - s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; - s->base = base; - s->it_shift = it_shift; - - register_savevm("serial", base, 1, serial_save, serial_load, s); - - s_io_memory = cpu_register_io_memory(0, serial_mm_read, - serial_mm_write, s); - cpu_register_physical_memory(base, 8 << it_shift, s_io_memory); - s->chr = chr; - qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s); - qemu_chr_add_event_handler(chr, serial_event); - return s; -} diff --git a/hw/sh7750.c b/hw/sh7750.c deleted file mode 100644 index 21f9bc0..0000000 --- a/hw/sh7750.c +++ /dev/null @@ -1,836 +0,0 @@ -/* - * SH7750 device - * - * Copyright (c) 2005 Samuel Tardieu - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include <stdio.h> -#include <assert.h> -#include "vl.h" -#include "sh7750_regs.h" -#include "sh7750_regnames.h" - -typedef struct { - uint8_t data[16]; - uint8_t length; /* Number of characters in the FIFO */ - uint8_t write_idx; /* Index of first character to write */ - uint8_t read_idx; /* Index of first character to read */ -} fifo; - -#define NB_DEVICES 4 - -typedef struct SH7750State { - /* CPU */ - CPUSH4State *cpu; - /* Peripheral frequency in Hz */ - uint32_t periph_freq; - /* SDRAM controller */ - uint16_t rfcr; - /* First serial port */ - CharDriverState *serial1; - uint8_t scscr1; - uint8_t scsmr1; - uint8_t scbrr1; - uint8_t scssr1; - uint8_t scssr1_read; - uint8_t sctsr1; - uint8_t sctsr1_loaded; - uint8_t sctdr1; - uint8_t scrdr1; - /* Second serial port */ - CharDriverState *serial2; - uint16_t sclsr2; - uint16_t scscr2; - uint16_t scfcr2; - uint16_t scfsr2; - uint16_t scsmr2; - uint8_t scbrr2; - fifo serial2_receive_fifo; - fifo serial2_transmit_fifo; - /* Timers */ - uint8_t tstr; - /* Timer 0 */ - QEMUTimer *timer0; - uint16_t tcr0; - uint32_t tcor0; - uint32_t tcnt0; - /* IO ports */ - uint16_t gpioic; - uint32_t pctra; - uint32_t pctrb; - uint16_t portdira; /* Cached */ - uint16_t portpullupa; /* Cached */ - uint16_t portdirb; /* Cached */ - uint16_t portpullupb; /* Cached */ - uint16_t pdtra; - uint16_t pdtrb; - uint16_t periph_pdtra; /* Imposed by the peripherals */ - uint16_t periph_portdira; /* Direction seen from the peripherals */ - uint16_t periph_pdtrb; /* Imposed by the peripherals */ - uint16_t periph_portdirb; /* Direction seen from the peripherals */ - sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ - /* Cache */ - uint32_t ccr; -} SH7750State; - -/********************************************************************** - Timers -**********************************************************************/ - -/* XXXXX At this time, timer0 works in underflow only mode, that is - the value of tcnt0 is read at alarm computation time and cannot - be read back by the guest OS */ - -static void start_timer0(SH7750State * s) -{ - uint64_t now, next, prescaler; - - if ((s->tcr0 & 6) == 6) { - fprintf(stderr, "rtc clock for timer 0 not supported\n"); - assert(0); - } - - if ((s->tcr0 & 7) == 5) { - fprintf(stderr, "timer 0 configuration not supported\n"); - assert(0); - } - - if ((s->tcr0 & 4) == 4) - prescaler = 1024; - else - prescaler = 4 << (s->tcr0 & 3); - - now = qemu_get_clock(vm_clock); - /* XXXXX */ - next = - now + muldiv64(prescaler * s->tcnt0, ticks_per_sec, - s->periph_freq); - if (next == now) - next = now + 1; - fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next); - fprintf(stderr, "timer will underflow in %f seconds\n", - (float) (next - now) / (float) ticks_per_sec); - - qemu_mod_timer(s->timer0, next); -} - -static void timer_start_changed(SH7750State * s) -{ - if (s->tstr & SH7750_TSTR_STR0) { - start_timer0(s); - } else { - fprintf(stderr, "timer 0 is stopped\n"); - qemu_del_timer(s->timer0); - } -} - -static void timer0_cb(void *opaque) -{ - SH7750State *s = opaque; - - s->tcnt0 = (uint32_t) 0; /* XXXXX */ - if (--s->tcnt0 == (uint32_t) - 1) { - fprintf(stderr, "timer 0 underflow\n"); - s->tcnt0 = s->tcor0; - s->tcr0 |= SH7750_TCR_UNF; - if (s->tcr0 & SH7750_TCR_UNIE) { - fprintf(stderr, - "interrupt generation for timer 0 not supported\n"); - assert(0); - } - } - start_timer0(s); -} - -static void init_timers(SH7750State * s) -{ - s->tcor0 = 0xffffffff; - s->tcnt0 = 0xffffffff; - s->timer0 = qemu_new_timer(vm_clock, &timer0_cb, s); -} - -/********************************************************************** - First serial port -**********************************************************************/ - -static int serial1_can_receive(void *opaque) -{ - SH7750State *s = opaque; - - return s->scscr1 & SH7750_SCSCR_RE; -} - -static void serial1_receive_char(SH7750State * s, uint8_t c) -{ - if (s->scssr1 & SH7750_SCSSR1_RDRF) { - s->scssr1 |= SH7750_SCSSR1_ORER; - return; - } - - s->scrdr1 = c; - s->scssr1 |= SH7750_SCSSR1_RDRF; -} - -static void serial1_receive(void *opaque, const uint8_t * buf, int size) -{ - SH7750State *s = opaque; - int i; - - for (i = 0; i < size; i++) { - serial1_receive_char(s, buf[i]); - } -} - -static void serial1_event(void *opaque, int event) -{ - assert(0); -} - -static void serial1_maybe_send(SH7750State * s) -{ - uint8_t c; - - if (s->scssr1 & SH7750_SCSSR1_TDRE) - return; - c = s->sctdr1; - s->scssr1 |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND; - if (s->scscr1 & SH7750_SCSCR_TIE) { - fprintf(stderr, "interrupts for serial port 1 not implemented\n"); - assert(0); - } - /* XXXXX Check for errors in write */ - qemu_chr_write(s->serial1, &c, 1); -} - -static void serial1_change_scssr1(SH7750State * s, uint8_t mem_value) -{ - uint8_t new_flags; - - /* If transmit disable, TDRE and TEND stays up */ - if ((s->scscr1 & SH7750_SCSCR_TE) == 0) { - mem_value |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND; - } - - /* Only clear bits which have been read before and do not set any bit - in the flags */ - new_flags = s->scssr1 & ~s->scssr1_read; /* Preserve unread flags */ - new_flags &= mem_value | ~s->scssr1_read; /* Clear read flags */ - - s->scssr1 = (new_flags & 0xf8) | (mem_value & 1); - s->scssr1_read &= mem_value; - - /* If TDRE has been cleared, TEND will also be cleared */ - if ((s->scssr1 & SH7750_SCSSR1_TDRE) == 0) { - s->scssr1 &= ~SH7750_SCSSR1_TEND; - } - - /* Check for transmission to start */ - serial1_maybe_send(s); -} - -static void serial1_update_parameters(SH7750State * s) -{ - QEMUSerialSetParams ssp; - - if (s->scsmr1 & SH7750_SCSMR_CHR_7) - ssp.data_bits = 7; - else - ssp.data_bits = 8; - if (s->scsmr1 & SH7750_SCSMR_PE) { - if (s->scsmr1 & SH7750_SCSMR_PM_ODD) - ssp.parity = 'O'; - else - ssp.parity = 'E'; - } else - ssp.parity = 'N'; - if (s->scsmr1 & SH7750_SCSMR_STOP_2) - ssp.stop_bits = 2; - else - ssp.stop_bits = 1; - fprintf(stderr, "SCSMR1=%04x SCBRR1=%02x\n", s->scsmr1, s->scbrr1); - ssp.speed = s->periph_freq / - (32 * s->scbrr1 * (1 << (2 * (s->scsmr1 & 3)))) - 1; - fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n", - ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed); - qemu_chr_ioctl(s->serial1, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); -} - -static void scscr1_changed(SH7750State * s) -{ - if (s->scscr1 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) { - if (!s->serial1) { - fprintf(stderr, "serial port 1 not bound to anything\n"); - assert(0); - } - serial1_update_parameters(s); - } - if ((s->scscr1 & SH7750_SCSCR_RE) == 0) { - s->scssr1 |= SH7750_SCSSR1_TDRE; - } -} - -static void init_serial1(SH7750State * s, int serial_nb) -{ - CharDriverState *chr; - - s->scssr1 = 0x84; - chr = serial_hds[serial_nb]; - if (!chr) { - fprintf(stderr, - "no serial port associated to SH7750 first serial port\n"); - return; - } - - s->serial1 = chr; - qemu_chr_add_read_handler(chr, serial1_can_receive, - serial1_receive, s); - qemu_chr_add_event_handler(chr, serial1_event); -} - -/********************************************************************** - Second serial port -**********************************************************************/ - -static int serial2_can_receive(void *opaque) -{ - SH7750State *s = opaque; - static uint8_t max_fifo_size[] = { 15, 1, 4, 6, 8, 10, 12, 14 }; - - return s->serial2_receive_fifo.length < - max_fifo_size[(s->scfcr2 >> 9) & 7]; -} - -static void serial2_adjust_receive_flags(SH7750State * s) -{ - static uint8_t max_fifo_size[] = { 1, 4, 8, 14 }; - - /* XXXXX Add interrupt generation */ - if (s->serial2_receive_fifo.length >= - max_fifo_size[(s->scfcr2 >> 7) & 3]) { - s->scfsr2 |= SH7750_SCFSR2_RDF; - s->scfsr2 &= ~SH7750_SCFSR2_DR; - } else { - s->scfsr2 &= ~SH7750_SCFSR2_RDF; - if (s->serial2_receive_fifo.length > 0) - s->scfsr2 |= SH7750_SCFSR2_DR; - else - s->scfsr2 &= ~SH7750_SCFSR2_DR; - } -} - -static void serial2_append_char(SH7750State * s, uint8_t c) -{ - if (s->serial2_receive_fifo.length == 16) { - /* Overflow */ - s->sclsr2 |= SH7750_SCLSR2_ORER; - return; - } - - s->serial2_receive_fifo.data[s->serial2_receive_fifo.write_idx++] = c; - s->serial2_receive_fifo.length++; - serial2_adjust_receive_flags(s); -} - -static void serial2_receive(void *opaque, const uint8_t * buf, int size) -{ - SH7750State *s = opaque; - int i; - - for (i = 0; i < size; i++) - serial2_append_char(s, buf[i]); -} - -static void serial2_event(void *opaque, int event) -{ - /* XXXXX */ - assert(0); -} - -static void serial2_update_parameters(SH7750State * s) -{ - QEMUSerialSetParams ssp; - - if (s->scsmr2 & SH7750_SCSMR_CHR_7) - ssp.data_bits = 7; - else - ssp.data_bits = 8; - if (s->scsmr2 & SH7750_SCSMR_PE) { - if (s->scsmr2 & SH7750_SCSMR_PM_ODD) - ssp.parity = 'O'; - else - ssp.parity = 'E'; - } else - ssp.parity = 'N'; - if (s->scsmr2 & SH7750_SCSMR_STOP_2) - ssp.stop_bits = 2; - else - ssp.stop_bits = 1; - fprintf(stderr, "SCSMR2=%04x SCBRR2=%02x\n", s->scsmr2, s->scbrr2); - ssp.speed = s->periph_freq / - (32 * s->scbrr2 * (1 << (2 * (s->scsmr2 & 3)))) - 1; - fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n", - ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed); - qemu_chr_ioctl(s->serial2, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); -} - -static void scscr2_changed(SH7750State * s) -{ - if (s->scscr2 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) { - if (!s->serial2) { - fprintf(stderr, "serial port 2 not bound to anything\n"); - assert(0); - } - serial2_update_parameters(s); - } -} - -static void init_serial2(SH7750State * s, int serial_nb) -{ - CharDriverState *chr; - - s->scfsr2 = 0x0060; - - chr = serial_hds[serial_nb]; - if (!chr) { - fprintf(stderr, - "no serial port associated to SH7750 second serial port\n"); - return; - } - - s->serial2 = chr; - qemu_chr_add_read_handler(chr, serial2_can_receive, - serial2_receive, s); - qemu_chr_add_event_handler(chr, serial2_event); -} - -static void init_serial_ports(SH7750State * s) -{ - init_serial1(s, 0); - init_serial2(s, 1); -} - -/********************************************************************** - I/O ports -**********************************************************************/ - -int sh7750_register_io_device(SH7750State * s, sh7750_io_device * device) -{ - int i; - - for (i = 0; i < NB_DEVICES; i++) { - if (s->devices[i] == NULL) { - s->devices[i] = device; - return 0; - } - } - return -1; -} - -static uint16_t portdir(uint32_t v) -{ -#define EVENPORTMASK(n) ((v & (1<<((n)<<1))) >> (n)) - return - EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) | - EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) | - EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) | - EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) | - EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) | - EVENPORTMASK(0); -} - -static uint16_t portpullup(uint32_t v) -{ -#define ODDPORTMASK(n) ((v & (1<<(((n)<<1)+1))) >> (n)) - return - ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) | - ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) | - ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) | - ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) | - ODDPORTMASK(1) | ODDPORTMASK(0); -} - -static uint16_t porta_lines(SH7750State * s) -{ - return (s->portdira & s->pdtra) | /* CPU */ - (s->periph_portdira & s->periph_pdtra) | /* Peripherals */ - (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */ -} - -static uint16_t portb_lines(SH7750State * s) -{ - return (s->portdirb & s->pdtrb) | /* CPU */ - (s->periph_portdirb & s->periph_pdtrb) | /* Peripherals */ - (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */ -} - -static void gen_port_interrupts(SH7750State * s) -{ - /* XXXXX interrupts not generated */ -} - -static void porta_changed(SH7750State * s, uint16_t prev) -{ - uint16_t currenta, changes; - int i, r = 0; - -#if 0 - fprintf(stderr, "porta changed from 0x%04x to 0x%04x\n", - prev, porta_lines(s)); - fprintf(stderr, "pdtra=0x%04x, pctra=0x%08x\n", s->pdtra, s->pctra); -#endif - currenta = porta_lines(s); - if (currenta == prev) - return; - changes = currenta ^ prev; - - for (i = 0; i < NB_DEVICES; i++) { - if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) { - r |= s->devices[i]->port_change_cb(currenta, portb_lines(s), - &s->periph_pdtra, - &s->periph_portdira, - &s->periph_pdtrb, - &s->periph_portdirb); - } - } - - if (r) - gen_port_interrupts(s); -} - -static void portb_changed(SH7750State * s, uint16_t prev) -{ - uint16_t currentb, changes; - int i, r = 0; - - currentb = portb_lines(s); - if (currentb == prev) - return; - changes = currentb ^ prev; - - for (i = 0; i < NB_DEVICES; i++) { - if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) { - r |= s->devices[i]->port_change_cb(portb_lines(s), currentb, - &s->periph_pdtra, - &s->periph_portdira, - &s->periph_pdtrb, - &s->periph_portdirb); - } - } - - if (r) - gen_port_interrupts(s); -} - -/********************************************************************** - Memory -**********************************************************************/ - -static void error_access(const char *kind, target_phys_addr_t addr) -{ - fprintf(stderr, "%s to %s (0x%08x) not supported\n", - kind, regname(addr), addr); -} - -static void ignore_access(const char *kind, target_phys_addr_t addr) -{ - fprintf(stderr, "%s to %s (0x%08x) ignored\n", - kind, regname(addr), addr); -} - -static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr) -{ - SH7750State *s = opaque; - uint8_t r; - - switch (addr) { - case SH7750_SCSSR1_A7: - r = s->scssr1; - s->scssr1_read |= r; - return s->scssr1; - case SH7750_SCRDR1_A7: - s->scssr1 &= ~SH7750_SCSSR1_RDRF; - return s->scrdr1; - default: - error_access("byte read", addr); - assert(0); - } -} - -static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) -{ - SH7750State *s = opaque; - uint16_t r; - - switch (addr) { - case SH7750_RFCR_A7: - fprintf(stderr, - "Read access to refresh count register, incrementing\n"); - return s->rfcr++; - case SH7750_TCR0_A7: - return s->tcr0; - case SH7750_SCLSR2_A7: - /* Read and clear overflow bit */ - r = s->sclsr2; - s->sclsr2 = 0; - return r; - case SH7750_SCSFR2_A7: - return s->scfsr2; - case SH7750_PDTRA_A7: - return porta_lines(s); - case SH7750_PDTRB_A7: - return portb_lines(s); - default: - error_access("word read", addr); - assert(0); - } -} - -static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SH7750State *s = opaque; - - switch (addr) { - case SH7750_MMUCR_A7: - return s->cpu->mmucr; - case SH7750_PTEH_A7: - return s->cpu->pteh; - case SH7750_PTEL_A7: - return s->cpu->ptel; - case SH7750_TTB_A7: - return s->cpu->ttb; - case SH7750_TEA_A7: - return s->cpu->tea; - case SH7750_TRA_A7: - return s->cpu->tra; - case SH7750_EXPEVT_A7: - return s->cpu->expevt; - case SH7750_INTEVT_A7: - return s->cpu->intevt; - case SH7750_CCR_A7: - return s->ccr; - case 0x1f000030: /* Processor version PVR */ - return 0x00050000; /* SH7750R */ - case 0x1f000040: /* Processor version CVR */ - return 0x00110000; /* Minimum caches */ - case 0x1f000044: /* Processor version PRR */ - return 0x00000100; /* SH7750R */ - default: - error_access("long read", addr); - assert(0); - } -} - -static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr, - uint32_t mem_value) -{ - SH7750State *s = opaque; - - switch (addr) { - /* PRECHARGE ? XXXXX */ - case SH7750_PRECHARGE0_A7: - case SH7750_PRECHARGE1_A7: - ignore_access("byte write", addr); - return; - case SH7750_SCBRR2_A7: - s->scbrr2 = mem_value; - return; - case SH7750_TSTR_A7: - s->tstr = mem_value; - timer_start_changed(s); - return; - case SH7750_SCSCR1_A7: - s->scscr1 = mem_value; - scscr1_changed(s); - return; - case SH7750_SCSMR1_A7: - s->scsmr1 = mem_value; - return; - case SH7750_SCBRR1_A7: - s->scbrr1 = mem_value; - return; - case SH7750_SCTDR1_A7: - s->scssr1 &= ~SH7750_SCSSR1_TEND; - s->sctdr1 = mem_value; - return; - case SH7750_SCSSR1_A7: - serial1_change_scssr1(s, mem_value); - return; - default: - error_access("byte write", addr); - assert(0); - } -} - -static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, - uint32_t mem_value) -{ - SH7750State *s = opaque; - uint16_t temp; - - switch (addr) { - /* SDRAM controller */ - case SH7750_SCBRR1_A7: - case SH7750_SCBRR2_A7: - case SH7750_BCR2_A7: - case SH7750_BCR3_A7: - case SH7750_RTCOR_A7: - case SH7750_RTCNT_A7: - case SH7750_RTCSR_A7: - ignore_access("word write", addr); - return; - /* IO ports */ - case SH7750_PDTRA_A7: - temp = porta_lines(s); - s->pdtra = mem_value; - porta_changed(s, temp); - return; - case SH7750_PDTRB_A7: - temp = portb_lines(s); - s->pdtrb = mem_value; - portb_changed(s, temp); - return; - case SH7750_RFCR_A7: - fprintf(stderr, "Write access to refresh count register\n"); - s->rfcr = mem_value; - return; - case SH7750_SCLSR2_A7: - s->sclsr2 = mem_value; - return; - case SH7750_SCSCR2_A7: - s->scscr2 = mem_value; - scscr2_changed(s); - return; - case SH7750_SCFCR2_A7: - s->scfcr2 = mem_value; - return; - case SH7750_SCSMR2_A7: - s->scsmr2 = mem_value; - return; - case SH7750_TCR0_A7: - s->tcr0 = mem_value; - return; - case SH7750_GPIOIC_A7: - s->gpioic = mem_value; - if (mem_value != 0) { - fprintf(stderr, "I/O interrupts not implemented\n"); - assert(0); - } - return; - default: - error_access("word write", addr); - assert(0); - } -} - -static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, - uint32_t mem_value) -{ - SH7750State *s = opaque; - uint16_t temp; - - switch (addr) { - /* SDRAM controller */ - case SH7750_BCR1_A7: - case SH7750_BCR4_A7: - case SH7750_WCR1_A7: - case SH7750_WCR2_A7: - case SH7750_WCR3_A7: - case SH7750_MCR_A7: - ignore_access("long write", addr); - return; - /* IO ports */ - case SH7750_PCTRA_A7: - temp = porta_lines(s); - s->pctra = mem_value; - s->portdira = portdir(mem_value); - s->portpullupa = portpullup(mem_value); - porta_changed(s, temp); - return; - case SH7750_PCTRB_A7: - temp = portb_lines(s); - s->pctrb = mem_value; - s->portdirb = portdir(mem_value); - s->portpullupb = portpullup(mem_value); - portb_changed(s, temp); - return; - case SH7750_TCNT0_A7: - s->tcnt0 = mem_value & 0xf; - return; - case SH7750_MMUCR_A7: - s->cpu->mmucr = mem_value; - return; - case SH7750_PTEH_A7: - s->cpu->pteh = mem_value; - return; - case SH7750_PTEL_A7: - s->cpu->ptel = mem_value; - return; - case SH7750_TTB_A7: - s->cpu->ttb = mem_value; - return; - case SH7750_TEA_A7: - s->cpu->tea = mem_value; - return; - case SH7750_TRA_A7: - s->cpu->tra = mem_value & 0x000007ff; - return; - case SH7750_EXPEVT_A7: - s->cpu->expevt = mem_value & 0x000007ff; - return; - case SH7750_INTEVT_A7: - s->cpu->intevt = mem_value & 0x000007ff; - return; - case SH7750_CCR_A7: - s->ccr = mem_value; - return; - default: - error_access("long write", addr); - assert(0); - } -} - -static CPUReadMemoryFunc *sh7750_mem_read[] = { - sh7750_mem_readb, - sh7750_mem_readw, - sh7750_mem_readl -}; - -static CPUWriteMemoryFunc *sh7750_mem_write[] = { - sh7750_mem_writeb, - sh7750_mem_writew, - sh7750_mem_writel -}; - -SH7750State *sh7750_init(CPUSH4State * cpu) -{ - SH7750State *s; - int sh7750_io_memory; - - s = qemu_mallocz(sizeof(SH7750State)); - s->cpu = cpu; - s->periph_freq = 60000000; /* 60MHz */ - sh7750_io_memory = cpu_register_io_memory(0, - sh7750_mem_read, - sh7750_mem_write, s); - cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory); - init_timers(s); - init_serial_ports(s); - return s; -} diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c deleted file mode 100644 index 5fcb0d6..0000000 --- a/hw/sh7750_regnames.c +++ /dev/null @@ -1,128 +0,0 @@ -#include "vl.h" -#include "sh7750_regs.h" - -#define REGNAME(r) {r, #r}, - -typedef struct { - uint32_t regaddr; - const char *regname; -} regname_t; - -static regname_t regnames[] = { - REGNAME(SH7750_PTEH_A7) - REGNAME(SH7750_PTEL_A7) - REGNAME(SH7750_PTEA_A7) - REGNAME(SH7750_TTB_A7) - REGNAME(SH7750_TEA_A7) - REGNAME(SH7750_MMUCR_A7) - REGNAME(SH7750_CCR_A7) - REGNAME(SH7750_QACR0_A7) - REGNAME(SH7750_QACR1_A7) - REGNAME(SH7750_TRA_A7) - REGNAME(SH7750_EXPEVT_A7) - REGNAME(SH7750_INTEVT_A7) - REGNAME(SH7750_STBCR_A7) - REGNAME(SH7750_STBCR2_A7) - REGNAME(SH7750_FRQCR_A7) - REGNAME(SH7750_WTCNT_A7) - REGNAME(SH7750_WTCSR_A7) - REGNAME(SH7750_R64CNT_A7) - REGNAME(SH7750_RSECCNT_A7) - REGNAME(SH7750_RMINCNT_A7) - REGNAME(SH7750_RHRCNT_A7) - REGNAME(SH7750_RWKCNT_A7) - REGNAME(SH7750_RDAYCNT_A7) - REGNAME(SH7750_RMONCNT_A7) - REGNAME(SH7750_RYRCNT_A7) - REGNAME(SH7750_RSECAR_A7) - REGNAME(SH7750_RMINAR_A7) - REGNAME(SH7750_RHRAR_A7) - REGNAME(SH7750_RWKAR_A7) - REGNAME(SH7750_RDAYAR_A7) - REGNAME(SH7750_RMONAR_A7) - REGNAME(SH7750_RCR1_A7) - REGNAME(SH7750_RCR2_A7) - REGNAME(SH7750_TOCR_A7) - REGNAME(SH7750_TSTR_A7) - REGNAME(SH7750_TCOR0_A7) - REGNAME(SH7750_TCOR1_A7) - REGNAME(SH7750_TCOR2_A7) - REGNAME(SH7750_TCNT0_A7) - REGNAME(SH7750_TCNT1_A7) - REGNAME(SH7750_TCNT2_A7) - REGNAME(SH7750_TCR0_A7) - REGNAME(SH7750_TCR1_A7) - REGNAME(SH7750_TCR2_A7) - REGNAME(SH7750_TCPR2_A7) - REGNAME(SH7750_BCR1_A7) - REGNAME(SH7750_BCR2_A7) - REGNAME(SH7750_WCR1_A7) - REGNAME(SH7750_WCR2_A7) - REGNAME(SH7750_WCR3_A7) - REGNAME(SH7750_MCR_A7) - REGNAME(SH7750_PCR_A7) - REGNAME(SH7750_RTCSR_A7) - REGNAME(SH7750_RTCNT_A7) - REGNAME(SH7750_RTCOR_A7) - REGNAME(SH7750_RFCR_A7) - REGNAME(SH7750_SAR0_A7) - REGNAME(SH7750_SAR1_A7) - REGNAME(SH7750_SAR2_A7) - REGNAME(SH7750_SAR3_A7) - REGNAME(SH7750_DAR0_A7) - REGNAME(SH7750_DAR1_A7) - REGNAME(SH7750_DAR2_A7) - REGNAME(SH7750_DAR3_A7) - REGNAME(SH7750_DMATCR0_A7) - REGNAME(SH7750_DMATCR1_A7) - REGNAME(SH7750_DMATCR2_A7) - REGNAME(SH7750_DMATCR3_A7) - REGNAME(SH7750_CHCR0_A7) - REGNAME(SH7750_CHCR1_A7) - REGNAME(SH7750_CHCR2_A7) - REGNAME(SH7750_CHCR3_A7) - REGNAME(SH7750_DMAOR_A7) - REGNAME(SH7750_SCRDR1_A7) - REGNAME(SH7750_SCRDR2_A7) - REGNAME(SH7750_SCTDR1_A7) - REGNAME(SH7750_SCTDR2_A7) - REGNAME(SH7750_SCSMR1_A7) - REGNAME(SH7750_SCSMR2_A7) - REGNAME(SH7750_SCSCR1_A7) - REGNAME(SH7750_SCSCR2_A7) - REGNAME(SH7750_SCSSR1_A7) - REGNAME(SH7750_SCSFR2_A7) - REGNAME(SH7750_SCSPTR1_A7) - REGNAME(SH7750_SCSPTR2_A7) - REGNAME(SH7750_SCBRR1_A7) - REGNAME(SH7750_SCBRR2_A7) - REGNAME(SH7750_SCFCR2_A7) - REGNAME(SH7750_SCFDR2_A7) - REGNAME(SH7750_SCLSR2_A7) - REGNAME(SH7750_SCSCMR1_A7) - REGNAME(SH7750_PCTRA_A7) - REGNAME(SH7750_PDTRA_A7) - REGNAME(SH7750_PCTRB_A7) - REGNAME(SH7750_PDTRB_A7) - REGNAME(SH7750_GPIOIC_A7) - REGNAME(SH7750_ICR_A7) - REGNAME(SH7750_IPRA_A7) - REGNAME(SH7750_IPRB_A7) - REGNAME(SH7750_IPRC_A7) - REGNAME(SH7750_BCR3_A7) - REGNAME(SH7750_BCR4_A7) - REGNAME(SH7750_PRECHARGE0_A7) - REGNAME(SH7750_PRECHARGE1_A7) {(uint32_t) - 1, 0} -}; - -const char *regname(uint32_t addr) -{ - unsigned int i; - - for (i = 0; regnames[i].regaddr != (uint32_t) - 1; i++) { - if (regnames[i].regaddr == addr) - return regnames[i].regname; - } - - return "<unknown reg>"; -} diff --git a/hw/sh7750_regnames.h b/hw/sh7750_regnames.h deleted file mode 100644 index 7463709..0000000 --- a/hw/sh7750_regnames.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _SH7750_REGNAMES_H -#define _SH7750_REGNAMES_H - -const char *regname(uint32_t addr); - -#endif /* _SH7750_REGNAMES_H */ diff --git a/hw/sh7750_regs.h b/hw/sh7750_regs.h deleted file mode 100644 index 44ae95b..0000000 --- a/hw/sh7750_regs.h +++ /dev/null @@ -1,1623 +0,0 @@ -/* - * SH-7750 memory-mapped registers - * This file based on information provided in the following document: - * "Hitachi SuperH (tm) RISC engine. SH7750 Series (SH7750, SH7750S) - * Hardware Manual" - * Document Number ADE-602-124C, Rev. 4.0, 4/21/00, Hitachi Ltd. - * - * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia - * Author: Alexandra Kossovsky <sasha@oktet.ru> - * Victor V. Vengerov <vvv@oktet.ru> - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.com/license/LICENSE. - * - * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp - */ - -#ifndef __SH7750_REGS_H__ -#define __SH7750_REGS_H__ - -/* - * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address) and - * in 0x1f000000 - 0x1fffffff (area 7 address) - */ -#define SH7750_P4_BASE 0xff000000 /* Accessable only in - priveleged mode */ -#define SH7750_A7_BASE 0x1f000000 /* Accessable only using TLB */ - -#define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs)) -#define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs)) - -/* - * MMU Registers - */ - -/* Page Table Entry High register - PTEH */ -#define SH7750_PTEH_REGOFS 0x000000 /* offset */ -#define SH7750_PTEH SH7750_P4_REG32(SH7750_PTEH_REGOFS) -#define SH7750_PTEH_A7 SH7750_A7_REG32(SH7750_PTEH_REGOFS) -#define SH7750_PTEH_VPN 0xfffffd00 /* Virtual page number */ -#define SH7750_PTEH_VPN_S 10 -#define SH7750_PTEH_ASID 0x000000ff /* Address space identifier */ -#define SH7750_PTEH_ASID_S 0 - -/* Page Table Entry Low register - PTEL */ -#define SH7750_PTEL_REGOFS 0x000004 /* offset */ -#define SH7750_PTEL SH7750_P4_REG32(SH7750_PTEL_REGOFS) -#define SH7750_PTEL_A7 SH7750_A7_REG32(SH7750_PTEL_REGOFS) -#define SH7750_PTEL_PPN 0x1ffffc00 /* Physical page number */ -#define SH7750_PTEL_PPN_S 10 -#define SH7750_PTEL_V 0x00000100 /* Validity (0-entry is invalid) */ -#define SH7750_PTEL_SZ1 0x00000080 /* Page size bit 1 */ -#define SH7750_PTEL_SZ0 0x00000010 /* Page size bit 0 */ -#define SH7750_PTEL_SZ_1KB 0x00000000 /* 1-kbyte page */ -#define SH7750_PTEL_SZ_4KB 0x00000010 /* 4-kbyte page */ -#define SH7750_PTEL_SZ_64KB 0x00000080 /* 64-kbyte page */ -#define SH7750_PTEL_SZ_1MB 0x00000090 /* 1-Mbyte page */ -#define SH7750_PTEL_PR 0x00000060 /* Protection Key Data */ -#define SH7750_PTEL_PR_ROPO 0x00000000 /* read-only in priv mode */ -#define SH7750_PTEL_PR_RWPO 0x00000020 /* read-write in priv mode */ -#define SH7750_PTEL_PR_ROPU 0x00000040 /* read-only in priv or user mode */ -#define SH7750_PTEL_PR_RWPU 0x00000060 /* read-write in priv or user mode */ -#define SH7750_PTEL_C 0x00000008 /* Cacheability - (0 - page not cacheable) */ -#define SH7750_PTEL_D 0x00000004 /* Dirty bit (1 - write has been - performed to a page) */ -#define SH7750_PTEL_SH 0x00000002 /* Share Status bit (1 - page are - shared by processes) */ -#define SH7750_PTEL_WT 0x00000001 /* Write-through bit, specifies the - cache write mode: - 0 - Copy-back mode - 1 - Write-through mode */ - -/* Page Table Entry Assistance register - PTEA */ -#define SH7750_PTEA_REGOFS 0x000034 /* offset */ -#define SH7750_PTEA SH7750_P4_REG32(SH7750_PTEA_REGOFS) -#define SH7750_PTEA_A7 SH7750_A7_REG32(SH7750_PTEA_REGOFS) -#define SH7750_PTEA_TC 0x00000008 /* Timing Control bit - 0 - use area 5 wait states - 1 - use area 6 wait states */ -#define SH7750_PTEA_SA 0x00000007 /* Space Attribute bits: */ -#define SH7750_PTEA_SA_UNDEF 0x00000000 /* 0 - undefined */ -#define SH7750_PTEA_SA_IOVAR 0x00000001 /* 1 - variable-size I/O space */ -#define SH7750_PTEA_SA_IO8 0x00000002 /* 2 - 8-bit I/O space */ -#define SH7750_PTEA_SA_IO16 0x00000003 /* 3 - 16-bit I/O space */ -#define SH7750_PTEA_SA_CMEM8 0x00000004 /* 4 - 8-bit common memory space */ -#define SH7750_PTEA_SA_CMEM16 0x00000005 /* 5 - 16-bit common memory space */ -#define SH7750_PTEA_SA_AMEM8 0x00000006 /* 6 - 8-bit attr memory space */ -#define SH7750_PTEA_SA_AMEM16 0x00000007 /* 7 - 16-bit attr memory space */ - - -/* Translation table base register */ -#define SH7750_TTB_REGOFS 0x000008 /* offset */ -#define SH7750_TTB SH7750_P4_REG32(SH7750_TTB_REGOFS) -#define SH7750_TTB_A7 SH7750_A7_REG32(SH7750_TTB_REGOFS) - -/* TLB exeption address register - TEA */ -#define SH7750_TEA_REGOFS 0x00000c /* offset */ -#define SH7750_TEA SH7750_P4_REG32(SH7750_TEA_REGOFS) -#define SH7750_TEA_A7 SH7750_A7_REG32(SH7750_TEA_REGOFS) - -/* MMU control register - MMUCR */ -#define SH7750_MMUCR_REGOFS 0x000010 /* offset */ -#define SH7750_MMUCR SH7750_P4_REG32(SH7750_MMUCR_REGOFS) -#define SH7750_MMUCR_A7 SH7750_A7_REG32(SH7750_MMUCR_REGOFS) -#define SH7750_MMUCR_AT 0x00000001 /* Address translation bit */ -#define SH7750_MMUCR_TI 0x00000004 /* TLB invalidate */ -#define SH7750_MMUCR_SV 0x00000100 /* Single Virtual Mode bit */ -#define SH7750_MMUCR_SQMD 0x00000200 /* Store Queue Mode bit */ -#define SH7750_MMUCR_URC 0x0000FC00 /* UTLB Replace Counter */ -#define SH7750_MMUCR_URC_S 10 -#define SH7750_MMUCR_URB 0x00FC0000 /* UTLB Replace Boundary */ -#define SH7750_MMUCR_URB_S 18 -#define SH7750_MMUCR_LRUI 0xFC000000 /* Least Recently Used ITLB */ -#define SH7750_MMUCR_LRUI_S 26 - - - - -/* - * Cache registers - * IC -- instructions cache - * OC -- operand cache - */ - -/* Cache Control Register - CCR */ -#define SH7750_CCR_REGOFS 0x00001c /* offset */ -#define SH7750_CCR SH7750_P4_REG32(SH7750_CCR_REGOFS) -#define SH7750_CCR_A7 SH7750_A7_REG32(SH7750_CCR_REGOFS) - -#define SH7750_CCR_IIX 0x00008000 /* IC index enable bit */ -#define SH7750_CCR_ICI 0x00000800 /* IC invalidation bit: - set it to clear IC */ -#define SH7750_CCR_ICE 0x00000100 /* IC enable bit */ -#define SH7750_CCR_OIX 0x00000080 /* OC index enable bit */ -#define SH7750_CCR_ORA 0x00000020 /* OC RAM enable bit - if you set OCE = 0, - you should set ORA = 0 */ -#define SH7750_CCR_OCI 0x00000008 /* OC invalidation bit */ -#define SH7750_CCR_CB 0x00000004 /* Copy-back bit for P1 area */ -#define SH7750_CCR_WT 0x00000002 /* Write-through bit for P0,U0,P3 area */ -#define SH7750_CCR_OCE 0x00000001 /* OC enable bit */ - -/* Queue address control register 0 - QACR0 */ -#define SH7750_QACR0_REGOFS 0x000038 /* offset */ -#define SH7750_QACR0 SH7750_P4_REG32(SH7750_QACR0_REGOFS) -#define SH7750_QACR0_A7 SH7750_A7_REG32(SH7750_QACR0_REGOFS) - -/* Queue address control register 1 - QACR1 */ -#define SH7750_QACR1_REGOFS 0x00003c /* offset */ -#define SH7750_QACR1 SH7750_P4_REG32(SH7750_QACR1_REGOFS) -#define SH7750_QACR1_A7 SH7750_A7_REG32(SH7750_QACR1_REGOFS) - - -/* - * Exeption-related registers - */ - -/* Immediate data for TRAPA instuction - TRA */ -#define SH7750_TRA_REGOFS 0x000020 /* offset */ -#define SH7750_TRA SH7750_P4_REG32(SH7750_TRA_REGOFS) -#define SH7750_TRA_A7 SH7750_A7_REG32(SH7750_TRA_REGOFS) - -#define SH7750_TRA_IMM 0x000003fd /* Immediate data operand */ -#define SH7750_TRA_IMM_S 2 - -/* Exeption event register - EXPEVT */ -#define SH7750_EXPEVT_REGOFS 0x000024 -#define SH7750_EXPEVT SH7750_P4_REG32(SH7750_EXPEVT_REGOFS) -#define SH7750_EXPEVT_A7 SH7750_A7_REG32(SH7750_EXPEVT_REGOFS) - -#define SH7750_EXPEVT_EX 0x00000fff /* Exeption code */ -#define SH7750_EXPEVT_EX_S 0 - -/* Interrupt event register */ -#define SH7750_INTEVT_REGOFS 0x000028 -#define SH7750_INTEVT SH7750_P4_REG32(SH7750_INTEVT_REGOFS) -#define SH7750_INTEVT_A7 SH7750_A7_REG32(SH7750_INTEVT_REGOFS) -#define SH7750_INTEVT_EX 0x00000fff /* Exeption code */ -#define SH7750_INTEVT_EX_S 0 - -/* - * Exception/interrupt codes - */ -#define SH7750_EVT_TO_NUM(evt) ((evt) >> 5) - -/* Reset exception category */ -#define SH7750_EVT_POWER_ON_RST 0x000 /* Power-on reset */ -#define SH7750_EVT_MANUAL_RST 0x020 /* Manual reset */ -#define SH7750_EVT_TLB_MULT_HIT 0x140 /* TLB multiple-hit exception */ - -/* General exception category */ -#define SH7750_EVT_USER_BREAK 0x1E0 /* User break */ -#define SH7750_EVT_IADDR_ERR 0x0E0 /* Instruction address error */ -#define SH7750_EVT_TLB_READ_MISS 0x040 /* ITLB miss exception / - DTLB miss exception (read) */ -#define SH7750_EVT_TLB_READ_PROTV 0x0A0 /* ITLB protection violation / - DTLB protection violation (read) */ -#define SH7750_EVT_ILLEGAL_INSTR 0x180 /* General Illegal Instruction - exception */ -#define SH7750_EVT_SLOT_ILLEGAL_INSTR 0x1A0 /* Slot Illegal Instruction - exception */ -#define SH7750_EVT_FPU_DISABLE 0x800 /* General FPU disable exception */ -#define SH7750_EVT_SLOT_FPU_DISABLE 0x820 /* Slot FPU disable exception */ -#define SH7750_EVT_DATA_READ_ERR 0x0E0 /* Data address error (read) */ -#define SH7750_EVT_DATA_WRITE_ERR 0x100 /* Data address error (write) */ -#define SH7750_EVT_DTLB_WRITE_MISS 0x060 /* DTLB miss exception (write) */ -#define SH7750_EVT_DTLB_WRITE_PROTV 0x0C0 /* DTLB protection violation - exception (write) */ -#define SH7750_EVT_FPU_EXCEPTION 0x120 /* FPU exception */ -#define SH7750_EVT_INITIAL_PGWRITE 0x080 /* Initial Page Write exception */ -#define SH7750_EVT_TRAPA 0x160 /* Unconditional trap (TRAPA) */ - -/* Interrupt exception category */ -#define SH7750_EVT_NMI 0x1C0 /* Non-maskable interrupt */ -#define SH7750_EVT_IRQ0 0x200 /* External Interrupt 0 */ -#define SH7750_EVT_IRQ1 0x220 /* External Interrupt 1 */ -#define SH7750_EVT_IRQ2 0x240 /* External Interrupt 2 */ -#define SH7750_EVT_IRQ3 0x260 /* External Interrupt 3 */ -#define SH7750_EVT_IRQ4 0x280 /* External Interrupt 4 */ -#define SH7750_EVT_IRQ5 0x2A0 /* External Interrupt 5 */ -#define SH7750_EVT_IRQ6 0x2C0 /* External Interrupt 6 */ -#define SH7750_EVT_IRQ7 0x2E0 /* External Interrupt 7 */ -#define SH7750_EVT_IRQ8 0x300 /* External Interrupt 8 */ -#define SH7750_EVT_IRQ9 0x320 /* External Interrupt 9 */ -#define SH7750_EVT_IRQA 0x340 /* External Interrupt A */ -#define SH7750_EVT_IRQB 0x360 /* External Interrupt B */ -#define SH7750_EVT_IRQC 0x380 /* External Interrupt C */ -#define SH7750_EVT_IRQD 0x3A0 /* External Interrupt D */ -#define SH7750_EVT_IRQE 0x3C0 /* External Interrupt E */ - -/* Peripheral Module Interrupts - Timer Unit (TMU) */ -#define SH7750_EVT_TUNI0 0x400 /* TMU Underflow Interrupt 0 */ -#define SH7750_EVT_TUNI1 0x420 /* TMU Underflow Interrupt 1 */ -#define SH7750_EVT_TUNI2 0x440 /* TMU Underflow Interrupt 2 */ -#define SH7750_EVT_TICPI2 0x460 /* TMU Input Capture Interrupt 2 */ - -/* Peripheral Module Interrupts - Real-Time Clock (RTC) */ -#define SH7750_EVT_RTC_ATI 0x480 /* Alarm Interrupt Request */ -#define SH7750_EVT_RTC_PRI 0x4A0 /* Periodic Interrupt Request */ -#define SH7750_EVT_RTC_CUI 0x4C0 /* Carry Interrupt Request */ - -/* Peripheral Module Interrupts - Serial Communication Interface (SCI) */ -#define SH7750_EVT_SCI_ERI 0x4E0 /* Receive Error */ -#define SH7750_EVT_SCI_RXI 0x500 /* Receive Data Register Full */ -#define SH7750_EVT_SCI_TXI 0x520 /* Transmit Data Register Empty */ -#define SH7750_EVT_SCI_TEI 0x540 /* Transmit End */ - -/* Peripheral Module Interrupts - Watchdog Timer (WDT) */ -#define SH7750_EVT_WDT_ITI 0x560 /* Interval Timer Interrupt - (used when WDT operates in - interval timer mode) */ - -/* Peripheral Module Interrupts - Memory Refresh Unit (REF) */ -#define SH7750_EVT_REF_RCMI 0x580 /* Compare-match Interrupt */ -#define SH7750_EVT_REF_ROVI 0x5A0 /* Refresh Counter Overflow - interrupt */ - -/* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */ -#define SH7750_EVT_HUDI 0x600 /* UDI interrupt */ - -/* Peripheral Module Interrupts - General-Purpose I/O (GPIO) */ -#define SH7750_EVT_GPIO 0x620 /* GPIO Interrupt */ - -/* Peripheral Module Interrupts - DMA Controller (DMAC) */ -#define SH7750_EVT_DMAC_DMTE0 0x640 /* DMAC 0 Transfer End Interrupt */ -#define SH7750_EVT_DMAC_DMTE1 0x660 /* DMAC 1 Transfer End Interrupt */ -#define SH7750_EVT_DMAC_DMTE2 0x680 /* DMAC 2 Transfer End Interrupt */ -#define SH7750_EVT_DMAC_DMTE3 0x6A0 /* DMAC 3 Transfer End Interrupt */ -#define SH7750_EVT_DMAC_DMAE 0x6C0 /* DMAC Address Error Interrupt */ - -/* Peripheral Module Interrupts - Serial Communication Interface with FIFO */ -/* (SCIF) */ -#define SH7750_EVT_SCIF_ERI 0x700 /* Receive Error */ -#define SH7750_EVT_SCIF_RXI 0x720 /* Receive FIFO Data Full or - Receive Data ready interrupt */ -#define SH7750_EVT_SCIF_BRI 0x740 /* Break or overrun error */ -#define SH7750_EVT_SCIF_TXI 0x760 /* Transmit FIFO Data Empty */ - -/* - * Power Management - */ -#define SH7750_STBCR_REGOFS 0xC00004 /* offset */ -#define SH7750_STBCR SH7750_P4_REG32(SH7750_STBCR_REGOFS) -#define SH7750_STBCR_A7 SH7750_A7_REG32(SH7750_STBCR_REGOFS) - -#define SH7750_STBCR_STBY 0x80 /* Specifies a transition to standby mode: - 0 - Transition to SLEEP mode on SLEEP - 1 - Transition to STANDBY mode on SLEEP */ -#define SH7750_STBCR_PHZ 0x40 /* State of peripheral module pins in - standby mode: - 0 - normal state - 1 - high-impendance state */ - -#define SH7750_STBCR_PPU 0x20 /* Peripheral module pins pull-up controls */ -#define SH7750_STBCR_MSTP4 0x10 /* Stopping the clock supply to DMAC */ -#define SH7750_STBCR_DMAC_STP SH7750_STBCR_MSTP4 -#define SH7750_STBCR_MSTP3 0x08 /* Stopping the clock supply to SCIF */ -#define SH7750_STBCR_SCIF_STP SH7750_STBCR_MSTP3 -#define SH7750_STBCR_MSTP2 0x04 /* Stopping the clock supply to TMU */ -#define SH7750_STBCR_TMU_STP SH7750_STBCR_MSTP2 -#define SH7750_STBCR_MSTP1 0x02 /* Stopping the clock supply to RTC */ -#define SH7750_STBCR_RTC_STP SH7750_STBCR_MSTP1 -#define SH7750_STBCR_MSPT0 0x01 /* Stopping the clock supply to SCI */ -#define SH7750_STBCR_SCI_STP SH7750_STBCR_MSTP0 - -#define SH7750_STBCR_STBY 0x80 - - -#define SH7750_STBCR2_REGOFS 0xC00010 /* offset */ -#define SH7750_STBCR2 SH7750_P4_REG32(SH7750_STBCR2_REGOFS) -#define SH7750_STBCR2_A7 SH7750_A7_REG32(SH7750_STBCR2_REGOFS) - -#define SH7750_STBCR2_DSLP 0x80 /* Specifies transition to deep sleep mode: - 0 - transition to sleep or standby mode - as it is specified in STBY bit - 1 - transition to deep sleep mode on - execution of SLEEP instruction */ -#define SH7750_STBCR2_MSTP6 0x02 /* Stopping the clock supply to Store Queue - in the cache controller */ -#define SH7750_STBCR2_SQ_STP SH7750_STBCR2_MSTP6 -#define SH7750_STBCR2_MSTP5 0x01 /* Stopping the clock supply to the User - Break Controller (UBC) */ -#define SH7750_STBCR2_UBC_STP SH7750_STBCR2_MSTP5 - -/* - * Clock Pulse Generator (CPG) - */ -#define SH7750_FRQCR_REGOFS 0xC00000 /* offset */ -#define SH7750_FRQCR SH7750_P4_REG32(SH7750_FRQCR_REGOFS) -#define SH7750_FRQCR_A7 SH7750_A7_REG32(SH7750_FRQCR_REGOFS) - -#define SH7750_FRQCR_CKOEN 0x0800 /* Clock Output Enable - 0 - CKIO pin goes to HiZ/pullup - 1 - Clock is output from CKIO */ -#define SH7750_FRQCR_PLL1EN 0x0400 /* PLL circuit 1 enable */ -#define SH7750_FRQCR_PLL2EN 0x0200 /* PLL circuit 2 enable */ - -#define SH7750_FRQCR_IFC 0x01C0 /* CPU clock frequency division ratio: */ -#define SH7750_FRQCR_IFCDIV1 0x0000 /* 0 - * 1 */ -#define SH7750_FRQCR_IFCDIV2 0x0040 /* 1 - * 1/2 */ -#define SH7750_FRQCR_IFCDIV3 0x0080 /* 2 - * 1/3 */ -#define SH7750_FRQCR_IFCDIV4 0x00C0 /* 3 - * 1/4 */ -#define SH7750_FRQCR_IFCDIV6 0x0100 /* 4 - * 1/6 */ -#define SH7750_FRQCR_IFCDIV8 0x0140 /* 5 - * 1/8 */ - -#define SH7750_FRQCR_BFC 0x0038 /* Bus clock frequency division ratio: */ -#define SH7750_FRQCR_BFCDIV1 0x0000 /* 0 - * 1 */ -#define SH7750_FRQCR_BFCDIV2 0x0008 /* 1 - * 1/2 */ -#define SH7750_FRQCR_BFCDIV3 0x0010 /* 2 - * 1/3 */ -#define SH7750_FRQCR_BFCDIV4 0x0018 /* 3 - * 1/4 */ -#define SH7750_FRQCR_BFCDIV6 0x0020 /* 4 - * 1/6 */ -#define SH7750_FRQCR_BFCDIV8 0x0028 /* 5 - * 1/8 */ - -#define SH7750_FRQCR_PFC 0x0007 /* Peripheral module clock frequency - division ratio: */ -#define SH7750_FRQCR_PFCDIV2 0x0000 /* 0 - * 1/2 */ -#define SH7750_FRQCR_PFCDIV3 0x0001 /* 1 - * 1/3 */ -#define SH7750_FRQCR_PFCDIV4 0x0002 /* 2 - * 1/4 */ -#define SH7750_FRQCR_PFCDIV6 0x0003 /* 3 - * 1/6 */ -#define SH7750_FRQCR_PFCDIV8 0x0004 /* 4 - * 1/8 */ - -/* - * Watchdog Timer (WDT) - */ - -/* Watchdog Timer Counter register - WTCNT */ -#define SH7750_WTCNT_REGOFS 0xC00008 /* offset */ -#define SH7750_WTCNT SH7750_P4_REG32(SH7750_WTCNT_REGOFS) -#define SH7750_WTCNT_A7 SH7750_A7_REG32(SH7750_WTCNT_REGOFS) -#define SH7750_WTCNT_KEY 0x5A00 /* When WTCNT byte register written, - you have to set the upper byte to - 0x5A */ - -/* Watchdog Timer Control/Status register - WTCSR */ -#define SH7750_WTCSR_REGOFS 0xC0000C /* offset */ -#define SH7750_WTCSR SH7750_P4_REG32(SH7750_WTCSR_REGOFS) -#define SH7750_WTCSR_A7 SH7750_A7_REG32(SH7750_WTCSR_REGOFS) -#define SH7750_WTCSR_KEY 0xA500 /* When WTCSR byte register written, - you have to set the upper byte to - 0xA5 */ -#define SH7750_WTCSR_TME 0x80 /* Timer enable (1-upcount start) */ -#define SH7750_WTCSR_MODE 0x40 /* Timer Mode Select: */ -#define SH7750_WTCSR_MODE_WT 0x40 /* Watchdog Timer Mode */ -#define SH7750_WTCSR_MODE_IT 0x00 /* Interval Timer Mode */ -#define SH7750_WTCSR_RSTS 0x20 /* Reset Select: */ -#define SH7750_WTCSR_RST_MAN 0x20 /* Manual Reset */ -#define SH7750_WTCSR_RST_PWR 0x00 /* Power-on Reset */ -#define SH7750_WTCSR_WOVF 0x10 /* Watchdog Timer Overflow Flag */ -#define SH7750_WTCSR_IOVF 0x08 /* Interval Timer Overflow Flag */ -#define SH7750_WTCSR_CKS 0x07 /* Clock Select: */ -#define SH7750_WTCSR_CKS_DIV32 0x00 /* 1/32 of frequency divider 2 input */ -#define SH7750_WTCSR_CKS_DIV64 0x01 /* 1/64 */ -#define SH7750_WTCSR_CKS_DIV128 0x02 /* 1/128 */ -#define SH7750_WTCSR_CKS_DIV256 0x03 /* 1/256 */ -#define SH7750_WTCSR_CKS_DIV512 0x04 /* 1/512 */ -#define SH7750_WTCSR_CKS_DIV1024 0x05 /* 1/1024 */ -#define SH7750_WTCSR_CKS_DIV2048 0x06 /* 1/2048 */ -#define SH7750_WTCSR_CKS_DIV4096 0x07 /* 1/4096 */ - -/* - * Real-Time Clock (RTC) - */ -/* 64-Hz Counter Register (byte, read-only) - R64CNT */ -#define SH7750_R64CNT_REGOFS 0xC80000 /* offset */ -#define SH7750_R64CNT SH7750_P4_REG32(SH7750_R64CNT_REGOFS) -#define SH7750_R64CNT_A7 SH7750_A7_REG32(SH7750_R64CNT_REGOFS) - -/* Second Counter Register (byte, BCD-coded) - RSECCNT */ -#define SH7750_RSECCNT_REGOFS 0xC80004 /* offset */ -#define SH7750_RSECCNT SH7750_P4_REG32(SH7750_RSECCNT_REGOFS) -#define SH7750_RSECCNT_A7 SH7750_A7_REG32(SH7750_RSECCNT_REGOFS) - -/* Minute Counter Register (byte, BCD-coded) - RMINCNT */ -#define SH7750_RMINCNT_REGOFS 0xC80008 /* offset */ -#define SH7750_RMINCNT SH7750_P4_REG32(SH7750_RMINCNT_REGOFS) -#define SH7750_RMINCNT_A7 SH7750_A7_REG32(SH7750_RMINCNT_REGOFS) - -/* Hour Counter Register (byte, BCD-coded) - RHRCNT */ -#define SH7750_RHRCNT_REGOFS 0xC8000C /* offset */ -#define SH7750_RHRCNT SH7750_P4_REG32(SH7750_RHRCNT_REGOFS) -#define SH7750_RHRCNT_A7 SH7750_A7_REG32(SH7750_RHRCNT_REGOFS) - -/* Day-of-Week Counter Register (byte) - RWKCNT */ -#define SH7750_RWKCNT_REGOFS 0xC80010 /* offset */ -#define SH7750_RWKCNT SH7750_P4_REG32(SH7750_RWKCNT_REGOFS) -#define SH7750_RWKCNT_A7 SH7750_A7_REG32(SH7750_RWKCNT_REGOFS) - -#define SH7750_RWKCNT_SUN 0 /* Sunday */ -#define SH7750_RWKCNT_MON 1 /* Monday */ -#define SH7750_RWKCNT_TUE 2 /* Tuesday */ -#define SH7750_RWKCNT_WED 3 /* Wednesday */ -#define SH7750_RWKCNT_THU 4 /* Thursday */ -#define SH7750_RWKCNT_FRI 5 /* Friday */ -#define SH7750_RWKCNT_SAT 6 /* Saturday */ - -/* Day Counter Register (byte, BCD-coded) - RDAYCNT */ -#define SH7750_RDAYCNT_REGOFS 0xC80014 /* offset */ -#define SH7750_RDAYCNT SH7750_P4_REG32(SH7750_RDAYCNT_REGOFS) -#define SH7750_RDAYCNT_A7 SH7750_A7_REG32(SH7750_RDAYCNT_REGOFS) - -/* Month Counter Register (byte, BCD-coded) - RMONCNT */ -#define SH7750_RMONCNT_REGOFS 0xC80018 /* offset */ -#define SH7750_RMONCNT SH7750_P4_REG32(SH7750_RMONCNT_REGOFS) -#define SH7750_RMONCNT_A7 SH7750_A7_REG32(SH7750_RMONCNT_REGOFS) - -/* Year Counter Register (half, BCD-coded) - RYRCNT */ -#define SH7750_RYRCNT_REGOFS 0xC8001C /* offset */ -#define SH7750_RYRCNT SH7750_P4_REG32(SH7750_RYRCNT_REGOFS) -#define SH7750_RYRCNT_A7 SH7750_A7_REG32(SH7750_RYRCNT_REGOFS) - -/* Second Alarm Register (byte, BCD-coded) - RSECAR */ -#define SH7750_RSECAR_REGOFS 0xC80020 /* offset */ -#define SH7750_RSECAR SH7750_P4_REG32(SH7750_RSECAR_REGOFS) -#define SH7750_RSECAR_A7 SH7750_A7_REG32(SH7750_RSECAR_REGOFS) -#define SH7750_RSECAR_ENB 0x80 /* Second Alarm Enable */ - -/* Minute Alarm Register (byte, BCD-coded) - RMINAR */ -#define SH7750_RMINAR_REGOFS 0xC80024 /* offset */ -#define SH7750_RMINAR SH7750_P4_REG32(SH7750_RMINAR_REGOFS) -#define SH7750_RMINAR_A7 SH7750_A7_REG32(SH7750_RMINAR_REGOFS) -#define SH7750_RMINAR_ENB 0x80 /* Minute Alarm Enable */ - -/* Hour Alarm Register (byte, BCD-coded) - RHRAR */ -#define SH7750_RHRAR_REGOFS 0xC80028 /* offset */ -#define SH7750_RHRAR SH7750_P4_REG32(SH7750_RHRAR_REGOFS) -#define SH7750_RHRAR_A7 SH7750_A7_REG32(SH7750_RHRAR_REGOFS) -#define SH7750_RHRAR_ENB 0x80 /* Hour Alarm Enable */ - -/* Day-of-Week Alarm Register (byte) - RWKAR */ -#define SH7750_RWKAR_REGOFS 0xC8002C /* offset */ -#define SH7750_RWKAR SH7750_P4_REG32(SH7750_RWKAR_REGOFS) -#define SH7750_RWKAR_A7 SH7750_A7_REG32(SH7750_RWKAR_REGOFS) -#define SH7750_RWKAR_ENB 0x80 /* Day-of-week Alarm Enable */ - -#define SH7750_RWKAR_SUN 0 /* Sunday */ -#define SH7750_RWKAR_MON 1 /* Monday */ -#define SH7750_RWKAR_TUE 2 /* Tuesday */ -#define SH7750_RWKAR_WED 3 /* Wednesday */ -#define SH7750_RWKAR_THU 4 /* Thursday */ -#define SH7750_RWKAR_FRI 5 /* Friday */ -#define SH7750_RWKAR_SAT 6 /* Saturday */ - -/* Day Alarm Register (byte, BCD-coded) - RDAYAR */ -#define SH7750_RDAYAR_REGOFS 0xC80030 /* offset */ -#define SH7750_RDAYAR SH7750_P4_REG32(SH7750_RDAYAR_REGOFS) -#define SH7750_RDAYAR_A7 SH7750_A7_REG32(SH7750_RDAYAR_REGOFS) -#define SH7750_RDAYAR_ENB 0x80 /* Day Alarm Enable */ - -/* Month Counter Register (byte, BCD-coded) - RMONAR */ -#define SH7750_RMONAR_REGOFS 0xC80034 /* offset */ -#define SH7750_RMONAR SH7750_P4_REG32(SH7750_RMONAR_REGOFS) -#define SH7750_RMONAR_A7 SH7750_A7_REG32(SH7750_RMONAR_REGOFS) -#define SH7750_RMONAR_ENB 0x80 /* Month Alarm Enable */ - -/* RTC Control Register 1 (byte) - RCR1 */ -#define SH7750_RCR1_REGOFS 0xC80038 /* offset */ -#define SH7750_RCR1 SH7750_P4_REG32(SH7750_RCR1_REGOFS) -#define SH7750_RCR1_A7 SH7750_A7_REG32(SH7750_RCR1_REGOFS) -#define SH7750_RCR1_CF 0x80 /* Carry Flag */ -#define SH7750_RCR1_CIE 0x10 /* Carry Interrupt Enable */ -#define SH7750_RCR1_AIE 0x08 /* Alarm Interrupt Enable */ -#define SH7750_RCR1_AF 0x01 /* Alarm Flag */ - -/* RTC Control Register 2 (byte) - RCR2 */ -#define SH7750_RCR2_REGOFS 0xC8003C /* offset */ -#define SH7750_RCR2 SH7750_P4_REG32(SH7750_RCR2_REGOFS) -#define SH7750_RCR2_A7 SH7750_A7_REG32(SH7750_RCR2_REGOFS) -#define SH7750_RCR2_PEF 0x80 /* Periodic Interrupt Flag */ -#define SH7750_RCR2_PES 0x70 /* Periodic Interrupt Enable: */ -#define SH7750_RCR2_PES_DIS 0x00 /* Periodic Interrupt Disabled */ -#define SH7750_RCR2_PES_DIV256 0x10 /* Generated at 1/256 sec interval */ -#define SH7750_RCR2_PES_DIV64 0x20 /* Generated at 1/64 sec interval */ -#define SH7750_RCR2_PES_DIV16 0x30 /* Generated at 1/16 sec interval */ -#define SH7750_RCR2_PES_DIV4 0x40 /* Generated at 1/4 sec interval */ -#define SH7750_RCR2_PES_DIV2 0x50 /* Generated at 1/2 sec interval */ -#define SH7750_RCR2_PES_x1 0x60 /* Generated at 1 sec interval */ -#define SH7750_RCR2_PES_x2 0x70 /* Generated at 2 sec interval */ -#define SH7750_RCR2_RTCEN 0x08 /* RTC Crystal Oscillator is Operated */ -#define SH7750_RCR2_ADJ 0x04 /* 30-Second Adjastment */ -#define SH7750_RCR2_RESET 0x02 /* Frequency divider circuits are reset */ -#define SH7750_RCR2_START 0x01 /* 0 - sec, min, hr, day-of-week, month, - year counters are stopped - 1 - sec, min, hr, day-of-week, month, - year counters operate normally */ - - -/* - * Timer Unit (TMU) - */ -/* Timer Output Control Register (byte) - TOCR */ -#define SH7750_TOCR_REGOFS 0xD80000 /* offset */ -#define SH7750_TOCR SH7750_P4_REG32(SH7750_TOCR_REGOFS) -#define SH7750_TOCR_A7 SH7750_A7_REG32(SH7750_TOCR_REGOFS) -#define SH7750_TOCR_TCOE 0x01 /* Timer Clock Pin Control: - 0 - TCLK is used as external clock - input or input capture control - 1 - TCLK is used as on-chip RTC - output clock pin */ - -/* Timer Start Register (byte) - TSTR */ -#define SH7750_TSTR_REGOFS 0xD80004 /* offset */ -#define SH7750_TSTR SH7750_P4_REG32(SH7750_TSTR_REGOFS) -#define SH7750_TSTR_A7 SH7750_A7_REG32(SH7750_TSTR_REGOFS) -#define SH7750_TSTR_STR2 0x04 /* TCNT2 performs count operations */ -#define SH7750_TSTR_STR1 0x02 /* TCNT1 performs count operations */ -#define SH7750_TSTR_STR0 0x01 /* TCNT0 performs count operations */ -#define SH7750_TSTR_STR(n) (1 << (n)) - -/* Timer Constant Register - TCOR0, TCOR1, TCOR2 */ -#define SH7750_TCOR_REGOFS(n) (0xD80008 + ((n)*12)) /* offset */ -#define SH7750_TCOR(n) SH7750_P4_REG32(SH7750_TCOR_REGOFS(n)) -#define SH7750_TCOR_A7(n) SH7750_A7_REG32(SH7750_TCOR_REGOFS(n)) -#define SH7750_TCOR0 SH7750_TCOR(0) -#define SH7750_TCOR1 SH7750_TCOR(1) -#define SH7750_TCOR2 SH7750_TCOR(2) -#define SH7750_TCOR0_A7 SH7750_TCOR_A7(0) -#define SH7750_TCOR1_A7 SH7750_TCOR_A7(1) -#define SH7750_TCOR2_A7 SH7750_TCOR_A7(2) - -/* Timer Counter Register - TCNT0, TCNT1, TCNT2 */ -#define SH7750_TCNT_REGOFS(n) (0xD8000C + ((n)*12)) /* offset */ -#define SH7750_TCNT(n) SH7750_P4_REG32(SH7750_TCNT_REGOFS(n)) -#define SH7750_TCNT_A7(n) SH7750_A7_REG32(SH7750_TCNT_REGOFS(n)) -#define SH7750_TCNT0 SH7750_TCNT(0) -#define SH7750_TCNT1 SH7750_TCNT(1) -#define SH7750_TCNT2 SH7750_TCNT(2) -#define SH7750_TCNT0_A7 SH7750_TCNT_A7(0) -#define SH7750_TCNT1_A7 SH7750_TCNT_A7(1) -#define SH7750_TCNT2_A7 SH7750_TCNT_A7(2) - -/* Timer Control Register (half) - TCR0, TCR1, TCR2 */ -#define SH7750_TCR_REGOFS(n) (0xD80010 + ((n)*12)) /* offset */ -#define SH7750_TCR(n) SH7750_P4_REG32(SH7750_TCR_REGOFS(n)) -#define SH7750_TCR_A7(n) SH7750_A7_REG32(SH7750_TCR_REGOFS(n)) -#define SH7750_TCR0 SH7750_TCR(0) -#define SH7750_TCR1 SH7750_TCR(1) -#define SH7750_TCR2 SH7750_TCR(2) -#define SH7750_TCR0_A7 SH7750_TCR_A7(0) -#define SH7750_TCR1_A7 SH7750_TCR_A7(1) -#define SH7750_TCR2_A7 SH7750_TCR_A7(2) - -#define SH7750_TCR2_ICPF 0x200 /* Input Capture Interrupt Flag - (1 - input capture has occured) */ -#define SH7750_TCR_UNF 0x100 /* Underflow flag */ -#define SH7750_TCR2_ICPE 0x0C0 /* Input Capture Control: */ -#define SH7750_TCR2_ICPE_DIS 0x000 /* Input Capture function is not used */ -#define SH7750_TCR2_ICPE_NOINT 0x080 /* Input Capture function is used, but - input capture interrupt is not - enabled */ -#define SH7750_TCR2_ICPE_INT 0x0C0 /* Input Capture function is used, - input capture interrupt enabled */ -#define SH7750_TCR_UNIE 0x020 /* Underflow Interrupt Control - (1 - underflow interrupt enabled) */ -#define SH7750_TCR_CKEG 0x018 /* Clock Edge selection: */ -#define SH7750_TCR_CKEG_RAISE 0x000 /* Count/capture on rising edge */ -#define SH7750_TCR_CKEG_FALL 0x008 /* Count/capture on falling edge */ -#define SH7750_TCR_CKEG_BOTH 0x018 /* Count/capture on both rising and - falling edges */ -#define SH7750_TCR_TPSC 0x007 /* Timer prescaler */ -#define SH7750_TCR_TPSC_DIV4 0x000 /* Counts on peripheral clock/4 */ -#define SH7750_TCR_TPSC_DIV16 0x001 /* Counts on peripheral clock/16 */ -#define SH7750_TCR_TPSC_DIV64 0x002 /* Counts on peripheral clock/64 */ -#define SH7750_TCR_TPSC_DIV256 0x003 /* Counts on peripheral clock/256 */ -#define SH7750_TCR_TPSC_DIV1024 0x004 /* Counts on peripheral clock/1024 */ -#define SH7750_TCR_TPSC_RTC 0x006 /* Counts on on-chip RTC output clk */ -#define SH7750_TCR_TPSC_EXT 0x007 /* Counts on external clock */ - -/* Input Capture Register (read-only) - TCPR2 */ -#define SH7750_TCPR2_REGOFS 0xD8002C /* offset */ -#define SH7750_TCPR2 SH7750_P4_REG32(SH7750_TCPR2_REGOFS) -#define SH7750_TCPR2_A7 SH7750_A7_REG32(SH7750_TCPR2_REGOFS) - -/* - * Bus State Controller - BSC - */ -/* Bus Control Register 1 - BCR1 */ -#define SH7750_BCR1_REGOFS 0x800000 /* offset */ -#define SH7750_BCR1 SH7750_P4_REG32(SH7750_BCR1_REGOFS) -#define SH7750_BCR1_A7 SH7750_A7_REG32(SH7750_BCR1_REGOFS) -#define SH7750_BCR1_ENDIAN 0x80000000 /* Endianness (1 - little endian) */ -#define SH7750_BCR1_MASTER 0x40000000 /* Master/Slave mode (1-master) */ -#define SH7750_BCR1_A0MPX 0x20000000 /* Area 0 Memory Type (0-SRAM,1-MPX) */ -#define SH7750_BCR1_IPUP 0x02000000 /* Input Pin Pull-up Control: - 0 - pull-up resistor is on for - control input pins - 1 - pull-up resistor is off */ -#define SH7750_BCR1_OPUP 0x01000000 /* Output Pin Pull-up Control: - 0 - pull-up resistor is on for - control output pins - 1 - pull-up resistor is off */ -#define SH7750_BCR1_A1MBC 0x00200000 /* Area 1 SRAM Byte Control Mode: - 0 - Area 1 SRAM is set to - normal mode - 1 - Area 1 SRAM is set to byte - control mode */ -#define SH7750_BCR1_A4MBC 0x00100000 /* Area 4 SRAM Byte Control Mode: - 0 - Area 4 SRAM is set to - normal mode - 1 - Area 4 SRAM is set to byte - control mode */ -#define SH7750_BCR1_BREQEN 0x00080000 /* BREQ Enable: - 0 - External requests are not - accepted - 1 - External requests are - accepted */ -#define SH7750_BCR1_PSHR 0x00040000 /* Partial Sharing Bit: - 0 - Master Mode - 1 - Partial-sharing Mode */ -#define SH7750_BCR1_MEMMPX 0x00020000 /* Area 1 to 6 MPX Interface: - 0 - SRAM/burst ROM interface - 1 - MPX interface */ -#define SH7750_BCR1_HIZMEM 0x00008000 /* High Impendance Control. Specifies - the state of A[25:0], BS\, CSn\, - RD/WR\, CE2A\, CE2B\ in standby - mode and when bus is released: - 0 - signals go to High-Z mode - 1 - signals driven */ -#define SH7750_BCR1_HIZCNT 0x00004000 /* High Impendance Control. Specifies - the state of the RAS\, RAS2\, WEn\, - CASn\, DQMn, RD\, CASS\, FRAME\, - RD2\ signals in standby mode and - when bus is released: - 0 - signals go to High-Z mode - 1 - signals driven */ -#define SH7750_BCR1_A0BST 0x00003800 /* Area 0 Burst ROM Control */ -#define SH7750_BCR1_A0BST_SRAM 0x0000 /* Area 0 accessed as SRAM i/f */ -#define SH7750_BCR1_A0BST_ROM4 0x0800 /* Area 0 accessed as burst ROM - interface, 4 cosequtive access */ -#define SH7750_BCR1_A0BST_ROM8 0x1000 /* Area 0 accessed as burst ROM - interface, 8 cosequtive access */ -#define SH7750_BCR1_A0BST_ROM16 0x1800 /* Area 0 accessed as burst ROM - interface, 16 cosequtive access */ -#define SH7750_BCR1_A0BST_ROM32 0x2000 /* Area 0 accessed as burst ROM - interface, 32 cosequtive access */ - -#define SH7750_BCR1_A5BST 0x00000700 /* Area 5 Burst ROM Control */ -#define SH7750_BCR1_A5BST_SRAM 0x0000 /* Area 5 accessed as SRAM i/f */ -#define SH7750_BCR1_A5BST_ROM4 0x0100 /* Area 5 accessed as burst ROM - interface, 4 cosequtive access */ -#define SH7750_BCR1_A5BST_ROM8 0x0200 /* Area 5 accessed as burst ROM - interface, 8 cosequtive access */ -#define SH7750_BCR1_A5BST_ROM16 0x0300 /* Area 5 accessed as burst ROM - interface, 16 cosequtive access */ -#define SH7750_BCR1_A5BST_ROM32 0x0400 /* Area 5 accessed as burst ROM - interface, 32 cosequtive access */ - -#define SH7750_BCR1_A6BST 0x000000E0 /* Area 6 Burst ROM Control */ -#define SH7750_BCR1_A6BST_SRAM 0x0000 /* Area 6 accessed as SRAM i/f */ -#define SH7750_BCR1_A6BST_ROM4 0x0020 /* Area 6 accessed as burst ROM - interface, 4 cosequtive access */ -#define SH7750_BCR1_A6BST_ROM8 0x0040 /* Area 6 accessed as burst ROM - interface, 8 cosequtive access */ -#define SH7750_BCR1_A6BST_ROM16 0x0060 /* Area 6 accessed as burst ROM - interface, 16 cosequtive access */ -#define SH7750_BCR1_A6BST_ROM32 0x0080 /* Area 6 accessed as burst ROM - interface, 32 cosequtive access */ - -#define SH7750_BCR1_DRAMTP 0x001C /* Area 2 and 3 Memory Type */ -#define SH7750_BCR1_DRAMTP_2SRAM_3SRAM 0x0000 /* Area 2 and 3 are SRAM or MPX - interface. */ -#define SH7750_BCR1_DRAMTP_2SRAM_3SDRAM 0x0008 /* Area 2 - SRAM/MPX, Area 3 - - synchronous DRAM */ -#define SH7750_BCR1_DRAMTP_2SDRAM_3SDRAM 0x000C /* Area 2 and 3 are synchronous - DRAM interface */ -#define SH7750_BCR1_DRAMTP_2SRAM_3DRAM 0x0010 /* Area 2 - SRAM/MPX, Area 3 - - DRAM interface */ -#define SH7750_BCR1_DRAMTP_2DRAM_3DRAM 0x0014 /* Area 2 and 3 are DRAM - interface */ - -#define SH7750_BCR1_A56PCM 0x00000001 /* Area 5 and 6 Bus Type: - 0 - SRAM interface - 1 - PCMCIA interface */ - -/* Bus Control Register 2 (half) - BCR2 */ -#define SH7750_BCR2_REGOFS 0x800004 /* offset */ -#define SH7750_BCR2 SH7750_P4_REG32(SH7750_BCR2_REGOFS) -#define SH7750_BCR2_A7 SH7750_A7_REG32(SH7750_BCR2_REGOFS) - -#define SH7750_BCR2_A0SZ 0xC000 /* Area 0 Bus Width */ -#define SH7750_BCR2_A0SZ_S 14 -#define SH7750_BCR2_A6SZ 0x3000 /* Area 6 Bus Width */ -#define SH7750_BCR2_A6SZ_S 12 -#define SH7750_BCR2_A5SZ 0x0C00 /* Area 5 Bus Width */ -#define SH7750_BCR2_A5SZ_S 10 -#define SH7750_BCR2_A4SZ 0x0300 /* Area 4 Bus Width */ -#define SH7750_BCR2_A4SZ_S 8 -#define SH7750_BCR2_A3SZ 0x00C0 /* Area 3 Bus Width */ -#define SH7750_BCR2_A3SZ_S 6 -#define SH7750_BCR2_A2SZ 0x0030 /* Area 2 Bus Width */ -#define SH7750_BCR2_A2SZ_S 4 -#define SH7750_BCR2_A1SZ 0x000C /* Area 1 Bus Width */ -#define SH7750_BCR2_A1SZ_S 2 -#define SH7750_BCR2_SZ_64 0 /* 64 bits */ -#define SH7750_BCR2_SZ_8 1 /* 8 bits */ -#define SH7750_BCR2_SZ_16 2 /* 16 bits */ -#define SH7750_BCR2_SZ_32 3 /* 32 bits */ -#define SH7750_BCR2_PORTEN 0x0001 /* Port Function Enable : - 0 - D51-D32 are not used as a port - 1 - D51-D32 are used as a port */ - -/* Wait Control Register 1 - WCR1 */ -#define SH7750_WCR1_REGOFS 0x800008 /* offset */ -#define SH7750_WCR1 SH7750_P4_REG32(SH7750_WCR1_REGOFS) -#define SH7750_WCR1_A7 SH7750_A7_REG32(SH7750_WCR1_REGOFS) -#define SH7750_WCR1_DMAIW 0x70000000 /* DACK Device Inter-Cycle Idle - specification */ -#define SH7750_WCR1_DMAIW_S 28 -#define SH7750_WCR1_A6IW 0x07000000 /* Area 6 Inter-Cycle Idle spec. */ -#define SH7750_WCR1_A6IW_S 24 -#define SH7750_WCR1_A5IW 0x00700000 /* Area 5 Inter-Cycle Idle spec. */ -#define SH7750_WCR1_A5IW_S 20 -#define SH7750_WCR1_A4IW 0x00070000 /* Area 4 Inter-Cycle Idle spec. */ -#define SH7750_WCR1_A4IW_S 16 -#define SH7750_WCR1_A3IW 0x00007000 /* Area 3 Inter-Cycle Idle spec. */ -#define SH7750_WCR1_A3IW_S 12 -#define SH7750_WCR1_A2IW 0x00000700 /* Area 2 Inter-Cycle Idle spec. */ -#define SH7750_WCR1_A2IW_S 8 -#define SH7750_WCR1_A1IW 0x00000070 /* Area 1 Inter-Cycle Idle spec. */ -#define SH7750_WCR1_A1IW_S 4 -#define SH7750_WCR1_A0IW 0x00000007 /* Area 0 Inter-Cycle Idle spec. */ -#define SH7750_WCR1_A0IW_S 0 - -/* Wait Control Register 2 - WCR2 */ -#define SH7750_WCR2_REGOFS 0x80000C /* offset */ -#define SH7750_WCR2 SH7750_P4_REG32(SH7750_WCR2_REGOFS) -#define SH7750_WCR2_A7 SH7750_A7_REG32(SH7750_WCR2_REGOFS) - -#define SH7750_WCR2_A6W 0xE0000000 /* Area 6 Wait Control */ -#define SH7750_WCR2_A6W_S 29 -#define SH7750_WCR2_A6B 0x1C000000 /* Area 6 Burst Pitch */ -#define SH7750_WCR2_A6B_S 26 -#define SH7750_WCR2_A5W 0x03800000 /* Area 5 Wait Control */ -#define SH7750_WCR2_A5W_S 23 -#define SH7750_WCR2_A5B 0x00700000 /* Area 5 Burst Pitch */ -#define SH7750_WCR2_A5B_S 20 -#define SH7750_WCR2_A4W 0x000E0000 /* Area 4 Wait Control */ -#define SH7750_WCR2_A4W_S 17 -#define SH7750_WCR2_A3W 0x0000E000 /* Area 3 Wait Control */ -#define SH7750_WCR2_A3W_S 13 -#define SH7750_WCR2_A2W 0x00000E00 /* Area 2 Wait Control */ -#define SH7750_WCR2_A2W_S 9 -#define SH7750_WCR2_A1W 0x000001C0 /* Area 1 Wait Control */ -#define SH7750_WCR2_A1W_S 6 -#define SH7750_WCR2_A0W 0x00000038 /* Area 0 Wait Control */ -#define SH7750_WCR2_A0W_S 3 -#define SH7750_WCR2_A0B 0x00000007 /* Area 0 Burst Pitch */ -#define SH7750_WCR2_A0B_S 0 - -#define SH7750_WCR2_WS0 0 /* 0 wait states inserted */ -#define SH7750_WCR2_WS1 1 /* 1 wait states inserted */ -#define SH7750_WCR2_WS2 2 /* 2 wait states inserted */ -#define SH7750_WCR2_WS3 3 /* 3 wait states inserted */ -#define SH7750_WCR2_WS6 4 /* 6 wait states inserted */ -#define SH7750_WCR2_WS9 5 /* 9 wait states inserted */ -#define SH7750_WCR2_WS12 6 /* 12 wait states inserted */ -#define SH7750_WCR2_WS15 7 /* 15 wait states inserted */ - -#define SH7750_WCR2_BPWS0 0 /* 0 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS1 1 /* 1 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS2 2 /* 2 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS3 3 /* 3 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS4 4 /* 4 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS5 5 /* 5 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS6 6 /* 6 wait states inserted from 2nd access */ -#define SH7750_WCR2_BPWS7 7 /* 7 wait states inserted from 2nd access */ - -/* DRAM CAS\ Assertion Delay (area 3,2) */ -#define SH7750_WCR2_DRAM_CAS_ASW1 0 /* 1 cycle */ -#define SH7750_WCR2_DRAM_CAS_ASW2 1 /* 2 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW3 2 /* 3 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW4 3 /* 4 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW7 4 /* 7 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW10 5 /* 10 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW13 6 /* 13 cycles */ -#define SH7750_WCR2_DRAM_CAS_ASW16 7 /* 16 cycles */ - -/* SDRAM CAS\ Latency Cycles */ -#define SH7750_WCR2_SDRAM_CAS_LAT1 1 /* 1 cycle */ -#define SH7750_WCR2_SDRAM_CAS_LAT2 2 /* 2 cycles */ -#define SH7750_WCR2_SDRAM_CAS_LAT3 3 /* 3 cycles */ -#define SH7750_WCR2_SDRAM_CAS_LAT4 4 /* 4 cycles */ -#define SH7750_WCR2_SDRAM_CAS_LAT5 5 /* 5 cycles */ - -/* Wait Control Register 3 - WCR3 */ -#define SH7750_WCR3_REGOFS 0x800010 /* offset */ -#define SH7750_WCR3 SH7750_P4_REG32(SH7750_WCR3_REGOFS) -#define SH7750_WCR3_A7 SH7750_A7_REG32(SH7750_WCR3_REGOFS) - -#define SH7750_WCR3_A6S 0x04000000 /* Area 6 Write Strobe Setup time */ -#define SH7750_WCR3_A6H 0x03000000 /* Area 6 Data Hold Time */ -#define SH7750_WCR3_A6H_S 24 -#define SH7750_WCR3_A5S 0x00400000 /* Area 5 Write Strobe Setup time */ -#define SH7750_WCR3_A5H 0x00300000 /* Area 5 Data Hold Time */ -#define SH7750_WCR3_A5H_S 20 -#define SH7750_WCR3_A4S 0x00040000 /* Area 4 Write Strobe Setup time */ -#define SH7750_WCR3_A4H 0x00030000 /* Area 4 Data Hold Time */ -#define SH7750_WCR3_A4H_S 16 -#define SH7750_WCR3_A3S 0x00004000 /* Area 3 Write Strobe Setup time */ -#define SH7750_WCR3_A3H 0x00003000 /* Area 3 Data Hold Time */ -#define SH7750_WCR3_A3H_S 12 -#define SH7750_WCR3_A2S 0x00000400 /* Area 2 Write Strobe Setup time */ -#define SH7750_WCR3_A2H 0x00000300 /* Area 2 Data Hold Time */ -#define SH7750_WCR3_A2H_S 8 -#define SH7750_WCR3_A1S 0x00000040 /* Area 1 Write Strobe Setup time */ -#define SH7750_WCR3_A1H 0x00000030 /* Area 1 Data Hold Time */ -#define SH7750_WCR3_A1H_S 4 -#define SH7750_WCR3_A0S 0x00000004 /* Area 0 Write Strobe Setup time */ -#define SH7750_WCR3_A0H 0x00000003 /* Area 0 Data Hold Time */ -#define SH7750_WCR3_A0H_S 0 - -#define SH7750_WCR3_DHWS_0 0 /* 0 wait states data hold time */ -#define SH7750_WCR3_DHWS_1 1 /* 1 wait states data hold time */ -#define SH7750_WCR3_DHWS_2 2 /* 2 wait states data hold time */ -#define SH7750_WCR3_DHWS_3 3 /* 3 wait states data hold time */ - -#define SH7750_MCR_REGOFS 0x800014 /* offset */ -#define SH7750_MCR SH7750_P4_REG32(SH7750_MCR_REGOFS) -#define SH7750_MCR_A7 SH7750_A7_REG32(SH7750_MCR_REGOFS) - -#define SH7750_MCR_RASD 0x80000000 /* RAS Down mode */ -#define SH7750_MCR_MRSET 0x40000000 /* SDRAM Mode Register Set */ -#define SH7750_MCR_PALL 0x00000000 /* SDRAM Precharge All cmd. Mode */ -#define SH7750_MCR_TRC 0x38000000 /* RAS Precharge Time at End of - Refresh: */ -#define SH7750_MCR_TRC_0 0x00000000 /* 0 */ -#define SH7750_MCR_TRC_3 0x08000000 /* 3 */ -#define SH7750_MCR_TRC_6 0x10000000 /* 6 */ -#define SH7750_MCR_TRC_9 0x18000000 /* 9 */ -#define SH7750_MCR_TRC_12 0x20000000 /* 12 */ -#define SH7750_MCR_TRC_15 0x28000000 /* 15 */ -#define SH7750_MCR_TRC_18 0x30000000 /* 18 */ -#define SH7750_MCR_TRC_21 0x38000000 /* 21 */ - -#define SH7750_MCR_TCAS 0x00800000 /* CAS Negation Period */ -#define SH7750_MCR_TCAS_1 0x00000000 /* 1 */ -#define SH7750_MCR_TCAS_2 0x00800000 /* 2 */ - -#define SH7750_MCR_TPC 0x00380000 /* DRAM: RAS Precharge Period - SDRAM: minimum number of cycles - until the next bank active cmd - is output after precharging */ -#define SH7750_MCR_TPC_S 19 -#define SH7750_MCR_TPC_SDRAM_1 0x00000000 /* 1 cycle */ -#define SH7750_MCR_TPC_SDRAM_2 0x00080000 /* 2 cycles */ -#define SH7750_MCR_TPC_SDRAM_3 0x00100000 /* 3 cycles */ -#define SH7750_MCR_TPC_SDRAM_4 0x00180000 /* 4 cycles */ -#define SH7750_MCR_TPC_SDRAM_5 0x00200000 /* 5 cycles */ -#define SH7750_MCR_TPC_SDRAM_6 0x00280000 /* 6 cycles */ -#define SH7750_MCR_TPC_SDRAM_7 0x00300000 /* 7 cycles */ -#define SH7750_MCR_TPC_SDRAM_8 0x00380000 /* 8 cycles */ - -#define SH7750_MCR_RCD 0x00030000 /* DRAM: RAS-CAS Assertion Delay time - SDRAM: bank active-read/write cmd - delay time */ -#define SH7750_MCR_RCD_DRAM_2 0x00000000 /* DRAM delay 2 clocks */ -#define SH7750_MCR_RCD_DRAM_3 0x00010000 /* DRAM delay 3 clocks */ -#define SH7750_MCR_RCD_DRAM_4 0x00020000 /* DRAM delay 4 clocks */ -#define SH7750_MCR_RCD_DRAM_5 0x00030000 /* DRAM delay 5 clocks */ -#define SH7750_MCR_RCD_SDRAM_2 0x00010000 /* DRAM delay 2 clocks */ -#define SH7750_MCR_RCD_SDRAM_3 0x00020000 /* DRAM delay 3 clocks */ -#define SH7750_MCR_RCD_SDRAM_4 0x00030000 /* DRAM delay 4 clocks */ - -#define SH7750_MCR_TRWL 0x0000E000 /* SDRAM Write Precharge Delay */ -#define SH7750_MCR_TRWL_1 0x00000000 /* 1 */ -#define SH7750_MCR_TRWL_2 0x00002000 /* 2 */ -#define SH7750_MCR_TRWL_3 0x00004000 /* 3 */ -#define SH7750_MCR_TRWL_4 0x00006000 /* 4 */ -#define SH7750_MCR_TRWL_5 0x00008000 /* 5 */ - -#define SH7750_MCR_TRAS 0x00001C00 /* DRAM: CAS-Before-RAS Refresh RAS - asserting period - SDRAM: Command interval after - synchronous DRAM refresh */ -#define SH7750_MCR_TRAS_DRAM_2 0x00000000 /* 2 */ -#define SH7750_MCR_TRAS_DRAM_3 0x00000400 /* 3 */ -#define SH7750_MCR_TRAS_DRAM_4 0x00000800 /* 4 */ -#define SH7750_MCR_TRAS_DRAM_5 0x00000C00 /* 5 */ -#define SH7750_MCR_TRAS_DRAM_6 0x00001000 /* 6 */ -#define SH7750_MCR_TRAS_DRAM_7 0x00001400 /* 7 */ -#define SH7750_MCR_TRAS_DRAM_8 0x00001800 /* 8 */ -#define SH7750_MCR_TRAS_DRAM_9 0x00001C00 /* 9 */ - -#define SH7750_MCR_TRAS_SDRAM_TRC_4 0x00000000 /* 4 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_5 0x00000400 /* 5 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_6 0x00000800 /* 6 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_7 0x00000C00 /* 7 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_8 0x00001000 /* 8 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_9 0x00001400 /* 9 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_10 0x00001800 /* 10 + TRC */ -#define SH7750_MCR_TRAS_SDRAM_TRC_11 0x00001C00 /* 11 + TRC */ - -#define SH7750_MCR_BE 0x00000200 /* Burst Enable */ -#define SH7750_MCR_SZ 0x00000180 /* Memory Data Size */ -#define SH7750_MCR_SZ_64 0x00000000 /* 64 bits */ -#define SH7750_MCR_SZ_16 0x00000100 /* 16 bits */ -#define SH7750_MCR_SZ_32 0x00000180 /* 32 bits */ - -#define SH7750_MCR_AMX 0x00000078 /* Address Multiplexing */ -#define SH7750_MCR_AMX_S 3 -#define SH7750_MCR_AMX_DRAM_8BIT_COL 0x00000000 /* 8-bit column addr */ -#define SH7750_MCR_AMX_DRAM_9BIT_COL 0x00000008 /* 9-bit column addr */ -#define SH7750_MCR_AMX_DRAM_10BIT_COL 0x00000010 /* 10-bit column addr */ -#define SH7750_MCR_AMX_DRAM_11BIT_COL 0x00000018 /* 11-bit column addr */ -#define SH7750_MCR_AMX_DRAM_12BIT_COL 0x00000020 /* 12-bit column addr */ -/* See SH7750 Hardware Manual for SDRAM address multiplexor selection */ - -#define SH7750_MCR_RFSH 0x00000004 /* Refresh Control */ -#define SH7750_MCR_RMODE 0x00000002 /* Refresh Mode: */ -#define SH7750_MCR_RMODE_NORMAL 0x00000000 /* Normal Refresh Mode */ -#define SH7750_MCR_RMODE_SELF 0x00000002 /* Self-Refresh Mode */ -#define SH7750_MCR_RMODE_EDO 0x00000001 /* EDO Mode */ - -/* SDRAM Mode Set address */ -#define SH7750_SDRAM_MODE_A2_BASE 0xFF900000 -#define SH7750_SDRAM_MODE_A3_BASE 0xFF940000 -#define SH7750_SDRAM_MODE_A2_32BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 2)) -#define SH7750_SDRAM_MODE_A3_32BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 2)) -#define SH7750_SDRAM_MODE_A2_64BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 3)) -#define SH7750_SDRAM_MODE_A3_64BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 3)) - - -/* PCMCIA Control Register (half) - PCR */ -#define SH7750_PCR_REGOFS 0x800018 /* offset */ -#define SH7750_PCR SH7750_P4_REG32(SH7750_PCR_REGOFS) -#define SH7750_PCR_A7 SH7750_A7_REG32(SH7750_PCR_REGOFS) - -#define SH7750_PCR_A5PCW 0xC000 /* Area 5 PCMCIA Wait - Number of wait - states to be added to the number of - waits specified by WCR2 in a low-speed - PCMCIA wait cycle */ -#define SH7750_PCR_A5PCW_0 0x0000 /* 0 waits inserted */ -#define SH7750_PCR_A5PCW_15 0x4000 /* 15 waits inserted */ -#define SH7750_PCR_A5PCW_30 0x8000 /* 30 waits inserted */ -#define SH7750_PCR_A5PCW_50 0xC000 /* 50 waits inserted */ - -#define SH7750_PCR_A6PCW 0x3000 /* Area 6 PCMCIA Wait - Number of wait - states to be added to the number of - waits specified by WCR2 in a low-speed - PCMCIA wait cycle */ -#define SH7750_PCR_A6PCW_0 0x0000 /* 0 waits inserted */ -#define SH7750_PCR_A6PCW_15 0x1000 /* 15 waits inserted */ -#define SH7750_PCR_A6PCW_30 0x2000 /* 30 waits inserted */ -#define SH7750_PCR_A6PCW_50 0x3000 /* 50 waits inserted */ - -#define SH7750_PCR_A5TED 0x0E00 /* Area 5 Address-OE\/WE\ Assertion Delay, - delay time from address output to - OE\/WE\ assertion on the connected - PCMCIA interface */ -#define SH7750_PCR_A5TED_S 9 -#define SH7750_PCR_A6TED 0x01C0 /* Area 6 Address-OE\/WE\ Assertion Delay */ -#define SH7750_PCR_A6TED_S 6 - -#define SH7750_PCR_TED_0WS 0 /* 0 Waits inserted */ -#define SH7750_PCR_TED_1WS 1 /* 1 Waits inserted */ -#define SH7750_PCR_TED_2WS 2 /* 2 Waits inserted */ -#define SH7750_PCR_TED_3WS 3 /* 3 Waits inserted */ -#define SH7750_PCR_TED_6WS 4 /* 6 Waits inserted */ -#define SH7750_PCR_TED_9WS 5 /* 9 Waits inserted */ -#define SH7750_PCR_TED_12WS 6 /* 12 Waits inserted */ -#define SH7750_PCR_TED_15WS 7 /* 15 Waits inserted */ - -#define SH7750_PCR_A5TEH 0x0038 /* Area 5 OE\/WE\ Negation Address delay, - address hold delay time from OE\/WE\ - negation in a write on the connected - PCMCIA interface */ -#define SH7750_PCR_A5TEH_S 3 - -#define SH7750_PCR_A6TEH 0x0007 /* Area 6 OE\/WE\ Negation Address delay */ -#define SH7750_PCR_A6TEH_S 0 - -#define SH7750_PCR_TEH_0WS 0 /* 0 Waits inserted */ -#define SH7750_PCR_TEH_1WS 1 /* 1 Waits inserted */ -#define SH7750_PCR_TEH_2WS 2 /* 2 Waits inserted */ -#define SH7750_PCR_TEH_3WS 3 /* 3 Waits inserted */ -#define SH7750_PCR_TEH_6WS 4 /* 6 Waits inserted */ -#define SH7750_PCR_TEH_9WS 5 /* 9 Waits inserted */ -#define SH7750_PCR_TEH_12WS 6 /* 12 Waits inserted */ -#define SH7750_PCR_TEH_15WS 7 /* 15 Waits inserted */ - -/* Refresh Timer Control/Status Register (half) - RTSCR */ -#define SH7750_RTCSR_REGOFS 0x80001C /* offset */ -#define SH7750_RTCSR SH7750_P4_REG32(SH7750_RTCSR_REGOFS) -#define SH7750_RTCSR_A7 SH7750_A7_REG32(SH7750_RTCSR_REGOFS) - -#define SH7750_RTCSR_KEY 0xA500 /* RTCSR write key */ -#define SH7750_RTCSR_CMF 0x0080 /* Compare-Match Flag (indicates a - match between the refresh timer - counter and refresh time constant) */ -#define SH7750_RTCSR_CMIE 0x0040 /* Compare-Match Interrupt Enable */ -#define SH7750_RTCSR_CKS 0x0038 /* Refresh Counter Clock Selects */ -#define SH7750_RTCSR_CKS_DIS 0x0000 /* Clock Input Disabled */ -#define SH7750_RTCSR_CKS_CKIO_DIV4 0x0008 /* Bus Clock / 4 */ -#define SH7750_RTCSR_CKS_CKIO_DIV16 0x0010 /* Bus Clock / 16 */ -#define SH7750_RTCSR_CKS_CKIO_DIV64 0x0018 /* Bus Clock / 64 */ -#define SH7750_RTCSR_CKS_CKIO_DIV256 0x0020 /* Bus Clock / 256 */ -#define SH7750_RTCSR_CKS_CKIO_DIV1024 0x0028 /* Bus Clock / 1024 */ -#define SH7750_RTCSR_CKS_CKIO_DIV2048 0x0030 /* Bus Clock / 2048 */ -#define SH7750_RTCSR_CKS_CKIO_DIV4096 0x0038 /* Bus Clock / 4096 */ - -#define SH7750_RTCSR_OVF 0x0004 /* Refresh Count Overflow Flag */ -#define SH7750_RTCSR_OVIE 0x0002 /* Refresh Count Overflow Interrupt - Enable */ -#define SH7750_RTCSR_LMTS 0x0001 /* Refresh Count Overflow Limit Select */ -#define SH7750_RTCSR_LMTS_1024 0x0000 /* Count Limit is 1024 */ -#define SH7750_RTCSR_LMTS_512 0x0001 /* Count Limit is 512 */ - -/* Refresh Timer Counter (half) - RTCNT */ -#define SH7750_RTCNT_REGOFS 0x800020 /* offset */ -#define SH7750_RTCNT SH7750_P4_REG32(SH7750_RTCNT_REGOFS) -#define SH7750_RTCNT_A7 SH7750_A7_REG32(SH7750_RTCNT_REGOFS) - -#define SH7750_RTCNT_KEY 0xA500 /* RTCNT write key */ - -/* Refresh Time Constant Register (half) - RTCOR */ -#define SH7750_RTCOR_REGOFS 0x800024 /* offset */ -#define SH7750_RTCOR SH7750_P4_REG32(SH7750_RTCOR_REGOFS) -#define SH7750_RTCOR_A7 SH7750_A7_REG32(SH7750_RTCOR_REGOFS) - -#define SH7750_RTCOR_KEY 0xA500 /* RTCOR write key */ - -/* Refresh Count Register (half) - RFCR */ -#define SH7750_RFCR_REGOFS 0x800028 /* offset */ -#define SH7750_RFCR SH7750_P4_REG32(SH7750_RFCR_REGOFS) -#define SH7750_RFCR_A7 SH7750_A7_REG32(SH7750_RFCR_REGOFS) - -#define SH7750_RFCR_KEY 0xA400 /* RFCR write key */ - -/* - * Direct Memory Access Controller (DMAC) - */ - -/* DMA Source Address Register - SAR0, SAR1, SAR2, SAR3 */ -#define SH7750_SAR_REGOFS(n) (0xA00000 + ((n)*16)) /* offset */ -#define SH7750_SAR(n) SH7750_P4_REG32(SH7750_SAR_REGOFS(n)) -#define SH7750_SAR_A7(n) SH7750_A7_REG32(SH7750_SAR_REGOFS(n)) -#define SH7750_SAR0 SH7750_SAR(0) -#define SH7750_SAR1 SH7750_SAR(1) -#define SH7750_SAR2 SH7750_SAR(2) -#define SH7750_SAR3 SH7750_SAR(3) -#define SH7750_SAR0_A7 SH7750_SAR_A7(0) -#define SH7750_SAR1_A7 SH7750_SAR_A7(1) -#define SH7750_SAR2_A7 SH7750_SAR_A7(2) -#define SH7750_SAR3_A7 SH7750_SAR_A7(3) - -/* DMA Destination Address Register - DAR0, DAR1, DAR2, DAR3 */ -#define SH7750_DAR_REGOFS(n) (0xA00004 + ((n)*16)) /* offset */ -#define SH7750_DAR(n) SH7750_P4_REG32(SH7750_DAR_REGOFS(n)) -#define SH7750_DAR_A7(n) SH7750_A7_REG32(SH7750_DAR_REGOFS(n)) -#define SH7750_DAR0 SH7750_DAR(0) -#define SH7750_DAR1 SH7750_DAR(1) -#define SH7750_DAR2 SH7750_DAR(2) -#define SH7750_DAR3 SH7750_DAR(3) -#define SH7750_DAR0_A7 SH7750_DAR_A7(0) -#define SH7750_DAR1_A7 SH7750_DAR_A7(1) -#define SH7750_DAR2_A7 SH7750_DAR_A7(2) -#define SH7750_DAR3_A7 SH7750_DAR_A7(3) - -/* DMA Transfer Count Register - DMATCR0, DMATCR1, DMATCR2, DMATCR3 */ -#define SH7750_DMATCR_REGOFS(n) (0xA00008 + ((n)*16)) /* offset */ -#define SH7750_DMATCR(n) SH7750_P4_REG32(SH7750_DMATCR_REGOFS(n)) -#define SH7750_DMATCR_A7(n) SH7750_A7_REG32(SH7750_DMATCR_REGOFS(n)) -#define SH7750_DMATCR0_P4 SH7750_DMATCR(0) -#define SH7750_DMATCR1_P4 SH7750_DMATCR(1) -#define SH7750_DMATCR2_P4 SH7750_DMATCR(2) -#define SH7750_DMATCR3_P4 SH7750_DMATCR(3) -#define SH7750_DMATCR0_A7 SH7750_DMATCR_A7(0) -#define SH7750_DMATCR1_A7 SH7750_DMATCR_A7(1) -#define SH7750_DMATCR2_A7 SH7750_DMATCR_A7(2) -#define SH7750_DMATCR3_A7 SH7750_DMATCR_A7(3) - -/* DMA Channel Control Register - CHCR0, CHCR1, CHCR2, CHCR3 */ -#define SH7750_CHCR_REGOFS(n) (0xA0000C + ((n)*16)) /* offset */ -#define SH7750_CHCR(n) SH7750_P4_REG32(SH7750_CHCR_REGOFS(n)) -#define SH7750_CHCR_A7(n) SH7750_A7_REG32(SH7750_CHCR_REGOFS(n)) -#define SH7750_CHCR0 SH7750_CHCR(0) -#define SH7750_CHCR1 SH7750_CHCR(1) -#define SH7750_CHCR2 SH7750_CHCR(2) -#define SH7750_CHCR3 SH7750_CHCR(3) -#define SH7750_CHCR0_A7 SH7750_CHCR_A7(0) -#define SH7750_CHCR1_A7 SH7750_CHCR_A7(1) -#define SH7750_CHCR2_A7 SH7750_CHCR_A7(2) -#define SH7750_CHCR3_A7 SH7750_CHCR_A7(3) - -#define SH7750_CHCR_SSA 0xE0000000 /* Source Address Space Attribute */ -#define SH7750_CHCR_SSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */ -#define SH7750_CHCR_SSA_DYNBSZ 0x20000000 /* Dynamic Bus Sizing I/O space */ -#define SH7750_CHCR_SSA_IO8 0x40000000 /* 8-bit I/O space */ -#define SH7750_CHCR_SSA_IO16 0x60000000 /* 16-bit I/O space */ -#define SH7750_CHCR_SSA_CMEM8 0x80000000 /* 8-bit common memory space */ -#define SH7750_CHCR_SSA_CMEM16 0xA0000000 /* 16-bit common memory space */ -#define SH7750_CHCR_SSA_AMEM8 0xC0000000 /* 8-bit attribute memory space */ -#define SH7750_CHCR_SSA_AMEM16 0xE0000000 /* 16-bit attribute memory space */ - -#define SH7750_CHCR_STC 0x10000000 /* Source Address Wait Control Select, - specifies CS5 or CS6 space wait - control for PCMCIA access */ - -#define SH7750_CHCR_DSA 0x0E000000 /* Source Address Space Attribute */ -#define SH7750_CHCR_DSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */ -#define SH7750_CHCR_DSA_DYNBSZ 0x02000000 /* Dynamic Bus Sizing I/O space */ -#define SH7750_CHCR_DSA_IO8 0x04000000 /* 8-bit I/O space */ -#define SH7750_CHCR_DSA_IO16 0x06000000 /* 16-bit I/O space */ -#define SH7750_CHCR_DSA_CMEM8 0x08000000 /* 8-bit common memory space */ -#define SH7750_CHCR_DSA_CMEM16 0x0A000000 /* 16-bit common memory space */ -#define SH7750_CHCR_DSA_AMEM8 0x0C000000 /* 8-bit attribute memory space */ -#define SH7750_CHCR_DSA_AMEM16 0x0E000000 /* 16-bit attribute memory space */ - -#define SH7750_CHCR_DTC 0x01000000 /* Destination Address Wait Control - Select, specifies CS5 or CS6 - space wait control for PCMCIA - access */ - -#define SH7750_CHCR_DS 0x00080000 /* DREQ\ Select : */ -#define SH7750_CHCR_DS_LOWLVL 0x00000000 /* Low Level Detection */ -#define SH7750_CHCR_DS_FALL 0x00080000 /* Falling Edge Detection */ - -#define SH7750_CHCR_RL 0x00040000 /* Request Check Level: */ -#define SH7750_CHCR_RL_ACTH 0x00000000 /* DRAK is an active high out */ -#define SH7750_CHCR_RL_ACTL 0x00040000 /* DRAK is an active low out */ - -#define SH7750_CHCR_AM 0x00020000 /* Acknowledge Mode: */ -#define SH7750_CHCR_AM_RD 0x00000000 /* DACK is output in read cycle */ -#define SH7750_CHCR_AM_WR 0x00020000 /* DACK is output in write cycle */ - -#define SH7750_CHCR_AL 0x00010000 /* Acknowledge Level: */ -#define SH7750_CHCR_AL_ACTH 0x00000000 /* DACK is an active high out */ -#define SH7750_CHCR_AL_ACTL 0x00010000 /* DACK is an active low out */ - -#define SH7750_CHCR_DM 0x0000C000 /* Destination Address Mode: */ -#define SH7750_CHCR_DM_FIX 0x00000000 /* Destination Addr Fixed */ -#define SH7750_CHCR_DM_INC 0x00004000 /* Destination Addr Incremented */ -#define SH7750_CHCR_DM_DEC 0x00008000 /* Destination Addr Decremented */ - -#define SH7750_CHCR_SM 0x00003000 /* Source Address Mode: */ -#define SH7750_CHCR_SM_FIX 0x00000000 /* Source Addr Fixed */ -#define SH7750_CHCR_SM_INC 0x00001000 /* Source Addr Incremented */ -#define SH7750_CHCR_SM_DEC 0x00002000 /* Source Addr Decremented */ - -#define SH7750_CHCR_RS 0x00000F00 /* Request Source Select: */ -#define SH7750_CHCR_RS_ER_DA_EA_TO_EA 0x000 /* External Request, Dual Address - Mode (External Addr Space-> - External Addr Space) */ -#define SH7750_CHCR_RS_ER_SA_EA_TO_ED 0x200 /* External Request, Single - Address Mode (External Addr - Space -> External Device) */ -#define SH7750_CHCR_RS_ER_SA_ED_TO_EA 0x300 /* External Request, Single - Address Mode, (External - Device -> External Addr - Space) */ -#define SH7750_CHCR_RS_AR_EA_TO_EA 0x400 /* Auto-Request (External Addr - Space -> External Addr Space) */ - -#define SH7750_CHCR_RS_AR_EA_TO_OCP 0x500 /* Auto-Request (External Addr - Space -> On-chip Peripheral - Module) */ -#define SH7750_CHCR_RS_AR_OCP_TO_EA 0x600 /* Auto-Request (On-chip - Peripheral Module -> - External Addr Space */ -#define SH7750_CHCR_RS_SCITX_EA_TO_SC 0x800 /* SCI Transmit-Data-Empty intr - transfer request (external - address space -> SCTDR1) */ -#define SH7750_CHCR_RS_SCIRX_SC_TO_EA 0x900 /* SCI Receive-Data-Full intr - transfer request (SCRDR1 -> - External Addr Space) */ -#define SH7750_CHCR_RS_SCIFTX_EA_TO_SC 0xA00 /* SCIF Transmit-Data-Empty intr - transfer request (external - address space -> SCFTDR1) */ -#define SH7750_CHCR_RS_SCIFRX_SC_TO_EA 0xB00 /* SCIF Receive-Data-Full intr - transfer request (SCFRDR2 -> - External Addr Space) */ -#define SH7750_CHCR_RS_TMU2_EA_TO_EA 0xC00 /* TMU Channel 2 (input capture - interrupt), (external address - space -> external address - space) */ -#define SH7750_CHCR_RS_TMU2_EA_TO_OCP 0xD00 /* TMU Channel 2 (input capture - interrupt), (external address - space -> on-chip peripheral - module) */ -#define SH7750_CHCR_RS_TMU2_OCP_TO_EA 0xE00 /* TMU Channel 2 (input capture - interrupt), (on-chip - peripheral module -> external - address space) */ - -#define SH7750_CHCR_TM 0x00000080 /* Transmit mode: */ -#define SH7750_CHCR_TM_CSTEAL 0x00000000 /* Cycle Steal Mode */ -#define SH7750_CHCR_TM_BURST 0x00000080 /* Burst Mode */ - -#define SH7750_CHCR_TS 0x00000070 /* Transmit Size: */ -#define SH7750_CHCR_TS_QUAD 0x00000000 /* Quadword Size (64 bits) */ -#define SH7750_CHCR_TS_BYTE 0x00000010 /* Byte Size (8 bit) */ -#define SH7750_CHCR_TS_WORD 0x00000020 /* Word Size (16 bit) */ -#define SH7750_CHCR_TS_LONG 0x00000030 /* Longword Size (32 bit) */ -#define SH7750_CHCR_TS_BLOCK 0x00000040 /* 32-byte block transfer */ - -#define SH7750_CHCR_IE 0x00000004 /* Interrupt Enable */ -#define SH7750_CHCR_TE 0x00000002 /* Transfer End */ -#define SH7750_CHCR_DE 0x00000001 /* DMAC Enable */ - -/* DMA Operation Register - DMAOR */ -#define SH7750_DMAOR_REGOFS 0xA00040 /* offset */ -#define SH7750_DMAOR SH7750_P4_REG32(SH7750_DMAOR_REGOFS) -#define SH7750_DMAOR_A7 SH7750_A7_REG32(SH7750_DMAOR_REGOFS) - -#define SH7750_DMAOR_DDT 0x00008000 /* On-Demand Data Transfer Mode */ - -#define SH7750_DMAOR_PR 0x00000300 /* Priority Mode: */ -#define SH7750_DMAOR_PR_0123 0x00000000 /* CH0 > CH1 > CH2 > CH3 */ -#define SH7750_DMAOR_PR_0231 0x00000100 /* CH0 > CH2 > CH3 > CH1 */ -#define SH7750_DMAOR_PR_2013 0x00000200 /* CH2 > CH0 > CH1 > CH3 */ -#define SH7750_DMAOR_PR_RR 0x00000300 /* Round-robin mode */ - -#define SH7750_DMAOR_COD 0x00000010 /* Check Overrun for DREQ\ */ -#define SH7750_DMAOR_AE 0x00000004 /* Address Error flag */ -#define SH7750_DMAOR_NMIF 0x00000002 /* NMI Flag */ -#define SH7750_DMAOR_DME 0x00000001 /* DMAC Master Enable */ - -/* - * Serial Communication Interface - SCI - * Serial Communication Interface with FIFO - SCIF - */ -/* SCI Receive Data Register (byte, read-only) - SCRDR1, SCFRDR2 */ -#define SH7750_SCRDR_REGOFS(n) ((n) == 1 ? 0xE00014 : 0xE80014) /* offset */ -#define SH7750_SCRDR(n) SH7750_P4_REG32(SH7750_SCRDR_REGOFS(n)) -#define SH7750_SCRDR1 SH7750_SCRDR(1) -#define SH7750_SCRDR2 SH7750_SCRDR(2) -#define SH7750_SCRDR_A7(n) SH7750_A7_REG32(SH7750_SCRDR_REGOFS(n)) -#define SH7750_SCRDR1_A7 SH7750_SCRDR_A7(1) -#define SH7750_SCRDR2_A7 SH7750_SCRDR_A7(2) - -/* SCI Transmit Data Register (byte) - SCTDR1, SCFTDR2 */ -#define SH7750_SCTDR_REGOFS(n) ((n) == 1 ? 0xE0000C : 0xE8000C) /* offset */ -#define SH7750_SCTDR(n) SH7750_P4_REG32(SH7750_SCTDR_REGOFS(n)) -#define SH7750_SCTDR1 SH7750_SCTDR(1) -#define SH7750_SCTDR2 SH7750_SCTDR(2) -#define SH7750_SCTDR_A7(n) SH7750_A7_REG32(SH7750_SCTDR_REGOFS(n)) -#define SH7750_SCTDR1_A7 SH7750_SCTDR_A7(1) -#define SH7750_SCTDR2_A7 SH7750_SCTDR_A7(2) - -/* SCI Serial Mode Register - SCSMR1(byte), SCSMR2(half) */ -#define SH7750_SCSMR_REGOFS(n) ((n) == 1 ? 0xE00000 : 0xE80000) /* offset */ -#define SH7750_SCSMR(n) SH7750_P4_REG32(SH7750_SCSMR_REGOFS(n)) -#define SH7750_SCSMR1 SH7750_SCSMR(1) -#define SH7750_SCSMR2 SH7750_SCSMR(2) -#define SH7750_SCSMR_A7(n) SH7750_A7_REG32(SH7750_SCSMR_REGOFS(n)) -#define SH7750_SCSMR1_A7 SH7750_SCSMR_A7(1) -#define SH7750_SCSMR2_A7 SH7750_SCSMR_A7(2) - -#define SH7750_SCSMR1_CA 0x80 /* Communication Mode (C/A\): */ -#define SH7750_SCSMR1_CA_ASYNC 0x00 /* Asynchronous Mode */ -#define SH7750_SCSMR1_CA_SYNC 0x80 /* Synchronous Mode */ -#define SH7750_SCSMR_CHR 0x40 /* Character Length: */ -#define SH7750_SCSMR_CHR_8 0x00 /* 8-bit data */ -#define SH7750_SCSMR_CHR_7 0x40 /* 7-bit data */ -#define SH7750_SCSMR_PE 0x20 /* Parity Enable */ -#define SH7750_SCSMR_PM 0x10 /* Parity Mode: */ -#define SH7750_SCSMR_PM_EVEN 0x00 /* Even Parity */ -#define SH7750_SCSMR_PM_ODD 0x10 /* Odd Parity */ -#define SH7750_SCSMR_STOP 0x08 /* Stop Bit Length: */ -#define SH7750_SCSMR_STOP_1 0x00 /* 1 stop bit */ -#define SH7750_SCSMR_STOP_2 0x08 /* 2 stop bit */ -#define SH7750_SCSMR1_MP 0x04 /* Multiprocessor Mode */ -#define SH7750_SCSMR_CKS 0x03 /* Clock Select */ -#define SH7750_SCSMR_CKS_S 0 -#define SH7750_SCSMR_CKS_DIV1 0x00 /* Periph clock */ -#define SH7750_SCSMR_CKS_DIV4 0x01 /* Periph clock / 4 */ -#define SH7750_SCSMR_CKS_DIV16 0x02 /* Periph clock / 16 */ -#define SH7750_SCSMR_CKS_DIV64 0x03 /* Periph clock / 64 */ - -/* SCI Serial Control Register - SCSCR1(byte), SCSCR2(half) */ -#define SH7750_SCSCR_REGOFS(n) ((n) == 1 ? 0xE00008 : 0xE80008) /* offset */ -#define SH7750_SCSCR(n) SH7750_P4_REG32(SH7750_SCSCR_REGOFS(n)) -#define SH7750_SCSCR1 SH7750_SCSCR(1) -#define SH7750_SCSCR2 SH7750_SCSCR(2) -#define SH7750_SCSCR_A7(n) SH7750_A7_REG32(SH7750_SCSCR_REGOFS(n)) -#define SH7750_SCSCR1_A7 SH7750_SCSCR_A7(1) -#define SH7750_SCSCR2_A7 SH7750_SCSCR_A7(2) - -#define SH7750_SCSCR_TIE 0x80 /* Transmit Interrupt Enable */ -#define SH7750_SCSCR_RIE 0x40 /* Receive Interrupt Enable */ -#define SH7750_SCSCR_TE 0x20 /* Transmit Enable */ -#define SH7750_SCSCR_RE 0x10 /* Receive Enable */ -#define SH7750_SCSCR1_MPIE 0x08 /* Multiprocessor Interrupt Enable */ -#define SH7750_SCSCR2_REIE 0x08 /* Receive Error Interrupt Enable */ -#define SH7750_SCSCR1_TEIE 0x04 /* Transmit End Interrupt Enable */ -#define SH7750_SCSCR1_CKE 0x03 /* Clock Enable: */ -#define SH7750_SCSCR_CKE_INTCLK 0x00 /* Use Internal Clock */ -#define SH7750_SCSCR_CKE_EXTCLK 0x02 /* Use External Clock from SCK */ -#define SH7750_SCSCR1_CKE_ASYNC_SCK_CLKOUT 0x01 /* Use SCK as a clock output - in asynchronous mode */ - -/* SCI Serial Status Register - SCSSR1(byte), SCSFR2(half) */ -#define SH7750_SCSSR_REGOFS(n) ((n) == 1 ? 0xE00010 : 0xE80010) /* offset */ -#define SH7750_SCSSR(n) SH7750_P4_REG32(SH7750_SCSSR_REGOFS(n)) -#define SH7750_SCSSR1 SH7750_SCSSR(1) -#define SH7750_SCSFR2 SH7750_SCSSR(2) -#define SH7750_SCSSR_A7(n) SH7750_A7_REG32(SH7750_SCSSR_REGOFS(n)) -#define SH7750_SCSSR1_A7 SH7750_SCSSR_A7(1) -#define SH7750_SCSFR2_A7 SH7750_SCSSR_A7(2) - -#define SH7750_SCSSR1_TDRE 0x80 /* Transmit Data Register Empty */ -#define SH7750_SCSSR1_RDRF 0x40 /* Receive Data Register Full */ -#define SH7750_SCSSR1_ORER 0x20 /* Overrun Error */ -#define SH7750_SCSSR1_FER 0x10 /* Framing Error */ -#define SH7750_SCSSR1_PER 0x08 /* Parity Error */ -#define SH7750_SCSSR1_TEND 0x04 /* Transmit End */ -#define SH7750_SCSSR1_MPB 0x02 /* Multiprocessor Bit */ -#define SH7750_SCSSR1_MPBT 0x01 /* Multiprocessor Bit Transfer */ - -#define SH7750_SCFSR2_PERN 0xF000 /* Number of Parity Errors */ -#define SH7750_SCFSR2_PERN_S 12 -#define SH7750_SCFSR2_FERN 0x0F00 /* Number of Framing Errors */ -#define SH7750_SCFSR2_FERN_S 8 -#define SH7750_SCFSR2_ER 0x0080 /* Receive Error */ -#define SH7750_SCFSR2_TEND 0x0040 /* Transmit End */ -#define SH7750_SCFSR2_TDFE 0x0020 /* Transmit FIFO Data Empty */ -#define SH7750_SCFSR2_BRK 0x0010 /* Break Detect */ -#define SH7750_SCFSR2_FER 0x0008 /* Framing Error */ -#define SH7750_SCFSR2_PER 0x0004 /* Parity Error */ -#define SH7750_SCFSR2_RDF 0x0002 /* Receive FIFO Data Full */ -#define SH7750_SCFSR2_DR 0x0001 /* Receive Data Ready */ - -/* SCI Serial Port Register - SCSPTR1(byte) */ -#define SH7750_SCSPTR1_REGOFS 0xE0001C /* offset */ -#define SH7750_SCSPTR1 SH7750_P4_REG32(SH7750_SCSPTR1_REGOFS) -#define SH7750_SCSPTR1_A7 SH7750_A7_REG32(SH7750_SCSPTR1_REGOFS) - -#define SH7750_SCSPTR1_EIO 0x80 /* Error Interrupt Only */ -#define SH7750_SCSPTR1_SPB1IO 0x08 /* 1: Output SPB1DT bit to SCK pin */ -#define SH7750_SCSPTR1_SPB1DT 0x04 /* Serial Port Clock Port Data */ -#define SH7750_SCSPTR1_SPB0IO 0x02 /* 1: Output SPB0DT bit to TxD pin */ -#define SH7750_SCSPTR1_SPB0DT 0x01 /* Serial Port Break Data */ - -/* SCIF Serial Port Register - SCSPTR2(half) */ -#define SH7750_SCSPTR2_REGOFS 0xE80020 /* offset */ -#define SH7750_SCSPTR2 SH7750_P4_REG32(SH7750_SCSPTR2_REGOFS) -#define SH7750_SCSPTR2_A7 SH7750_A7_REG32(SH7750_SCSPTR2_REGOFS) - -#define SH7750_SCSPTR2_RTSIO 0x80 /* 1: Output RTSDT bit to RTS2\ pin */ -#define SH7750_SCSPTR2_RTSDT 0x40 /* RTS Port Data */ -#define SH7750_SCSPTR2_CTSIO 0x20 /* 1: Output CTSDT bit to CTS2\ pin */ -#define SH7750_SCSPTR2_CTSDT 0x10 /* CTS Port Data */ -#define SH7750_SCSPTR2_SPB2IO 0x02 /* 1: Output SPBDT bit to TxD2 pin */ -#define SH7750_SCSPTR2_SPB2DT 0x01 /* Serial Port Break Data */ - -/* SCI Bit Rate Register - SCBRR1(byte), SCBRR2(byte) */ -#define SH7750_SCBRR_REGOFS(n) ((n) == 1 ? 0xE00004 : 0xE80004) /* offset */ -#define SH7750_SCBRR(n) SH7750_P4_REG32(SH7750_SCBRR_REGOFS(n)) -#define SH7750_SCBRR1 SH7750_SCBRR_P4(1) -#define SH7750_SCBRR2 SH7750_SCBRR_P4(2) -#define SH7750_SCBRR_A7(n) SH7750_A7_REG32(SH7750_SCBRR_REGOFS(n)) -#define SH7750_SCBRR1_A7 SH7750_SCBRR_A7(1) -#define SH7750_SCBRR2_A7 SH7750_SCBRR_A7(2) - -/* SCIF FIFO Control Register - SCFCR2(half) */ -#define SH7750_SCFCR2_REGOFS 0xE80018 /* offset */ -#define SH7750_SCFCR2 SH7750_P4_REG32(SH7750_SCFCR2_REGOFS) -#define SH7750_SCFCR2_A7 SH7750_A7_REG32(SH7750_SCFCR2_REGOFS) - -#define SH7750_SCFCR2_RSTRG 0x700 /* RTS2\ Output Active Trigger; RTS2\ - signal goes to high level when the - number of received data stored in - FIFO exceeds the trigger number */ -#define SH7750_SCFCR2_RSTRG_15 0x000 /* 15 bytes */ -#define SH7750_SCFCR2_RSTRG_1 0x000 /* 1 byte */ -#define SH7750_SCFCR2_RSTRG_4 0x000 /* 4 bytes */ -#define SH7750_SCFCR2_RSTRG_6 0x000 /* 6 bytes */ -#define SH7750_SCFCR2_RSTRG_8 0x000 /* 8 bytes */ -#define SH7750_SCFCR2_RSTRG_10 0x000 /* 10 bytes */ -#define SH7750_SCFCR2_RSTRG_14 0x000 /* 14 bytes */ - -#define SH7750_SCFCR2_RTRG 0x0C0 /* Receive FIFO Data Number Trigger, - Receive Data Full (RDF) Flag sets - when number of receive data bytes is - equal or greater than the trigger - number */ -#define SH7750_SCFCR2_RTRG_1 0x000 /* 1 byte */ -#define SH7750_SCFCR2_RTRG_4 0x040 /* 4 bytes */ -#define SH7750_SCFCR2_RTRG_8 0x080 /* 8 bytes */ -#define SH7750_SCFCR2_RTRG_14 0x0C0 /* 14 bytes */ - -#define SH7750_SCFCR2_TTRG 0x030 /* Transmit FIFO Data Number Trigger, - Transmit FIFO Data Register Empty (TDFE) - flag sets when the number of remaining - transmit data bytes is equal or less - than the trigger number */ -#define SH7750_SCFCR2_TTRG_8 0x000 /* 8 bytes */ -#define SH7750_SCFCR2_TTRG_4 0x010 /* 4 bytes */ -#define SH7750_SCFCR2_TTRG_2 0x020 /* 2 bytes */ -#define SH7750_SCFCR2_TTRG_1 0x030 /* 1 byte */ - -#define SH7750_SCFCR2_MCE 0x008 /* Modem Control Enable */ -#define SH7750_SCFCR2_TFRST 0x004 /* Transmit FIFO Data Register Reset, - invalidates the transmit data in the - transmit FIFO */ -#define SH7750_SCFCR2_RFRST 0x002 /* Receive FIFO Data Register Reset, - invalidates the receive data in the - receive FIFO data register and resets - it to the empty state */ -#define SH7750_SCFCR2_LOOP 0x001 /* Loopback Test */ - -/* SCIF FIFO Data Count Register - SCFDR2(half, read-only) */ -#define SH7750_SCFDR2_REGOFS 0xE8001C /* offset */ -#define SH7750_SCFDR2 SH7750_P4_REG32(SH7750_SCFDR2_REGOFS) -#define SH7750_SCFDR2_A7 SH7750_A7_REG32(SH7750_SCFDR2_REGOFS) - -#define SH7750_SCFDR2_T 0x1F00 /* Number of untransmitted data bytes - in transmit FIFO */ -#define SH7750_SCFDR2_T_S 8 -#define SH7750_SCFDR2_R 0x001F /* Number of received data bytes in - receive FIFO */ -#define SH7750_SCFDR2_R_S 0 - -/* SCIF Line Status Register - SCLSR2(half, read-only) */ -#define SH7750_SCLSR2_REGOFS 0xE80024 /* offset */ -#define SH7750_SCLSR2 SH7750_P4_REG32(SH7750_SCLSR2_REGOFS) -#define SH7750_SCLSR2_A7 SH7750_A7_REG32(SH7750_SCLSR2_REGOFS) - -#define SH7750_SCLSR2_ORER 0x0001 /* Overrun Error */ - -/* - * SCI-based Smart Card Interface - */ -/* Smart Card Mode Register - SCSCMR1(byte) */ -#define SH7750_SCSCMR1_REGOFS 0xE00018 /* offset */ -#define SH7750_SCSCMR1 SH7750_P4_REG32(SH7750_SCSCMR1_REGOFS) -#define SH7750_SCSCMR1_A7 SH7750_A7_REG32(SH7750_SCSCMR1_REGOFS) - -#define SH7750_SCSCMR1_SDIR 0x08 /* Smart Card Data Transfer Direction: */ -#define SH7750_SCSCMR1_SDIR_LSBF 0x00 /* LSB-first */ -#define SH7750_SCSCMR1_SDIR_MSBF 0x08 /* MSB-first */ - -#define SH7750_SCSCMR1_SINV 0x04 /* Smart Card Data Inversion */ -#define SH7750_SCSCMR1_SMIF 0x01 /* Smart Card Interface Mode Select */ - -/* Smart-card specific bits in other registers */ -/* SCSMR1: */ -#define SH7750_SCSMR1_GSM 0x80 /* GSM mode select */ - -/* SCSSR1: */ -#define SH7750_SCSSR1_ERS 0x10 /* Error Signal Status */ - -/* - * I/O Ports - */ -/* Port Control Register A - PCTRA */ -#define SH7750_PCTRA_REGOFS 0x80002C /* offset */ -#define SH7750_PCTRA SH7750_P4_REG32(SH7750_PCTRA_REGOFS) -#define SH7750_PCTRA_A7 SH7750_A7_REG32(SH7750_PCTRA_REGOFS) - -#define SH7750_PCTRA_PBPUP(n) 0 /* Bit n is pulled up */ -#define SH7750_PCTRA_PBNPUP(n) (1 << ((n)*2+1)) /* Bit n is not pulled up */ -#define SH7750_PCTRA_PBINP(n) 0 /* Bit n is an input */ -#define SH7750_PCTRA_PBOUT(n) (1 << ((n)*2)) /* Bit n is an output */ - -/* Port Data Register A - PDTRA(half) */ -#define SH7750_PDTRA_REGOFS 0x800030 /* offset */ -#define SH7750_PDTRA SH7750_P4_REG32(SH7750_PDTRA_REGOFS) -#define SH7750_PDTRA_A7 SH7750_A7_REG32(SH7750_PDTRA_REGOFS) - -#define SH7750_PDTRA_BIT(n) (1 << (n)) - -/* Port Control Register B - PCTRB */ -#define SH7750_PCTRB_REGOFS 0x800040 /* offset */ -#define SH7750_PCTRB SH7750_P4_REG32(SH7750_PCTRB_REGOFS) -#define SH7750_PCTRB_A7 SH7750_A7_REG32(SH7750_PCTRB_REGOFS) - -#define SH7750_PCTRB_PBPUP(n) 0 /* Bit n is pulled up */ -#define SH7750_PCTRB_PBNPUP(n) (1 << ((n-16)*2+1)) /* Bit n is not pulled up */ -#define SH7750_PCTRB_PBINP(n) 0 /* Bit n is an input */ -#define SH7750_PCTRB_PBOUT(n) (1 << ((n-16)*2)) /* Bit n is an output */ - -/* Port Data Register B - PDTRB(half) */ -#define SH7750_PDTRB_REGOFS 0x800044 /* offset */ -#define SH7750_PDTRB SH7750_P4_REG32(SH7750_PDTRB_REGOFS) -#define SH7750_PDTRB_A7 SH7750_A7_REG32(SH7750_PDTRB_REGOFS) - -#define SH7750_PDTRB_BIT(n) (1 << ((n)-16)) - -/* GPIO Interrupt Control Register - GPIOIC(half) */ -#define SH7750_GPIOIC_REGOFS 0x800048 /* offset */ -#define SH7750_GPIOIC SH7750_P4_REG32(SH7750_GPIOIC_REGOFS) -#define SH7750_GPIOIC_A7 SH7750_A7_REG32(SH7750_GPIOIC_REGOFS) - -#define SH7750_GPIOIC_PTIREN(n) (1 << (n)) /* Port n is used as a GPIO int */ - -/* - * Interrupt Controller - INTC - */ -/* Interrupt Control Register - ICR (half) */ -#define SH7750_ICR_REGOFS 0xD00000 /* offset */ -#define SH7750_ICR SH7750_P4_REG32(SH7750_ICR_REGOFS) -#define SH7750_ICR_A7 SH7750_A7_REG32(SH7750_ICR_REGOFS) - -#define SH7750_ICR_NMIL 0x8000 /* NMI Input Level */ -#define SH7750_ICR_MAI 0x4000 /* NMI Interrupt Mask */ - -#define SH7750_ICR_NMIB 0x0200 /* NMI Block Mode: */ -#define SH7750_ICR_NMIB_BLK 0x0000 /* NMI requests held pending while - SR.BL bit is set to 1 */ -#define SH7750_ICR_NMIB_NBLK 0x0200 /* NMI requests detected when SR.BL bit - set to 1 */ - -#define SH7750_ICR_NMIE 0x0100 /* NMI Edge Select: */ -#define SH7750_ICR_NMIE_FALL 0x0000 /* Interrupt request detected on falling - edge of NMI input */ -#define SH7750_ICR_NMIE_RISE 0x0100 /* Interrupt request detected on rising - edge of NMI input */ - -#define SH7750_ICR_IRLM 0x0080 /* IRL Pin Mode: */ -#define SH7750_ICR_IRLM_ENC 0x0000 /* IRL\ pins used as a level-encoded - interrupt requests */ -#define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four independent - interrupt requests */ - -/* Interrupt Priority Register A - IPRA (half) */ -#define SH7750_IPRA_REGOFS 0xD00004 /* offset */ -#define SH7750_IPRA SH7750_P4_REG32(SH7750_IPRA_REGOFS) -#define SH7750_IPRA_A7 SH7750_A7_REG32(SH7750_IPRA_REGOFS) - -#define SH7750_IPRA_TMU0 0xF000 /* TMU0 interrupt priority */ -#define SH7750_IPRA_TMU0_S 12 -#define SH7750_IPRA_TMU1 0x0F00 /* TMU1 interrupt priority */ -#define SH7750_IPRA_TMU1_S 8 -#define SH7750_IPRA_TMU2 0x00F0 /* TMU2 interrupt priority */ -#define SH7750_IPRA_TMU2_S 4 -#define SH7750_IPRA_RTC 0x000F /* RTC interrupt priority */ -#define SH7750_IPRA_RTC_S 0 - -/* Interrupt Priority Register B - IPRB (half) */ -#define SH7750_IPRB_REGOFS 0xD00008 /* offset */ -#define SH7750_IPRB SH7750_P4_REG32(SH7750_IPRB_REGOFS) -#define SH7750_IPRB_A7 SH7750_A7_REG32(SH7750_IPRB_REGOFS) - -#define SH7750_IPRB_WDT 0xF000 /* WDT interrupt priority */ -#define SH7750_IPRB_WDT_S 12 -#define SH7750_IPRB_REF 0x0F00 /* Memory Refresh unit interrupt - priority */ -#define SH7750_IPRB_REF_S 8 -#define SH7750_IPRB_SCI1 0x00F0 /* SCI1 interrupt priority */ -#define SH7750_IPRB_SCI1_S 4 - -/* Interrupt Priority Register ó - IPRó (half) */ -#define SH7750_IPRC_REGOFS 0xD00004 /* offset */ -#define SH7750_IPRC SH7750_P4_REG32(SH7750_IPRC_REGOFS) -#define SH7750_IPRC_A7 SH7750_A7_REG32(SH7750_IPRC_REGOFS) - -#define SH7750_IPRC_GPIO 0xF000 /* GPIO interrupt priority */ -#define SH7750_IPRC_GPIO_S 12 -#define SH7750_IPRC_DMAC 0x0F00 /* DMAC interrupt priority */ -#define SH7750_IPRC_DMAC_S 8 -#define SH7750_IPRC_SCIF 0x00F0 /* SCIF interrupt priority */ -#define SH7750_IPRC_SCIF_S 4 -#define SH7750_IPRC_HUDI 0x000F /* H-UDI interrupt priority */ -#define SH7750_IPRC_HUDI_S 0 - - -/* - * User Break Controller registers - */ -#define SH7750_BARA 0x200000 /* Break address regiser A */ -#define SH7750_BAMRA 0x200004 /* Break address mask regiser A */ -#define SH7750_BBRA 0x200008 /* Break bus cycle regiser A */ -#define SH7750_BARB 0x20000c /* Break address regiser B */ -#define SH7750_BAMRB 0x200010 /* Break address mask regiser B */ -#define SH7750_BBRB 0x200014 /* Break bus cycle regiser B */ -#define SH7750_BASRB 0x000018 /* Break ASID regiser B */ -#define SH7750_BDRB 0x200018 /* Break data regiser B */ -#define SH7750_BDMRB 0x20001c /* Break data mask regiser B */ -#define SH7750_BRCR 0x200020 /* Break control register */ - -#define SH7750_BRCR_UDBE 0x0001 /* User break debug enable bit */ - -/* - * Missing in RTEMS, added for QEMU - */ -#define SH7750_BCR3_A7 0x1f800050 -#define SH7750_BCR4_A7 0x1e0a00f0 -#define SH7750_PRECHARGE0_A7 0x1f900088 -#define SH7750_PRECHARGE1_A7 0x1f940088 - -#endif diff --git a/hw/shix.c b/hw/shix.c deleted file mode 100644 index 9577c09..0000000 --- a/hw/shix.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * SHIX 2.0 board description - * - * Copyright (c) 2005 Samuel Tardieu - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -/* - Shix 2.0 board by Alexis Polti, described at - http://perso.enst.fr/~polti/realisations/shix20/ - - More information in target-sh4/README.sh4 -*/ -#include "vl.h" - -#define BIOS_FILENAME "shix_bios.bin" -#define BIOS_ADDRESS 0xA0000000 - -void DMA_run(void) -{ - /* XXXXX */ -} - -void irq_info(void) -{ - /* XXXXX */ -} - -void pic_set_irq(int irq, int level) -{ - /* XXXXX */ -} - -void pic_info() -{ - /* XXXXX */ -} - -void vga_update_display() -{ - /* XXXXX */ -} - -void vga_invalidate_display() -{ - /* XXXXX */ -} - -void vga_screen_dump(const char *filename) -{ - /* XXXXX */ -} - -void shix_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState * ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) -{ - int ret; - CPUState *env; - struct SH7750State *s; - - printf("Initializing CPU\n"); - env = cpu_init(); - - /* Allocate memory space */ - printf("Allocating ROM\n"); - cpu_register_physical_memory(0x00000000, 0x00004000, IO_MEM_ROM); - printf("Allocating SDRAM 1\n"); - cpu_register_physical_memory(0x08000000, 0x01000000, 0x00004000); - printf("Allocating SDRAM 2\n"); - cpu_register_physical_memory(0x0c000000, 0x01000000, 0x01004000); - - /* Load BIOS in 0 (and access it through P2, 0xA0000000) */ - printf("%s: load BIOS '%s'\n", __func__, BIOS_FILENAME); - ret = load_image(BIOS_FILENAME, phys_ram_base); - if (ret < 0) { /* Check bios size */ - fprintf(stderr, "ret=%d\n", ret); - fprintf(stderr, "qemu: could not load SHIX bios '%s'\n", - BIOS_FILENAME); - exit(1); - } - - /* Register peripherals */ - s = sh7750_init(env); - /* XXXXX Check success */ - tc58128_init(s, "shix_linux_nand.bin", NULL); - fprintf(stderr, "initialization terminated\n"); -} - -QEMUMachine shix_machine = { - "shix", - "shix card", - shix_init -}; diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c deleted file mode 100644 index 288fb50..0000000 --- a/hw/slavio_intctl.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * QEMU Sparc SLAVIO interrupt controller emulation - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -//#define DEBUG_IRQ_COUNT -//#define DEBUG_IRQ - -#ifdef DEBUG_IRQ -#define DPRINTF(fmt, args...) \ -do { printf("IRQ: " fmt , ##args); } while (0) -#else -#define DPRINTF(fmt, args...) -#endif - -/* - * Registers of interrupt controller in sun4m. - * - * This is the interrupt controller part of chip STP2001 (Slave I/O), also - * produced as NCR89C105. See - * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt - * - * There is a system master controller and one for each cpu. - * - */ - -#define MAX_CPUS 16 - -typedef struct SLAVIO_INTCTLState { - uint32_t intreg_pending[MAX_CPUS]; - uint32_t intregm_pending; - uint32_t intregm_disabled; - uint32_t target_cpu; -#ifdef DEBUG_IRQ_COUNT - uint64_t irq_count[32]; -#endif - CPUState *cpu_envs[MAX_CPUS]; -} SLAVIO_INTCTLState; - -#define INTCTL_MAXADDR 0xf -#define INTCTLM_MAXADDR 0xf -static void slavio_check_interrupts(void *opaque); - -// per-cpu interrupt controller -static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SLAVIO_INTCTLState *s = opaque; - uint32_t saddr; - int cpu; - - cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; - saddr = (addr & INTCTL_MAXADDR) >> 2; - switch (saddr) { - case 0: - return s->intreg_pending[cpu]; - default: - break; - } - return 0; -} - -static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SLAVIO_INTCTLState *s = opaque; - uint32_t saddr; - int cpu; - - cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12; - saddr = (addr & INTCTL_MAXADDR) >> 2; - switch (saddr) { - case 1: // clear pending softints - if (val & 0x4000) - val |= 80000000; - val &= 0xfffe0000; - s->intreg_pending[cpu] &= ~val; - DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); - break; - case 2: // set softint - val &= 0xfffe0000; - s->intreg_pending[cpu] |= val; - slavio_check_interrupts(s); - DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]); - break; - default: - break; - } -} - -static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = { - slavio_intctl_mem_readl, - slavio_intctl_mem_readl, - slavio_intctl_mem_readl, -}; - -static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = { - slavio_intctl_mem_writel, - slavio_intctl_mem_writel, - slavio_intctl_mem_writel, -}; - -// master system interrupt controller -static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SLAVIO_INTCTLState *s = opaque; - uint32_t saddr; - - saddr = (addr & INTCTLM_MAXADDR) >> 2; - switch (saddr) { - case 0: - return s->intregm_pending & 0x7fffffff; - case 1: - return s->intregm_disabled; - case 4: - return s->target_cpu; - default: - break; - } - return 0; -} - -static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SLAVIO_INTCTLState *s = opaque; - uint32_t saddr; - - saddr = (addr & INTCTLM_MAXADDR) >> 2; - switch (saddr) { - case 2: // clear (enable) - // Force clear unused bits - val &= ~0x4fb2007f; - s->intregm_disabled &= ~val; - DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); - slavio_check_interrupts(s); - break; - case 3: // set (disable, clear pending) - // Force clear unused bits - val &= ~0x4fb2007f; - s->intregm_disabled |= val; - s->intregm_pending &= ~val; - DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled); - break; - case 4: - s->target_cpu = val & (MAX_CPUS - 1); - DPRINTF("Set master irq cpu %d\n", s->target_cpu); - break; - default: - break; - } -} - -static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = { - slavio_intctlm_mem_readl, - slavio_intctlm_mem_readl, - slavio_intctlm_mem_readl, -}; - -static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = { - slavio_intctlm_mem_writel, - slavio_intctlm_mem_writel, - slavio_intctlm_mem_writel, -}; - -void slavio_pic_info(void *opaque) -{ - SLAVIO_INTCTLState *s = opaque; - int i; - - for (i = 0; i < MAX_CPUS; i++) { - term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]); - } - term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled); -} - -void slavio_irq_info(void *opaque) -{ -#ifndef DEBUG_IRQ_COUNT - term_printf("irq statistic code not compiled.\n"); -#else - SLAVIO_INTCTLState *s = opaque; - int i; - int64_t count; - - term_printf("IRQ statistics:\n"); - for (i = 0; i < 32; i++) { - count = s->irq_count[i]; - if (count > 0) - term_printf("%2d: %" PRId64 "\n", i, count); - } -#endif -} - -static const uint32_t intbit_to_level[32] = { - 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12, - 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0, -}; - -static void slavio_check_interrupts(void *opaque) -{ - CPUState *env; - SLAVIO_INTCTLState *s = opaque; - uint32_t pending = s->intregm_pending; - unsigned int i, j, max = 0; - - pending &= ~s->intregm_disabled; - - if (pending && !(s->intregm_disabled & 0x80000000)) { - for (i = 0; i < 32; i++) { - if (pending & (1 << i)) { - if (max < intbit_to_level[i]) - max = intbit_to_level[i]; - } - } - env = s->cpu_envs[s->target_cpu]; - if (!env) { - DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending); - } - else { - if (env->halted) - env->halted = 0; - if (env->interrupt_index == 0) { - DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max); -#ifdef DEBUG_IRQ_COUNT - s->irq_count[max]++; -#endif - env->interrupt_index = TT_EXTINT | max; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } - else - DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index); - } - } - else - DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled); - - for (i = 0; i < MAX_CPUS; i++) { - max = 0; - env = s->cpu_envs[i]; - if (!env) - continue; - for (j = 17; j < 32; j++) { - if (s->intreg_pending[i] & (1 << j)) { - if (max < j - 16) - max = j - 16; - } - } - if (max > 0) { - if (env->halted) - env->halted = 0; - if (env->interrupt_index == 0) { - DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending); -#ifdef DEBUG_IRQ_COUNT - s->irq_count[max]++; -#endif - env->interrupt_index = TT_EXTINT | max; - cpu_interrupt(env, CPU_INTERRUPT_HARD); - } - } - } -} - -/* - * "irq" here is the bit number in the system interrupt register to - * separate serial and keyboard interrupts sharing a level. - */ -void slavio_pic_set_irq(void *opaque, int irq, int level) -{ - SLAVIO_INTCTLState *s = opaque; - - DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level); - if (irq < 32) { - uint32_t mask = 1 << irq; - uint32_t pil = intbit_to_level[irq]; - if (pil > 0) { - if (level) { - s->intregm_pending |= mask; - s->intreg_pending[s->target_cpu] |= 1 << pil; - } - else { - s->intregm_pending &= ~mask; - s->intreg_pending[s->target_cpu] &= ~(1 << pil); - } - } - } - slavio_check_interrupts(s); -} - -void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu) -{ - SLAVIO_INTCTLState *s = opaque; - - DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level); - if (cpu == (unsigned int)-1) { - slavio_pic_set_irq(opaque, irq, level); - return; - } - if (irq < 32) { - uint32_t pil = intbit_to_level[irq]; - if (pil > 0) { - if (level) { - s->intreg_pending[cpu] |= 1 << pil; - } - else { - s->intreg_pending[cpu] &= ~(1 << pil); - } - } - } - slavio_check_interrupts(s); -} - -static void slavio_intctl_save(QEMUFile *f, void *opaque) -{ - SLAVIO_INTCTLState *s = opaque; - int i; - - for (i = 0; i < MAX_CPUS; i++) { - qemu_put_be32s(f, &s->intreg_pending[i]); - } - qemu_put_be32s(f, &s->intregm_pending); - qemu_put_be32s(f, &s->intregm_disabled); - qemu_put_be32s(f, &s->target_cpu); -} - -static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id) -{ - SLAVIO_INTCTLState *s = opaque; - int i; - - if (version_id != 1) - return -EINVAL; - - for (i = 0; i < MAX_CPUS; i++) { - qemu_get_be32s(f, &s->intreg_pending[i]); - } - qemu_get_be32s(f, &s->intregm_pending); - qemu_get_be32s(f, &s->intregm_disabled); - qemu_get_be32s(f, &s->target_cpu); - return 0; -} - -static void slavio_intctl_reset(void *opaque) -{ - SLAVIO_INTCTLState *s = opaque; - int i; - - for (i = 0; i < MAX_CPUS; i++) { - s->intreg_pending[i] = 0; - } - s->intregm_disabled = ~0xffb2007f; - s->intregm_pending = 0; - s->target_cpu = 0; -} - -void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env) -{ - SLAVIO_INTCTLState *s = opaque; - s->cpu_envs[cpu] = env; -} - -void *slavio_intctl_init(uint32_t addr, uint32_t addrg) -{ - int slavio_intctl_io_memory, slavio_intctlm_io_memory, i; - SLAVIO_INTCTLState *s; - - s = qemu_mallocz(sizeof(SLAVIO_INTCTLState)); - if (!s) - return NULL; - - for (i = 0; i < MAX_CPUS; i++) { - slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s); - cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory); - } - - slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s); - cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory); - - register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s); - qemu_register_reset(slavio_intctl_reset, s); - slavio_intctl_reset(s); - return s; -} - diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c deleted file mode 100644 index 904f44e..0000000 --- a/hw/slavio_misc.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * QEMU Sparc SLAVIO aux io port emulation - * - * Copyright (c) 2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -/* debug misc */ -//#define DEBUG_MISC - -/* - * This is the auxio port, chip control and system control part of - * chip STP2001 (Slave I/O), also produced as NCR89C105. See - * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt - * - * This also includes the PMC CPU idle controller. - */ - -#ifdef DEBUG_MISC -#define MISC_DPRINTF(fmt, args...) \ -do { printf("MISC: " fmt , ##args); } while (0) -#else -#define MISC_DPRINTF(fmt, args...) -#endif - -typedef struct MiscState { - int irq; - uint8_t config; - uint8_t aux1, aux2; - uint8_t diag, mctrl, sysctrl; -} MiscState; - -#define MISC_MAXADDR 1 - -static void slavio_misc_update_irq(void *opaque) -{ - MiscState *s = opaque; - - if ((s->aux2 & 0x4) && (s->config & 0x8)) { - pic_set_irq(s->irq, 1); - } else { - pic_set_irq(s->irq, 0); - } -} - -static void slavio_misc_reset(void *opaque) -{ - MiscState *s = opaque; - - // Diagnostic and system control registers not cleared in reset - s->config = s->aux1 = s->aux2 = s->mctrl = 0; -} - -void slavio_set_power_fail(void *opaque, int power_failing) -{ - MiscState *s = opaque; - - MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config); - if (power_failing && (s->config & 0x8)) { - s->aux2 |= 0x4; - } else { - s->aux2 &= ~0x4; - } - slavio_misc_update_irq(s); -} - -static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - MiscState *s = opaque; - - switch (addr & 0xfff0000) { - case 0x1800000: - MISC_DPRINTF("Write config %2.2x\n", val & 0xff); - s->config = val & 0xff; - slavio_misc_update_irq(s); - break; - case 0x1900000: - MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff); - s->aux1 = val & 0xff; - break; - case 0x1910000: - val &= 0x3; - MISC_DPRINTF("Write aux2 %2.2x\n", val); - val |= s->aux2 & 0x4; - if (val & 0x2) // Clear Power Fail int - val &= 0x1; - s->aux2 = val; - if (val & 1) - qemu_system_shutdown_request(); - slavio_misc_update_irq(s); - break; - case 0x1a00000: - MISC_DPRINTF("Write diag %2.2x\n", val & 0xff); - s->diag = val & 0xff; - break; - case 0x1b00000: - MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff); - s->mctrl = val & 0xff; - break; - case 0x1f00000: - MISC_DPRINTF("Write system control %2.2x\n", val & 0xff); - if (val & 1) { - s->sysctrl = 0x2; - qemu_system_reset_request(); - } - break; - case 0xa000000: - MISC_DPRINTF("Write power management %2.2x\n", val & 0xff); -#if 0 - // XXX almost works - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); -#endif - break; - } -} - -static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr) -{ - MiscState *s = opaque; - uint32_t ret = 0; - - switch (addr & 0xfff0000) { - case 0x1800000: - ret = s->config; - MISC_DPRINTF("Read config %2.2x\n", ret); - break; - case 0x1900000: - ret = s->aux1; - MISC_DPRINTF("Read aux1 %2.2x\n", ret); - break; - case 0x1910000: - ret = s->aux2; - MISC_DPRINTF("Read aux2 %2.2x\n", ret); - break; - case 0x1a00000: - ret = s->diag; - MISC_DPRINTF("Read diag %2.2x\n", ret); - break; - case 0x1b00000: - ret = s->mctrl; - MISC_DPRINTF("Read modem control %2.2x\n", ret); - break; - case 0x1f00000: - MISC_DPRINTF("Read system control %2.2x\n", ret); - ret = s->sysctrl; - break; - case 0xa000000: - MISC_DPRINTF("Read power management %2.2x\n", ret); - break; - } - return ret; -} - -static CPUReadMemoryFunc *slavio_misc_mem_read[3] = { - slavio_misc_mem_readb, - slavio_misc_mem_readb, - slavio_misc_mem_readb, -}; - -static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = { - slavio_misc_mem_writeb, - slavio_misc_mem_writeb, - slavio_misc_mem_writeb, -}; - -static void slavio_misc_save(QEMUFile *f, void *opaque) -{ - MiscState *s = opaque; - - qemu_put_be32s(f, &s->irq); - qemu_put_8s(f, &s->config); - qemu_put_8s(f, &s->aux1); - qemu_put_8s(f, &s->aux2); - qemu_put_8s(f, &s->diag); - qemu_put_8s(f, &s->mctrl); - qemu_put_8s(f, &s->sysctrl); -} - -static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id) -{ - MiscState *s = opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_be32s(f, &s->irq); - qemu_get_8s(f, &s->config); - qemu_get_8s(f, &s->aux1); - qemu_get_8s(f, &s->aux2); - qemu_get_8s(f, &s->diag); - qemu_get_8s(f, &s->mctrl); - qemu_get_8s(f, &s->sysctrl); - return 0; -} - -void *slavio_misc_init(uint32_t base, int irq) -{ - int slavio_misc_io_memory; - MiscState *s; - - s = qemu_mallocz(sizeof(MiscState)); - if (!s) - return NULL; - - slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s); - // Slavio control - cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory); - // AUX 1 - cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory); - // AUX 2 - cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory); - // Diagnostics - cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory); - // Modem control - cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory); - // System control - cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory); - // Power management - cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory); - - s->irq = irq; - - register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s); - qemu_register_reset(slavio_misc_reset, s); - slavio_misc_reset(s); - return s; -} diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c deleted file mode 100644 index b13e7c4..0000000 --- a/hw/slavio_serial.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * QEMU Sparc SLAVIO serial port emulation - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -/* debug serial */ -//#define DEBUG_SERIAL - -/* debug keyboard */ -//#define DEBUG_KBD - -/* debug mouse */ -//#define DEBUG_MOUSE - -/* - * This is the serial port, mouse and keyboard part of chip STP2001 - * (Slave I/O), also produced as NCR89C105. See - * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt - * - * The serial ports implement full AMD AM8530 or Zilog Z8530 chips, - * mouse and keyboard ports don't implement all functions and they are - * only asynchronous. There is no DMA. - * - */ - -#ifdef DEBUG_SERIAL -#define SER_DPRINTF(fmt, args...) \ -do { printf("SER: " fmt , ##args); } while (0) -#define pic_set_irq(irq, level) \ -do { printf("SER: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0) -#else -#define SER_DPRINTF(fmt, args...) -#endif -#ifdef DEBUG_KBD -#define KBD_DPRINTF(fmt, args...) \ -do { printf("KBD: " fmt , ##args); } while (0) -#else -#define KBD_DPRINTF(fmt, args...) -#endif -#ifdef DEBUG_MOUSE -#define MS_DPRINTF(fmt, args...) \ -do { printf("SER: " fmt , ##args); } while (0) -#else -#define MS_DPRINTF(fmt, args...) -#endif - -typedef enum { - chn_a, chn_b, -} chn_id_t; - -typedef enum { - ser, kbd, mouse, -} chn_type_t; - -#define KBD_QUEUE_SIZE 256 - -typedef struct { - uint8_t data[KBD_QUEUE_SIZE]; - int rptr, wptr, count; -} KBDQueue; - -typedef struct ChannelState { - int irq; - int reg; - int rxint, txint; - chn_id_t chn; // this channel, A (base+4) or B (base+0) - chn_type_t type; - struct ChannelState *otherchn; - uint8_t rx, tx, wregs[16], rregs[16]; - KBDQueue queue; - CharDriverState *chr; -} ChannelState; - -struct SerialState { - struct ChannelState chn[2]; -}; - -#define SERIAL_MAXADDR 7 - -static void handle_kbd_command(ChannelState *s, int val); -static int serial_can_receive(void *opaque); -static void serial_receive_byte(ChannelState *s, int ch); - -static void put_queue(void *opaque, int b) -{ - ChannelState *s = opaque; - KBDQueue *q = &s->queue; - - KBD_DPRINTF("put: 0x%02x\n", b); - if (q->count >= KBD_QUEUE_SIZE) - return; - q->data[q->wptr] = b; - if (++q->wptr == KBD_QUEUE_SIZE) - q->wptr = 0; - q->count++; - serial_receive_byte(s, 0); -} - -static uint32_t get_queue(void *opaque) -{ - ChannelState *s = opaque; - KBDQueue *q = &s->queue; - int val; - - if (q->count == 0) { - return 0; - } else { - val = q->data[q->rptr]; - if (++q->rptr == KBD_QUEUE_SIZE) - q->rptr = 0; - q->count--; - } - KBD_DPRINTF("get 0x%02x\n", val); - if (q->count > 0) - serial_receive_byte(s, 0); - return val; -} - -static void slavio_serial_update_irq(ChannelState *s) -{ - if ((s->wregs[1] & 1) && // interrupts enabled - (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending - ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) && - s->rxint == 1) || // rx ints enabled, pending - ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p - pic_set_irq(s->irq, 1); - } else { - pic_set_irq(s->irq, 0); - } -} - -static void slavio_serial_reset_chn(ChannelState *s) -{ - int i; - - s->reg = 0; - for (i = 0; i < SERIAL_MAXADDR; i++) { - s->rregs[i] = 0; - s->wregs[i] = 0; - } - s->wregs[4] = 4; - s->wregs[9] = 0xc0; - s->wregs[11] = 8; - s->wregs[14] = 0x30; - s->wregs[15] = 0xf8; - s->rregs[0] = 0x44; - s->rregs[1] = 6; - - s->rx = s->tx = 0; - s->rxint = s->txint = 0; -} - -static void slavio_serial_reset(void *opaque) -{ - SerialState *s = opaque; - slavio_serial_reset_chn(&s->chn[0]); - slavio_serial_reset_chn(&s->chn[1]); -} - -static inline void clr_rxint(ChannelState *s) -{ - s->rxint = 0; - if (s->chn == 0) - s->rregs[3] &= ~0x20; - else { - s->otherchn->rregs[3] &= ~4; - } - slavio_serial_update_irq(s); -} - -static inline void set_rxint(ChannelState *s) -{ - s->rxint = 1; - if (s->chn == 0) - s->rregs[3] |= 0x20; - else { - s->otherchn->rregs[3] |= 4; - } - slavio_serial_update_irq(s); -} - -static inline void clr_txint(ChannelState *s) -{ - s->txint = 0; - if (s->chn == 0) - s->rregs[3] &= ~0x10; - else { - s->otherchn->rregs[3] &= ~2; - } - slavio_serial_update_irq(s); -} - -static inline void set_txint(ChannelState *s) -{ - s->txint = 1; - if (s->chn == 0) - s->rregs[3] |= 0x10; - else { - s->otherchn->rregs[3] |= 2; - } - slavio_serial_update_irq(s); -} - -static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SerialState *ser = opaque; - ChannelState *s; - uint32_t saddr; - int newreg, channel; - - val &= 0xff; - saddr = (addr & 3) >> 1; - channel = (addr & SERIAL_MAXADDR) >> 2; - s = &ser->chn[channel]; - switch (saddr) { - case 0: - SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff); - newreg = 0; - switch (s->reg) { - case 0: - newreg = val & 7; - val &= 0x38; - switch (val) { - case 8: - newreg |= 0x8; - break; - case 0x20: - clr_rxint(s); - break; - case 0x28: - clr_txint(s); - break; - case 0x38: - clr_rxint(s); - clr_txint(s); - break; - default: - break; - } - break; - case 1 ... 8: - case 10 ... 15: - s->wregs[s->reg] = val; - break; - case 9: - switch (val & 0xc0) { - case 0: - default: - break; - case 0x40: - slavio_serial_reset_chn(&ser->chn[1]); - return; - case 0x80: - slavio_serial_reset_chn(&ser->chn[0]); - return; - case 0xc0: - slavio_serial_reset(ser); - return; - } - break; - default: - break; - } - if (s->reg == 0) - s->reg = newreg; - else - s->reg = 0; - break; - case 1: - SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val); - if (s->wregs[5] & 8) { // tx enabled - s->tx = val; - if (s->chr) - qemu_chr_write(s->chr, &s->tx, 1); - else if (s->type == kbd) { - handle_kbd_command(s, val); - } - s->txint = 1; - s->rregs[0] |= 4; // Tx buffer empty - s->rregs[1] |= 1; // All sent - set_txint(s); - slavio_serial_update_irq(s); - } - break; - default: - break; - } -} - -static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) -{ - SerialState *ser = opaque; - ChannelState *s; - uint32_t saddr; - uint32_t ret; - int channel; - - saddr = (addr & 3) >> 1; - channel = (addr & SERIAL_MAXADDR) >> 2; - s = &ser->chn[channel]; - switch (saddr) { - case 0: - SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]); - ret = s->rregs[s->reg]; - s->reg = 0; - return ret; - case 1: - s->rregs[0] &= ~1; - clr_rxint(s); - if (s->type == kbd) - ret = get_queue(s); - else - ret = s->rx; - SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', ret); - return ret; - default: - break; - } - return 0; -} - -static int serial_can_receive(void *opaque) -{ - ChannelState *s = opaque; - if (((s->wregs[3] & 1) == 0) // Rx not enabled - || ((s->rregs[0] & 1) == 1)) // char already available - return 0; - else - return 1; -} - -static void serial_receive_byte(ChannelState *s, int ch) -{ - SER_DPRINTF("put ch %d\n", ch); - s->rregs[0] |= 1; - s->rx = ch; - set_rxint(s); -} - -static void serial_receive_break(ChannelState *s) -{ - s->rregs[0] |= 0x80; - slavio_serial_update_irq(s); -} - -static void serial_receive1(void *opaque, const uint8_t *buf, int size) -{ - ChannelState *s = opaque; - serial_receive_byte(s, buf[0]); -} - -static void serial_event(void *opaque, int event) -{ - ChannelState *s = opaque; - if (event == CHR_EVENT_BREAK) - serial_receive_break(s); -} - -static CPUReadMemoryFunc *slavio_serial_mem_read[3] = { - slavio_serial_mem_readb, - slavio_serial_mem_readb, - slavio_serial_mem_readb, -}; - -static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = { - slavio_serial_mem_writeb, - slavio_serial_mem_writeb, - slavio_serial_mem_writeb, -}; - -static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s) -{ - qemu_put_be32s(f, &s->irq); - qemu_put_be32s(f, &s->reg); - qemu_put_be32s(f, &s->rxint); - qemu_put_be32s(f, &s->txint); - qemu_put_8s(f, &s->rx); - qemu_put_8s(f, &s->tx); - qemu_put_buffer(f, s->wregs, 16); - qemu_put_buffer(f, s->rregs, 16); -} - -static void slavio_serial_save(QEMUFile *f, void *opaque) -{ - SerialState *s = opaque; - - slavio_serial_save_chn(f, &s->chn[0]); - slavio_serial_save_chn(f, &s->chn[1]); -} - -static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id) -{ - if (version_id != 1) - return -EINVAL; - - qemu_get_be32s(f, &s->irq); - qemu_get_be32s(f, &s->reg); - qemu_get_be32s(f, &s->rxint); - qemu_get_be32s(f, &s->txint); - qemu_get_8s(f, &s->rx); - qemu_get_8s(f, &s->tx); - qemu_get_buffer(f, s->wregs, 16); - qemu_get_buffer(f, s->rregs, 16); - return 0; -} - -static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) -{ - SerialState *s = opaque; - int ret; - - ret = slavio_serial_load_chn(f, &s->chn[0], version_id); - if (ret != 0) - return ret; - ret = slavio_serial_load_chn(f, &s->chn[1], version_id); - return ret; - -} - -SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2) -{ - int slavio_serial_io_memory, i; - SerialState *s; - - s = qemu_mallocz(sizeof(SerialState)); - if (!s) - return NULL; - - slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); - cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); - - s->chn[0].chr = chr1; - s->chn[1].chr = chr2; - - for (i = 0; i < 2; i++) { - s->chn[i].irq = irq; - s->chn[i].chn = 1 - i; - s->chn[i].type = ser; - if (s->chn[i].chr) { - qemu_chr_add_read_handler(s->chn[i].chr, serial_can_receive, serial_receive1, &s->chn[i]); - qemu_chr_add_event_handler(s->chn[i].chr, serial_event); - } - } - s->chn[0].otherchn = &s->chn[1]; - s->chn[1].otherchn = &s->chn[0]; - register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s); - qemu_register_reset(slavio_serial_reset, s); - slavio_serial_reset(s); - return s; -} - -static const uint8_t keycodes[128] = { - 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12, - 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112, - 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0, - 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66, - 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67, -}; - -static void sunkbd_event(void *opaque, int ch) -{ - ChannelState *s = opaque; - int release = ch & 0x80; - - ch = keycodes[ch & 0x7f]; - KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press"); - put_queue(s, ch | release); -} - -static void handle_kbd_command(ChannelState *s, int val) -{ - KBD_DPRINTF("Command %d\n", val); - switch (val) { - case 1: // Reset, return type code - put_queue(s, 0xff); - put_queue(s, 5); // Type 5 - break; - case 7: // Query layout - put_queue(s, 0xfe); - put_queue(s, 0x20); // XXX, layout? - break; - default: - break; - } -} - -static void sunmouse_event(void *opaque, - int dx, int dy, int dz, int buttons_state) -{ - ChannelState *s = opaque; - int ch; - - // XXX - ch = 0x42; - serial_receive_byte(s, ch); -} - -void slavio_serial_ms_kbd_init(int base, int irq) -{ - int slavio_serial_io_memory, i; - SerialState *s; - - s = qemu_mallocz(sizeof(SerialState)); - if (!s) - return; - for (i = 0; i < 2; i++) { - s->chn[i].irq = irq; - s->chn[i].chn = 1 - i; - s->chn[i].chr = NULL; - } - s->chn[0].otherchn = &s->chn[1]; - s->chn[1].otherchn = &s->chn[0]; - s->chn[0].type = mouse; - s->chn[1].type = kbd; - - slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); - cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); - - qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0); - qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); - qemu_register_reset(slavio_serial_reset, s); - slavio_serial_reset(s); -} diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c deleted file mode 100644 index 976f0d4..0000000 --- a/hw/slavio_timer.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * QEMU Sparc SLAVIO timer controller emulation - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -//#define DEBUG_TIMER - -#ifdef DEBUG_TIMER -#define DPRINTF(fmt, args...) \ -do { printf("TIMER: " fmt , ##args); } while (0) -#else -#define DPRINTF(fmt, args...) -#endif - -/* - * Registers of hardware timer in sun4m. - * - * This is the timer/counter part of chip STP2001 (Slave I/O), also - * produced as NCR89C105. See - * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt - * - * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0 - * are zero. Bit 31 is 1 when count has been reached. - * - * Per-CPU timers interrupt local CPU, system timer uses normal - * interrupt routing. - * - */ - -typedef struct SLAVIO_TIMERState { - uint32_t limit, count, counthigh; - int64_t count_load_time; - int64_t expire_time; - int64_t stop_time, tick_offset; - QEMUTimer *irq_timer; - int irq; - int reached, stopped; - int mode; // 0 = processor, 1 = user, 2 = system - unsigned int cpu; -} SLAVIO_TIMERState; - -#define TIMER_MAXADDR 0x1f -#define CNT_FREQ 2000000 - -// Update count, set irq, update expire_time -static void slavio_timer_get_out(SLAVIO_TIMERState *s) -{ - int out; - int64_t diff, ticks, count; - uint32_t limit; - - // There are three clock tick units: CPU ticks, register units - // (nanoseconds), and counter ticks (500 ns). - if (s->mode == 1 && s->stopped) - ticks = s->stop_time; - else - ticks = qemu_get_clock(vm_clock) - s->tick_offset; - - out = (ticks > s->expire_time); - if (out) - s->reached = 0x80000000; - if (!s->limit) - limit = 0x7fffffff; - else - limit = s->limit; - - // Convert register units to counter ticks - limit = limit >> 9; - - // Convert cpu ticks to counter ticks - diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec); - - // Calculate what the counter should be, convert to register - // units - count = diff % limit; - s->count = count << 9; - s->counthigh = count >> 22; - - // Expire time: CPU ticks left to next interrupt - // Convert remaining counter ticks to CPU ticks - s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ); - - DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" PRId64 " stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode); - - if (s->mode != 1) - pic_set_irq_cpu(s->irq, out, s->cpu); -} - -// timer callback -static void slavio_timer_irq(void *opaque) -{ - SLAVIO_TIMERState *s = opaque; - - if (!s->irq_timer) - return; - slavio_timer_get_out(s); - if (s->mode != 1) - qemu_mod_timer(s->irq_timer, s->expire_time); -} - -static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr) -{ - SLAVIO_TIMERState *s = opaque; - uint32_t saddr; - - saddr = (addr & TIMER_MAXADDR) >> 2; - switch (saddr) { - case 0: - // read limit (system counter mode) or read most signifying - // part of counter (user mode) - if (s->mode != 1) { - // clear irq - pic_set_irq_cpu(s->irq, 0, s->cpu); - s->count_load_time = qemu_get_clock(vm_clock); - s->reached = 0; - return s->limit; - } - else { - slavio_timer_get_out(s); - return s->counthigh & 0x7fffffff; - } - case 1: - // read counter and reached bit (system mode) or read lsbits - // of counter (user mode) - slavio_timer_get_out(s); - if (s->mode != 1) - return (s->count & 0x7fffffff) | s->reached; - else - return s->count; - case 3: - // read start/stop status - return s->stopped; - case 4: - // read user/system mode - return s->mode & 1; - default: - return 0; - } -} - -static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - SLAVIO_TIMERState *s = opaque; - uint32_t saddr; - - saddr = (addr & TIMER_MAXADDR) >> 2; - switch (saddr) { - case 0: - // set limit, reset counter - s->count_load_time = qemu_get_clock(vm_clock); - // fall through - case 2: - // set limit without resetting counter - if (!val) - s->limit = 0x7fffffff; - else - s->limit = val & 0x7fffffff; - slavio_timer_irq(s); - break; - case 3: - // start/stop user counter - if (s->mode == 1) { - if (val & 1) { - s->stop_time = qemu_get_clock(vm_clock); - s->stopped = 1; - } - else { - if (s->stopped) - s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time; - s->stopped = 0; - } - } - break; - case 4: - // bit 0: user (1) or system (0) counter mode - if (s->mode == 0 || s->mode == 1) - s->mode = val & 1; - break; - default: - break; - } -} - -static CPUReadMemoryFunc *slavio_timer_mem_read[3] = { - slavio_timer_mem_readl, - slavio_timer_mem_readl, - slavio_timer_mem_readl, -}; - -static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = { - slavio_timer_mem_writel, - slavio_timer_mem_writel, - slavio_timer_mem_writel, -}; - -static void slavio_timer_save(QEMUFile *f, void *opaque) -{ - SLAVIO_TIMERState *s = opaque; - - qemu_put_be32s(f, &s->limit); - qemu_put_be32s(f, &s->count); - qemu_put_be32s(f, &s->counthigh); - qemu_put_be64s(f, &s->count_load_time); - qemu_put_be64s(f, &s->expire_time); - qemu_put_be64s(f, &s->stop_time); - qemu_put_be64s(f, &s->tick_offset); - qemu_put_be32s(f, &s->irq); - qemu_put_be32s(f, &s->reached); - qemu_put_be32s(f, &s->stopped); - qemu_put_be32s(f, &s->mode); -} - -static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id) -{ - SLAVIO_TIMERState *s = opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_be32s(f, &s->limit); - qemu_get_be32s(f, &s->count); - qemu_get_be32s(f, &s->counthigh); - qemu_get_be64s(f, &s->count_load_time); - qemu_get_be64s(f, &s->expire_time); - qemu_get_be64s(f, &s->stop_time); - qemu_get_be64s(f, &s->tick_offset); - qemu_get_be32s(f, &s->irq); - qemu_get_be32s(f, &s->reached); - qemu_get_be32s(f, &s->stopped); - qemu_get_be32s(f, &s->mode); - return 0; -} - -static void slavio_timer_reset(void *opaque) -{ - SLAVIO_TIMERState *s = opaque; - - s->limit = 0; - s->count = 0; - s->count_load_time = qemu_get_clock(vm_clock);; - s->stop_time = s->count_load_time; - s->tick_offset = 0; - s->reached = 0; - s->mode &= 2; - s->stopped = 1; - slavio_timer_get_out(s); -} - -void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu) -{ - int slavio_timer_io_memory; - SLAVIO_TIMERState *s; - - s = qemu_mallocz(sizeof(SLAVIO_TIMERState)); - if (!s) - return; - s->irq = irq; - s->mode = mode; - s->cpu = cpu; - s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s); - - slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read, - slavio_timer_mem_write, s); - cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory); - register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s); - qemu_register_reset(slavio_timer_reset, s); - slavio_timer_reset(s); -} diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 214e92e..28b5c5d 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -8,6 +8,7 @@ */ #include "vl.h" +#include "irq.h" /* For crc32 */ #include <zlib.h> @@ -24,8 +25,7 @@ typedef struct { uint16_t gpr; uint16_t ptr; uint16_t ercv; - void *pic; - int irq; + qemu_irq irq; int bank; int packet_num; int tx_alloc; @@ -86,7 +86,7 @@ static void smc91c111_update(smc91c111_state *s) if (s->tx_fifo_done_len != 0) s->int_level |= INT_TX; level = (s->int_level & s->int_mask) != 0; - pic_set_irq_new(s->pic, s->irq, level); + qemu_set_irq(s->irq, level); } /* Try to allocate a packet. Returns 0x80 on failure. */ @@ -159,7 +159,6 @@ static void smc91c111_do_tx(smc91c111_state *s) int len; int control; int add_crc; - uint32_t crc; int packetnum; uint8_t *p; @@ -192,7 +191,7 @@ static void smc91c111_do_tx(smc91c111_state *s) about. */ add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0; if (add_crc) { - crc = crc32(~0, p, len); + uint32_t crc = crc32(~0, p, len); memcpy(p + len, &crc, 4); len += 4; } @@ -692,7 +691,7 @@ static CPUWriteMemoryFunc *smc91c111_writefn[] = { smc91c111_writel }; -void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq) +void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) { smc91c111_state *s; int iomemtype; @@ -702,7 +701,6 @@ void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq) smc91c111_writefn, s); cpu_register_physical_memory(base, 16, iomemtype); s->base = base; - s->pic = pic; s->irq = irq; memcpy(s->macaddr, nd->macaddr, 6); diff --git a/hw/sun4m.c b/hw/sun4m.c deleted file mode 100644 index 203732f..0000000 --- a/hw/sun4m.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * QEMU Sun4m System Emulator - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -#define KERNEL_LOAD_ADDR 0x00004000 -#define CMDLINE_ADDR 0x007ff000 -#define INITRD_LOAD_ADDR 0x00800000 -#define PROM_SIZE_MAX (256 * 1024) -#define PROM_ADDR 0xffd00000 -#define PROM_FILENAME "openbios-sparc32" -#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */ -#define PHYS_JJ_IDPROM_OFF 0x1FD8 -#define PHYS_JJ_EEPROM_SIZE 0x2000 -// IRQs are not PIL ones, but master interrupt controller register -// bits -#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */ -#define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */ -#define PHYS_JJ_SLAVIO 0x70000000 /* Slavio base */ -#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */ -#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */ -#define PHYS_JJ_ESP_IRQ 18 -#define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */ -#define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */ -#define PHYS_JJ_LE_IRQ 16 -#define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */ -#define PHYS_JJ_CLOCK_IRQ 7 -#define PHYS_JJ_CLOCK1 0x71D10000 /* System timer/counter, L10 */ -#define PHYS_JJ_CLOCK1_IRQ 19 -#define PHYS_JJ_INTR0 0x71E00000 /* Per-CPU interrupt control registers */ -#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */ -#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */ -#define PHYS_JJ_MS_KBD_IRQ 14 -#define PHYS_JJ_SER 0x71100000 /* Serial */ -#define PHYS_JJ_SER_IRQ 15 -#define PHYS_JJ_FDC 0x71400000 /* Floppy */ -#define PHYS_JJ_FLOPPY_IRQ 22 -#define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */ -#define MAX_CPUS 16 - -/* TSC handling */ - -uint64_t cpu_get_tsc() -{ - return qemu_get_clock(vm_clock); -} - -int DMA_get_channel_mode (int nchan) -{ - return 0; -} -int DMA_read_memory (int nchan, void *buf, int pos, int size) -{ - return 0; -} -int DMA_write_memory (int nchan, void *buf, int pos, int size) -{ - return 0; -} -void DMA_hold_DREQ (int nchan) {} -void DMA_release_DREQ (int nchan) {} -void DMA_schedule(int nchan) {} -void DMA_run (void) {} -void DMA_init (int high_page_enable) {} -void DMA_register_channel (int nchan, - DMA_transfer_handler transfer_handler, - void *opaque) -{ -} - -static void nvram_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) -{ - m48t59_write(nvram, addr++, (value >> 8) & 0xff); - m48t59_write(nvram, addr++, value & 0xff); -} - -static void nvram_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) -{ - m48t59_write(nvram, addr++, value >> 24); - m48t59_write(nvram, addr++, (value >> 16) & 0xff); - m48t59_write(nvram, addr++, (value >> 8) & 0xff); - m48t59_write(nvram, addr++, value & 0xff); -} - -static void nvram_set_string (m48t59_t *nvram, uint32_t addr, - const unsigned char *str, uint32_t max) -{ - unsigned int i; - - for (i = 0; i < max && str[i] != '\0'; i++) { - m48t59_write(nvram, addr + i, str[i]); - } - m48t59_write(nvram, addr + max - 1, '\0'); -} - -static m48t59_t *nvram; - -extern int nographic; - -static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline, - int boot_device, uint32_t RAM_size, - uint32_t kernel_size, - int width, int height, int depth) -{ - unsigned char tmp = 0; - int i, j; - - // Try to match PPC NVRAM - nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16); - nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */ - // NVRAM_size, arch not applicable - m48t59_write(nvram, 0x2D, smp_cpus & 0xff); - m48t59_write(nvram, 0x2E, 0); - m48t59_write(nvram, 0x2F, nographic & 0xff); - nvram_set_lword(nvram, 0x30, RAM_size); - m48t59_write(nvram, 0x34, boot_device & 0xff); - nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR); - nvram_set_lword(nvram, 0x3C, kernel_size); - if (cmdline) { - strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); - nvram_set_lword(nvram, 0x40, CMDLINE_ADDR); - nvram_set_lword(nvram, 0x44, strlen(cmdline)); - } - // initrd_image, initrd_size passed differently - nvram_set_word(nvram, 0x54, width); - nvram_set_word(nvram, 0x56, height); - nvram_set_word(nvram, 0x58, depth); - - // Sun4m specific use - i = 0x1fd8; - m48t59_write(nvram, i++, 0x01); - m48t59_write(nvram, i++, 0x80); /* Sun4m OBP */ - j = 0; - m48t59_write(nvram, i++, macaddr[j++]); - m48t59_write(nvram, i++, macaddr[j++]); - m48t59_write(nvram, i++, macaddr[j++]); - m48t59_write(nvram, i++, macaddr[j++]); - m48t59_write(nvram, i++, macaddr[j++]); - m48t59_write(nvram, i, macaddr[j]); - - /* Calculate checksum */ - for (i = 0x1fd8; i < 0x1fe7; i++) { - tmp ^= m48t59_read(nvram, i); - } - m48t59_write(nvram, 0x1fe7, tmp); -} - -static void *slavio_intctl; - -void pic_info() -{ - slavio_pic_info(slavio_intctl); -} - -void irq_info() -{ - slavio_irq_info(slavio_intctl); -} - -void pic_set_irq(int irq, int level) -{ - slavio_pic_set_irq(slavio_intctl, irq, level); -} - -void pic_set_irq_new(void *opaque, int irq, int level) -{ - pic_set_irq(irq, level); -} - -void pic_set_irq_cpu(int irq, int level, unsigned int cpu) -{ - slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu); -} - -static void *iommu; - -uint32_t iommu_translate(uint32_t addr) -{ - return iommu_translate_local(iommu, addr); -} - -static void *slavio_misc; - -void qemu_system_powerdown(void) -{ - slavio_set_power_fail(slavio_misc, 1); -} - -static void main_cpu_reset(void *opaque) -{ - CPUState *env = opaque; - cpu_reset(env); -} - -/* Sun4m hardware initialisation */ -static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) -{ - CPUState *env, *envs[MAX_CPUS]; - char buf[1024]; - int ret, linux_boot; - unsigned int i; - long vram_size = 0x100000, prom_offset, initrd_size, kernel_size; - - linux_boot = (kernel_filename != NULL); - - /* init CPUs */ - for(i = 0; i < smp_cpus; i++) { - env = cpu_init(); - envs[i] = env; - if (i != 0) - env->halted = 1; - register_savevm("cpu", i, 3, cpu_save, cpu_load, env); - qemu_register_reset(main_cpu_reset, env); - } - /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, 0); - - iommu = iommu_init(PHYS_JJ_IOMMU); - slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G); - for(i = 0; i < smp_cpus; i++) { - slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); - } - - tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); - if (nd_table[0].vlan) { - if (nd_table[0].model == NULL - || strcmp(nd_table[0].model, "lance") == 0) { - lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); - } else { - fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); - exit (1); - } - } - nvram = m48t59_init(0, PHYS_JJ_EEPROM, 0, PHYS_JJ_EEPROM_SIZE, 8); - for (i = 0; i < MAX_CPUS; i++) { - slavio_timer_init(PHYS_JJ_CLOCK + i * TARGET_PAGE_SIZE, PHYS_JJ_CLOCK_IRQ, 0, i); - } - slavio_timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ, 2, (unsigned int)-1); - slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ); - // Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device - // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device - slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); - fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); - esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA); - slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ); - - prom_offset = ram_size + vram_size; - cpu_register_physical_memory(PROM_ADDR, - (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, - prom_offset | IO_MEM_ROM); - - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); - ret = load_elf(buf, 0, NULL); - if (ret < 0) { - fprintf(stderr, "qemu: could not load prom '%s'\n", - buf); - exit(1); - } - - kernel_size = 0; - if (linux_boot) { - kernel_size = load_elf(kernel_filename, -0xf0000000, NULL); - if (kernel_size < 0) - kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) - kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - - /* load initrd */ - initrd_size = 0; - if (initrd_filename) { - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } - if (initrd_size > 0) { - for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) - == 0x48647253) { // HdrS - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); - break; - } - } - } - } - nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth); -} - -QEMUMachine sun4m_machine = { - "sun4m", - "Sun4m platform", - sun4m_init, -}; diff --git a/hw/sun4u.c b/hw/sun4u.c deleted file mode 100644 index 6d41369..0000000 --- a/hw/sun4u.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * QEMU Sun4u System Emulator - * - * Copyright (c) 2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -#include "m48t59.h" - -#define KERNEL_LOAD_ADDR 0x00404000 -#define CMDLINE_ADDR 0x003ff000 -#define INITRD_LOAD_ADDR 0x00300000 -#define PROM_SIZE_MAX (512 * 1024) -#define PROM_ADDR 0x1fff0000000ULL -#define APB_SPECIAL_BASE 0x1fe00000000ULL -#define APB_MEM_BASE 0x1ff00000000ULL -#define VGA_BASE (APB_MEM_BASE + 0x400000ULL) -#define PROM_FILENAME "openbios-sparc64" -#define NVRAM_SIZE 0x2000 - -/* TSC handling */ - -uint64_t cpu_get_tsc() -{ - return qemu_get_clock(vm_clock); -} - -int DMA_get_channel_mode (int nchan) -{ - return 0; -} -int DMA_read_memory (int nchan, void *buf, int pos, int size) -{ - return 0; -} -int DMA_write_memory (int nchan, void *buf, int pos, int size) -{ - return 0; -} -void DMA_hold_DREQ (int nchan) {} -void DMA_release_DREQ (int nchan) {} -void DMA_schedule(int nchan) {} -void DMA_run (void) {} -void DMA_init (int high_page_enable) {} -void DMA_register_channel (int nchan, - DMA_transfer_handler transfer_handler, - void *opaque) -{ -} - -/* NVRAM helpers */ -void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value) -{ - m48t59_write(nvram, addr, value); -} - -uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr) -{ - return m48t59_read(nvram, addr); -} - -void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value) -{ - m48t59_write(nvram, addr, value >> 8); - m48t59_write(nvram, addr + 1, value & 0xFF); -} - -uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr) -{ - uint16_t tmp; - - tmp = m48t59_read(nvram, addr) << 8; - tmp |= m48t59_read(nvram, addr + 1); - - return tmp; -} - -void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value) -{ - m48t59_write(nvram, addr, value >> 24); - m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF); - m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF); - m48t59_write(nvram, addr + 3, value & 0xFF); -} - -uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr) -{ - uint32_t tmp; - - tmp = m48t59_read(nvram, addr) << 24; - tmp |= m48t59_read(nvram, addr + 1) << 16; - tmp |= m48t59_read(nvram, addr + 2) << 8; - tmp |= m48t59_read(nvram, addr + 3); - - return tmp; -} - -void NVRAM_set_string (m48t59_t *nvram, uint32_t addr, - const unsigned char *str, uint32_t max) -{ - int i; - - for (i = 0; i < max && str[i] != '\0'; i++) { - m48t59_write(nvram, addr + i, str[i]); - } - m48t59_write(nvram, addr + max - 1, '\0'); -} - -int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max) -{ - int i; - - memset(dst, 0, max); - for (i = 0; i < max; i++) { - dst[i] = NVRAM_get_byte(nvram, addr + i); - if (dst[i] == '\0') - break; - } - - return i; -} - -static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value) -{ - uint16_t tmp; - uint16_t pd, pd1, pd2; - - tmp = prev >> 8; - pd = prev ^ value; - pd1 = pd & 0x000F; - pd2 = ((pd >> 4) & 0x000F) ^ pd1; - tmp ^= (pd1 << 3) | (pd1 << 8); - tmp ^= pd2 | (pd2 << 7) | (pd2 << 12); - - return tmp; -} - -uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count) -{ - uint32_t i; - uint16_t crc = 0xFFFF; - int odd; - - odd = count & 1; - count &= ~1; - for (i = 0; i != count; i++) { - crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i)); - } - if (odd) { - crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8); - } - - return crc; -} - -extern int nographic; - -int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size, - const unsigned char *arch, - uint32_t RAM_size, int boot_device, - uint32_t kernel_image, uint32_t kernel_size, - const char *cmdline, - uint32_t initrd_image, uint32_t initrd_size, - uint32_t NVRAM_image, - int width, int height, int depth) -{ - uint16_t crc; - - /* Set parameters for Open Hack'Ware BIOS */ - NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16); - NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */ - NVRAM_set_word(nvram, 0x14, NVRAM_size); - NVRAM_set_string(nvram, 0x20, arch, 16); - NVRAM_set_byte(nvram, 0x2f, nographic & 0xff); - NVRAM_set_lword(nvram, 0x30, RAM_size); - NVRAM_set_byte(nvram, 0x34, boot_device); - NVRAM_set_lword(nvram, 0x38, kernel_image); - NVRAM_set_lword(nvram, 0x3C, kernel_size); - if (cmdline) { - /* XXX: put the cmdline in NVRAM too ? */ - strcpy(phys_ram_base + CMDLINE_ADDR, cmdline); - NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR); - NVRAM_set_lword(nvram, 0x44, strlen(cmdline)); - } else { - NVRAM_set_lword(nvram, 0x40, 0); - NVRAM_set_lword(nvram, 0x44, 0); - } - NVRAM_set_lword(nvram, 0x48, initrd_image); - NVRAM_set_lword(nvram, 0x4C, initrd_size); - NVRAM_set_lword(nvram, 0x50, NVRAM_image); - - NVRAM_set_word(nvram, 0x54, width); - NVRAM_set_word(nvram, 0x56, height); - NVRAM_set_word(nvram, 0x58, depth); - crc = NVRAM_compute_crc(nvram, 0x00, 0xF8); - NVRAM_set_word(nvram, 0xFC, crc); - - return 0; -} - -void pic_info() -{ -} - -void irq_info() -{ -} - -void pic_set_irq(int irq, int level) -{ -} - -void pic_set_irq_new(void *opaque, int irq, int level) -{ -} - -void qemu_system_powerdown(void) -{ -} - -static void main_cpu_reset(void *opaque) -{ - CPUState *env = opaque; - cpu_reset(env); -} - -static const int ide_iobase[2] = { 0x1f0, 0x170 }; -static const int ide_iobase2[2] = { 0x3f6, 0x376 }; -static const int ide_irq[2] = { 14, 15 }; - -static const int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; -static const int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; - -static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; -static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; - -static fdctrl_t *floppy_controller; - -/* Sun4u hardware initialisation */ -static void sun4u_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) -{ - CPUState *env; - char buf[1024]; - m48t59_t *nvram; - int ret, linux_boot; - unsigned int i; - long prom_offset, initrd_size, kernel_size; - PCIBus *pci_bus; - - linux_boot = (kernel_filename != NULL); - - env = cpu_init(); - register_savevm("cpu", 0, 3, cpu_save, cpu_load, env); - qemu_register_reset(main_cpu_reset, env); - - /* allocate RAM */ - cpu_register_physical_memory(0, ram_size, 0); - - prom_offset = ram_size + vga_ram_size; - cpu_register_physical_memory(PROM_ADDR, - (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, - prom_offset | IO_MEM_ROM); - - snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME); - ret = load_elf(buf, 0, NULL); - if (ret < 0) { - fprintf(stderr, "qemu: could not load prom '%s'\n", - buf); - exit(1); - } - - kernel_size = 0; - initrd_size = 0; - if (linux_boot) { - /* XXX: put correct offset */ - kernel_size = load_elf(kernel_filename, 0, NULL); - if (kernel_size < 0) - kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) - kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR); - if (kernel_size < 0) { - fprintf(stderr, "qemu: could not load kernel '%s'\n", - kernel_filename); - exit(1); - } - - /* load initrd */ - if (initrd_filename) { - initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); - if (initrd_size < 0) { - fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", - initrd_filename); - exit(1); - } - } - if (initrd_size > 0) { - for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) { - if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i) - == 0x48647253) { // HdrS - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR); - stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size); - break; - } - } - } - } - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL); - isa_mem_base = VGA_BASE; - pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size); - - for(i = 0; i < MAX_SERIAL_PORTS; i++) { - if (serial_hds[i]) { - serial_init(&pic_set_irq_new, NULL, - serial_io[i], serial_irq[i], serial_hds[i]); - } - } - - for(i = 0; i < MAX_PARALLEL_PORTS; i++) { - if (parallel_hds[i]) { - parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]); - } - } - - for(i = 0; i < nb_nics; i++) { - if (!nd_table[i].model) - nd_table[i].model = "ne2k_pci"; - pci_nic_init(pci_bus, &nd_table[i]); - } - - pci_cmd646_ide_init(pci_bus, bs_table, 1); - kbd_init(); - floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); - nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59); - sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device, - KERNEL_LOAD_ADDR, kernel_size, - kernel_cmdline, - INITRD_LOAD_ADDR, initrd_size, - /* XXX: need an option to load a NVRAM image */ - 0, - graphic_width, graphic_height, graphic_depth); - -} - -QEMUMachine sun4u_machine = { - "sun4u", - "Sun4u platform", - sun4u_init, -}; diff --git a/hw/tc58128.c b/hw/tc58128.c deleted file mode 100644 index a8b26f7..0000000 --- a/hw/tc58128.c +++ /dev/null @@ -1,181 +0,0 @@ -#include <assert.h> -#include "vl.h" - -#define CE1 0x0100 -#define CE2 0x0200 -#define RE 0x0400 -#define WE 0x0800 -#define ALE 0x1000 -#define CLE 0x2000 -#define RDY1 0x4000 -#define RDY2 0x8000 -#define RDY(n) ((n) == 0 ? RDY1 : RDY2) - -typedef enum { WAIT, READ1, READ2, READ3 } state_t; - -typedef struct { - uint8_t *flash_contents; - state_t state; - uint32_t address; - uint8_t address_cycle; -} tc58128_dev; - -static tc58128_dev tc58128_devs[2]; - -#define FLASH_SIZE (16*1024*1024) - -void init_dev(tc58128_dev * dev, char *filename) -{ - int ret, blocks; - - dev->state = WAIT; - dev->flash_contents = qemu_mallocz(FLASH_SIZE); - memset(dev->flash_contents, 0xff, FLASH_SIZE); - if (!dev->flash_contents) { - fprintf(stderr, "could not alloc memory for flash\n"); - exit(1); - } - if (filename) { - /* Load flash image skipping the first block */ - ret = load_image(filename, dev->flash_contents + 528 * 32); - if (ret < 0) { - fprintf(stderr, "ret=%d\n", ret); - fprintf(stderr, "qemu: could not load flash image %s\n", - filename); - exit(1); - } else { - /* Build first block with number of blocks */ - blocks = (ret + 528 * 32 - 1) / (528 * 32); - dev->flash_contents[0] = blocks & 0xff; - dev->flash_contents[1] = (blocks >> 8) & 0xff; - dev->flash_contents[2] = (blocks >> 16) & 0xff; - dev->flash_contents[3] = (blocks >> 24) & 0xff; - fprintf(stderr, "loaded %d bytes for %s into flash\n", ret, - filename); - } - } -} - -void handle_command(tc58128_dev * dev, uint8_t command) -{ - switch (command) { - case 0xff: - fprintf(stderr, "reset flash device\n"); - dev->state = WAIT; - break; - case 0x00: - fprintf(stderr, "read mode 1\n"); - dev->state = READ1; - dev->address_cycle = 0; - break; - case 0x01: - fprintf(stderr, "read mode 2\n"); - dev->state = READ2; - dev->address_cycle = 0; - break; - case 0x50: - fprintf(stderr, "read mode 3\n"); - dev->state = READ3; - dev->address_cycle = 0; - break; - default: - fprintf(stderr, "unknown flash command 0x%02x\n", command); - assert(0); - } -} - -void handle_address(tc58128_dev * dev, uint8_t data) -{ - switch (dev->state) { - case READ1: - case READ2: - case READ3: - switch (dev->address_cycle) { - case 0: - dev->address = data; - if (dev->state == READ2) - dev->address |= 0x100; - else if (dev->state == READ3) - dev->address |= 0x200; - break; - case 1: - dev->address += data * 528 * 0x100; - break; - case 2: - dev->address += data * 528; - fprintf(stderr, "address pointer in flash: 0x%08x\n", - dev->address); - break; - default: - /* Invalid data */ - assert(0); - } - dev->address_cycle++; - break; - default: - assert(0); - } -} - -uint8_t handle_read(tc58128_dev * dev) -{ -#if 0 - if (dev->address % 0x100000 == 0) - fprintf(stderr, "reading flash at address 0x%08x\n", dev->address); -#endif - return dev->flash_contents[dev->address++]; -} - -/* We never mark the device as busy, so interrupts cannot be triggered - XXXXX */ - -int tc58128_cb(uint16_t porta, uint16_t portb, - uint16_t * periph_pdtra, uint16_t * periph_portadir, - uint16_t * periph_pdtrb, uint16_t * periph_portbdir) -{ - int dev; - - if ((porta & CE1) == 0) - dev = 0; - else if ((porta & CE2) == 0) - dev = 1; - else - return 0; /* No device selected */ - - if ((porta & RE) && (porta & WE)) { - /* Nothing to do, assert ready and return to input state */ - *periph_portadir &= 0xff00; - *periph_portadir |= RDY(dev); - *periph_pdtra |= RDY(dev); - return 1; - } - - if (porta & CLE) { - /* Command */ - assert((porta & WE) == 0); - handle_command(&tc58128_devs[dev], porta & 0x00ff); - } else if (porta & ALE) { - assert((porta & WE) == 0); - handle_address(&tc58128_devs[dev], porta & 0x00ff); - } else if ((porta & RE) == 0) { - *periph_portadir |= 0x00ff; - *periph_pdtra &= 0xff00; - *periph_pdtra |= handle_read(&tc58128_devs[dev]); - } else { - assert(0); - } - return 1; -} - -static sh7750_io_device tc58128 = { - RE | WE, /* Port A triggers */ - 0, /* Port B triggers */ - tc58128_cb /* Callback */ -}; - -int tc58128_init(struct SH7750State *s, char *zone1, char *zone2) -{ - init_dev(&tc58128_devs[0], zone1); - init_dev(&tc58128_devs[1], zone2); - return sh7750_register_io_device(s, &tc58128); -} diff --git a/hw/tcx.c b/hw/tcx.c deleted file mode 100644 index a3a2114..0000000 --- a/hw/tcx.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * QEMU TCX Frame buffer - * - * Copyright (c) 2003-2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -#define MAXX 1024 -#define MAXY 768 -#define TCX_DAC_NREGS 16 - -typedef struct TCXState { - uint32_t addr; - DisplayState *ds; - uint8_t *vram; - unsigned long vram_offset; - uint16_t width, height; - uint8_t r[256], g[256], b[256]; - uint8_t dac_index, dac_state; -} TCXState; - -static void tcx_screen_dump(void *opaque, const char *filename); - -static void tcx_draw_line32(TCXState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - int x; - uint8_t val; - - for(x = 0; x < width; x++) { - val = *s++; - *d++ = s1->b[val]; - *d++ = s1->g[val]; - *d++ = s1->r[val]; - d++; - } -} - -static void tcx_draw_line24(TCXState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - int x; - uint8_t val; - - for(x = 0; x < width; x++) { - val = *s++; - *d++ = s1->b[val]; - *d++ = s1->g[val]; - *d++ = s1->r[val]; - } -} - -static void tcx_draw_line8(TCXState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - int x; - uint8_t val; - - for(x = 0; x < width; x++) { - val = *s++; - /* XXX translate between palettes? */ - *d++ = val; - } -} - -/* Fixed line length 1024 allows us to do nice tricks not possible on - VGA... */ -static void tcx_update_display(void *opaque) -{ - TCXState *ts = opaque; - uint32_t page; - int y, page_min, page_max, y_start, dd, ds; - uint8_t *d, *s; - void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width); - - if (ts->ds->depth == 0) - return; - page = ts->vram_offset; - y_start = -1; - page_min = 0x7fffffff; - page_max = -1; - d = ts->ds->data; - s = ts->vram; - dd = ts->ds->linesize; - ds = 1024; - - switch (ts->ds->depth) { - case 32: - f = tcx_draw_line32; - break; - case 24: - f = tcx_draw_line24; - break; - default: - case 8: - f = tcx_draw_line8; - break; - case 0: - return; - } - - for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) { - if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) { - if (y_start < 0) - y_start = y; - if (page < page_min) - page_min = page; - if (page > page_max) - page_max = page; - f(ts, d, s, ts->width); - d += dd; - s += ds; - f(ts, d, s, ts->width); - d += dd; - s += ds; - f(ts, d, s, ts->width); - d += dd; - s += ds; - f(ts, d, s, ts->width); - d += dd; - s += ds; - } else { - if (y_start >= 0) { - /* flush to display */ - dpy_update(ts->ds, 0, y_start, - ts->width, y - y_start); - y_start = -1; - } - d += dd * 4; - s += ds * 4; - } - } - if (y_start >= 0) { - /* flush to display */ - dpy_update(ts->ds, 0, y_start, - ts->width, y - y_start); - } - /* reset modified pages */ - if (page_max != -1) { - cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, - VGA_DIRTY_FLAG); - } -} - -static void tcx_invalidate_display(void *opaque) -{ - TCXState *s = opaque; - int i; - - for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) { - cpu_physical_memory_set_dirty(s->vram_offset + i); - } -} - -static void tcx_save(QEMUFile *f, void *opaque) -{ - TCXState *s = opaque; - - qemu_put_be32s(f, (uint32_t *)&s->addr); - qemu_put_be32s(f, (uint32_t *)&s->vram); - qemu_put_be16s(f, (uint16_t *)&s->height); - qemu_put_be16s(f, (uint16_t *)&s->width); - qemu_put_buffer(f, s->r, 256); - qemu_put_buffer(f, s->g, 256); - qemu_put_buffer(f, s->b, 256); - qemu_put_8s(f, &s->dac_index); - qemu_put_8s(f, &s->dac_state); -} - -static int tcx_load(QEMUFile *f, void *opaque, int version_id) -{ - TCXState *s = opaque; - - if (version_id != 1) - return -EINVAL; - - qemu_get_be32s(f, (uint32_t *)&s->addr); - qemu_get_be32s(f, (uint32_t *)&s->vram); - qemu_get_be16s(f, (uint16_t *)&s->height); - qemu_get_be16s(f, (uint16_t *)&s->width); - qemu_get_buffer(f, s->r, 256); - qemu_get_buffer(f, s->g, 256); - qemu_get_buffer(f, s->b, 256); - qemu_get_8s(f, &s->dac_index); - qemu_get_8s(f, &s->dac_state); - return 0; -} - -static void tcx_reset(void *opaque) -{ - TCXState *s = opaque; - - /* Initialize palette */ - memset(s->r, 0, 256); - memset(s->g, 0, 256); - memset(s->b, 0, 256); - s->r[255] = s->g[255] = s->b[255] = 255; - memset(s->vram, 0, MAXX*MAXY); - cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY, - VGA_DIRTY_FLAG); - s->dac_index = 0; - s->dac_state = 0; -} - -static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr) -{ - return 0; -} - -static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - TCXState *s = opaque; - uint32_t saddr; - - saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2; - switch (saddr) { - case 0: - s->dac_index = val >> 24; - s->dac_state = 0; - break; - case 1: - switch (s->dac_state) { - case 0: - s->r[s->dac_index] = val >> 24; - s->dac_state++; - break; - case 1: - s->g[s->dac_index] = val >> 24; - s->dac_state++; - break; - case 2: - s->b[s->dac_index] = val >> 24; - default: - s->dac_state = 0; - break; - } - break; - default: - break; - } - return; -} - -static CPUReadMemoryFunc *tcx_dac_read[3] = { - tcx_dac_readl, - tcx_dac_readl, - tcx_dac_readl, -}; - -static CPUWriteMemoryFunc *tcx_dac_write[3] = { - tcx_dac_writel, - tcx_dac_writel, - tcx_dac_writel, -}; - -void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, - unsigned long vram_offset, int vram_size, int width, int height) -{ - TCXState *s; - int io_memory; - - s = qemu_mallocz(sizeof(TCXState)); - if (!s) - return; - s->ds = ds; - s->addr = addr; - s->vram = vram_base; - s->vram_offset = vram_offset; - s->width = width; - s->height = height; - - cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset); - io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s); - cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory); - - graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display, - tcx_screen_dump, s); - register_savevm("tcx", addr, 1, tcx_save, tcx_load, s); - qemu_register_reset(tcx_reset, s); - tcx_reset(s); - dpy_resize(s->ds, width, height); -} - -static void tcx_screen_dump(void *opaque, const char *filename) -{ - TCXState *s = opaque; - FILE *f; - uint8_t *d, *d1, v; - int y, x; - - f = fopen(filename, "wb"); - if (!f) - return; - fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255); - d1 = s->vram; - for(y = 0; y < s->height; y++) { - d = d1; - for(x = 0; x < s->width; x++) { - v = *d; - fputc(s->r[v], f); - fputc(s->g[v], f); - fputc(s->b[v], f); - d++; - } - d1 += MAXX; - } - fclose(f); - return; -} - - - diff --git a/hw/unin_pci.c b/hw/unin_pci.c deleted file mode 100644 index a7e3600..0000000 --- a/hw/unin_pci.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * QEMU Uninorth PCI host (for all Mac99 and newer machines) - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -typedef target_phys_addr_t pci_addr_t; -#include "pci_host.h" - -typedef PCIHostState UNINState; - -static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - UNINState *s = opaque; - int i; - -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - for (i = 11; i < 32; i++) { - if ((val & (1 << i)) != 0) - break; - } -#if 0 - s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11); -#else - s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11); -#endif -} - -static uint32_t pci_unin_main_config_readl (void *opaque, - target_phys_addr_t addr) -{ - UNINState *s = opaque; - uint32_t val; - int devfn; - - devfn = (s->config_reg >> 8) & 0xFF; - val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_main_config_write[] = { - &pci_unin_main_config_writel, - &pci_unin_main_config_writel, - &pci_unin_main_config_writel, -}; - -static CPUReadMemoryFunc *pci_unin_main_config_read[] = { - &pci_unin_main_config_readl, - &pci_unin_main_config_readl, - &pci_unin_main_config_readl, -}; - -static CPUWriteMemoryFunc *pci_unin_main_write[] = { - &pci_host_data_writeb, - &pci_host_data_writew, - &pci_host_data_writel, -}; - -static CPUReadMemoryFunc *pci_unin_main_read[] = { - &pci_host_data_readb, - &pci_host_data_readw, - &pci_host_data_readl, -}; - -#if 0 - -static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - UNINState *s = opaque; - -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - s->config_reg = 0x80000000 | (val & ~0x00000001); -} - -static uint32_t pci_unin_config_readl (void *opaque, - target_phys_addr_t addr) -{ - UNINState *s = opaque; - uint32_t val; - - val = (s->config_reg | 0x00000001) & ~0x80000000; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - - return val; -} - -static CPUWriteMemoryFunc *pci_unin_config_write[] = { - &pci_unin_config_writel, - &pci_unin_config_writel, - &pci_unin_config_writel, -}; - -static CPUReadMemoryFunc *pci_unin_config_read[] = { - &pci_unin_config_readl, - &pci_unin_config_readl, - &pci_unin_config_readl, -}; - -static CPUWriteMemoryFunc *pci_unin_write[] = { - &pci_host_pci_writeb, - &pci_host_pci_writew, - &pci_host_pci_writel, -}; - -static CPUReadMemoryFunc *pci_unin_read[] = { - &pci_host_pci_readb, - &pci_host_pci_readw, - &pci_host_pci_readl, -}; -#endif - -static void pci_unin_set_irq(PCIDevice *d, void *pic, int irq_num, int level) -{ - openpic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level); -} - -PCIBus *pci_pmac_init(void *pic) -{ - UNINState *s; - PCIDevice *d; - int pci_mem_config, pci_mem_data; - - /* Use values found on a real PowerMac */ - /* Uninorth main bus */ - s = qemu_mallocz(sizeof(UNINState)); - s->bus = pci_register_bus(pci_unin_set_irq, NULL, 11 << 3); - - pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, - pci_unin_main_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read, - pci_unin_main_write, s); - cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data); - d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice), - 11 << 3, NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x1F; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer - -#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly - /* pci-to-pci bridge */ - d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3, - NULL, NULL); - d->config[0x00] = 0x11; // vendor_id : TI - d->config[0x01] = 0x10; - d->config[0x02] = 0x26; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x05; // revision - d->config[0x0A] = 0x04; // class_sub = pci2pci - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x20; // latency_timer - d->config[0x0E] = 0x01; // header_type - - d->config[0x18] = 0x01; // primary_bus - d->config[0x19] = 0x02; // secondary_bus - d->config[0x1A] = 0x02; // subordinate_bus - d->config[0x1B] = 0x20; // secondary_latency_timer - d->config[0x1C] = 0x11; // io_base - d->config[0x1D] = 0x01; // io_limit - d->config[0x20] = 0x00; // memory_base - d->config[0x21] = 0x80; - d->config[0x22] = 0x00; // memory_limit - d->config[0x23] = 0x80; - d->config[0x24] = 0x01; // prefetchable_memory_base - d->config[0x25] = 0x80; - d->config[0x26] = 0xF1; // prefectchable_memory_limit - d->config[0x27] = 0x7F; - // d->config[0x34] = 0xdc // capabilities_pointer -#endif -#if 0 // XXX: not needed for now - /* Uninorth AGP bus */ - s = &pci_bridge[1]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, - pci_unin_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_read, - pci_unin_write, s); - cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data); - - d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3, - NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x20; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - // d->config[0x34] = 0x80; // capabilities_pointer -#endif - -#if 0 // XXX: not needed for now - /* Uninorth internal bus */ - s = &pci_bridge[2]; - pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, - pci_unin_config_write, s); - pci_mem_data = cpu_register_io_memory(0, pci_unin_read, - pci_unin_write, s); - cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config); - cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data); - - d = pci_register_device("Uni-north internal", sizeof(PCIDevice), - 3, 11 << 3, NULL, NULL); - d->config[0x00] = 0x6b; // vendor_id : Apple - d->config[0x01] = 0x10; - d->config[0x02] = 0x1E; // device_id - d->config[0x03] = 0x00; - d->config[0x08] = 0x00; // revision - d->config[0x0A] = 0x00; // class_sub = pci host - d->config[0x0B] = 0x06; // class_base = PCI_bridge - d->config[0x0C] = 0x08; // cache_line_size - d->config[0x0D] = 0x10; // latency_timer - d->config[0x0E] = 0x00; // header_type - d->config[0x34] = 0x00; // capabilities_pointer -#endif - return s->bus; -} - diff --git a/hw/usb-hid.c b/hw/usb-hid.c index 8fc0b74..93f46db 100644 --- a/hw/usb-hid.c +++ b/hw/usb-hid.c @@ -323,10 +323,16 @@ static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len) return l; } -static void usb_mouse_handle_reset(USBDevice *dev) +static void usb_mouse_handle_reset(USBDevice *dev, int destroy) { USBMouseState *s = (USBMouseState *)dev; + if (destroy) { + qemu_add_mouse_event_handler(NULL, NULL, 0); + qemu_free(s); + return; + } + s->dx = 0; s->dy = 0; s->dz = 0; @@ -500,14 +506,6 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, return ret; } -static void usb_mouse_handle_destroy(USBDevice *dev) -{ - USBMouseState *s = (USBMouseState *)dev; - - qemu_add_mouse_event_handler(NULL, NULL, 0); - qemu_free(s); -} - USBDevice *usb_tablet_init(void) { USBMouseState *s; @@ -521,7 +519,6 @@ USBDevice *usb_tablet_init(void) s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_data = usb_mouse_handle_data; - s->dev.handle_destroy = usb_mouse_handle_destroy; s->kind = USB_TABLET; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); @@ -542,7 +539,6 @@ USBDevice *usb_mouse_init(void) s->dev.handle_reset = usb_mouse_handle_reset; s->dev.handle_control = usb_mouse_handle_control; s->dev.handle_data = usb_mouse_handle_data; - s->dev.handle_destroy = usb_mouse_handle_destroy; s->kind = USB_MOUSE; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); diff --git a/hw/usb-hub.c b/hw/usb-hub.c index 8350931..2eba905 100644 --- a/hw/usb-hub.c +++ b/hw/usb-hub.c @@ -199,9 +199,11 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev) } } -static void usb_hub_handle_reset(USBDevice *dev) +static void usb_hub_handle_reset(USBDevice *dev, int destroy) { /* XXX: do it */ + if (destroy) + qemu_free(dev); } static int usb_hub_handle_control(USBDevice *dev, int request, int value, @@ -523,13 +525,6 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid, return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len); } -static void usb_hub_handle_destroy(USBDevice *dev) -{ - USBHubState *s = (USBHubState *)dev; - - qemu_free(s); -} - USBDevice *usb_hub_init(int nb_ports) { USBHubState *s; @@ -548,7 +543,6 @@ USBDevice *usb_hub_init(int nb_ports) s->dev.handle_reset = usb_hub_handle_reset; s->dev.handle_control = usb_hub_handle_control; s->dev.handle_data = usb_hub_handle_data; - s->dev.handle_destroy = usb_hub_handle_destroy; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub"); diff --git a/hw/usb-msd.c b/hw/usb-msd.c index ff2047d..3dccfb9 100644 --- a/hw/usb-msd.c +++ b/hw/usb-msd.c @@ -112,12 +112,16 @@ static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail) s->mode = USB_MSDM_CSW; } -static void usb_msd_handle_reset(USBDevice *dev) +static void usb_msd_handle_reset(USBDevice *dev, int destroy) { MSDState *s = (MSDState *)dev; DPRINTF("Reset\n"); s->mode = USB_MSDM_CBW; + if (destroy) { + scsi_disk_destroy(s->scsi_dev); + qemu_free(s); + } } static int usb_msd_handle_control(USBDevice *dev, int request, int value, @@ -365,13 +369,6 @@ static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep, return ret; } -static void usb_msd_handle_destroy(USBDevice *dev) -{ - MSDState *s = (MSDState *)dev; - - scsi_disk_destroy(s->scsi_dev); - qemu_free(s); -} USBDevice *usb_msd_init(const char *filename) { @@ -391,12 +388,11 @@ USBDevice *usb_msd_init(const char *filename) s->dev.handle_reset = usb_msd_handle_reset; s->dev.handle_control = usb_msd_handle_control; s->dev.handle_data = usb_msd_handle_data; - s->dev.handle_destroy = usb_msd_handle_destroy; snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)", filename); s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s); - usb_msd_handle_reset((USBDevice *)s); + usb_msd_handle_reset((USBDevice *)s, 0); return (USBDevice *)s; } diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c deleted file mode 100644 index 1a6e013..0000000 --- a/hw/usb-uhci.c +++ /dev/null @@ -1,674 +0,0 @@ -/* - * USB UHCI controller emulation - * - * Copyright (c) 2005 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" - -//#define DEBUG -//#define DEBUG_PACKET - -#define UHCI_CMD_GRESET (1 << 2) -#define UHCI_CMD_HCRESET (1 << 1) -#define UHCI_CMD_RS (1 << 0) - -#define UHCI_STS_HCHALTED (1 << 5) -#define UHCI_STS_HCPERR (1 << 4) -#define UHCI_STS_HSERR (1 << 3) -#define UHCI_STS_RD (1 << 2) -#define UHCI_STS_USBERR (1 << 1) -#define UHCI_STS_USBINT (1 << 0) - -#define TD_CTRL_SPD (1 << 29) -#define TD_CTRL_ERROR_SHIFT 27 -#define TD_CTRL_IOS (1 << 25) -#define TD_CTRL_IOC (1 << 24) -#define TD_CTRL_ACTIVE (1 << 23) -#define TD_CTRL_STALL (1 << 22) -#define TD_CTRL_BABBLE (1 << 20) -#define TD_CTRL_NAK (1 << 19) -#define TD_CTRL_TIMEOUT (1 << 18) - -#define UHCI_PORT_RESET (1 << 9) -#define UHCI_PORT_LSDA (1 << 8) -#define UHCI_PORT_ENC (1 << 3) -#define UHCI_PORT_EN (1 << 2) -#define UHCI_PORT_CSC (1 << 1) -#define UHCI_PORT_CCS (1 << 0) - -#define FRAME_TIMER_FREQ 1000 - -#define FRAME_MAX_LOOPS 100 - -#define NB_PORTS 2 - -typedef struct UHCIPort { - USBPort port; - uint16_t ctrl; -} UHCIPort; - -typedef struct UHCIState { - PCIDevice dev; - uint16_t cmd; /* cmd register */ - uint16_t status; - uint16_t intr; /* interrupt enable register */ - uint16_t frnum; /* frame number */ - uint32_t fl_base_addr; /* frame list base address */ - uint8_t sof_timing; - uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ - QEMUTimer *frame_timer; - UHCIPort ports[NB_PORTS]; -} UHCIState; - -typedef struct UHCI_TD { - uint32_t link; - uint32_t ctrl; /* see TD_CTRL_xxx */ - uint32_t token; - uint32_t buffer; -} UHCI_TD; - -typedef struct UHCI_QH { - uint32_t link; - uint32_t el_link; -} UHCI_QH; - -static void uhci_attach(USBPort *port1, USBDevice *dev); - -static void uhci_update_irq(UHCIState *s) -{ - int level; - if (((s->status2 & 1) && (s->intr & (1 << 2))) || - ((s->status2 & 2) && (s->intr & (1 << 3))) || - ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) || - ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) || - (s->status & UHCI_STS_HSERR) || - (s->status & UHCI_STS_HCPERR)) { - level = 1; - } else { - level = 0; - } - pci_set_irq(&s->dev, 3, level); -} - -static void uhci_reset(UHCIState *s) -{ - uint8_t *pci_conf; - int i; - UHCIPort *port; - - pci_conf = s->dev.config; - - pci_conf[0x6a] = 0x01; /* usb clock */ - pci_conf[0x6b] = 0x00; - s->cmd = 0; - s->status = 0; - s->status2 = 0; - s->intr = 0; - s->fl_base_addr = 0; - s->sof_timing = 64; - for(i = 0; i < NB_PORTS; i++) { - port = &s->ports[i]; - port->ctrl = 0x0080; - if (port->port.dev) - uhci_attach(&port->port, port->port.dev); - } -} - -static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - UHCIState *s = opaque; - - addr &= 0x1f; - switch(addr) { - case 0x0c: - s->sof_timing = val; - break; - } -} - -static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr) -{ - UHCIState *s = opaque; - uint32_t val; - - addr &= 0x1f; - switch(addr) { - case 0x0c: - val = s->sof_timing; - break; - default: - val = 0xff; - break; - } - return val; -} - -static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val) -{ - UHCIState *s = opaque; - - addr &= 0x1f; -#ifdef DEBUG - printf("uhci writew port=0x%04x val=0x%04x\n", addr, val); -#endif - switch(addr) { - case 0x00: - if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) { - /* start frame processing */ - qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock)); - s->status &= ~UHCI_STS_HCHALTED; - } else if (!(val & UHCI_CMD_RS)) { - s->status |= UHCI_STS_HCHALTED; - } - if (val & UHCI_CMD_GRESET) { - UHCIPort *port; - USBDevice *dev; - int i; - - /* send reset on the USB bus */ - for(i = 0; i < NB_PORTS; i++) { - port = &s->ports[i]; - dev = port->port.dev; - if (dev) { - dev->handle_packet(dev, - USB_MSG_RESET, 0, 0, NULL, 0); - } - } - uhci_reset(s); - return; - } - if (val & UHCI_CMD_HCRESET) { - uhci_reset(s); - return; - } - s->cmd = val; - break; - case 0x02: - s->status &= ~val; - /* XXX: the chip spec is not coherent, so we add a hidden - register to distinguish between IOC and SPD */ - if (val & UHCI_STS_USBINT) - s->status2 = 0; - uhci_update_irq(s); - break; - case 0x04: - s->intr = val; - uhci_update_irq(s); - break; - case 0x06: - if (s->status & UHCI_STS_HCHALTED) - s->frnum = val & 0x7ff; - break; - case 0x10 ... 0x1f: - { - UHCIPort *port; - USBDevice *dev; - int n; - - n = (addr >> 1) & 7; - if (n >= NB_PORTS) - return; - port = &s->ports[n]; - dev = port->port.dev; - if (dev) { - /* port reset */ - if ( (val & UHCI_PORT_RESET) && - !(port->ctrl & UHCI_PORT_RESET) ) { - dev->handle_packet(dev, - USB_MSG_RESET, 0, 0, NULL, 0); - } - } - port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb); - /* some bits are reset when a '1' is written to them */ - port->ctrl &= ~(val & 0x000a); - } - break; - } -} - -static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr) -{ - UHCIState *s = opaque; - uint32_t val; - - addr &= 0x1f; - switch(addr) { - case 0x00: - val = s->cmd; - break; - case 0x02: - val = s->status; - break; - case 0x04: - val = s->intr; - break; - case 0x06: - val = s->frnum; - break; - case 0x10 ... 0x1f: - { - UHCIPort *port; - int n; - n = (addr >> 1) & 7; - if (n >= NB_PORTS) - goto read_default; - port = &s->ports[n]; - val = port->ctrl; - } - break; - default: - read_default: - val = 0xff7f; /* disabled port */ - break; - } -#ifdef DEBUG - printf("uhci readw port=0x%04x val=0x%04x\n", addr, val); -#endif - return val; -} - -static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val) -{ - UHCIState *s = opaque; - - addr &= 0x1f; -#ifdef DEBUG - printf("uhci writel port=0x%04x val=0x%08x\n", addr, val); -#endif - switch(addr) { - case 0x08: - s->fl_base_addr = val & ~0xfff; - break; - } -} - -static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr) -{ - UHCIState *s = opaque; - uint32_t val; - - addr &= 0x1f; - switch(addr) { - case 0x08: - val = s->fl_base_addr; - break; - default: - val = 0xffffffff; - break; - } - return val; -} - -static void uhci_attach(USBPort *port1, USBDevice *dev) -{ - UHCIState *s = port1->opaque; - UHCIPort *port = &s->ports[port1->index]; - - if (dev) { - if (port->port.dev) { - usb_attach(port1, NULL); - } - /* set connect status */ - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; - - /* update speed */ - if (dev->speed == USB_SPEED_LOW) - port->ctrl |= UHCI_PORT_LSDA; - else - port->ctrl &= ~UHCI_PORT_LSDA; - port->port.dev = dev; - /* send the attach message */ - dev->handle_packet(dev, - USB_MSG_ATTACH, 0, 0, NULL, 0); - } else { - /* set connect status */ - if (port->ctrl & UHCI_PORT_CCS) { - port->ctrl &= ~UHCI_PORT_CCS; - port->ctrl |= UHCI_PORT_CSC; - } - /* disable port */ - if (port->ctrl & UHCI_PORT_EN) { - port->ctrl &= ~UHCI_PORT_EN; - port->ctrl |= UHCI_PORT_ENC; - } - dev = port->port.dev; - if (dev) { - /* send the detach message */ - dev->handle_packet(dev, - USB_MSG_DETACH, 0, 0, NULL, 0); - } - port->port.dev = NULL; - } -} - -static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, - uint8_t devaddr, uint8_t devep, - uint8_t *data, int len) -{ - UHCIPort *port; - USBDevice *dev; - int i, ret; - -#ifdef DEBUG_PACKET - { - const char *pidstr; - switch(pid) { - case USB_TOKEN_SETUP: pidstr = "SETUP"; break; - case USB_TOKEN_IN: pidstr = "IN"; break; - case USB_TOKEN_OUT: pidstr = "OUT"; break; - default: pidstr = "?"; break; - } - printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n", - s->frnum, pidstr, devaddr, devep, len); - if (pid != USB_TOKEN_IN) { - printf(" data_out="); - for(i = 0; i < len; i++) { - printf(" %02x", data[i]); - } - printf("\n"); - } - } -#endif - for(i = 0; i < NB_PORTS; i++) { - port = &s->ports[i]; - dev = port->port.dev; - if (dev && (port->ctrl & UHCI_PORT_EN)) { - ret = dev->handle_packet(dev, pid, - devaddr, devep, - data, len); - if (ret != USB_RET_NODEV) { -#ifdef DEBUG_PACKET - { - printf(" ret=%d ", ret); - if (pid == USB_TOKEN_IN && ret > 0) { - printf("data_in="); - for(i = 0; i < ret; i++) { - printf(" %02x", data[i]); - } - } - printf("\n"); - } -#endif - return ret; - } - } - } - return USB_RET_NODEV; -} - -/* return -1 if fatal error (frame must be stopped) - 0 if TD successful - 1 if TD unsuccessful or inactive -*/ -static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) -{ - uint8_t pid; - uint8_t buf[1280]; - int len, max_len, err, ret; - - if (td->ctrl & TD_CTRL_IOC) { - *int_mask |= 0x01; - } - - if (!(td->ctrl & TD_CTRL_ACTIVE)) - return 1; - - /* TD is active */ - max_len = ((td->token >> 21) + 1) & 0x7ff; - pid = td->token & 0xff; - switch(pid) { - case USB_TOKEN_OUT: - case USB_TOKEN_SETUP: - cpu_physical_memory_read(td->buffer, buf, max_len); - ret = uhci_broadcast_packet(s, pid, - (td->token >> 8) & 0x7f, - (td->token >> 15) & 0xf, - buf, max_len); - len = max_len; - break; - case USB_TOKEN_IN: - ret = uhci_broadcast_packet(s, pid, - (td->token >> 8) & 0x7f, - (td->token >> 15) & 0xf, - buf, max_len); - if (ret >= 0) { - len = ret; - if (len > max_len) { - len = max_len; - ret = USB_RET_BABBLE; - } - if (len > 0) { - /* write the data back */ - cpu_physical_memory_write(td->buffer, buf, len); - } - } else { - len = 0; - } - break; - default: - /* invalid pid : frame interrupted */ - s->status |= UHCI_STS_HCPERR; - uhci_update_irq(s); - return -1; - } - if (td->ctrl & TD_CTRL_IOS) - td->ctrl &= ~TD_CTRL_ACTIVE; - if (ret >= 0) { - td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff); - td->ctrl &= ~TD_CTRL_ACTIVE; - if (pid == USB_TOKEN_IN && - (td->ctrl & TD_CTRL_SPD) && - len < max_len) { - *int_mask |= 0x02; - /* short packet: do not update QH */ - return 1; - } else { - /* success */ - return 0; - } - } else { - switch(ret) { - default: - case USB_RET_NODEV: - do_timeout: - td->ctrl |= TD_CTRL_TIMEOUT; - err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3; - if (err != 0) { - err--; - if (err == 0) { - td->ctrl &= ~TD_CTRL_ACTIVE; - s->status |= UHCI_STS_USBERR; - uhci_update_irq(s); - } - } - td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | - (err << TD_CTRL_ERROR_SHIFT); - return 1; - case USB_RET_NAK: - td->ctrl |= TD_CTRL_NAK; - if (pid == USB_TOKEN_SETUP) - goto do_timeout; - return 1; - case USB_RET_STALL: - td->ctrl |= TD_CTRL_STALL; - td->ctrl &= ~TD_CTRL_ACTIVE; - return 1; - case USB_RET_BABBLE: - td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; - td->ctrl &= ~TD_CTRL_ACTIVE; - /* frame interrupted */ - return -1; - } - } -} - -static void uhci_frame_timer(void *opaque) -{ - UHCIState *s = opaque; - int64_t expire_time; - uint32_t frame_addr, link, old_td_ctrl, val; - int int_mask, cnt, ret; - UHCI_TD td; - UHCI_QH qh; - - if (!(s->cmd & UHCI_CMD_RS)) { - qemu_del_timer(s->frame_timer); - /* set hchalted bit in status - UHCI11D 2.1.2 */ - s->status |= UHCI_STS_HCHALTED; - return; - } - frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2); - cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4); - le32_to_cpus(&link); - int_mask = 0; - cnt = FRAME_MAX_LOOPS; - while ((link & 1) == 0) { - if (--cnt == 0) - break; - /* valid frame */ - if (link & 2) { - /* QH */ - cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh)); - le32_to_cpus(&qh.link); - le32_to_cpus(&qh.el_link); - depth_first: - if (qh.el_link & 1) { - /* no element : go to next entry */ - link = qh.link; - } else if (qh.el_link & 2) { - /* QH */ - link = qh.el_link; - } else { - /* TD */ - if (--cnt == 0) - break; - cpu_physical_memory_read(qh.el_link & ~0xf, - (uint8_t *)&td, sizeof(td)); - le32_to_cpus(&td.link); - le32_to_cpus(&td.ctrl); - le32_to_cpus(&td.token); - le32_to_cpus(&td.buffer); - old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, &td, &int_mask); - /* update the status bits of the TD */ - if (old_td_ctrl != td.ctrl) { - val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((qh.el_link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); - } - if (ret < 0) - break; /* interrupted frame */ - if (ret == 0) { - /* update qh element link */ - qh.el_link = td.link; - val = cpu_to_le32(qh.el_link); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); - if (qh.el_link & 4) { - /* depth first */ - goto depth_first; - } - } - /* go to next entry */ - link = qh.link; - } - } else { - /* TD */ - cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td)); - le32_to_cpus(&td.link); - le32_to_cpus(&td.ctrl); - le32_to_cpus(&td.token); - le32_to_cpus(&td.buffer); - old_td_ctrl = td.ctrl; - ret = uhci_handle_td(s, &td, &int_mask); - /* update the status bits of the TD */ - if (old_td_ctrl != td.ctrl) { - val = cpu_to_le32(td.ctrl); - cpu_physical_memory_write((link & ~0xf) + 4, - (const uint8_t *)&val, - sizeof(val)); - } - if (ret < 0) - break; /* interrupted frame */ - link = td.link; - } - } - s->frnum = (s->frnum + 1) & 0x7ff; - if (int_mask) { - s->status2 |= int_mask; - s->status |= UHCI_STS_USBINT; - uhci_update_irq(s); - } - /* prepare the timer for the next frame */ - expire_time = qemu_get_clock(vm_clock) + - (ticks_per_sec / FRAME_TIMER_FREQ); - qemu_mod_timer(s->frame_timer, expire_time); -} - -static void uhci_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - UHCIState *s = (UHCIState *)pci_dev; - - register_ioport_write(addr, 32, 2, uhci_ioport_writew, s); - register_ioport_read(addr, 32, 2, uhci_ioport_readw, s); - register_ioport_write(addr, 32, 4, uhci_ioport_writel, s); - register_ioport_read(addr, 32, 4, uhci_ioport_readl, s); - register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s); - register_ioport_read(addr, 32, 1, uhci_ioport_readb, s); -} - -void usb_uhci_init(PCIBus *bus, int devfn) -{ - UHCIState *s; - uint8_t *pci_conf; - int i; - - s = (UHCIState *)pci_register_device(bus, - "USB-UHCI", sizeof(UHCIState), - devfn, NULL, NULL); - pci_conf = s->dev.config; - pci_conf[0x00] = 0x86; - pci_conf[0x01] = 0x80; - pci_conf[0x02] = 0x20; - pci_conf[0x03] = 0x70; - pci_conf[0x08] = 0x01; // revision number - pci_conf[0x09] = 0x00; - pci_conf[0x0a] = 0x03; - pci_conf[0x0b] = 0x0c; - pci_conf[0x0e] = 0x00; // header_type - pci_conf[0x3d] = 4; // interrupt pin 3 - pci_conf[0x60] = 0x10; // release number - - for(i = 0; i < NB_PORTS; i++) { - qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach); - } - s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s); - - uhci_reset(s); - - /* Use region 4 for consistency with real hardware. BSD guests seem - to rely on this. */ - pci_register_io_region(&s->dev, 4, 0x20, - PCI_ADDRESS_SPACE_IO, uhci_map); -} @@ -55,7 +55,10 @@ int usb_generic_handle_packet(USBDevice *s, int pid, s->remote_wakeup = 0; s->addr = 0; s->state = USB_STATE_DEFAULT; - s->handle_reset(s); + s->handle_reset(s, 0); + break; + case USB_MSG_DESTROY: + s->handle_reset(s, 1); break; case USB_TOKEN_SETUP: if (s->state < USB_STATE_DEFAULT || devaddr != s->addr) @@ -29,6 +29,7 @@ #define USB_MSG_ATTACH 0x100 #define USB_MSG_DETACH 0x101 #define USB_MSG_RESET 0x102 +#define USB_MSG_DESTROY 0x103 #define USB_RET_NODEV (-1) #define USB_RET_NAK (-2) @@ -116,14 +117,12 @@ struct USBDevice { int (*handle_packet)(USBDevice *dev, int pid, uint8_t devaddr, uint8_t devep, uint8_t *data, int len); - void (*handle_destroy)(USBDevice *dev); - int speed; /* The following fields are used by the generic USB device layer. They are here just to avoid creating a new structure for them. */ - void (*handle_reset)(USBDevice *dev); + void (*handle_reset)(USBDevice *dev, int destroy); int (*handle_control)(USBDevice *dev, int request, int value, int index, int length, uint8_t *data); int (*handle_data)(USBDevice *dev, int pid, uint8_t devep, diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c deleted file mode 100644 index 34a4bc6..0000000 --- a/hw/versatile_pci.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * ARM Versatile/PB PCI host controller - * - * Copyright (c) 2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the LGPL. - */ - -#include "vl.h" - -static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr) -{ - return addr & 0xf8ff; -} - -static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - pci_data_write(opaque, vpb_pci_config_addr (addr), val, 1); -} - -static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2); -} - -static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr, - uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4); -} - -static uint32_t pci_vpb_config_readb (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - val = pci_data_read(opaque, vpb_pci_config_addr (addr), 1); - return val; -} - -static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr) -{ - uint32_t val; - val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} - -static CPUWriteMemoryFunc *pci_vpb_config_write[] = { - &pci_vpb_config_writeb, - &pci_vpb_config_writew, - &pci_vpb_config_writel, -}; - -static CPUReadMemoryFunc *pci_vpb_config_read[] = { - &pci_vpb_config_readb, - &pci_vpb_config_readw, - &pci_vpb_config_readl, -}; - -static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) -{ - pic_set_irq_new(pic, 27 + irq_num, level); -} - -PCIBus *pci_vpb_init(void *pic) -{ - PCIBus *s; - PCIDevice *d; - int mem_config; - - s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3); - /* ??? Register memory space. */ - - mem_config = cpu_register_io_memory(0, pci_vpb_config_read, - pci_vpb_config_write, s); - /* Selfconfig area. */ - cpu_register_physical_memory(0x41000000, 0x10000, mem_config); - /* Normal config area. */ - cpu_register_physical_memory(0x42000000, 0x10000, mem_config); - - d = pci_register_device(s, "Versatile/PB PCI Controller", - sizeof(PCIDevice), -1, NULL, NULL); - d->config[0x00] = 0xee; // vendor_id - d->config[0x01] = 0x10; - d->config[0x02] = 0x00; // device_id - d->config[0x03] = 0x03; - d->config[0x04] = 0x00; - d->config[0x05] = 0x00; - d->config[0x06] = 0x20; - d->config[0x07] = 0x02; - d->config[0x08] = 0x00; // revision - d->config[0x09] = 0x00; // programming i/f - d->config[0x0A] = 0x40; // class_sub = pci host - d->config[0x0B] = 0x0b; // class_base = PCI_bridge - d->config[0x0D] = 0x10; // latency_timer - - return s; -} - diff --git a/hw/versatilepb.c b/hw/versatilepb.c deleted file mode 100644 index 28ec137..0000000 --- a/hw/versatilepb.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * ARM Versatile Platform/Application Baseboard System emulation. - * - * Copyright (c) 2005-2006 CodeSourcery. - * Written by Paul Brook - * - * This code is licenced under the GPL. - */ - -#include "vl.h" -#include "arm_pic.h" - -#define LOCK_VALUE 0xa05f - -/* Primary interrupt controller. */ - -typedef struct vpb_sic_state -{ - arm_pic_handler handler; - uint32_t base; - uint32_t level; - uint32_t mask; - uint32_t pic_enable; - void *parent; - int irq; -} vpb_sic_state; - -static void vpb_sic_update(vpb_sic_state *s) -{ - uint32_t flags; - - flags = s->level & s->mask; - pic_set_irq_new(s->parent, s->irq, flags != 0); -} - -static void vpb_sic_update_pic(vpb_sic_state *s) -{ - int i; - uint32_t mask; - - for (i = 21; i <= 30; i++) { - mask = 1u << i; - if (!(s->pic_enable & mask)) - continue; - pic_set_irq_new(s->parent, i, (s->level & mask) != 0); - } -} - -static void vpb_sic_set_irq(void *opaque, int irq, int level) -{ - vpb_sic_state *s = (vpb_sic_state *)opaque; - if (level) - s->level |= 1u << irq; - else - s->level &= ~(1u << irq); - if (s->pic_enable & (1u << irq)) - pic_set_irq_new(s->parent, irq, level); - vpb_sic_update(s); -} - -static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset) -{ - vpb_sic_state *s = (vpb_sic_state *)opaque; - - offset -= s->base; - switch (offset >> 2) { - case 0: /* STATUS */ - return s->level & s->mask; - case 1: /* RAWSTAT */ - return s->level; - case 2: /* ENABLE */ - return s->mask; - case 4: /* SOFTINT */ - return s->level & 1; - case 8: /* PICENABLE */ - return s->pic_enable; - default: - printf ("vpb_sic_read: Bad register offset 0x%x\n", offset); - return 0; - } -} - -static void vpb_sic_write(void *opaque, target_phys_addr_t offset, - uint32_t value) -{ - vpb_sic_state *s = (vpb_sic_state *)opaque; - offset -= s->base; - - switch (offset >> 2) { - case 2: /* ENSET */ - s->mask |= value; - break; - case 3: /* ENCLR */ - s->mask &= ~value; - break; - case 4: /* SOFTINTSET */ - if (value) - s->mask |= 1; - break; - case 5: /* SOFTINTCLR */ - if (value) - s->mask &= ~1u; - break; - case 8: /* PICENSET */ - s->pic_enable |= (value & 0x7fe00000); - vpb_sic_update_pic(s); - break; - case 9: /* PICENCLR */ - s->pic_enable &= ~value; - vpb_sic_update_pic(s); - break; - default: - printf ("vpb_sic_write: Bad register offset 0x%x\n", offset); - return; - } - vpb_sic_update(s); -} - -static CPUReadMemoryFunc *vpb_sic_readfn[] = { - vpb_sic_read, - vpb_sic_read, - vpb_sic_read -}; - -static CPUWriteMemoryFunc *vpb_sic_writefn[] = { - vpb_sic_write, - vpb_sic_write, - vpb_sic_write -}; - -static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq) -{ - vpb_sic_state *s; - int iomemtype; - - s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state)); - if (!s) - return NULL; - s->handler = vpb_sic_set_irq; - s->base = base; - s->parent = parent; - s->irq = irq; - iomemtype = cpu_register_io_memory(0, vpb_sic_readfn, - vpb_sic_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - /* ??? Save/restore. */ - return s; -} - -/* System controller. */ - -typedef struct { - uint32_t base; - uint32_t leds; - uint16_t lockval; - uint32_t cfgdata1; - uint32_t cfgdata2; - uint32_t flags; - uint32_t nvflags; - uint32_t resetlevel; -} vpb_sys_state; - -static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset) -{ - vpb_sys_state *s = (vpb_sys_state *)opaque; - - offset -= s->base; - switch (offset) { - case 0x00: /* ID */ - return 0x41007004; - case 0x04: /* SW */ - /* General purpose hardware switches. - We don't have a useful way of exposing these to the user. */ - return 0; - case 0x08: /* LED */ - return s->leds; - case 0x20: /* LOCK */ - return s->lockval; - case 0x0c: /* OSC0 */ - case 0x10: /* OSC1 */ - case 0x14: /* OSC2 */ - case 0x18: /* OSC3 */ - case 0x1c: /* OSC4 */ - case 0x24: /* 100HZ */ - /* ??? Implement these. */ - return 0; - case 0x28: /* CFGDATA1 */ - return s->cfgdata1; - case 0x2c: /* CFGDATA2 */ - return s->cfgdata2; - case 0x30: /* FLAGS */ - return s->flags; - case 0x38: /* NVFLAGS */ - return s->nvflags; - case 0x40: /* RESETCTL */ - return s->resetlevel; - case 0x44: /* PCICTL */ - return 1; - case 0x48: /* MCI */ - return 0; - case 0x4c: /* FLASH */ - return 0; - case 0x50: /* CLCD */ - return 0x1000; - case 0x54: /* CLCDSER */ - return 0; - case 0x58: /* BOOTCS */ - return 0; - case 0x5c: /* 24MHz */ - /* ??? not implemented. */ - return 0; - case 0x60: /* MISC */ - return 0; - case 0x64: /* DMAPSR0 */ - case 0x68: /* DMAPSR1 */ - case 0x6c: /* DMAPSR2 */ - case 0x8c: /* OSCRESET0 */ - case 0x90: /* OSCRESET1 */ - case 0x94: /* OSCRESET2 */ - case 0x98: /* OSCRESET3 */ - case 0x9c: /* OSCRESET4 */ - case 0xc0: /* SYS_TEST_OSC0 */ - case 0xc4: /* SYS_TEST_OSC1 */ - case 0xc8: /* SYS_TEST_OSC2 */ - case 0xcc: /* SYS_TEST_OSC3 */ - case 0xd0: /* SYS_TEST_OSC4 */ - return 0; - default: - printf ("vpb_sys_read: Bad register offset 0x%x\n", offset); - return 0; - } -} - -static void vpb_sys_write(void *opaque, target_phys_addr_t offset, - uint32_t val) -{ - vpb_sys_state *s = (vpb_sys_state *)opaque; - offset -= s->base; - - switch (offset) { - case 0x08: /* LED */ - s->leds = val; - case 0x0c: /* OSC0 */ - case 0x10: /* OSC1 */ - case 0x14: /* OSC2 */ - case 0x18: /* OSC3 */ - case 0x1c: /* OSC4 */ - /* ??? */ - break; - case 0x20: /* LOCK */ - if (val == LOCK_VALUE) - s->lockval = val; - else - s->lockval = val & 0x7fff; - break; - case 0x28: /* CFGDATA1 */ - /* ??? Need to implement this. */ - s->cfgdata1 = val; - break; - case 0x2c: /* CFGDATA2 */ - /* ??? Need to implement this. */ - s->cfgdata2 = val; - break; - case 0x30: /* FLAGSSET */ - s->flags |= val; - break; - case 0x34: /* FLAGSCLR */ - s->flags &= ~val; - break; - case 0x38: /* NVFLAGSSET */ - s->nvflags |= val; - break; - case 0x3c: /* NVFLAGSCLR */ - s->nvflags &= ~val; - break; - case 0x40: /* RESETCTL */ - if (s->lockval == LOCK_VALUE) { - s->resetlevel = val; - if (val & 0x100) - cpu_abort(cpu_single_env, "Board reset\n"); - } - break; - case 0x44: /* PCICTL */ - /* nothing to do. */ - break; - case 0x4c: /* FLASH */ - case 0x50: /* CLCD */ - case 0x54: /* CLCDSER */ - case 0x64: /* DMAPSR0 */ - case 0x68: /* DMAPSR1 */ - case 0x6c: /* DMAPSR2 */ - case 0x8c: /* OSCRESET0 */ - case 0x90: /* OSCRESET1 */ - case 0x94: /* OSCRESET2 */ - case 0x98: /* OSCRESET3 */ - case 0x9c: /* OSCRESET4 */ - break; - default: - printf ("vpb_sys_write: Bad register offset 0x%x\n", offset); - return; - } -} - -static CPUReadMemoryFunc *vpb_sys_readfn[] = { - vpb_sys_read, - vpb_sys_read, - vpb_sys_read -}; - -static CPUWriteMemoryFunc *vpb_sys_writefn[] = { - vpb_sys_write, - vpb_sys_write, - vpb_sys_write -}; - -static vpb_sys_state *vpb_sys_init(uint32_t base) -{ - vpb_sys_state *s; - int iomemtype; - - s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state)); - if (!s) - return NULL; - s->base = base; - iomemtype = cpu_register_io_memory(0, vpb_sys_readfn, - vpb_sys_writefn, s); - cpu_register_physical_memory(base, 0x00000fff, iomemtype); - /* ??? Save/restore. */ - return s; -} - -/* Board init. */ - -/* The AB and PB boards both use the same core, just with different - peripherans and expansion busses. For now we emulate a subset of the - PB peripherals and just change the board ID. */ - -static void versatile_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename, int board_id) -{ - CPUState *env; - void *pic; - void *sic; - void *scsi_hba; - PCIBus *pci_bus; - NICInfo *nd; - int n; - int done_smc = 0; - - env = cpu_init(); - cpu_arm_set_model(env, ARM_CPUID_ARM926); - /* ??? RAM shoud repeat to fill physical memory space. */ - /* SDRAM at address zero. */ - cpu_register_physical_memory(0, ram_size, IO_MEM_RAM); - - vpb_sys_init(0x10000000); - pic = arm_pic_init_cpu(env); - pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ); - sic = vpb_sic_init(0x10003000, pic, 31); - pl050_init(0x10006000, sic, 3, 0); - pl050_init(0x10007000, sic, 4, 1); - - pci_bus = pci_vpb_init(sic); - /* The Versatile PCI bridge does not provide access to PCI IO space, - so many of the qemu PCI devices are not useable. */ - for(n = 0; n < nb_nics; n++) { - nd = &nd_table[n]; - if (!nd->model) - nd->model = done_smc ? "rtl8139" : "smc91c111"; - if (strcmp(nd->model, "smc91c111") == 0) { - smc91c111_init(nd, 0x10010000, sic, 25); - } else { - pci_nic_init(pci_bus, nd); - } - } - if (usb_enabled) { - usb_ohci_init(pci_bus, 3, -1); - } - scsi_hba = lsi_scsi_init(pci_bus, -1); - for (n = 0; n < MAX_DISKS; n++) { - if (bs_table[n]) { - lsi_scsi_attach(scsi_hba, bs_table[n], n); - } - } - - pl011_init(0x101f1000, pic, 12, serial_hds[0]); - pl011_init(0x101f2000, pic, 13, serial_hds[1]); - pl011_init(0x101f3000, pic, 14, serial_hds[2]); - pl011_init(0x10009000, sic, 6, serial_hds[3]); - - pl080_init(0x10130000, pic, 17); - sp804_init(0x101e2000, pic, 4); - sp804_init(0x101e3000, pic, 5); - - /* The versatile/PB actually has a modified Color LCD controller - that includes hardware cursor support from the PL111. */ - pl110_init(ds, 0x10120000, pic, 16, 1); - - /* Memory map for Versatile/PB: */ - /* 0x10000000 System registers. */ - /* 0x10001000 PCI controller config registers. */ - /* 0x10002000 Serial bus interface. */ - /* 0x10003000 Secondary interrupt controller. */ - /* 0x10004000 AACI (audio). */ - /* 0x10005000 MMCI0. */ - /* 0x10006000 KMI0 (keyboard). */ - /* 0x10007000 KMI1 (mouse). */ - /* 0x10008000 Character LCD Interface. */ - /* 0x10009000 UART3. */ - /* 0x1000a000 Smart card 1. */ - /* 0x1000b000 MMCI1. */ - /* 0x10010000 Ethernet. */ - /* 0x10020000 USB. */ - /* 0x10100000 SSMC. */ - /* 0x10110000 MPMC. */ - /* 0x10120000 CLCD Controller. */ - /* 0x10130000 DMA Controller. */ - /* 0x10140000 Vectored interrupt controller. */ - /* 0x101d0000 AHB Monitor Interface. */ - /* 0x101e0000 System Controller. */ - /* 0x101e1000 Watchdog Interface. */ - /* 0x101e2000 Timer 0/1. */ - /* 0x101e3000 Timer 2/3. */ - /* 0x101e4000 GPIO port 0. */ - /* 0x101e5000 GPIO port 1. */ - /* 0x101e6000 GPIO port 2. */ - /* 0x101e7000 GPIO port 3. */ - /* 0x101e8000 RTC. */ - /* 0x101f0000 Smart card 0. */ - /* 0x101f1000 UART0. */ - /* 0x101f2000 UART1. */ - /* 0x101f3000 UART2. */ - /* 0x101f4000 SSPI. */ - - arm_load_kernel(ram_size, kernel_filename, kernel_cmdline, - initrd_filename, board_id); -} - -static void vpb_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) -{ - versatile_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, - initrd_filename, 0x183); -} - -static void vab_init(int ram_size, int vga_ram_size, int boot_device, - DisplayState *ds, const char **fd_filename, int snapshot, - const char *kernel_filename, const char *kernel_cmdline, - const char *initrd_filename) -{ - versatile_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, - initrd_filename, 0x25e); -} - -QEMUMachine versatilepb_machine = { - "versatilepb", - "ARM Versatile/PB (ARM926EJ-S)", - vpb_init, -}; - -QEMUMachine versatileab_machine = { - "versatileab", - "ARM Versatile/AB (ARM926EJ-S)", - vab_init, -}; diff --git a/hw/vga.c b/hw/vga.c deleted file mode 100644 index 8f748b3..0000000 --- a/hw/vga.c +++ /dev/null @@ -1,1945 +0,0 @@ -/* - * QEMU VGA Emulator. - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "vl.h" -#include "vga_int.h" - -//#define DEBUG_VGA -//#define DEBUG_VGA_MEM -//#define DEBUG_VGA_REG - -//#define DEBUG_BOCHS_VBE - -/* force some bits to zero */ -const uint8_t sr_mask[8] = { - (uint8_t)~0xfc, - (uint8_t)~0xc2, - (uint8_t)~0xf0, - (uint8_t)~0xc0, - (uint8_t)~0xf1, - (uint8_t)~0xff, - (uint8_t)~0xff, - (uint8_t)~0x00, -}; - -const uint8_t gr_mask[16] = { - (uint8_t)~0xf0, /* 0x00 */ - (uint8_t)~0xf0, /* 0x01 */ - (uint8_t)~0xf0, /* 0x02 */ - (uint8_t)~0xe0, /* 0x03 */ - (uint8_t)~0xfc, /* 0x04 */ - (uint8_t)~0x84, /* 0x05 */ - (uint8_t)~0xf0, /* 0x06 */ - (uint8_t)~0xf0, /* 0x07 */ - (uint8_t)~0x00, /* 0x08 */ - (uint8_t)~0xff, /* 0x09 */ - (uint8_t)~0xff, /* 0x0a */ - (uint8_t)~0xff, /* 0x0b */ - (uint8_t)~0xff, /* 0x0c */ - (uint8_t)~0xff, /* 0x0d */ - (uint8_t)~0xff, /* 0x0e */ - (uint8_t)~0xff, /* 0x0f */ -}; - -#define cbswap_32(__x) \ -((uint32_t)( \ - (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ - (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ - (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ - (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) - -#ifdef WORDS_BIGENDIAN -#define PAT(x) cbswap_32(x) -#else -#define PAT(x) (x) -#endif - -#ifdef WORDS_BIGENDIAN -#define BIG 1 -#else -#define BIG 0 -#endif - -#ifdef WORDS_BIGENDIAN -#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff) -#else -#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff) -#endif - -static const uint32_t mask16[16] = { - PAT(0x00000000), - PAT(0x000000ff), - PAT(0x0000ff00), - PAT(0x0000ffff), - PAT(0x00ff0000), - PAT(0x00ff00ff), - PAT(0x00ffff00), - PAT(0x00ffffff), - PAT(0xff000000), - PAT(0xff0000ff), - PAT(0xff00ff00), - PAT(0xff00ffff), - PAT(0xffff0000), - PAT(0xffff00ff), - PAT(0xffffff00), - PAT(0xffffffff), -}; - -#undef PAT - -#ifdef WORDS_BIGENDIAN -#define PAT(x) (x) -#else -#define PAT(x) cbswap_32(x) -#endif - -static const uint32_t dmask16[16] = { - PAT(0x00000000), - PAT(0x000000ff), - PAT(0x0000ff00), - PAT(0x0000ffff), - PAT(0x00ff0000), - PAT(0x00ff00ff), - PAT(0x00ffff00), - PAT(0x00ffffff), - PAT(0xff000000), - PAT(0xff0000ff), - PAT(0xff00ff00), - PAT(0xff00ffff), - PAT(0xffff0000), - PAT(0xffff00ff), - PAT(0xffffff00), - PAT(0xffffffff), -}; - -static const uint32_t dmask4[4] = { - PAT(0x00000000), - PAT(0x0000ffff), - PAT(0xffff0000), - PAT(0xffffffff), -}; - -static uint32_t expand4[256]; -static uint16_t expand2[256]; -static uint8_t expand4to8[16]; - -VGAState *vga_state; -int vga_io_memory; - -static void vga_screen_dump(void *opaque, const char *filename); - -static uint32_t vga_ioport_read(void *opaque, uint32_t addr) -{ - VGAState *s = opaque; - int val, index; - - /* check port range access depending on color/monochrome mode */ - if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) || - (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) { - val = 0xff; - } else { - switch(addr) { - case 0x3c0: - if (s->ar_flip_flop == 0) { - val = s->ar_index; - } else { - val = 0; - } - break; - case 0x3c1: - index = s->ar_index & 0x1f; - if (index < 21) - val = s->ar[index]; - else - val = 0; - break; - case 0x3c2: - val = s->st00; - break; - case 0x3c4: - val = s->sr_index; - break; - case 0x3c5: - val = s->sr[s->sr_index]; -#ifdef DEBUG_VGA_REG - printf("vga: read SR%x = 0x%02x\n", s->sr_index, val); -#endif - break; - case 0x3c7: - val = s->dac_state; - break; - case 0x3c8: - val = s->dac_write_index; - break; - case 0x3c9: - val = s->palette[s->dac_read_index * 3 + s->dac_sub_index]; - if (++s->dac_sub_index == 3) { - s->dac_sub_index = 0; - s->dac_read_index++; - } - break; - case 0x3ca: - val = s->fcr; - break; - case 0x3cc: - val = s->msr; - break; - case 0x3ce: - val = s->gr_index; - break; - case 0x3cf: - val = s->gr[s->gr_index]; -#ifdef DEBUG_VGA_REG - printf("vga: read GR%x = 0x%02x\n", s->gr_index, val); -#endif - break; - case 0x3b4: - case 0x3d4: - val = s->cr_index; - break; - case 0x3b5: - case 0x3d5: - val = s->cr[s->cr_index]; -#ifdef DEBUG_VGA_REG - printf("vga: read CR%x = 0x%02x\n", s->cr_index, val); -#endif - break; - case 0x3ba: - case 0x3da: - /* just toggle to fool polling */ - s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE; - val = s->st01; - s->ar_flip_flop = 0; - break; - default: - val = 0x00; - break; - } - } -#if defined(DEBUG_VGA) - printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val); -#endif - return val; -} - -static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) -{ - VGAState *s = opaque; - int index; - - /* check port range access depending on color/monochrome mode */ - if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) || - (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) - return; - -#ifdef DEBUG_VGA - printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val); -#endif - - switch(addr) { - case 0x3c0: - if (s->ar_flip_flop == 0) { - val &= 0x3f; - s->ar_index = val; - } else { - index = s->ar_index & 0x1f; - switch(index) { - case 0x00 ... 0x0f: - s->ar[index] = val & 0x3f; - break; - case 0x10: - s->ar[index] = val & ~0x10; - break; - case 0x11: - s->ar[index] = val; - break; - case 0x12: - s->ar[index] = val & ~0xc0; - break; - case 0x13: - s->ar[index] = val & ~0xf0; - break; - case 0x14: - s->ar[index] = val & ~0xf0; - break; - default: - break; - } - } - s->ar_flip_flop ^= 1; - break; - case 0x3c2: - s->msr = val & ~0x10; - break; - case 0x3c4: - s->sr_index = val & 7; - break; - case 0x3c5: -#ifdef DEBUG_VGA_REG - printf("vga: write SR%x = 0x%02x\n", s->sr_index, val); -#endif - s->sr[s->sr_index] = val & sr_mask[s->sr_index]; - break; - case 0x3c7: - s->dac_read_index = val; - s->dac_sub_index = 0; - s->dac_state = 3; - break; - case 0x3c8: - s->dac_write_index = val; - s->dac_sub_index = 0; - s->dac_state = 0; - break; - case 0x3c9: - s->dac_cache[s->dac_sub_index] = val; - if (++s->dac_sub_index == 3) { - memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3); - s->dac_sub_index = 0; - s->dac_write_index++; - } - break; - case 0x3ce: - s->gr_index = val & 0x0f; - break; - case 0x3cf: -#ifdef DEBUG_VGA_REG - printf("vga: write GR%x = 0x%02x\n", s->gr_index, val); -#endif - s->gr[s->gr_index] = val & gr_mask[s->gr_index]; - break; - case 0x3b4: - case 0x3d4: - s->cr_index = val; - break; - case 0x3b5: - case 0x3d5: -#ifdef DEBUG_VGA_REG - printf("vga: write CR%x = 0x%02x\n", s->cr_index, val); -#endif - /* handle CR0-7 protection */ - if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) { - /* can always write bit 4 of CR7 */ - if (s->cr_index == 7) - s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10); - return; - } - switch(s->cr_index) { - case 0x01: /* horizontal display end */ - case 0x07: - case 0x09: - case 0x0c: - case 0x0d: - case 0x12: /* veritcal display end */ - s->cr[s->cr_index] = val; - break; - default: - s->cr[s->cr_index] = val; - break; - } - break; - case 0x3ba: - case 0x3da: - s->fcr = val & 0x10; - break; - } -} - -#ifdef CONFIG_BOCHS_VBE -static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr) -{ - VGAState *s = opaque; - uint32_t val; - val = s->vbe_index; - return val; -} - -static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr) -{ - VGAState *s = opaque; - uint32_t val; - - if (s->vbe_index <= VBE_DISPI_INDEX_NB) { - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) { - switch(s->vbe_index) { - /* XXX: do not hardcode ? */ - case VBE_DISPI_INDEX_XRES: - val = VBE_DISPI_MAX_XRES; - break; - case VBE_DISPI_INDEX_YRES: - val = VBE_DISPI_MAX_YRES; - break; - case VBE_DISPI_INDEX_BPP: - val = VBE_DISPI_MAX_BPP; - break; - default: - val = s->vbe_regs[s->vbe_index]; - break; - } - } else { - val = s->vbe_regs[s->vbe_index]; - } - } else { - val = 0; - } -#ifdef DEBUG_BOCHS_VBE - printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val); -#endif - return val; -} - -static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val) -{ - VGAState *s = opaque; - s->vbe_index = val; -} - -static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val) -{ - VGAState *s = opaque; - - if (s->vbe_index <= VBE_DISPI_INDEX_NB) { -#ifdef DEBUG_BOCHS_VBE - printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val); -#endif - switch(s->vbe_index) { - case VBE_DISPI_INDEX_ID: - if (val == VBE_DISPI_ID0 || - val == VBE_DISPI_ID1 || - val == VBE_DISPI_ID2) { - s->vbe_regs[s->vbe_index] = val; - } - break; - case VBE_DISPI_INDEX_XRES: - if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) { - s->vbe_regs[s->vbe_index] = val; - } - break; - case VBE_DISPI_INDEX_YRES: - if (val <= VBE_DISPI_MAX_YRES) { - s->vbe_regs[s->vbe_index] = val; - } - break; - case VBE_DISPI_INDEX_BPP: - if (val == 0) - val = 8; - if (val == 4 || val == 8 || val == 15 || - val == 16 || val == 24 || val == 32) { - s->vbe_regs[s->vbe_index] = val; - } - break; - case VBE_DISPI_INDEX_BANK: - val &= s->vbe_bank_mask; - s->vbe_regs[s->vbe_index] = val; - s->bank_offset = (val << 16); - break; - case VBE_DISPI_INDEX_ENABLE: - if ((val & VBE_DISPI_ENABLED) && - !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) { - int h, shift_control; - - s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = - s->vbe_regs[VBE_DISPI_INDEX_XRES]; - s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = - s->vbe_regs[VBE_DISPI_INDEX_YRES]; - s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0; - s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0; - - if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) - s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1; - else - s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * - ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); - s->vbe_start_addr = 0; - - /* clear the screen (should be done in BIOS) */ - if (!(val & VBE_DISPI_NOCLEARMEM)) { - memset(s->vram_ptr, 0, - s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset); - } - - /* we initialize the VGA graphic mode (should be done - in BIOS) */ - s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */ - s->cr[0x17] |= 3; /* no CGA modes */ - s->cr[0x13] = s->vbe_line_offset >> 3; - /* width */ - s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1; - /* height (only meaningful if < 1024) */ - h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1; - s->cr[0x12] = h; - s->cr[0x07] = (s->cr[0x07] & ~0x42) | - ((h >> 7) & 0x02) | ((h >> 3) & 0x40); - /* line compare to 1023 */ - s->cr[0x18] = 0xff; - s->cr[0x07] |= 0x10; - s->cr[0x09] |= 0x40; - - if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) { - shift_control = 0; - s->sr[0x01] &= ~8; /* no double line */ - } else { - shift_control = 2; - s->sr[4] |= 0x08; /* set chain 4 mode */ - s->sr[2] |= 0x0f; /* activate all planes */ - } - s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5); - s->cr[0x09] &= ~0x9f; /* no double scan */ - } else { - /* XXX: the bios should do that */ - s->bank_offset = 0; - } - s->vbe_regs[s->vbe_index] = val; - break; - case VBE_DISPI_INDEX_VIRT_WIDTH: - { - int w, h, line_offset; - - if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES]) - return; - w = val; - if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) - line_offset = w >> 1; - else - line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); - h = s->vram_size / line_offset; - /* XXX: support weird bochs semantics ? */ - if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES]) - return; - s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w; - s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h; - s->vbe_line_offset = line_offset; - } - break; - case VBE_DISPI_INDEX_X_OFFSET: - case VBE_DISPI_INDEX_Y_OFFSET: - { - int x; - s->vbe_regs[s->vbe_index] = val; - s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET]; - x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET]; - if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) - s->vbe_start_addr += x >> 1; - else - s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3); - s->vbe_start_addr >>= 2; - } - break; - default: - break; - } - } -} -#endif - -/* called for accesses between 0xa0000 and 0xc0000 */ -uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr) -{ - VGAState *s = opaque; - int memory_map_mode, plane; - uint32_t ret; - - /* convert to VGA memory offset */ - memory_map_mode = (s->gr[6] >> 2) & 3; - addr &= 0x1ffff; - switch(memory_map_mode) { - case 0: - break; - case 1: - if (addr >= 0x10000) - return 0xff; - addr += s->bank_offset; - break; - case 2: - addr -= 0x10000; - if (addr >= 0x8000) - return 0xff; - break; - default: - case 3: - addr -= 0x18000; - if (addr >= 0x8000) - return 0xff; - break; - } - - if (s->sr[4] & 0x08) { - /* chain 4 mode : simplest access */ - ret = s->vram_ptr[addr]; - } else if (s->gr[5] & 0x10) { - /* odd/even mode (aka text mode mapping) */ - plane = (s->gr[4] & 2) | (addr & 1); - ret = s->vram_ptr[((addr & ~1) << 1) | plane]; - } else { - /* standard VGA latched access */ - s->latch = ((uint32_t *)s->vram_ptr)[addr]; - - if (!(s->gr[5] & 0x08)) { - /* read mode 0 */ - plane = s->gr[4]; - ret = GET_PLANE(s->latch, plane); - } else { - /* read mode 1 */ - ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]]; - ret |= ret >> 16; - ret |= ret >> 8; - ret = (~ret) & 0xff; - } - } - return ret; -} - -static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = vga_mem_readb(opaque, addr) << 8; - v |= vga_mem_readb(opaque, addr + 1); -#else - v = vga_mem_readb(opaque, addr); - v |= vga_mem_readb(opaque, addr + 1) << 8; -#endif - return v; -} - -static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr) -{ - uint32_t v; -#ifdef TARGET_WORDS_BIGENDIAN - v = vga_mem_readb(opaque, addr) << 24; - v |= vga_mem_readb(opaque, addr + 1) << 16; - v |= vga_mem_readb(opaque, addr + 2) << 8; - v |= vga_mem_readb(opaque, addr + 3); -#else - v = vga_mem_readb(opaque, addr); - v |= vga_mem_readb(opaque, addr + 1) << 8; - v |= vga_mem_readb(opaque, addr + 2) << 16; - v |= vga_mem_readb(opaque, addr + 3) << 24; -#endif - return v; -} - -/* called for accesses between 0xa0000 and 0xc0000 */ -void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - VGAState *s = opaque; - int memory_map_mode, plane, write_mode, b, func_select, mask; - uint32_t write_mask, bit_mask, set_mask; - -#ifdef DEBUG_VGA_MEM - printf("vga: [0x%x] = 0x%02x\n", addr, val); -#endif - /* convert to VGA memory offset */ - memory_map_mode = (s->gr[6] >> 2) & 3; - addr &= 0x1ffff; - switch(memory_map_mode) { - case 0: - break; - case 1: - if (addr >= 0x10000) - return; - addr += s->bank_offset; - break; - case 2: - addr -= 0x10000; - if (addr >= 0x8000) - return; - break; - default: - case 3: - addr -= 0x18000; - if (addr >= 0x8000) - return; - break; - } - - if (s->sr[4] & 0x08) { - /* chain 4 mode : simplest access */ - plane = addr & 3; - mask = (1 << plane); - if (s->sr[2] & mask) { - s->vram_ptr[addr] = val; -#ifdef DEBUG_VGA_MEM - printf("vga: chain4: [0x%x]\n", addr); -#endif - s->plane_updated |= mask; /* only used to detect font change */ - cpu_physical_memory_set_dirty(s->vram_offset + addr); - } - } else if (s->gr[5] & 0x10) { - /* odd/even mode (aka text mode mapping) */ - plane = (s->gr[4] & 2) | (addr & 1); - mask = (1 << plane); - if (s->sr[2] & mask) { - addr = ((addr & ~1) << 1) | plane; - s->vram_ptr[addr] = val; -#ifdef DEBUG_VGA_MEM - printf("vga: odd/even: [0x%x]\n", addr); -#endif - s->plane_updated |= mask; /* only used to detect font change */ - cpu_physical_memory_set_dirty(s->vram_offset + addr); - } - } else { - /* standard VGA latched access */ - write_mode = s->gr[5] & 3; - switch(write_mode) { - default: - case 0: - /* rotate */ - b = s->gr[3] & 7; - val = ((val >> b) | (val << (8 - b))) & 0xff; - val |= val << 8; - val |= val << 16; - - /* apply set/reset mask */ - set_mask = mask16[s->gr[1]]; - val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask); - bit_mask = s->gr[8]; - break; - case 1: - val = s->latch; - goto do_write; - case 2: - val = mask16[val & 0x0f]; - bit_mask = s->gr[8]; - break; - case 3: - /* rotate */ - b = s->gr[3] & 7; - val = (val >> b) | (val << (8 - b)); - - bit_mask = s->gr[8] & val; - val = mask16[s->gr[0]]; - break; - } - - /* apply logical operation */ - func_select = s->gr[3] >> 3; - switch(func_select) { - case 0: - default: - /* nothing to do */ - break; - case 1: - /* and */ - val &= s->latch; - break; - case 2: - /* or */ - val |= s->latch; - break; - case 3: - /* xor */ - val ^= s->latch; - break; - } - - /* apply bit mask */ - bit_mask |= bit_mask << 8; - bit_mask |= bit_mask << 16; - val = (val & bit_mask) | (s->latch & ~bit_mask); - - do_write: - /* mask data according to sr[2] */ - mask = s->sr[2]; - s->plane_updated |= mask; /* only used to detect font change */ - write_mask = mask16[mask]; - ((uint32_t *)s->vram_ptr)[addr] = - (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | - (val & write_mask); -#ifdef DEBUG_VGA_MEM - printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", - addr * 4, write_mask, val); -#endif - cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2)); - } -} - -static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - vga_mem_writeb(opaque, addr, (val >> 8) & 0xff); - vga_mem_writeb(opaque, addr + 1, val & 0xff); -#else - vga_mem_writeb(opaque, addr, val & 0xff); - vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); -#endif -} - -static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ -#ifdef TARGET_WORDS_BIGENDIAN - vga_mem_writeb(opaque, addr, (val >> 24) & 0xff); - vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff); - vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff); - vga_mem_writeb(opaque, addr + 3, val & 0xff); -#else - vga_mem_writeb(opaque, addr, val & 0xff); - vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff); - vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff); - vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff); -#endif -} - -typedef void vga_draw_glyph8_func(uint8_t *d, int linesize, - const uint8_t *font_ptr, int h, - uint32_t fgcol, uint32_t bgcol); -typedef void vga_draw_glyph9_func(uint8_t *d, int linesize, - const uint8_t *font_ptr, int h, - uint32_t fgcol, uint32_t bgcol, int dup9); -typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, - const uint8_t *s, int width); - -static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6); -} - -static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3); -} - -static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b) -{ - return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3); -} - -static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b) -{ - return (r << 16) | (g << 8) | b; -} - -static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b) -{ - return (b << 16) | (g << 8) | r; -} - -#define DEPTH 8 -#include "vga_template.h" - -#define DEPTH 15 -#include "vga_template.h" - -#define DEPTH 16 -#include "vga_template.h" - -#define DEPTH 32 -#include "vga_template.h" - -#define BGR_FORMAT -#define DEPTH 32 -#include "vga_template.h" - -static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b) -{ - unsigned int col; - col = rgb_to_pixel8(r, g, b); - col |= col << 8; - col |= col << 16; - return col; -} - -static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b) -{ - unsigned int col; - col = rgb_to_pixel15(r, g, b); - col |= col << 16; - return col; -} - -static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b) -{ - unsigned int col; - col = rgb_to_pixel16(r, g, b); - col |= col << 16; - return col; -} - -static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b) -{ - unsigned int col; - col = rgb_to_pixel32(r, g, b); - return col; -} - -static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b) -{ - unsigned int col; - col = rgb_to_pixel32bgr(r, g, b); - return col; -} - -/* return true if the palette was modified */ -static int update_palette16(VGAState *s) -{ - int full_update, i; - uint32_t v, col, *palette; - - full_update = 0; - palette = s->last_palette; - for(i = 0; i < 16; i++) { - v = s->ar[i]; - if (s->ar[0x10] & 0x80) - v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf); - else - v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f); - v = v * 3; - col = s->rgb_to_pixel(c6_to_8(s->palette[v]), - c6_to_8(s->palette[v + 1]), - c6_to_8(s->palette[v + 2])); - if (col != palette[i]) { - full_update = 1; - palette[i] = col; - } - } - return full_update; -} - -/* return true if the palette was modified */ -static int update_palette256(VGAState *s) -{ - int full_update, i; - uint32_t v, col, *palette; - - full_update = 0; - palette = s->last_palette; - v = 0; - for(i = 0; i < 256; i++) { - col = s->rgb_to_pixel(c6_to_8(s->palette[v]), - c6_to_8(s->palette[v + 1]), - c6_to_8(s->palette[v + 2])); - if (col != palette[i]) { - full_update = 1; - palette[i] = col; - } - v += 3; - } - return full_update; -} - -static void vga_get_offsets(VGAState *s, - uint32_t *pline_offset, - uint32_t *pstart_addr) -{ - uint32_t start_addr, line_offset; -#ifdef CONFIG_BOCHS_VBE - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { - line_offset = s->vbe_line_offset; - start_addr = s->vbe_start_addr; - } else -#endif - { - /* compute line_offset in bytes */ - line_offset = s->cr[0x13]; - line_offset <<= 3; - - /* starting address */ - start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8); - } - *pline_offset = line_offset; - *pstart_addr = start_addr; -} - -/* update start_addr and line_offset. Return TRUE if modified */ -static int update_basic_params(VGAState *s) -{ - int full_update; - uint32_t start_addr, line_offset, line_compare; - - full_update = 0; - - s->get_offsets(s, &line_offset, &start_addr); - /* line compare */ - line_compare = s->cr[0x18] | - ((s->cr[0x07] & 0x10) << 4) | - ((s->cr[0x09] & 0x40) << 3); - - if (line_offset != s->line_offset || - start_addr != s->start_addr || - line_compare != s->line_compare) { - s->line_offset = line_offset; - s->start_addr = start_addr; - s->line_compare = line_compare; - full_update = 1; - } - return full_update; -} - -#define NB_DEPTHS 5 - -static inline int get_depth_index(DisplayState *s) -{ - switch(s->depth) { - default: - case 8: - return 0; - case 15: - return 1; - case 16: - return 2; - case 32: - if (s->bgr) - return 4; - else - return 3; - } -} - -static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = { - vga_draw_glyph8_8, - vga_draw_glyph8_16, - vga_draw_glyph8_16, - vga_draw_glyph8_32, - vga_draw_glyph8_32, -}; - -static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = { - vga_draw_glyph16_8, - vga_draw_glyph16_16, - vga_draw_glyph16_16, - vga_draw_glyph16_32, - vga_draw_glyph16_32, -}; - -static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = { - vga_draw_glyph9_8, - vga_draw_glyph9_16, - vga_draw_glyph9_16, - vga_draw_glyph9_32, - vga_draw_glyph9_32, -}; - -static const uint8_t cursor_glyph[32 * 4] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -}; - -/* - * Text mode update - * Missing: - * - double scan - * - double width - * - underline - * - flashing - */ -static void vga_draw_text(VGAState *s, int full_update) -{ - int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr; - int cx_min, cx_max, linesize, x_incr; - uint32_t offset, fgcol, bgcol, v, cursor_offset; - uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr; - const uint8_t *font_ptr, *font_base[2]; - int dup9, line_offset, depth_index; - uint32_t *palette; - uint32_t *ch_attr_ptr; - vga_draw_glyph8_func *vga_draw_glyph8; - vga_draw_glyph9_func *vga_draw_glyph9; - - full_update |= update_palette16(s); - palette = s->last_palette; - - /* compute font data address (in plane 2) */ - v = s->sr[3]; - offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2; - if (offset != s->font_offsets[0]) { - s->font_offsets[0] = offset; - full_update = 1; - } - font_base[0] = s->vram_ptr + offset; - - offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2; - font_base[1] = s->vram_ptr + offset; - if (offset != s->font_offsets[1]) { - s->font_offsets[1] = offset; - full_update = 1; - } - if (s->plane_updated & (1 << 2)) { - /* if the plane 2 was modified since the last display, it - indicates the font may have been modified */ - s->plane_updated = 0; - full_update = 1; - } - full_update |= update_basic_params(s); - - line_offset = s->line_offset; - s1 = s->vram_ptr + (s->start_addr * 4); - - /* total width & height */ - cheight = (s->cr[9] & 0x1f) + 1; - cw = 8; - if (!(s->sr[1] & 0x01)) - cw = 9; - if (s->sr[1] & 0x08) - cw = 16; /* NOTE: no 18 pixel wide */ - x_incr = cw * ((s->ds->depth + 7) >> 3); - width = (s->cr[0x01] + 1); - if (s->cr[0x06] == 100) { - /* ugly hack for CGA 160x100x16 - explain me the logic */ - height = 100; - } else { - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); - height = (height + 1) / cheight; - } - if ((height * width) > CH_ATTR_SIZE) { - /* better than nothing: exit if transient size is too big */ - return; - } - - if (width != s->last_width || height != s->last_height || - cw != s->last_cw || cheight != s->last_ch) { - s->last_scr_width = width * cw; - s->last_scr_height = height * cheight; - dpy_resize(s->ds, s->last_scr_width, s->last_scr_height); - s->last_width = width; - s->last_height = height; - s->last_ch = cheight; - s->last_cw = cw; - full_update = 1; - } - cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr; - if (cursor_offset != s->cursor_offset || - s->cr[0xa] != s->cursor_start || - s->cr[0xb] != s->cursor_end) { - /* if the cursor position changed, we update the old and new - chars */ - if (s->cursor_offset < CH_ATTR_SIZE) - s->last_ch_attr[s->cursor_offset] = -1; - if (cursor_offset < CH_ATTR_SIZE) - s->last_ch_attr[cursor_offset] = -1; - s->cursor_offset = cursor_offset; - s->cursor_start = s->cr[0xa]; - s->cursor_end = s->cr[0xb]; - } - cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4; - - depth_index = get_depth_index(s->ds); - if (cw == 16) - vga_draw_glyph8 = vga_draw_glyph16_table[depth_index]; - else - vga_draw_glyph8 = vga_draw_glyph8_table[depth_index]; - vga_draw_glyph9 = vga_draw_glyph9_table[depth_index]; - - dest = s->ds->data; - linesize = s->ds->linesize; - ch_attr_ptr = s->last_ch_attr; - for(cy = 0; cy < height; cy++) { - d1 = dest; - src = s1; - cx_min = width; - cx_max = -1; - for(cx = 0; cx < width; cx++) { - ch_attr = *(uint16_t *)src; - if (full_update || ch_attr != *ch_attr_ptr) { - if (cx < cx_min) - cx_min = cx; - if (cx > cx_max) - cx_max = cx; - *ch_attr_ptr = ch_attr; -#ifdef WORDS_BIGENDIAN - ch = ch_attr >> 8; - cattr = ch_attr & 0xff; -#else - ch = ch_attr & 0xff; - cattr = ch_attr >> 8; -#endif - font_ptr = font_base[(cattr >> 3) & 1]; - font_ptr += 32 * 4 * ch; - bgcol = palette[cattr >> 4]; - fgcol = palette[cattr & 0x0f]; - if (cw != 9) { - vga_draw_glyph8(d1, linesize, - font_ptr, cheight, fgcol, bgcol); - } else { - dup9 = 0; - if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04)) - dup9 = 1; - vga_draw_glyph9(d1, linesize, - font_ptr, cheight, fgcol, bgcol, dup9); - } - if (src == cursor_ptr && - !(s->cr[0x0a] & 0x20)) { - int line_start, line_last, h; - /* draw the cursor */ - line_start = s->cr[0x0a] & 0x1f; - line_last = s->cr[0x0b] & 0x1f; - /* XXX: check that */ - if (line_last > cheight - 1) - line_last = cheight - 1; - if (line_last >= line_start && line_start < cheight) { - h = line_last - line_start + 1; - d = d1 + linesize * line_start; - if (cw != 9) { - vga_draw_glyph8(d, linesize, - cursor_glyph, h, fgcol, bgcol); - } else { - vga_draw_glyph9(d, linesize, - cursor_glyph, h, fgcol, bgcol, 1); - } - } - } - } - d1 += x_incr; - src += 4; - ch_attr_ptr++; - } - if (cx_max != -1) { - dpy_update(s->ds, cx_min * cw, cy * cheight, - (cx_max - cx_min + 1) * cw, cheight); - } - dest += linesize * cheight; - s1 += line_offset; - } -} - -enum { - VGA_DRAW_LINE2, - VGA_DRAW_LINE2D2, - VGA_DRAW_LINE4, - VGA_DRAW_LINE4D2, - VGA_DRAW_LINE8D2, - VGA_DRAW_LINE8, - VGA_DRAW_LINE15, - VGA_DRAW_LINE16, - VGA_DRAW_LINE24, - VGA_DRAW_LINE32, - VGA_DRAW_LINE_NB, -}; - -static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = { - vga_draw_line2_8, - vga_draw_line2_16, - vga_draw_line2_16, - vga_draw_line2_32, - vga_draw_line2_32, - - vga_draw_line2d2_8, - vga_draw_line2d2_16, - vga_draw_line2d2_16, - vga_draw_line2d2_32, - vga_draw_line2d2_32, - - vga_draw_line4_8, - vga_draw_line4_16, - vga_draw_line4_16, - vga_draw_line4_32, - vga_draw_line4_32, - - vga_draw_line4d2_8, - vga_draw_line4d2_16, - vga_draw_line4d2_16, - vga_draw_line4d2_32, - vga_draw_line4d2_32, - - vga_draw_line8d2_8, - vga_draw_line8d2_16, - vga_draw_line8d2_16, - vga_draw_line8d2_32, - vga_draw_line8d2_32, - - vga_draw_line8_8, - vga_draw_line8_16, - vga_draw_line8_16, - vga_draw_line8_32, - vga_draw_line8_32, - - vga_draw_line15_8, - vga_draw_line15_15, - vga_draw_line15_16, - vga_draw_line15_32, - vga_draw_line15_32bgr, - - vga_draw_line16_8, - vga_draw_line16_15, - vga_draw_line16_16, - vga_draw_line16_32, - vga_draw_line16_32bgr, - - vga_draw_line24_8, - vga_draw_line24_15, - vga_draw_line24_16, - vga_draw_line24_32, - vga_draw_line24_32bgr, - - vga_draw_line32_8, - vga_draw_line32_15, - vga_draw_line32_16, - vga_draw_line32_32, - vga_draw_line32_32bgr, -}; - -typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b); - -static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = { - rgb_to_pixel8_dup, - rgb_to_pixel15_dup, - rgb_to_pixel16_dup, - rgb_to_pixel32_dup, - rgb_to_pixel32bgr_dup, -}; - -static int vga_get_bpp(VGAState *s) -{ - int ret; -#ifdef CONFIG_BOCHS_VBE - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { - ret = s->vbe_regs[VBE_DISPI_INDEX_BPP]; - } else -#endif - { - ret = 0; - } - return ret; -} - -static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight) -{ - int width, height; - -#ifdef CONFIG_BOCHS_VBE - if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) { - width = s->vbe_regs[VBE_DISPI_INDEX_XRES]; - height = s->vbe_regs[VBE_DISPI_INDEX_YRES]; - } else -#endif - { - width = (s->cr[0x01] + 1) * 8; - height = s->cr[0x12] | - ((s->cr[0x07] & 0x02) << 7) | - ((s->cr[0x07] & 0x40) << 3); - height = (height + 1); - } - *pwidth = width; - *pheight = height; -} - -void vga_invalidate_scanlines(VGAState *s, int y1, int y2) -{ - int y; - if (y1 >= VGA_MAX_HEIGHT) - return; - if (y2 >= VGA_MAX_HEIGHT) - y2 = VGA_MAX_HEIGHT; - for(y = y1; y < y2; y++) { - s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f); - } -} - -/* - * graphic modes - */ -static void vga_draw_graphic(VGAState *s, int full_update) -{ - int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask; - int width, height, shift_control, line_offset, page0, page1, bwidth; - int disp_width, multi_scan, multi_run; - uint8_t *d; - uint32_t v, addr1, addr; - vga_draw_line_func *vga_draw_line; - - full_update |= update_basic_params(s); - - s->get_resolution(s, &width, &height); - disp_width = width; - - shift_control = (s->gr[0x05] >> 5) & 3; - double_scan = (s->cr[0x09] >> 7); - if (shift_control != 1) { - multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1; - } else { - /* in CGA modes, multi_scan is ignored */ - /* XXX: is it correct ? */ - multi_scan = double_scan; - } - multi_run = multi_scan; - if (shift_control != s->shift_control || - double_scan != s->double_scan) { - full_update = 1; - s->shift_control = shift_control; - s->double_scan = double_scan; - } - - if (shift_control == 0) { - full_update |= update_palette16(s); - if (s->sr[0x01] & 8) { - v = VGA_DRAW_LINE4D2; - disp_width <<= 1; - } else { - v = VGA_DRAW_LINE4; - } - } else if (shift_control == 1) { - full_update |= update_palette16(s); - if (s->sr[0x01] & 8) { - v = VGA_DRAW_LINE2D2; - disp_width <<= 1; - } else { - v = VGA_DRAW_LINE2; - } - } else { - switch(s->get_bpp(s)) { - default: - case 0: - full_update |= update_palette256(s); - v = VGA_DRAW_LINE8D2; - break; - case 8: - full_update |= update_palette256(s); - v = VGA_DRAW_LINE8; - break; - case 15: - v = VGA_DRAW_LINE15; - break; - case 16: - v = VGA_DRAW_LINE16; - break; - case 24: - v = VGA_DRAW_LINE24; - break; - case 32: - v = VGA_DRAW_LINE32; - break; - } - } - vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)]; - - if (disp_width != s->last_width || - height != s->last_height) { - dpy_resize(s->ds, disp_width, height); - s->last_scr_width = disp_width; - s->last_scr_height = height; - s->last_width = disp_width; - s->last_height = height; - full_update = 1; - } - if (s->cursor_invalidate) - s->cursor_invalidate(s); - - line_offset = s->line_offset; -#if 0 - printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n", - width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]); -#endif - addr1 = (s->start_addr * 4); - bwidth = width * 4; - y_start = -1; - page_min = 0x7fffffff; - page_max = -1; - d = s->ds->data; - linesize = s->ds->linesize; - y1 = 0; - for(y = 0; y < height; y++) { - addr = addr1; - if (!(s->cr[0x17] & 1)) { - int shift; - /* CGA compatibility handling */ - shift = 14 + ((s->cr[0x17] >> 6) & 1); - addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift); - } - if (!(s->cr[0x17] & 2)) { - addr = (addr & ~0x8000) | ((y1 & 2) << 14); - } - page0 = s->vram_offset + (addr & TARGET_PAGE_MASK); - page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK); - update = full_update | - cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) | - cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG); - if ((page1 - page0) > TARGET_PAGE_SIZE) { - /* if wide line, can use another page */ - update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE, - VGA_DIRTY_FLAG); - } - /* explicit invalidation for the hardware cursor */ - update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1; - if (update) { - if (y_start < 0) - y_start = y; - if (page0 < page_min) - page_min = page0; - if (page1 > page_max) - page_max = page1; - vga_draw_line(s, d, s->vram_ptr + addr, width); - if (s->cursor_draw_line) - s->cursor_draw_line(s, d, y); - } else { - if (y_start >= 0) { - /* flush to display */ - dpy_update(s->ds, 0, y_start, - disp_width, y - y_start); - y_start = -1; - } - } - if (!multi_run) { - mask = (s->cr[0x17] & 3) ^ 3; - if ((y1 & mask) == mask) - addr1 += line_offset; - y1++; - multi_run = multi_scan; - } else { - multi_run--; - } - /* line compare acts on the displayed lines */ - if (y == s->line_compare) - addr1 = 0; - d += linesize; - } - if (y_start >= 0) { - /* flush to display */ - dpy_update(s->ds, 0, y_start, - disp_width, y - y_start); - } - /* reset modified pages */ - if (page_max != -1) { - cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE, - VGA_DIRTY_FLAG); - } - memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4); -} - -static void vga_draw_blank(VGAState *s, int full_update) -{ - int i, w, val; - uint8_t *d; - - if (!full_update) - return; - if (s->last_scr_width <= 0 || s->last_scr_height <= 0) - return; - if (s->ds->depth == 8) - val = s->rgb_to_pixel(0, 0, 0); - else - val = 0; - w = s->last_scr_width * ((s->ds->depth + 7) >> 3); - d = s->ds->data; - for(i = 0; i < s->last_scr_height; i++) { - memset(d, val, w); - d += s->ds->linesize; - } - dpy_update(s->ds, 0, 0, - s->last_scr_width, s->last_scr_height); -} - -#define GMODE_TEXT 0 -#define GMODE_GRAPH 1 -#define GMODE_BLANK 2 - -static void vga_update_display(void *opaque) -{ - VGAState *s = (VGAState *)opaque; - int full_update, graphic_mode; - - if (s->ds->depth == 0) { - /* nothing to do */ - } else { - s->rgb_to_pixel = - rgb_to_pixel_dup_table[get_depth_index(s->ds)]; - - full_update = 0; - if (!(s->ar_index & 0x20)) { - graphic_mode = GMODE_BLANK; - } else { - graphic_mode = s->gr[6] & 1; - } - if (graphic_mode != s->graphic_mode) { - s->graphic_mode = graphic_mode; - full_update = 1; - } - switch(graphic_mode) { - case GMODE_TEXT: - vga_draw_text(s, full_update); - break; - case GMODE_GRAPH: - vga_draw_graphic(s, full_update); - break; - case GMODE_BLANK: - default: - vga_draw_blank(s, full_update); - break; - } - } -} - -/* force a full display refresh */ -static void vga_invalidate_display(void *opaque) -{ - VGAState *s = (VGAState *)opaque; - - s->last_width = -1; - s->last_height = -1; -} - -static void vga_reset(VGAState *s) -{ - memset(s, 0, sizeof(VGAState)); - s->graphic_mode = -1; /* force full update */ -} - -static CPUReadMemoryFunc *vga_mem_read[3] = { - vga_mem_readb, - vga_mem_readw, - vga_mem_readl, -}; - -static CPUWriteMemoryFunc *vga_mem_write[3] = { - vga_mem_writeb, - vga_mem_writew, - vga_mem_writel, -}; - -static void vga_save(QEMUFile *f, void *opaque) -{ - VGAState *s = opaque; - int i; - - qemu_put_be32s(f, &s->latch); - qemu_put_8s(f, &s->sr_index); - qemu_put_buffer(f, s->sr, 8); - qemu_put_8s(f, &s->gr_index); - qemu_put_buffer(f, s->gr, 16); - qemu_put_8s(f, &s->ar_index); - qemu_put_buffer(f, s->ar, 21); - qemu_put_be32s(f, &s->ar_flip_flop); - qemu_put_8s(f, &s->cr_index); - qemu_put_buffer(f, s->cr, 256); - qemu_put_8s(f, &s->msr); - qemu_put_8s(f, &s->fcr); - qemu_put_8s(f, &s->st00); - qemu_put_8s(f, &s->st01); - - qemu_put_8s(f, &s->dac_state); - qemu_put_8s(f, &s->dac_sub_index); - qemu_put_8s(f, &s->dac_read_index); - qemu_put_8s(f, &s->dac_write_index); - qemu_put_buffer(f, s->dac_cache, 3); - qemu_put_buffer(f, s->palette, 768); - - qemu_put_be32s(f, &s->bank_offset); -#ifdef CONFIG_BOCHS_VBE - qemu_put_byte(f, 1); - qemu_put_be16s(f, &s->vbe_index); - for(i = 0; i < VBE_DISPI_INDEX_NB; i++) - qemu_put_be16s(f, &s->vbe_regs[i]); - qemu_put_be32s(f, &s->vbe_start_addr); - qemu_put_be32s(f, &s->vbe_line_offset); - qemu_put_be32s(f, &s->vbe_bank_mask); -#else - qemu_put_byte(f, 0); -#endif -} - -static int vga_load(QEMUFile *f, void *opaque, int version_id) -{ - VGAState *s = opaque; - int is_vbe, i; - - if (version_id != 1) - return -EINVAL; - - qemu_get_be32s(f, &s->latch); - qemu_get_8s(f, &s->sr_index); - qemu_get_buffer(f, s->sr, 8); - qemu_get_8s(f, &s->gr_index); - qemu_get_buffer(f, s->gr, 16); - qemu_get_8s(f, &s->ar_index); - qemu_get_buffer(f, s->ar, 21); - qemu_get_be32s(f, &s->ar_flip_flop); - qemu_get_8s(f, &s->cr_index); - qemu_get_buffer(f, s->cr, 256); - qemu_get_8s(f, &s->msr); - qemu_get_8s(f, &s->fcr); - qemu_get_8s(f, &s->st00); - qemu_get_8s(f, &s->st01); - - qemu_get_8s(f, &s->dac_state); - qemu_get_8s(f, &s->dac_sub_index); - qemu_get_8s(f, &s->dac_read_index); - qemu_get_8s(f, &s->dac_write_index); - qemu_get_buffer(f, s->dac_cache, 3); - qemu_get_buffer(f, s->palette, 768); - - qemu_get_be32s(f, &s->bank_offset); - is_vbe = qemu_get_byte(f); -#ifdef CONFIG_BOCHS_VBE - if (!is_vbe) - return -EINVAL; - qemu_get_be16s(f, &s->vbe_index); - for(i = 0; i < VBE_DISPI_INDEX_NB; i++) - qemu_get_be16s(f, &s->vbe_regs[i]); - qemu_get_be32s(f, &s->vbe_start_addr); - qemu_get_be32s(f, &s->vbe_line_offset); - qemu_get_be32s(f, &s->vbe_bank_mask); -#else - if (is_vbe) - return -EINVAL; -#endif - - /* force refresh */ - s->graphic_mode = -1; - return 0; -} - -static void vga_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - VGAState *s = vga_state; - if (region_num == PCI_ROM_SLOT) { - cpu_register_physical_memory(addr, s->bios_size, s->bios_offset); - } else { - cpu_register_physical_memory(addr, s->vram_size, s->vram_offset); - } -} - -void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size) -{ - int i, j, v, b; - - for(i = 0;i < 256; i++) { - v = 0; - for(j = 0; j < 8; j++) { - v |= ((i >> j) & 1) << (j * 4); - } - expand4[i] = v; - - v = 0; - for(j = 0; j < 4; j++) { - v |= ((i >> (2 * j)) & 3) << (j * 4); - } - expand2[i] = v; - } - for(i = 0; i < 16; i++) { - v = 0; - for(j = 0; j < 4; j++) { - b = ((i >> j) & 1); - v |= b << (2 * j); - v |= b << (2 * j + 1); - } - expand4to8[i] = v; - } - - vga_reset(s); - - s->vram_ptr = vga_ram_base; - s->vram_offset = vga_ram_offset; - s->vram_size = vga_ram_size; - s->ds = ds; - s->get_bpp = vga_get_bpp; - s->get_offsets = vga_get_offsets; - s->get_resolution = vga_get_resolution; - graphic_console_init(s->ds, vga_update_display, vga_invalidate_display, - vga_screen_dump, s); - /* XXX: currently needed for display */ - vga_state = s; -} - - -int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size, - unsigned long vga_bios_offset, int vga_bios_size) -{ - VGAState *s; - - s = qemu_mallocz(sizeof(VGAState)); - if (!s) - return -1; - - vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size); - - register_savevm("vga", 0, 1, vga_save, vga_load, s); - - register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s); - - register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s); - register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s); - register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s); - register_ioport_write(0x3da, 1, 1, vga_ioport_write, s); - - register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s); - - register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s); - register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s); - register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s); - register_ioport_read(0x3da, 1, 1, vga_ioport_read, s); - s->bank_offset = 0; - -#ifdef CONFIG_BOCHS_VBE - s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0; - s->vbe_bank_mask = ((s->vram_size >> 16) - 1); -#if defined (TARGET_I386) - register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s); - register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s); - - register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s); - register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s); - - /* old Bochs IO ports */ - register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s); - register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s); - - register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s); - register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); -#else - register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s); - register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s); - - register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s); - register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s); -#endif -#endif /* CONFIG_BOCHS_VBE */ - - vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s); - cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, - vga_io_memory); - - if (bus) { - PCIDevice *d; - uint8_t *pci_conf; - - d = pci_register_device(bus, "VGA", - sizeof(PCIDevice), - -1, NULL, NULL); - pci_conf = d->config; - pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID) - pci_conf[0x01] = 0x12; - pci_conf[0x02] = 0x11; - pci_conf[0x03] = 0x11; - pci_conf[0x0a] = 0x00; // VGA controller - pci_conf[0x0b] = 0x03; - pci_conf[0x0e] = 0x00; // header_type - - /* XXX: vga_ram_size must be a power of two */ - pci_register_io_region(d, 0, vga_ram_size, - PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); - if (vga_bios_size != 0) { - unsigned int bios_total_size; - s->bios_offset = vga_bios_offset; - s->bios_size = vga_bios_size; - /* must be a power of two */ - bios_total_size = 1; - while (bios_total_size < vga_bios_size) - bios_total_size <<= 1; - pci_register_io_region(d, PCI_ROM_SLOT, bios_total_size, - PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map); - } - } else { -#ifdef CONFIG_BOCHS_VBE - /* XXX: use optimized standard vga accesses */ - cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, - vga_ram_size, vga_ram_offset); -#endif - } - return 0; -} - -/********************************************************/ -/* vga screen dump */ - -static int vga_save_w, vga_save_h; - -static void vga_save_dpy_update(DisplayState *s, - int x, int y, int w, int h) -{ -} - -static void vga_save_dpy_resize(DisplayState *s, int w, int h) -{ - s->linesize = w * 4; - s->data = qemu_malloc(h * s->linesize); - vga_save_w = w; - vga_save_h = h; -} - -static void vga_save_dpy_refresh(DisplayState *s) -{ -} - -static int ppm_save(const char *filename, uint8_t *data, - int w, int h, int linesize) -{ - FILE *f; - uint8_t *d, *d1; - unsigned int v; - int y, x; - - f = fopen(filename, "wb"); - if (!f) - return -1; - fprintf(f, "P6\n%d %d\n%d\n", - w, h, 255); - d1 = data; - for(y = 0; y < h; y++) { - d = d1; - for(x = 0; x < w; x++) { - v = *(uint32_t *)d; - fputc((v >> 16) & 0xff, f); - fputc((v >> 8) & 0xff, f); - fputc((v) & 0xff, f); - d += 4; - } - d1 += linesize; - } - fclose(f); - return 0; -} - -/* save the vga display in a PPM image even if no display is - available */ -static void vga_screen_dump(void *opaque, const char *filename) -{ - VGAState *s = (VGAState *)opaque; - DisplayState *saved_ds, ds1, *ds = &ds1; - - /* XXX: this is a little hackish */ - vga_invalidate_display(s); - saved_ds = s->ds; - - memset(ds, 0, sizeof(DisplayState)); - ds->dpy_update = vga_save_dpy_update; - ds->dpy_resize = vga_save_dpy_resize; - ds->dpy_refresh = vga_save_dpy_refresh; - ds->depth = 32; - - s->ds = ds; - s->graphic_mode = -1; - vga_update_display(s); - - if (ds->data) { - ppm_save(filename, ds->data, vga_save_w, vga_save_h, - s->ds->linesize); - qemu_free(ds->data); - } - s->ds = saved_ds; -} diff --git a/hw/vga_int.h b/hw/vga_int.h deleted file mode 100644 index b33ab57..0000000 --- a/hw/vga_int.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * QEMU internal VGA defines. - * - * Copyright (c) 2003-2004 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#define MSR_COLOR_EMULATION 0x01 -#define MSR_PAGE_SELECT 0x20 - -#define ST01_V_RETRACE 0x08 -#define ST01_DISP_ENABLE 0x01 - -/* bochs VBE support */ -#define CONFIG_BOCHS_VBE - -#define VBE_DISPI_MAX_XRES 1600 -#define VBE_DISPI_MAX_YRES 1200 -#define VBE_DISPI_MAX_BPP 32 - -#define VBE_DISPI_INDEX_ID 0x0 -#define VBE_DISPI_INDEX_XRES 0x1 -#define VBE_DISPI_INDEX_YRES 0x2 -#define VBE_DISPI_INDEX_BPP 0x3 -#define VBE_DISPI_INDEX_ENABLE 0x4 -#define VBE_DISPI_INDEX_BANK 0x5 -#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 -#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 -#define VBE_DISPI_INDEX_X_OFFSET 0x8 -#define VBE_DISPI_INDEX_Y_OFFSET 0x9 -#define VBE_DISPI_INDEX_NB 0xa - -#define VBE_DISPI_ID0 0xB0C0 -#define VBE_DISPI_ID1 0xB0C1 -#define VBE_DISPI_ID2 0xB0C2 - -#define VBE_DISPI_DISABLED 0x00 -#define VBE_DISPI_ENABLED 0x01 -#define VBE_DISPI_GETCAPS 0x02 -#define VBE_DISPI_8BIT_DAC 0x20 -#define VBE_DISPI_LFB_ENABLED 0x40 -#define VBE_DISPI_NOCLEARMEM 0x80 - -#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 - -#ifdef CONFIG_BOCHS_VBE - -#define VGA_STATE_COMMON_BOCHS_VBE \ - uint16_t vbe_index; \ - uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; \ - uint32_t vbe_start_addr; \ - uint32_t vbe_line_offset; \ - uint32_t vbe_bank_mask; - -#else - -#define VGA_STATE_COMMON_BOCHS_VBE - -#endif /* !CONFIG_BOCHS_VBE */ - -#define CH_ATTR_SIZE (160 * 100) -#define VGA_MAX_HEIGHT 2048 - -#define VGA_STATE_COMMON \ - uint8_t *vram_ptr; \ - unsigned long vram_offset; \ - unsigned int vram_size; \ - unsigned long bios_offset; \ - unsigned int bios_size; \ - uint32_t latch; \ - uint8_t sr_index; \ - uint8_t sr[256]; \ - uint8_t gr_index; \ - uint8_t gr[256]; \ - uint8_t ar_index; \ - uint8_t ar[21]; \ - int ar_flip_flop; \ - uint8_t cr_index; \ - uint8_t cr[256]; /* CRT registers */ \ - uint8_t msr; /* Misc Output Register */ \ - uint8_t fcr; /* Feature Control Register */ \ - uint8_t st00; /* status 0 */ \ - uint8_t st01; /* status 1 */ \ - uint8_t dac_state; \ - uint8_t dac_sub_index; \ - uint8_t dac_read_index; \ - uint8_t dac_write_index; \ - uint8_t dac_cache[3]; /* used when writing */ \ - uint8_t palette[768]; \ - int32_t bank_offset; \ - int (*get_bpp)(struct VGAState *s); \ - void (*get_offsets)(struct VGAState *s, \ - uint32_t *pline_offset, \ - uint32_t *pstart_addr); \ - void (*get_resolution)(struct VGAState *s, \ - int *pwidth, \ - int *pheight); \ - VGA_STATE_COMMON_BOCHS_VBE \ - /* display refresh support */ \ - DisplayState *ds; \ - uint32_t font_offsets[2]; \ - int graphic_mode; \ - uint8_t shift_control; \ - uint8_t double_scan; \ - uint32_t line_offset; \ - uint32_t line_compare; \ - uint32_t start_addr; \ - uint32_t plane_updated; \ - uint8_t last_cw, last_ch; \ - uint32_t last_width, last_height; /* in chars or pixels */ \ - uint32_t last_scr_width, last_scr_height; /* in pixels */ \ - uint8_t cursor_start, cursor_end; \ - uint32_t cursor_offset; \ - unsigned int (*rgb_to_pixel)(unsigned int r, \ - unsigned int g, unsigned b); \ - /* hardware mouse cursor support */ \ - uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \ - void (*cursor_invalidate)(struct VGAState *s); \ - void (*cursor_draw_line)(struct VGAState *s, uint8_t *d, int y); \ - /* tell for each page if it has been updated since the last time */ \ - uint32_t last_palette[256]; \ - uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */ - - -typedef struct VGAState { - VGA_STATE_COMMON -} VGAState; - -static inline int c6_to_8(int v) -{ - int b; - v &= 0x3f; - b = v & 1; - return (v << 2) | (b << 1) | b; -} - -void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, - unsigned long vga_ram_offset, int vga_ram_size); -uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr); -void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val); -void vga_invalidate_scanlines(VGAState *s, int y1, int y2); - -void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1, - int poffset, int w, - unsigned int color0, unsigned int color1, - unsigned int color_xor); -void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1, - int poffset, int w, - unsigned int color0, unsigned int color1, - unsigned int color_xor); -void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1, - int poffset, int w, - unsigned int color0, unsigned int color1, - unsigned int color_xor); - -extern const uint8_t sr_mask[8]; -extern const uint8_t gr_mask[16]; diff --git a/hw/vga_template.h b/hw/vga_template.h deleted file mode 100644 index e7e8cb8..0000000 --- a/hw/vga_template.h +++ /dev/null @@ -1,525 +0,0 @@ -/* - * QEMU VGA Emulator templates - * - * Copyright (c) 2003 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#if DEPTH == 8 -#define BPP 1 -#define PIXEL_TYPE uint8_t -#elif DEPTH == 15 || DEPTH == 16 -#define BPP 2 -#define PIXEL_TYPE uint16_t -#elif DEPTH == 32 -#define BPP 4 -#define PIXEL_TYPE uint32_t -#else -#error unsupport depth -#endif - -#ifdef BGR_FORMAT -#define PIXEL_NAME glue(DEPTH, bgr) -#else -#define PIXEL_NAME DEPTH -#endif /* BGR_FORMAT */ - -#if DEPTH != 15 && !defined(BGR_FORMAT) - -static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, - uint32_t font_data, - uint32_t xorcol, - uint32_t bgcol) -{ -#if BPP == 1 - ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol; - ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; -#elif BPP == 2 - ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol; - ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol; - ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol; - ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; -#else - ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; - ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; -#endif -} - -static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize, - const uint8_t *font_ptr, int h, - uint32_t fgcol, uint32_t bgcol) -{ - uint32_t font_data, xorcol; - - xorcol = bgcol ^ fgcol; - do { - font_data = font_ptr[0]; - glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol); - font_ptr += 4; - d += linesize; - } while (--h); -} - -static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize, - const uint8_t *font_ptr, int h, - uint32_t fgcol, uint32_t bgcol) -{ - uint32_t font_data, xorcol; - - xorcol = bgcol ^ fgcol; - do { - font_data = font_ptr[0]; - glue(vga_draw_glyph_line_, DEPTH)(d, - expand4to8[font_data >> 4], - xorcol, bgcol); - glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP, - expand4to8[font_data & 0x0f], - xorcol, bgcol); - font_ptr += 4; - d += linesize; - } while (--h); -} - -static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize, - const uint8_t *font_ptr, int h, - uint32_t fgcol, uint32_t bgcol, int dup9) -{ - uint32_t font_data, xorcol, v; - - xorcol = bgcol ^ fgcol; - do { - font_data = font_ptr[0]; -#if BPP == 1 - cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol); - v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol; - cpu_to_32wu(((uint32_t *)d)+1, v); - if (dup9) - ((uint8_t *)d)[8] = v >> (24 * (1 - BIG)); - else - ((uint8_t *)d)[8] = bgcol; - -#elif BPP == 2 - cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol); - cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol); - cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol); - v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol; - cpu_to_32wu(((uint32_t *)d)+3, v); - if (dup9) - ((uint16_t *)d)[8] = v >> (16 * (1 - BIG)); - else - ((uint16_t *)d)[8] = bgcol; -#else - ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol; - ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol; - v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol; - ((uint32_t *)d)[7] = v; - if (dup9) - ((uint32_t *)d)[8] = v; - else - ((uint32_t *)d)[8] = bgcol; -#endif - font_ptr += 4; - d += linesize; - } while (--h); -} - -/* - * 4 color mode - */ -static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - uint32_t plane_mask, *palette, data, v; - int x; - - palette = s1->last_palette; - plane_mask = mask16[s1->ar[0x12] & 0xf]; - width >>= 3; - for(x = 0; x < width; x++) { - data = ((uint32_t *)s)[0]; - data &= plane_mask; - v = expand2[GET_PLANE(data, 0)]; - v |= expand2[GET_PLANE(data, 2)] << 2; - ((PIXEL_TYPE *)d)[0] = palette[v >> 12]; - ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf]; - ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf]; - ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf]; - - v = expand2[GET_PLANE(data, 1)]; - v |= expand2[GET_PLANE(data, 3)] << 2; - ((PIXEL_TYPE *)d)[4] = palette[v >> 12]; - ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf]; - ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf]; - ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf]; - d += BPP * 8; - s += 4; - } -} - -#if BPP == 1 -#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v) -#elif BPP == 2 -#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v) -#else -#define PUT_PIXEL2(d, n, v) \ -((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v) -#endif - -/* - * 4 color mode, dup2 horizontal - */ -static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - uint32_t plane_mask, *palette, data, v; - int x; - - palette = s1->last_palette; - plane_mask = mask16[s1->ar[0x12] & 0xf]; - width >>= 3; - for(x = 0; x < width; x++) { - data = ((uint32_t *)s)[0]; - data &= plane_mask; - v = expand2[GET_PLANE(data, 0)]; - v |= expand2[GET_PLANE(data, 2)] << 2; - PUT_PIXEL2(d, 0, palette[v >> 12]); - PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]); - PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]); - PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]); - - v = expand2[GET_PLANE(data, 1)]; - v |= expand2[GET_PLANE(data, 3)] << 2; - PUT_PIXEL2(d, 4, palette[v >> 12]); - PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]); - PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); - PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); - d += BPP * 16; - s += 4; - } -} - -/* - * 16 color mode - */ -static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - uint32_t plane_mask, data, v, *palette; - int x; - - palette = s1->last_palette; - plane_mask = mask16[s1->ar[0x12] & 0xf]; - width >>= 3; - for(x = 0; x < width; x++) { - data = ((uint32_t *)s)[0]; - data &= plane_mask; - v = expand4[GET_PLANE(data, 0)]; - v |= expand4[GET_PLANE(data, 1)] << 1; - v |= expand4[GET_PLANE(data, 2)] << 2; - v |= expand4[GET_PLANE(data, 3)] << 3; - ((PIXEL_TYPE *)d)[0] = palette[v >> 28]; - ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf]; - ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf]; - ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf]; - ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf]; - ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf]; - ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf]; - ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf]; - d += BPP * 8; - s += 4; - } -} - -/* - * 16 color mode, dup2 horizontal - */ -static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - uint32_t plane_mask, data, v, *palette; - int x; - - palette = s1->last_palette; - plane_mask = mask16[s1->ar[0x12] & 0xf]; - width >>= 3; - for(x = 0; x < width; x++) { - data = ((uint32_t *)s)[0]; - data &= plane_mask; - v = expand4[GET_PLANE(data, 0)]; - v |= expand4[GET_PLANE(data, 1)] << 1; - v |= expand4[GET_PLANE(data, 2)] << 2; - v |= expand4[GET_PLANE(data, 3)] << 3; - PUT_PIXEL2(d, 0, palette[v >> 28]); - PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]); - PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]); - PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]); - PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]); - PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]); - PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]); - PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]); - d += BPP * 16; - s += 4; - } -} - -/* - * 256 color mode, double pixels - * - * XXX: add plane_mask support (never used in standard VGA modes) - */ -static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - uint32_t *palette; - int x; - - palette = s1->last_palette; - width >>= 3; - for(x = 0; x < width; x++) { - PUT_PIXEL2(d, 0, palette[s[0]]); - PUT_PIXEL2(d, 1, palette[s[1]]); - PUT_PIXEL2(d, 2, palette[s[2]]); - PUT_PIXEL2(d, 3, palette[s[3]]); - d += BPP * 8; - s += 4; - } -} - -/* - * standard 256 color mode - * - * XXX: add plane_mask support (never used in standard VGA modes) - */ -static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - uint32_t *palette; - int x; - - palette = s1->last_palette; - width >>= 3; - for(x = 0; x < width; x++) { - ((PIXEL_TYPE *)d)[0] = palette[s[0]]; - ((PIXEL_TYPE *)d)[1] = palette[s[1]]; - ((PIXEL_TYPE *)d)[2] = palette[s[2]]; - ((PIXEL_TYPE *)d)[3] = palette[s[3]]; - ((PIXEL_TYPE *)d)[4] = palette[s[4]]; - ((PIXEL_TYPE *)d)[5] = palette[s[5]]; - ((PIXEL_TYPE *)d)[6] = palette[s[6]]; - ((PIXEL_TYPE *)d)[7] = palette[s[7]]; - d += BPP * 8; - s += 8; - } -} - -void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, - const uint8_t *src1, - int poffset, int w, - unsigned int color0, - unsigned int color1, - unsigned int color_xor) -{ - const uint8_t *plane0, *plane1; - int x, b0, b1; - uint8_t *d; - - d = d1; - plane0 = src1; - plane1 = src1 + poffset; - for(x = 0; x < w; x++) { - b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1; - b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1; -#if DEPTH == 8 - switch(b0 | (b1 << 1)) { - case 0: - break; - case 1: - d[0] ^= color_xor; - break; - case 2: - d[0] = color0; - break; - case 3: - d[0] = color1; - break; - } -#elif DEPTH == 16 - switch(b0 | (b1 << 1)) { - case 0: - break; - case 1: - ((uint16_t *)d)[0] ^= color_xor; - break; - case 2: - ((uint16_t *)d)[0] = color0; - break; - case 3: - ((uint16_t *)d)[0] = color1; - break; - } -#elif DEPTH == 32 - switch(b0 | (b1 << 1)) { - case 0: - break; - case 1: - ((uint32_t *)d)[0] ^= color_xor; - break; - case 2: - ((uint32_t *)d)[0] = color0; - break; - case 3: - ((uint32_t *)d)[0] = color1; - break; - } -#else -#error unsupported depth -#endif - d += BPP; - } -} - -#endif /* DEPTH != 15 */ - - -/* XXX: optimize */ - -/* - * 15 bit color - */ -static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ -#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) - memcpy(d, s, width * 2); -#else - int w; - uint32_t v, r, g, b; - - w = width; - do { - v = lduw_raw((void *)s); - r = (v >> 7) & 0xf8; - g = (v >> 2) & 0xf8; - b = (v << 3) & 0xf8; - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); - s += 2; - d += BPP; - } while (--w != 0); -#endif -} - -/* - * 16 bit color - */ -static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ -#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) - memcpy(d, s, width * 2); -#else - int w; - uint32_t v, r, g, b; - - w = width; - do { - v = lduw_raw((void *)s); - r = (v >> 8) & 0xf8; - g = (v >> 3) & 0xfc; - b = (v << 3) & 0xf8; - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); - s += 2; - d += BPP; - } while (--w != 0); -#endif -} - -/* - * 24 bit color - */ -static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ - int w; - uint32_t r, g, b; - - w = width; - do { -#if defined(TARGET_WORDS_BIGENDIAN) - r = s[0]; - g = s[1]; - b = s[2]; -#else - b = s[0]; - g = s[1]; - r = s[2]; -#endif - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); - s += 3; - d += BPP; - } while (--w != 0); -} - -/* - * 32 bit color - */ -static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d, - const uint8_t *s, int width) -{ -#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT) - memcpy(d, s, width * 4); -#else - int w; - uint32_t r, g, b; - - w = width; - do { -#if defined(TARGET_WORDS_BIGENDIAN) - r = s[1]; - g = s[2]; - b = s[3]; -#else - b = s[0]; - g = s[1]; - r = s[2]; -#endif - ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b); - s += 4; - d += BPP; - } while (--w != 0); -#endif -} - -#undef PUT_PIXEL2 -#undef DEPTH -#undef BPP -#undef PIXEL_TYPE -#undef PIXEL_NAME -#undef BGR_FORMAT |