diff mbox series

[3/3] hw/ppc: Add emulation of AmigaOne XE board

Message ID 624a60acb0b81e6837b249890c59f3010ab12bbc.1696542537.git.balaton@eik.bme.hu
State New
Headers show
Series Add emulation of AmigaOne XE board | expand

Commit Message

BALATON Zoltan Oct. 5, 2023, 10:13 p.m. UTC
The AmigaOne is a rebranded MAI Teron board that uses U-Boot firmware
with patches to support AmigaOS and is very similar to pegasos2 so can
be easily emulated sharing most code with pegasos2. The reason to
emulate it is that AmigaOS comes in different versions for AmigaOne
and PegasosII which only have drivers for one machine and firmware so
these only run on the specific machine. Adding this board allows
another AmigaOS version to be used reusing already existing peagasos2
emulation. (The AmigaOne was the first of these boards so likely most
widespread which then inspired Pegasos that was later replaced with
PegasosII due to problems with Articia S, so these have a lot of
similarity. Pegasos mainly ran MorphOS while the PegasosII version of
AmigaOS was added later and therefore less common than the AmigaOne
version.)

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
 MAINTAINERS                             |   8 ++
 configs/devices/ppc-softmmu/default.mak |   1 +
 hw/ppc/Kconfig                          |   7 +
 hw/ppc/amigaone.c                       | 164 ++++++++++++++++++++++++
 hw/ppc/meson.build                      |   2 +
 5 files changed, 182 insertions(+)
 create mode 100644 hw/ppc/amigaone.c

Comments

Philippe Mathieu-Daudé Oct. 9, 2023, 6:24 a.m. UTC | #1
Hi Zoltan,

On 6/10/23 00:13, BALATON Zoltan wrote:
> The AmigaOne is a rebranded MAI Teron board that uses U-Boot firmware
> with patches to support AmigaOS and is very similar to pegasos2 so can
> be easily emulated sharing most code with pegasos2. The reason to
> emulate it is that AmigaOS comes in different versions for AmigaOne
> and PegasosII which only have drivers for one machine and firmware so
> these only run on the specific machine. Adding this board allows
> another AmigaOS version to be used reusing already existing peagasos2
> emulation. (The AmigaOne was the first of these boards so likely most
> widespread which then inspired Pegasos that was later replaced with
> PegasosII due to problems with Articia S, so these have a lot of
> similarity. Pegasos mainly ran MorphOS while the PegasosII version of
> AmigaOS was added later and therefore less common than the AmigaOne
> version.)
> 
> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
> ---
>   MAINTAINERS                             |   8 ++
>   configs/devices/ppc-softmmu/default.mak |   1 +
>   hw/ppc/Kconfig                          |   7 +
>   hw/ppc/amigaone.c                       | 164 ++++++++++++++++++++++++
>   hw/ppc/meson.build                      |   2 +
>   5 files changed, 182 insertions(+)
>   create mode 100644 hw/ppc/amigaone.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7f0e20fde6..03f908c153 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1490,6 +1490,14 @@ F: hw/pci-host/mv64361.c
>   F: hw/pci-host/mv643xx.h
>   F: include/hw/pci-host/mv64361.h
>   
> +amigaone

'AmigaOne' like in subject and description?

> +M: BALATON Zoltan <balaton@eik.bme.hu>
> +L: qemu-ppc@nongnu.org
> +S: Maintained
> +F: hw/ppc/amigaone.c
> +F: hw/pci-host/articia.c
> +F: include/hw/pci-host/articia.h
> +
>   Virtual Open Firmware (VOF)
>   M: Alexey Kardashevskiy <aik@ozlabs.ru>


