diff mbox

[1/7] hw/arm/mps2: Implement skeleton mps2-an385 and mps2-an511 board models

Message ID 1499771839-32518-2-git-send-email-peter.maydell@linaro.org
State New
Headers show

Commit Message

Peter Maydell July 11, 2017, 11:17 a.m. UTC
Model the ARM MPS2/MPS2+ FPGA based development board.

The MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger
FPGA but is otherwise the same as the 2). Since the CPU itself
and most of the devices are in the FPGA, the details of the board
as seen by the guest depend significantly on the FPGA image.

We model the following FPGA images:
 "mps2_an385" -- Cortex-M3 as documented in ARM Application Note AN385
 "mps2_an511" -- Cortex-M3 'DesignStart' as documented in AN511

They are fairly similar but differ in the details for some
peripherals.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 hw/arm/Makefile.objs            |   1 +
 hw/arm/mps2.c                   | 273 ++++++++++++++++++++++++++++++++++++++++
 default-configs/arm-softmmu.mak |   1 +
 3 files changed, 275 insertions(+)
 create mode 100644 hw/arm/mps2.c

Comments

Alistair Francis July 11, 2017, 2:33 p.m. UTC | #1
On Tue, Jul 11, 2017 at 1:17 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Model the ARM MPS2/MPS2+ FPGA based development board.
>
> The MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger
> FPGA but is otherwise the same as the 2). Since the CPU itself
> and most of the devices are in the FPGA, the details of the board
> as seen by the guest depend significantly on the FPGA image.
>
> We model the following FPGA images:
>  "mps2_an385" -- Cortex-M3 as documented in ARM Application Note AN385
>  "mps2_an511" -- Cortex-M3 'DesignStart' as documented in AN511
>
> They are fairly similar but differ in the details for some
> peripherals.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  hw/arm/Makefile.objs            |   1 +
>  hw/arm/mps2.c                   | 273 ++++++++++++++++++++++++++++++++++++++++
>  default-configs/arm-softmmu.mak |   1 +
>  3 files changed, 275 insertions(+)
>  create mode 100644 hw/arm/mps2.c
>
> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
> index 4c5c4ee..a2e56ec 100644
> --- a/hw/arm/Makefile.objs
> +++ b/hw/arm/Makefile.objs
> @@ -18,3 +18,4 @@ obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
>  obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
>  obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
>  obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
> +obj-$(CONFIG_MPS2) += mps2.o

Is this file name possibly too generic? Should it be arm-mps2 instead.

I don't see any other boards with the same name from a Google search,
but it just seems a bit vague having a three letter acronym.

> diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
> new file mode 100644
> index 0000000..28838bc
> --- /dev/null
> +++ b/hw/arm/mps2.c
> @@ -0,0 +1,273 @@
> +/*
> + * ARM V2M MPS2 board emulation.
> + *
> + * Copyright (c) 2017 Linaro Limited
> + * Written by Peter Maydell
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License version 2 or
> + *  (at your option) any later version.
> + */
> +
> +/* The MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger
> + * FPGA but is otherwise the same as the 2). Since the CPU itself
> + * and most of the devices are in the FPGA, the details of the board
> + * as seen by the guest depend significantly on the FPGA image.
> + * We model the following FPGA images:
> + *  "mps2_an385" -- Cortex-M3 as documented in ARM Application Note AN385
> + *  "mps2_an511" -- Cortex-M3 'DesignStart' as documented in AN511
> + *
> + * Links to the TRM for the board itself and to the various Application
> + * Notes which document the FPGA images can be found here:
> + *   https://developer.arm.com/products/system-design/development-boards/cortex-m-prototyping-system
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/error-report.h"
> +#include "hw/arm/arm.h"
> +#include "hw/arm/armv7m.h"
> +#include "hw/boards.h"
> +#include "exec/address-spaces.h"
> +#include "hw/misc/unimp.h"
> +
> +typedef enum MPS2FPGAType {
> +    FPGA_AN385,
> +    FPGA_AN511,
> +} MPS2FPGAType;
> +
> +typedef struct {
> +    MachineClass parent;
> +    MPS2FPGAType fpga_type;
> +    const char *cpu_model;
> +} MPS2MachineClass;
> +
> +typedef struct {
> +    MachineState parent;
> +
> +    ARMv7MState armv7m;
> +    MemoryRegion psram;
> +    MemoryRegion ssram1;
> +    MemoryRegion ssram1_m;
> +    MemoryRegion ssram23;
> +    MemoryRegion ssram23_m;
> +    MemoryRegion blockram;
> +    MemoryRegion blockram_m1;
> +    MemoryRegion blockram_m2;
> +    MemoryRegion blockram_m3;
> +    MemoryRegion sram;
> +} MPS2MachineState;
> +
> +#define TYPE_MPS2_MACHINE "mps2"

This public name seems too common as well. I am just worried it'll
conflict with something one day.

> +#define TYPE_MPS2_AN385_MACHINE MACHINE_TYPE_NAME("mps2-an385")
> +#define TYPE_MPS2_AN511_MACHINE MACHINE_TYPE_NAME("mps2-an511")
> +
> +#define MPS2_MACHINE(obj)                                       \
> +    OBJECT_CHECK(MPS2MachineState, obj, TYPE_MPS2_MACHINE)
> +#define MPS2_MACHINE_GET_CLASS(obj) \
> +    OBJECT_GET_CLASS(MPS2MachineClass, obj, TYPE_MPS2_MACHINE)
> +#define MPS2_MACHINE_CLASS(klass) \
> +    OBJECT_CLASS_CHECK(MPS2MachineClass, klass, TYPE_MPS2_MACHINE)
> +
> +/* Main SYSCLK frequency in Hz */
> +#define SYSCLK_FRQ 25000000
> +
> +/* Initialize the auxiliary RAM region @mr and map it into
> + * the memory map at @base.
> + */
> +static void make_ram(MemoryRegion *mr, const char *name,
> +                     hwaddr base, hwaddr size)
> +{
> +    memory_region_init_ram(mr, NULL, name, size, &error_fatal);
> +    vmstate_register_ram_global(mr);
> +    memory_region_add_subregion(get_system_memory(), base, mr);
> +}
> +
> +/* Create an alias of an entire original MemoryRegion @orig
> + * located at @base in the memory map.
> + */
> +static void make_ram_alias(MemoryRegion *mr, const char *name,
> +                           MemoryRegion *orig, hwaddr base)
> +{
> +    memory_region_init_alias(mr, NULL, name, orig, 0,
> +                             memory_region_size(orig));
> +    memory_region_add_subregion(get_system_memory(), base, mr);
> +}
> +
> +static void mps2_common_init(MachineState *machine)
> +{
> +    MPS2MachineState *mms = MPS2_MACHINE(machine);
> +    MPS2MachineClass *mmc = MPS2_MACHINE_GET_CLASS(machine);
> +
> +    if (!machine->cpu_model) {
> +        machine->cpu_model = mmc->cpu_model;
> +    }
> +
> +    if (strcmp(machine->cpu_model, mmc->cpu_model) != 0) {
> +        error_report("This board can only be used with CPU %s", mmc->cpu_model);
> +        exit(1);
> +    }
> +
> +    MemoryRegion *system_memory = get_system_memory();
> +
> +    DeviceState *armv7m;

These should be at the top of the function.

> +
> +    /* The FPGA images have an odd combination of different RAMs,
> +     * because in hardware they are different implementations and
> +     * connected to different buses, giving varying performance/size
> +     * tradeoffs. For QEMU they're all just RAM, though. We arbitrarily
> +     * call the 16MB our "system memory", as it's the largest lump.
> +     *
> +     * Common to both boards:
> +     *  0x21000000..0x21ffffff : PSRAM (16MB)
> +     * AN385 only:
> +     *  0x00000000 .. 0x003fffff : ZBT SSRAM1
> +     *  0x00400000 .. 0x007fffff : mirror of ZBT SSRAM1
> +     *  0x20000000 .. 0x203fffff : ZBT SSRAM 2&3
> +     *  0x20400000 .. 0x207fffff : mirror of ZBT SSRAM 2&3
> +     *  0x01000000 .. 0x01003fff : block RAM (16K)
> +     *  0x01004000 .. 0x01007fff : mirror of above
> +     *  0x01008000 .. 0x0100bfff : mirror of above
> +     *  0x0100c000 .. 0x0100ffff : mirror of above
> +     * AN511 only:
> +     *  0x00000000 .. 0x0003ffff : FPGA block RAM
> +     *  0x00400000 .. 0x007fffff : ZBT SSRAM1
> +     *  0x20000000 .. 0x2001ffff : SRAM
> +     *  0x20400000 .. 0x207fffff : ZBT SSRAM 2&3
> +     *
> +     * The AN385 has a feature where the lowest 16K can be mapped
> +     * either to the bottom of the ZBT SSRAM1 or to the block RAM.
> +     * This is of no use for QEMU so we don't implement it (as if
> +     * zbt_boot_ctrl is always zero).
> +     */
> +    memory_region_allocate_system_memory(&mms->psram,
> +                                         NULL, "mps.ram", 0x1000000);
> +    memory_region_add_subregion(system_memory, 0x21000000, &mms->psram);
> +
> +    switch (mmc->fpga_type) {
> +    case FPGA_AN385:
> +        make_ram(&mms->ssram1, "mps.ssram1", 0x0, 0x400000);
> +        make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", &mms->ssram1, 0x400000);
> +        make_ram(&mms->ssram23, "mps.ssram23", 0x20000000, 0x400000);
> +        make_ram_alias(&mms->ssram23_m, "mps.ssram23_m",
> +                       &mms->ssram23, 0x20400000);
> +        make_ram(&mms->blockram, "mps.blockram", 0x01000000, 0x4000);
> +        make_ram_alias(&mms->blockram_m1, "mps.blockram_m1",
> +                       &mms->blockram, 0x01004000);
> +        make_ram_alias(&mms->blockram_m2, "mps.blockram_m2",
> +                       &mms->blockram, 0x01008000);
> +        make_ram_alias(&mms->blockram_m3, "mps.blockram_m3",
> +                       &mms->blockram, 0x0100c000);
> +        break;
> +    case FPGA_AN511:
> +        make_ram(&mms->blockram, "mps.blockram", 0x0, 0x40000);
> +        make_ram(&mms->ssram1, "mps.ssram1", 0x00400000, 0x00800000);
> +        make_ram(&mms->sram, "mps.sram", 0x20000000, 0x20000);
> +        make_ram(&mms->ssram23, "mps.ssram23", 0x20400000, 0x400000);
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> +
> +    object_initialize(&mms->armv7m, sizeof(mms->armv7m), TYPE_ARMV7M);
> +    armv7m = DEVICE(&mms->armv7m);
> +    qdev_set_parent_bus(armv7m, sysbus_get_default());
> +    switch (mmc->fpga_type) {
> +    case FPGA_AN385:
> +        qdev_prop_set_uint32(armv7m, "num-irq", 32);
> +        break;
> +    case FPGA_AN511:
> +        qdev_prop_set_uint32(armv7m, "num-irq", 64);
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
> +    qdev_prop_set_string(armv7m, "cpu-model", machine->cpu_model);
> +    object_property_set_link(OBJECT(&mms->armv7m), OBJECT(system_memory),
> +                             "memory", &error_abort);
> +    object_property_set_bool(OBJECT(&mms->armv7m), true, "realized",
> +                             &error_fatal);
> +
> +    create_unimplemented_device("zbtsmram mirror", 0x00400000, 0x00400000);
> +    create_unimplemented_device("RESERVED 1", 0x00800000, 0x00800000);
> +    create_unimplemented_device("Block RAM", 0x01000000, 0x00010000);
> +    create_unimplemented_device("RESERVED 2", 0x01010000, 0x1EFF0000);
> +    create_unimplemented_device("RESERVED 3", 0x20800000, 0x00800000);
> +    create_unimplemented_device("PSRAM", 0x21000000, 0x01000000);
> +    /* These three ranges all cover multiple devices; we may implement
> +     * some of them below (in which case the real device takes precedence
> +     * over the unimplemented-region mapping).
> +     */
> +    create_unimplemented_device("CMSDK APB peripheral region @0x40000000",
> +                                0x40000000, 0x00010000);
> +    create_unimplemented_device("CMSDK peripheral region @0x40010000",
> +                                0x40010000, 0x00010000);
> +    create_unimplemented_device("Extra peripheral region @0x40020000",
> +                                0x40020000, 0x00010000);
> +    create_unimplemented_device("RESERVED 4", 0x40030000, 0x001D0000);
> +    create_unimplemented_device("Ethernet", 0x40200000, 0x00100000);
> +    create_unimplemented_device("VGA", 0x41000000, 0x0200000);

I did not know this was an option, this is pretty cool.

Besides the name I think this patch looks good.

Thanks,
Alistair
Peter Maydell July 11, 2017, 4:35 p.m. UTC | #2
On 11 July 2017 at 15:33, Alistair Francis <alistair23@gmail.com> wrote:
> On Tue, Jul 11, 2017 at 1:17 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> Model the ARM MPS2/MPS2+ FPGA based development board.
>>
>> The MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger
>> FPGA but is otherwise the same as the 2). Since the CPU itself
>> and most of the devices are in the FPGA, the details of the board
>> as seen by the guest depend significantly on the FPGA image.
>>
>> We model the following FPGA images:
>>  "mps2_an385" -- Cortex-M3 as documented in ARM Application Note AN385
>>  "mps2_an511" -- Cortex-M3 'DesignStart' as documented in AN511
>>
>> They are fairly similar but differ in the details for some
>> peripherals.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  hw/arm/Makefile.objs            |   1 +
>>  hw/arm/mps2.c                   | 273 ++++++++++++++++++++++++++++++++++++++++
>>  default-configs/arm-softmmu.mak |   1 +
>>  3 files changed, 275 insertions(+)
>>  create mode 100644 hw/arm/mps2.c
>>
>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>> index 4c5c4ee..a2e56ec 100644
>> --- a/hw/arm/Makefile.objs
>> +++ b/hw/arm/Makefile.objs
>> @@ -18,3 +18,4 @@ obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
>>  obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
>>  obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
>>  obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
>> +obj-$(CONFIG_MPS2) += mps2.o
>
> Is this file name possibly too generic? Should it be arm-mps2 instead.

It's already in hw/arm/, and we don't ever do anything that
confuses foo.o in one directory with foo.o in another.
(Also none of the other board or SoCs have 'arm' prepended.)

> I don't see any other boards with the same name from a Google search,
> but it just seems a bit vague having a three letter acronym.

>> +#define TYPE_MPS2_MACHINE "mps2"
>
> This public name seems too common as well. I am just worried it'll
> conflict with something one day.

I can see the issue, but on the other hand the type name is not
external ABI, so we can always rename it later if we have to.
The board names themselves (mps2-an385 and mps2-an511) on the
other hand we have to get right from the start. I'm not sure
tacking an arm- on the front of those helps; they're already
pretty ungainly.

The other possible name floating around here is "v2m-mps",
which at least some of the docs refer to as the name of
the motherboard. There's a lot of just of just plain "MPS2", though.

(I note that we've had 'kzm' and 'z2' since forever and they
haven't ever conflicted with anything despite being pretty short.)

I dunno; I'll have a think about it. Naming is hard...

>> +
>> +    MemoryRegion *system_memory = get_system_memory();
>> +
>> +    DeviceState *armv7m;
>
> These should be at the top of the function.

Fixed (along with the 'sccdev' added to the DeviceState
line in a later patch).

>> +    create_unimplemented_device("CMSDK APB peripheral region @0x40000000",
>> +                                0x40000000, 0x00010000);
>> +    create_unimplemented_device("CMSDK peripheral region @0x40010000",
>> +                                0x40010000, 0x00010000);
>> +    create_unimplemented_device("Extra peripheral region @0x40020000",
>> +                                0x40020000, 0x00010000);
>> +    create_unimplemented_device("RESERVED 4", 0x40030000, 0x001D0000);
>> +    create_unimplemented_device("Ethernet", 0x40200000, 0x00100000);
>> +    create_unimplemented_device("VGA", 0x41000000, 0x0200000);
>
> I did not know this was an option, this is pretty cool.

Yeah. It's really nice for bringing up a board model because
you can just add -d unimp to your command line and get the
info about what devices the guest is prodding that you need
to implement next.

thanks
-- PMM
Philippe Mathieu-Daudé July 11, 2017, 5:47 p.m. UTC | #3
On 07/11/2017 01:35 PM, Peter Maydell wrote:
> On 11 July 2017 at 15:33, Alistair Francis <alistair23@gmail.com> wrote:
>> On Tue, Jul 11, 2017 at 1:17 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
[...]
>>> +    create_unimplemented_device("RESERVED 4", 0x40030000, 0x001D0000);
>>> +    create_unimplemented_device("Ethernet", 0x40200000, 0x00100000);
>>> +    create_unimplemented_device("VGA", 0x41000000, 0x0200000);
>>
>> I did not know this was an option, this is pretty cool.
> 
> Yeah. It's really nice for bringing up a board model because
> you can just add -d unimp to your command line and get the
> info about what devices the guest is prodding that you need
> to implement next.

For reverse engineering this is the best device ever :P
Alistair Francis July 13, 2017, 7:27 a.m. UTC | #4
On Tue, Jul 11, 2017 at 6:35 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 11 July 2017 at 15:33, Alistair Francis <alistair23@gmail.com> wrote:
>> On Tue, Jul 11, 2017 at 1:17 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> Model the ARM MPS2/MPS2+ FPGA based development board.
>>>
>>> The MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger
>>> FPGA but is otherwise the same as the 2). Since the CPU itself
>>> and most of the devices are in the FPGA, the details of the board
>>> as seen by the guest depend significantly on the FPGA image.
>>>
>>> We model the following FPGA images:
>>>  "mps2_an385" -- Cortex-M3 as documented in ARM Application Note AN385
>>>  "mps2_an511" -- Cortex-M3 'DesignStart' as documented in AN511
>>>
>>> They are fairly similar but differ in the details for some
>>> peripherals.
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>> ---
>>>  hw/arm/Makefile.objs            |   1 +
>>>  hw/arm/mps2.c                   | 273 ++++++++++++++++++++++++++++++++++++++++
>>>  default-configs/arm-softmmu.mak |   1 +
>>>  3 files changed, 275 insertions(+)
>>>  create mode 100644 hw/arm/mps2.c
>>>
>>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>>> index 4c5c4ee..a2e56ec 100644
>>> --- a/hw/arm/Makefile.objs
>>> +++ b/hw/arm/Makefile.objs
>>> @@ -18,3 +18,4 @@ obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
>>>  obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
>>>  obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
>>>  obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
>>> +obj-$(CONFIG_MPS2) += mps2.o
>>
>> Is this file name possibly too generic? Should it be arm-mps2 instead.
>
> It's already in hw/arm/, and we don't ever do anything that
> confuses foo.o in one directory with foo.o in another.
> (Also none of the other board or SoCs have 'arm' prepended.)
>
>> I don't see any other boards with the same name from a Google search,
>> but it just seems a bit vague having a three letter acronym.
>
>>> +#define TYPE_MPS2_MACHINE "mps2"
>>
>> This public name seems too common as well. I am just worried it'll
>> conflict with something one day.
>
> I can see the issue, but on the other hand the type name is not
> external ABI, so we can always rename it later if we have to.

That's true, but it's still not ideal to be changing device names willy nilly.

> The board names themselves (mps2-an385 and mps2-an511) on the
> other hand we have to get right from the start. I'm not sure
> tacking an arm- on the front of those helps; they're already
> pretty ungainly.

I think the boards are already long enough to be unique and probably
don't need an 'arm-'. Although I think having the vendor name does
clarify what the board is. Imagine a user is querying QEMU for what
boards it supports and sees a board name they don't recognise. It will
be a lot easier to figure out what board this is is you search "ARM
MPS2" instead of just MPS2.

>
> The other possible name floating around here is "v2m-mps",
> which at least some of the docs refer to as the name of
> the motherboard. There's a lot of just of just plain "MPS2", though.

I guess what we generally do is copy the spec/datasheet. So if it is
in there then the name is fine.

>
> (I note that we've had 'kzm' and 'z2' since forever and they
> haven't ever conflicted with anything despite being pretty short.)

Good point.

>
> I dunno; I'll have a think about it. Naming is hard...
>
>>> +
>>> +    MemoryRegion *system_memory = get_system_memory();
>>> +
>>> +    DeviceState *armv7m;
>>
>> These should be at the top of the function.
>
> Fixed (along with the 'sccdev' added to the DeviceState
> line in a later patch).
>
>>> +    create_unimplemented_device("CMSDK APB peripheral region @0x40000000",
>>> +                                0x40000000, 0x00010000);
>>> +    create_unimplemented_device("CMSDK peripheral region @0x40010000",
>>> +                                0x40010000, 0x00010000);
>>> +    create_unimplemented_device("Extra peripheral region @0x40020000",
>>> +                                0x40020000, 0x00010000);
>>> +    create_unimplemented_device("RESERVED 4", 0x40030000, 0x001D0000);
>>> +    create_unimplemented_device("Ethernet", 0x40200000, 0x00100000);
>>> +    create_unimplemented_device("VGA", 0x41000000, 0x0200000);
>>
>> I did not know this was an option, this is pretty cool.
>
> Yeah. It's really nice for bringing up a board model because
> you can just add -d unimp to your command line and get the
> info about what devices the guest is prodding that you need
> to implement next.

Yeah, this is great!

Thanks,
Alistair

>
> thanks
> -- PMM
Peter Maydell July 13, 2017, 10:39 a.m. UTC | #5
On 13 July 2017 at 08:27, Alistair Francis <alistair23@gmail.com> wrote:
> On Tue, Jul 11, 2017 at 6:35 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> On 11 July 2017 at 15:33, Alistair Francis <alistair23@gmail.com> wrote:
>>> On Tue, Jul 11, 2017 at 1:17 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>>> +#define TYPE_MPS2_MACHINE "mps2"
>>>
>>> This public name seems too common as well. I am just worried it'll
>>> conflict with something one day.
>>
>> I can see the issue, but on the other hand the type name is not
>> external ABI, so we can always rename it later if we have to.
>
> That's true, but it's still not ideal to be changing device names willy nilly.
>
>> The board names themselves (mps2-an385 and mps2-an511) on the
>> other hand we have to get right from the start. I'm not sure
>> tacking an arm- on the front of those helps; they're already
>> pretty ungainly.
>
> I think the boards are already long enough to be unique and probably
> don't need an 'arm-'. Although I think having the vendor name does
> clarify what the board is. Imagine a user is querying QEMU for what
> boards it supports and sees a board name they don't recognise. It will
> be a lot easier to figure out what board this is is you search "ARM
> MPS2" instead of just MPS2.

"ARM" is in the long description you get from -M help:
mps2-an385           ARM MPS2 with AN385 FPGA image for Cortex-M3
mps2-an511           ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3

(compare existing
realview-pb-a8       ARM RealView Platform Baseboard for Cortex-A8
etc)

Having thought about it a bit I think there are two options:
(1) stick with what we have here, just using "mps2" in type
and filenames
(2) use "arm-mps2" instead (in filenames, typenames and the board
names)
since I don't much like having the base machine type be 'arm-mps2'
but the board names just 'mps2-an385' &c.

But of the two I overall prefer (1) still.

thanks
-- PMM
diff mbox

Patch

diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 4c5c4ee..a2e56ec 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -18,3 +18,4 @@  obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o
 obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o
 obj-$(CONFIG_FSL_IMX6) += fsl-imx6.o sabrelite.o
 obj-$(CONFIG_ASPEED_SOC) += aspeed_soc.o aspeed.o
+obj-$(CONFIG_MPS2) += mps2.o
diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c
new file mode 100644
index 0000000..28838bc
--- /dev/null
+++ b/hw/arm/mps2.c
@@ -0,0 +1,273 @@ 
+/*
+ * ARM V2M MPS2 board emulation.
+ *
+ * Copyright (c) 2017 Linaro Limited
+ * Written by Peter Maydell
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 or
+ *  (at your option) any later version.
+ */
+
+/* The MPS2 and MPS2+ dev boards are FPGA based (the 2+ has a bigger
+ * FPGA but is otherwise the same as the 2). Since the CPU itself
+ * and most of the devices are in the FPGA, the details of the board
+ * as seen by the guest depend significantly on the FPGA image.
+ * We model the following FPGA images:
+ *  "mps2_an385" -- Cortex-M3 as documented in ARM Application Note AN385
+ *  "mps2_an511" -- Cortex-M3 'DesignStart' as documented in AN511
+ *
+ * Links to the TRM for the board itself and to the various Application
+ * Notes which document the FPGA images can be found here:
+ *   https://developer.arm.com/products/system-design/development-boards/cortex-m-prototyping-system
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "hw/arm/arm.h"
+#include "hw/arm/armv7m.h"
+#include "hw/boards.h"
+#include "exec/address-spaces.h"
+#include "hw/misc/unimp.h"
+
+typedef enum MPS2FPGAType {
+    FPGA_AN385,
+    FPGA_AN511,
+} MPS2FPGAType;
+
+typedef struct {
+    MachineClass parent;
+    MPS2FPGAType fpga_type;
+    const char *cpu_model;
+} MPS2MachineClass;
+
+typedef struct {
+    MachineState parent;
+
+    ARMv7MState armv7m;
+    MemoryRegion psram;
+    MemoryRegion ssram1;
+    MemoryRegion ssram1_m;
+    MemoryRegion ssram23;
+    MemoryRegion ssram23_m;
+    MemoryRegion blockram;
+    MemoryRegion blockram_m1;
+    MemoryRegion blockram_m2;
+    MemoryRegion blockram_m3;
+    MemoryRegion sram;
+} MPS2MachineState;
+
+#define TYPE_MPS2_MACHINE "mps2"
+#define TYPE_MPS2_AN385_MACHINE MACHINE_TYPE_NAME("mps2-an385")
+#define TYPE_MPS2_AN511_MACHINE MACHINE_TYPE_NAME("mps2-an511")
+
+#define MPS2_MACHINE(obj)                                       \
+    OBJECT_CHECK(MPS2MachineState, obj, TYPE_MPS2_MACHINE)
+#define MPS2_MACHINE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(MPS2MachineClass, obj, TYPE_MPS2_MACHINE)
+#define MPS2_MACHINE_CLASS(klass) \
+    OBJECT_CLASS_CHECK(MPS2MachineClass, klass, TYPE_MPS2_MACHINE)
+
+/* Main SYSCLK frequency in Hz */
+#define SYSCLK_FRQ 25000000
+
+/* Initialize the auxiliary RAM region @mr and map it into
+ * the memory map at @base.
+ */
+static void make_ram(MemoryRegion *mr, const char *name,
+                     hwaddr base, hwaddr size)
+{
+    memory_region_init_ram(mr, NULL, name, size, &error_fatal);
+    vmstate_register_ram_global(mr);
+    memory_region_add_subregion(get_system_memory(), base, mr);
+}
+
+/* Create an alias of an entire original MemoryRegion @orig
+ * located at @base in the memory map.
+ */
+static void make_ram_alias(MemoryRegion *mr, const char *name,
+                           MemoryRegion *orig, hwaddr base)
+{
+    memory_region_init_alias(mr, NULL, name, orig, 0,
+                             memory_region_size(orig));
+    memory_region_add_subregion(get_system_memory(), base, mr);
+}
+
+static void mps2_common_init(MachineState *machine)
+{
+    MPS2MachineState *mms = MPS2_MACHINE(machine);
+    MPS2MachineClass *mmc = MPS2_MACHINE_GET_CLASS(machine);
+
+    if (!machine->cpu_model) {
+        machine->cpu_model = mmc->cpu_model;
+    }
+
+    if (strcmp(machine->cpu_model, mmc->cpu_model) != 0) {
+        error_report("This board can only be used with CPU %s", mmc->cpu_model);
+        exit(1);
+    }
+
+    MemoryRegion *system_memory = get_system_memory();
+
+    DeviceState *armv7m;
+
+    /* The FPGA images have an odd combination of different RAMs,
+     * because in hardware they are different implementations and
+     * connected to different buses, giving varying performance/size
+     * tradeoffs. For QEMU they're all just RAM, though. We arbitrarily
+     * call the 16MB our "system memory", as it's the largest lump.
+     *
+     * Common to both boards:
+     *  0x21000000..0x21ffffff : PSRAM (16MB)
+     * AN385 only:
+     *  0x00000000 .. 0x003fffff : ZBT SSRAM1
+     *  0x00400000 .. 0x007fffff : mirror of ZBT SSRAM1
+     *  0x20000000 .. 0x203fffff : ZBT SSRAM 2&3
+     *  0x20400000 .. 0x207fffff : mirror of ZBT SSRAM 2&3
+     *  0x01000000 .. 0x01003fff : block RAM (16K)
+     *  0x01004000 .. 0x01007fff : mirror of above
+     *  0x01008000 .. 0x0100bfff : mirror of above
+     *  0x0100c000 .. 0x0100ffff : mirror of above
+     * AN511 only:
+     *  0x00000000 .. 0x0003ffff : FPGA block RAM
+     *  0x00400000 .. 0x007fffff : ZBT SSRAM1
+     *  0x20000000 .. 0x2001ffff : SRAM
+     *  0x20400000 .. 0x207fffff : ZBT SSRAM 2&3
+     *
+     * The AN385 has a feature where the lowest 16K can be mapped
+     * either to the bottom of the ZBT SSRAM1 or to the block RAM.
+     * This is of no use for QEMU so we don't implement it (as if
+     * zbt_boot_ctrl is always zero).
+     */
+    memory_region_allocate_system_memory(&mms->psram,
+                                         NULL, "mps.ram", 0x1000000);
+    memory_region_add_subregion(system_memory, 0x21000000, &mms->psram);
+
+    switch (mmc->fpga_type) {
+    case FPGA_AN385:
+        make_ram(&mms->ssram1, "mps.ssram1", 0x0, 0x400000);
+        make_ram_alias(&mms->ssram1_m, "mps.ssram1_m", &mms->ssram1, 0x400000);
+        make_ram(&mms->ssram23, "mps.ssram23", 0x20000000, 0x400000);
+        make_ram_alias(&mms->ssram23_m, "mps.ssram23_m",
+                       &mms->ssram23, 0x20400000);
+        make_ram(&mms->blockram, "mps.blockram", 0x01000000, 0x4000);
+        make_ram_alias(&mms->blockram_m1, "mps.blockram_m1",
+                       &mms->blockram, 0x01004000);
+        make_ram_alias(&mms->blockram_m2, "mps.blockram_m2",
+                       &mms->blockram, 0x01008000);
+        make_ram_alias(&mms->blockram_m3, "mps.blockram_m3",
+                       &mms->blockram, 0x0100c000);
+        break;
+    case FPGA_AN511:
+        make_ram(&mms->blockram, "mps.blockram", 0x0, 0x40000);
+        make_ram(&mms->ssram1, "mps.ssram1", 0x00400000, 0x00800000);
+        make_ram(&mms->sram, "mps.sram", 0x20000000, 0x20000);
+        make_ram(&mms->ssram23, "mps.ssram23", 0x20400000, 0x400000);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+
+    object_initialize(&mms->armv7m, sizeof(mms->armv7m), TYPE_ARMV7M);
+    armv7m = DEVICE(&mms->armv7m);
+    qdev_set_parent_bus(armv7m, sysbus_get_default());
+    switch (mmc->fpga_type) {
+    case FPGA_AN385:
+        qdev_prop_set_uint32(armv7m, "num-irq", 32);
+        break;
+    case FPGA_AN511:
+        qdev_prop_set_uint32(armv7m, "num-irq", 64);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    qdev_prop_set_string(armv7m, "cpu-model", machine->cpu_model);
+    object_property_set_link(OBJECT(&mms->armv7m), OBJECT(system_memory),
+                             "memory", &error_abort);
+    object_property_set_bool(OBJECT(&mms->armv7m), true, "realized",
+                             &error_fatal);
+
+    create_unimplemented_device("zbtsmram mirror", 0x00400000, 0x00400000);
+    create_unimplemented_device("RESERVED 1", 0x00800000, 0x00800000);
+    create_unimplemented_device("Block RAM", 0x01000000, 0x00010000);
+    create_unimplemented_device("RESERVED 2", 0x01010000, 0x1EFF0000);
+    create_unimplemented_device("RESERVED 3", 0x20800000, 0x00800000);
+    create_unimplemented_device("PSRAM", 0x21000000, 0x01000000);
+    /* These three ranges all cover multiple devices; we may implement
+     * some of them below (in which case the real device takes precedence
+     * over the unimplemented-region mapping).
+     */
+    create_unimplemented_device("CMSDK APB peripheral region @0x40000000",
+                                0x40000000, 0x00010000);
+    create_unimplemented_device("CMSDK peripheral region @0x40010000",
+                                0x40010000, 0x00010000);
+    create_unimplemented_device("Extra peripheral region @0x40020000",
+                                0x40020000, 0x00010000);
+    create_unimplemented_device("RESERVED 4", 0x40030000, 0x001D0000);
+    create_unimplemented_device("Ethernet", 0x40200000, 0x00100000);
+    create_unimplemented_device("VGA", 0x41000000, 0x0200000);
+
+    system_clock_scale = NANOSECONDS_PER_SECOND / SYSCLK_FRQ;
+
+    armv7m_load_kernel(ARM_CPU(first_cpu), machine->kernel_filename,
+                       0x400000);
+}
+
+static void mps2_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->init = mps2_common_init;
+    mc->max_cpus = 1;
+}
+
+static void mps2_an385_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+    MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc);
+
+    mc->desc = "ARM MPS2 with AN385 FPGA image for Cortex-M3";
+    mmc->fpga_type = FPGA_AN385;
+    mmc->cpu_model = "cortex-m3";
+}
+
+static void mps2_an511_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+    MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc);
+
+    mc->desc = "ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3";
+    mmc->fpga_type = FPGA_AN511;
+    mmc->cpu_model = "cortex-m3";
+}
+
+static const TypeInfo mps2_info = {
+    .name = TYPE_MPS2_MACHINE,
+    .parent = TYPE_MACHINE,
+    .abstract = true,
+    .instance_size = sizeof(MPS2MachineState),
+    .class_size = sizeof(MPS2MachineClass),
+    .class_init = mps2_class_init,
+};
+
+static const TypeInfo mps2_an385_info = {
+    .name = TYPE_MPS2_AN385_MACHINE,
+    .parent = TYPE_MPS2_MACHINE,
+    .class_init = mps2_an385_class_init,
+};
+
+static const TypeInfo mps2_an511_info = {
+    .name = TYPE_MPS2_AN511_MACHINE,
+    .parent = TYPE_MPS2_MACHINE,
+    .class_init = mps2_an511_class_init,
+};
+
+static void mps2_machine_init(void)
+{
+    type_register_static(&mps2_info);
+    type_register_static(&mps2_an385_info);
+    type_register_static(&mps2_an511_info);
+}
+
+type_init(mps2_machine_init);
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 93e995d..bfd2a88 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -83,6 +83,7 @@  CONFIG_ONENAND=y
 CONFIG_TUSB6010=y
 CONFIG_IMX=y
 CONFIG_MAINSTONE=y
+CONFIG_MPS2=y
 CONFIG_NSERIES=y
 CONFIG_RASPI=y
 CONFIG_REALVIEW=y