> +static void amigaone_init(MachineState *machine)
> +{
> +    PowerPCCPU *cpu;
> +    CPUPPCState *env;
> +    MemoryRegion *rom, *pci_mem, *mr;
> +    const char *fwname = machine->firmware ?: PROM_FILENAME;
> +    char *filename;
> +    ssize_t sz;
> +    PCIBus *pci_bus;
> +    Object *via;
> +    DeviceState *dev;
> +    I2CBus *i2c_bus;
> +    uint8_t *spd_data;
> +    int i;
> +
> +    /* init CPU */
> +    cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
> +    env = &cpu->env;
> +    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
> +        error_report("Incompatible CPU, only 6xx bus supported");
> +        exit(1);
> +    }
> +    cpu_ppc_tb_init(env, BUS_FREQ_HZ / 4);
> +    qemu_register_reset(amigaone_cpu_reset, cpu);
> +
> +    /* RAM */
> +    if (machine->ram_size > 2 * GiB) {
> +        error_report("RAM size more than 2 GiB is not supported");
> +        exit(1);
> +    }
> +    memory_region_add_subregion(get_system_memory(), 0, machine->ram);
> +    if (machine->ram_size < 1 * GiB + 32 * KiB) {
> +        /* Firmware uses this area for startup */

This is odd. Does this machine really support 2GiB?

Could it be 1GiB max, mapped twice?

> +        mr = g_new(MemoryRegion, 1);
> +        memory_region_init_ram(mr, NULL, "init-cache", 32 * KiB, &error_fatal);
> +        memory_region_add_subregion(get_system_memory(), 0x40000000, mr);
> +    }
> +
> +    /* allocate and load firmware */
> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, fwname);
> +    if (!filename) {
> +        error_report("Could not find firmware '%s'", fwname);
> +        exit(1);
> +    }
> +    rom = g_new(MemoryRegion, 1);
> +    memory_region_init_rom(rom, NULL, "rom", PROM_SIZE, &error_fatal);
> +    memory_region_add_subregion(get_system_memory(), PROM_ADDR, rom);
> +    sz = load_image_targphys(filename, PROM_ADDR, PROM_SIZE);
> +    if (sz <= 0 || sz > PROM_SIZE) {
> +        error_report("Could not load firmware '%s'", filename);
> +        exit(1);
> +    }
> +    g_free(filename);
> +
> +    /* Articia S */
> +    dev = sysbus_create_simple(TYPE_ARTICIA, 0xfe000000, NULL);
> +
> +    i2c_bus = I2C_BUS(qdev_get_child_bus(dev, "smbus"));
> +    if (machine->ram_size > 512 * MiB) {
> +        spd_data = spd_data_generate(SDR, machine->ram_size / 2);
> +    } else {
> +        spd_data = spd_data_generate(SDR, machine->ram_size);
> +    }
> +    fix_spd_data(spd_data);
> +    smbus_eeprom_init_one(i2c_bus, 0x51, spd_data);
> +    if (machine->ram_size > 512 * MiB) {
> +        smbus_eeprom_init_one(i2c_bus, 0x52, spd_data);
> +    }

This seems to confirm my doubts, you use at most 2 SPD of 512MiB DIMMs,
so max for this machine is 1 GiB.

> +    pci_mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> +    mr = g_new(MemoryRegion, 1);
> +    memory_region_init_alias(mr, OBJECT(dev), "pci-mem-low", pci_mem,
> +                             0, 0x1000000);
> +    memory_region_add_subregion(get_system_memory(), 0xfd000000, mr);
> +    mr = g_new(MemoryRegion, 1);
> +    memory_region_init_alias(mr, OBJECT(dev), "pci-mem-high", pci_mem,
> +                             0x80000000, 0x7d000000);
> +    memory_region_add_subregion(get_system_memory(), 0x80000000, mr);
> +    pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
> +
> +    /* VIA VT82c686B South Bridge (multifunction PCI device) */
> +    via = OBJECT(pci_create_simple_multifunction(pci_bus, PCI_DEVFN(7, 0),
> +                                                 TYPE_VT82C686B_ISA));
> +    object_property_add_alias(OBJECT(machine), "rtc-time",
> +                              object_resolve_path_component(via, "rtc"),
> +                              "date");
> +    qdev_connect_gpio_out(DEVICE(via), 0,
> +                          qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_INT));
> +    for (i = 0; i < PCI_NUM_PINS; i++) {
> +        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in_named(DEVICE(via),
> +                                                             "pirq", i));
> +    }
> +    pci_ide_create_devs(PCI_DEVICE(object_resolve_path_component(via, "ide")));
> +    pci_vga_init(pci_bus);
> +}
BALATON Zoltan Oct. 9, 2023, 11:56 a.m. UTC | #2
On Mon, 9 Oct 2023, Philippe Mathieu-Daudé wrote:
> Hi Zoltan,
>
> On 6/10/23 00:13, BALATON Zoltan wrote:
>> The AmigaOne is a rebranded MAI Teron board that uses U-Boot firmware
>> with patches to support AmigaOS and is very similar to pegasos2 so can
>> be easily emulated sharing most code with pegasos2. The reason to
>> emulate it is that AmigaOS comes in different versions for AmigaOne
>> and PegasosII which only have drivers for one machine and firmware so
>> these only run on the specific machine. Adding this board allows
>> another AmigaOS version to be used reusing already existing peagasos2
>> emulation. (The AmigaOne was the first of these boards so likely most
>> widespread which then inspired Pegasos that was later replaced with
>> PegasosII due to problems with Articia S, so these have a lot of
>> similarity. Pegasos mainly ran MorphOS while the PegasosII version of
>> AmigaOS was added later and therefore less common than the AmigaOne
>> version.)
>> 
>> Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
>> ---
>>   MAINTAINERS                             |   8 ++
>>   configs/devices/ppc-softmmu/default.mak |   1 +
>>   hw/ppc/Kconfig                          |   7 +
>>   hw/ppc/amigaone.c                       | 164 ++++++++++++++++++++++++
>>   hw/ppc/meson.build                      |   2 +
>>   5 files changed, 182 insertions(+)
>>   create mode 100644 hw/ppc/amigaone.c
>> 
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 7f0e20fde6..03f908c153 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -1490,6 +1490,14 @@ F: hw/pci-host/mv64361.c
>>   F: hw/pci-host/mv643xx.h
>>   F: include/hw/pci-host/mv64361.h
>>   +amigaone
>
> 'AmigaOne' like in subject and description?

The machine option is called amigaone and for pegasos2 and sam460ex I've 
also used the machine name so for consistency it's the same here.

>> +M: BALATON Zoltan <balaton@eik.bme.hu>
>> +L: qemu-ppc@nongnu.org
>> +S: Maintained
>> +F: hw/ppc/amigaone.c
>> +F: hw/pci-host/articia.c
>> +F: include/hw/pci-host/articia.h
>> +
>>   Virtual Open Firmware (VOF)
>>   M: Alexey Kardashevskiy <aik@ozlabs.ru>
>
>
>> +static void amigaone_init(MachineState *machine)
>> +{
>> +    PowerPCCPU *cpu;
>> +    CPUPPCState *env;
>> +    MemoryRegion *rom, *pci_mem, *mr;
>> +    const char *fwname = machine->firmware ?: PROM_FILENAME;
>> +    char *filename;
>> +    ssize_t sz;
>> +    PCIBus *pci_bus;
>> +    Object *via;
>> +    DeviceState *dev;
>> +    I2CBus *i2c_bus;
>> +    uint8_t *spd_data;
>> +    int i;
>> +
>> +    /* init CPU */
>> +    cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
>> +    env = &cpu->env;
>> +    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
>> +        error_report("Incompatible CPU, only 6xx bus supported");
>> +        exit(1);
>> +    }
>> +    cpu_ppc_tb_init(env, BUS_FREQ_HZ / 4);
>> +    qemu_register_reset(amigaone_cpu_reset, cpu);
>> +
>> +    /* RAM */
>> +    if (machine->ram_size > 2 * GiB) {
>> +        error_report("RAM size more than 2 GiB is not supported");
>> +        exit(1);
>> +    }
>> +    memory_region_add_subregion(get_system_memory(), 0, machine->ram);
>> +    if (machine->ram_size < 1 * GiB + 32 * KiB) {
>> +        /* Firmware uses this area for startup */
>
> This is odd. Does this machine really support 2GiB?
>
> Could it be 1GiB max, mapped twice?

Apparently AmigaOne XE does support 2GB:

https://forum.amiga.org/index.php?topic=54563.0
https://www.amigans.net/modules/newbb/viewtopic.php?viewmode=compact&order=DESC&topic_id=2262&forum=3

(As most other 32bit PPC machines it does not support more as memory above 
2GB is reserved for IO.)

The sam460ex does something similar where I think CPU cache can be mapped 
as RAM at 0x4_0000_0000 and is used for start up before the memory 
controller is initialised by firmware. Maybe something similar is done 
here but as we don't emulate the memory controller we just need to make 
sure there's some RAM here. Either the system memory is big enough or we 
map some RAM for the firmware at 1GB (the same is done in sam460ex as well 
but there these aren't overlapping with system RAM so ne need for check 
on RAM size there).

>> +        mr = g_new(MemoryRegion, 1);
>> +        memory_region_init_ram(mr, NULL, "init-cache", 32 * KiB, 
>> &error_fatal);
>> +        memory_region_add_subregion(get_system_memory(), 0x40000000, mr);
>> +    }
>> +
>> +    /* allocate and load firmware */
>> +    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, fwname);
>> +    if (!filename) {
>> +        error_report("Could not find firmware '%s'", fwname);
>> +        exit(1);
>> +    }
>> +    rom = g_new(MemoryRegion, 1);
>> +    memory_region_init_rom(rom, NULL, "rom", PROM_SIZE, &error_fatal);
>> +    memory_region_add_subregion(get_system_memory(), PROM_ADDR, rom);
>> +    sz = load_image_targphys(filename, PROM_ADDR, PROM_SIZE);
>> +    if (sz <= 0 || sz > PROM_SIZE) {
>> +        error_report("Could not load firmware '%s'", filename);
>> +        exit(1);
>> +    }
>> +    g_free(filename);
>> +
>> +    /* Articia S */
>> +    dev = sysbus_create_simple(TYPE_ARTICIA, 0xfe000000, NULL);
>> +
>> +    i2c_bus = I2C_BUS(qdev_get_child_bus(dev, "smbus"));
>> +    if (machine->ram_size > 512 * MiB) {
>> +        spd_data = spd_data_generate(SDR, machine->ram_size / 2);
>> +    } else {
>> +        spd_data = spd_data_generate(SDR, machine->ram_size);
>> +    }
>> +    fix_spd_data(spd_data);
>> +    smbus_eeprom_init_one(i2c_bus, 0x51, spd_data);
>> +    if (machine->ram_size > 512 * MiB) {
>> +        smbus_eeprom_init_one(i2c_bus, 0x52, spd_data);
>> +    }
>
> This seems to confirm my doubts, you use at most 2 SPD of 512MiB DIMMs,
> so max for this machine is 1 GiB.

The firmware has some limitation on DIMM bank size and cannot support 1 GB 
bank size, hence we need to fix it up above 512k but it works up to 2g:

$ qemu-system-ppc -M amigaone -m 2g -serial stdio -bios u-boot-amigaone.bin

U-Boot 1.1.1 (Mar  3 2005 - 16:42:53), Build: 03/03/05

CPU:   MPC7457 v1.2 @ 1150 MHz
Board: AmigaOne
DRAM:
Information for SIMM bank 0:
Number of banks: 2
Number of row addresses: 14
Number of coumns addresses: 10
SIMM is not registered
Supported burst lenghts: 8 4
Supported CAS latencies: CAS 3
RAS to CAS latency: 2
Precharge latency: 2
SDRAM highest CAS latency: 250
SDRAM 2nd highest CAS latency: 120
SDRAM data width: 8
Auto Refresh supported
Refresh time: 782 clocks
Bank 0 size: 512 MB
Bank 1 size: 512 MB


Information for SIMM bank 1:
Number of banks: 2
Number of row addresses: 14
Number of coumns addresses: 10
SIMM is not registered
Supported burst lenghts: 8 4
Supported CAS latencies: CAS 3
RAS to CAS latency: 2
Precharge latency: 2
SDRAM highest CAS latency: 250
SDRAM 2nd highest CAS latency: 120
SDRAM data width: 8
Auto Refresh supported
Refresh time: 782 clocks
Bank 0 size: 512 MB
Bank 1 size: 512 MB

DIMM0_B0_SCR0 = 0x00000000
DIMM0_B1_SCR0 = 0x00000000
DIMM0_B2_SCR0 = 0x00000000
DIMM0_B3_SCR0 = 0x00000000
Using CAS 4 (slow)
Using CAS 4 (slow)
DRAM_GCR0 = 0x00000000
Refresh set to 1561 clocks, auto refresh on
DRAM_REFRESH0 = 0x00019619
Mode bank 0: 0x00008042
Mode bank 1: 0x00008042
Mode bank 2: 0x00008042
Mode bank 3: 0x00008042
2048 MB
FLASH:  0 kB
*** Warning - bad CRC, using default environment

I plan to rework spd_data_generate again at some point to get rid of these 
fix up and to allow machines to better control it (e.g. currently you 
can't have 768k RAM which would be a valid config) but for now this works 
without touching smbus_eeprom generation so I can look at that later. 
(Actually I had that working before in my original spd_eeprom_generate 
patches which returned error to the board but later it was "simplified" 
and that functionality was lost. As more boards use it now I plan to 
restore that but maybe only in next devel cycle as the current one works 
for the common cases.)

Regards,
BALATON Zoltan

>> +    pci_mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
>> +    mr = g_new(MemoryRegion, 1);
>> +    memory_region_init_alias(mr, OBJECT(dev), "pci-mem-low", pci_mem,
>> +                             0, 0x1000000);
>> +    memory_region_add_subregion(get_system_memory(), 0xfd000000, mr);
>> +    mr = g_new(MemoryRegion, 1);
>> +    memory_region_init_alias(mr, OBJECT(dev), "pci-mem-high", pci_mem,
>> +                             0x80000000, 0x7d000000);
>> +    memory_region_add_subregion(get_system_memory(), 0x80000000, mr);
>> +    pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
>> +
>> +    /* VIA VT82c686B South Bridge (multifunction PCI device) */
>> +    via = OBJECT(pci_create_simple_multifunction(pci_bus, PCI_DEVFN(7, 0),
>> +                                                 TYPE_VT82C686B_ISA));
>> +    object_property_add_alias(OBJECT(machine), "rtc-time",
>> +                              object_resolve_path_component(via, "rtc"),
>> +                              "date");
>> +    qdev_connect_gpio_out(DEVICE(via), 0,
>> +                          qdev_get_gpio_in(DEVICE(cpu), 
>> PPC6xx_INPUT_INT));
>> +    for (i = 0; i < PCI_NUM_PINS; i++) {
>> +        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in_named(DEVICE(via),
>> +                                                             "pirq", i));
>> +    }
>> +    pci_ide_create_devs(PCI_DEVICE(object_resolve_path_component(via, 
>> "ide")));
>> +    pci_vga_init(pci_bus);
>> +}
>
>
>
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 7f0e20fde6..03f908c153 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1490,6 +1490,14 @@  F: hw/pci-host/mv64361.c
 F: hw/pci-host/mv643xx.h
 F: include/hw/pci-host/mv64361.h
 
+amigaone
+M: BALATON Zoltan <balaton@eik.bme.hu>
+L: qemu-ppc@nongnu.org
+S: Maintained
+F: hw/ppc/amigaone.c
+F: hw/pci-host/articia.c
+F: include/hw/pci-host/articia.h
+
 Virtual Open Firmware (VOF)
 M: Alexey Kardashevskiy <aik@ozlabs.ru>
 R: David Gibson <david@gibson.dropbear.id.au>
diff --git a/configs/devices/ppc-softmmu/default.mak b/configs/devices/ppc-softmmu/default.mak
index a887f5438b..b85fd2bcd7 100644
--- a/configs/devices/ppc-softmmu/default.mak
+++ b/configs/devices/ppc-softmmu/default.mak
@@ -14,6 +14,7 @@  CONFIG_SAM460EX=y
 CONFIG_MAC_OLDWORLD=y
 CONFIG_MAC_NEWWORLD=y
 
+CONFIG_AMIGAONE=y
 CONFIG_PEGASOS2=y
 
 # For PReP
diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig
index 5dfbf47ef5..56f0475a8e 100644
--- a/hw/ppc/Kconfig
+++ b/hw/ppc/Kconfig
@@ -69,6 +69,13 @@  config SAM460EX
     select USB_OHCI
     select FDT_PPC
 
+config AMIGAONE
+    bool
+    imply ATI_VGA
+    select ARTICIA
+    select VT82C686
+    select SMBUS_EEPROM
+
 config PEGASOS2
     bool
     imply ATI_VGA
diff --git a/hw/ppc/amigaone.c b/hw/ppc/amigaone.c
new file mode 100644
index 0000000000..3589924c8a
--- /dev/null
+++ b/hw/ppc/amigaone.c
@@ -0,0 +1,164 @@ 
+/*
+ * QEMU Eyetech AmigaOne/Mai Logic Teron emulation
+ *
+ * Copyright (c) 2023 BALATON Zoltan
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/datadir.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
+#include "hw/ppc/ppc.h"
+#include "hw/boards.h"
+#include "hw/loader.h"
+#include "hw/pci-host/articia.h"
+#include "hw/isa/vt82c686.h"
+#include "hw/ide/pci.h"
+#include "hw/i2c/smbus_eeprom.h"
+#include "hw/ppc/ppc.h"
+#include "sysemu/reset.h"
+#include "kvm_ppc.h"
+
+#define BUS_FREQ_HZ 100000000
+
+/*
+ * Firmware binary available at
+ * https://www.hyperion-entertainment.com/index.php/downloads?view=files&parent=28
+ * then "tail -c 524288 updater.image >u-boot-amigaone.bin"
+ *
+ * BIOS emulator in firmware cannot run QEMU vgabios and hangs on it, use
+ * -device VGA,romfile=VGABIOS-lgpl-latest.bin
+ * from http://www.nongnu.org/vgabios/ instead.
+ */
+#define PROM_FILENAME "u-boot-amigaone.bin"
+#define PROM_ADDR 0xfff00000
+#define PROM_SIZE (512 * KiB)
+
+static void amigaone_cpu_reset(void *opaque)
+{
+    PowerPCCPU *cpu = opaque;
+
+    cpu_reset(CPU(cpu));
+    cpu_ppc_tb_reset(&cpu->env);
+}
+
+static void fix_spd_data(uint8_t *spd)
+{
+    uint32_t bank_size = 4 * MiB * spd[31];
+    uint32_t rows = bank_size / spd[13] / spd[17];
+    spd[3] = ctz32(rows) - spd[4];
+}
+
+static void amigaone_init(MachineState *machine)
+{
+    PowerPCCPU *cpu;
+    CPUPPCState *env;
+    MemoryRegion *rom, *pci_mem, *mr;
+    const char *fwname = machine->firmware ?: PROM_FILENAME;
+    char *filename;
+    ssize_t sz;
+    PCIBus *pci_bus;
+    Object *via;
+    DeviceState *dev;
+    I2CBus *i2c_bus;
+    uint8_t *spd_data;
+    int i;
+
+    /* init CPU */
+    cpu = POWERPC_CPU(cpu_create(machine->cpu_type));
+    env = &cpu->env;
+    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
+        error_report("Incompatible CPU, only 6xx bus supported");
+        exit(1);
+    }
+    cpu_ppc_tb_init(env, BUS_FREQ_HZ / 4);
+    qemu_register_reset(amigaone_cpu_reset, cpu);
+
+    /* RAM */
+    if (machine->ram_size > 2 * GiB) {
+        error_report("RAM size more than 2 GiB is not supported");
+        exit(1);
+    }
+    memory_region_add_subregion(get_system_memory(), 0, machine->ram);
+    if (machine->ram_size < 1 * GiB + 32 * KiB) {
+        /* Firmware uses this area for startup */
+        mr = g_new(MemoryRegion, 1);
+        memory_region_init_ram(mr, NULL, "init-cache", 32 * KiB, &error_fatal);
+        memory_region_add_subregion(get_system_memory(), 0x40000000, mr);
+    }
+
+    /* allocate and load firmware */
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, fwname);
+    if (!filename) {
+        error_report("Could not find firmware '%s'", fwname);
+        exit(1);
+    }
+    rom = g_new(MemoryRegion, 1);
+    memory_region_init_rom(rom, NULL, "rom", PROM_SIZE, &error_fatal);
+    memory_region_add_subregion(get_system_memory(), PROM_ADDR, rom);
+    sz = load_image_targphys(filename, PROM_ADDR, PROM_SIZE);
+    if (sz <= 0 || sz > PROM_SIZE) {
+        error_report("Could not load firmware '%s'", filename);
+        exit(1);
+    }
+    g_free(filename);
+
+    /* Articia S */
+    dev = sysbus_create_simple(TYPE_ARTICIA, 0xfe000000, NULL);
+
+    i2c_bus = I2C_BUS(qdev_get_child_bus(dev, "smbus"));
+    if (machine->ram_size > 512 * MiB) {
+        spd_data = spd_data_generate(SDR, machine->ram_size / 2);
+    } else {
+        spd_data = spd_data_generate(SDR, machine->ram_size);
+    }
+    fix_spd_data(spd_data);
+    smbus_eeprom_init_one(i2c_bus, 0x51, spd_data);
+    if (machine->ram_size > 512 * MiB) {
+        smbus_eeprom_init_one(i2c_bus, 0x52, spd_data);
+    }
+
+    pci_mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+    mr = g_new(MemoryRegion, 1);
+    memory_region_init_alias(mr, OBJECT(dev), "pci-mem-low", pci_mem,
+                             0, 0x1000000);
+    memory_region_add_subregion(get_system_memory(), 0xfd000000, mr);
+    mr = g_new(MemoryRegion, 1);
+    memory_region_init_alias(mr, OBJECT(dev), "pci-mem-high", pci_mem,
+                             0x80000000, 0x7d000000);
+    memory_region_add_subregion(get_system_memory(), 0x80000000, mr);
+    pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
+
+    /* VIA VT82c686B South Bridge (multifunction PCI device) */
+    via = OBJECT(pci_create_simple_multifunction(pci_bus, PCI_DEVFN(7, 0),
+                                                 TYPE_VT82C686B_ISA));
+    object_property_add_alias(OBJECT(machine), "rtc-time",
+                              object_resolve_path_component(via, "rtc"),
+                              "date");
+    qdev_connect_gpio_out(DEVICE(via), 0,
+                          qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_INT));
+    for (i = 0; i < PCI_NUM_PINS; i++) {
+        qdev_connect_gpio_out(dev, i, qdev_get_gpio_in_named(DEVICE(via),
+                                                             "pirq", i));
+    }
+    pci_ide_create_devs(PCI_DEVICE(object_resolve_path_component(via, "ide")));
+    pci_vga_init(pci_bus);
+}
+
+static void amigaone_machine_init(MachineClass *mc)
+{
+    mc->desc = "Eyetech AmigaOne/Mai Logic Teron";
+    mc->init = amigaone_init;
+    mc->block_default_type = IF_IDE;
+    mc->default_cpu_type = POWERPC_CPU_TYPE_NAME("7457_v1.2");
+    mc->default_display = "std";
+    mc->default_ram_id = "ram";
+    mc->default_ram_size = 128 * MiB;
+}
+
+DEFINE_MACHINE("amigaone", amigaone_machine_init)
diff --git a/hw/ppc/meson.build b/hw/ppc/meson.build
index 7c2c52434a..0f76f4cce4 100644
--- a/hw/ppc/meson.build
+++ b/hw/ppc/meson.build
@@ -81,6 +81,8 @@  ppc_ss.add(when: 'CONFIG_E500', if_true: files(
 ))
 # PowerPC 440 Xilinx ML507 reference board.
 ppc_ss.add(when: 'CONFIG_VIRTEX', if_true: files('virtex_ml507.c'))
+# a1xe
+ppc_ss.add(when: 'CONFIG_AMIGAONE', if_true: files('amigaone.c'))
 # Pegasos2
 ppc_ss.add(when: 'CONFIG_PEGASOS2', if_true: files('pegasos2.c'))