The djMEMC controller is used to store information related to the physical memory configuration. Co-developed-by: Laurent Vivier <laurent@vivier.eu> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20231004083806.757242-3-mark.cave-ayland@ilande.co.uk> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
		
			
				
	
	
		
			136 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			136 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * djMEMC, macintosh memory and interrupt controller
 | 
						|
 * (Quadra 610/650/800 & Centris 610/650)
 | 
						|
 *
 | 
						|
 *    https://mac68k.info/wiki/display/mac68k/djMEMC+Information
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
 */
 | 
						|
 | 
						|
#include "qemu/osdep.h"
 | 
						|
#include "qemu/log.h"
 | 
						|
#include "migration/vmstate.h"
 | 
						|
#include "hw/misc/djmemc.h"
 | 
						|
#include "hw/qdev-properties.h"
 | 
						|
#include "trace.h"
 | 
						|
 | 
						|
 | 
						|
#define DJMEMC_INTERLEAVECONF   0x0
 | 
						|
#define DJMEMC_BANK0CONF        0x4
 | 
						|
#define DJMEMC_BANK1CONF        0x8
 | 
						|
#define DJMEMC_BANK2CONF        0xc
 | 
						|
#define DJMEMC_BANK3CONF        0x10
 | 
						|
#define DJMEMC_BANK4CONF        0x14
 | 
						|
#define DJMEMC_BANK5CONF        0x18
 | 
						|
#define DJMEMC_BANK6CONF        0x1c
 | 
						|
#define DJMEMC_BANK7CONF        0x20
 | 
						|
#define DJMEMC_BANK8CONF        0x24
 | 
						|
#define DJMEMC_BANK9CONF        0x28
 | 
						|
#define DJMEMC_MEMTOP           0x2c
 | 
						|
#define DJMEMC_CONFIG           0x30
 | 
						|
#define DJMEMC_REFRESH          0x34
 | 
						|
 | 
						|
 | 
						|
static uint64_t djmemc_read(void *opaque, hwaddr addr, unsigned size)
 | 
						|
{
 | 
						|
    DJMEMCState *s = opaque;
 | 
						|
    uint64_t val = 0;
 | 
						|
 | 
						|
    switch (addr) {
 | 
						|
    case DJMEMC_INTERLEAVECONF:
 | 
						|
    case DJMEMC_BANK0CONF ... DJMEMC_BANK9CONF:
 | 
						|
    case DJMEMC_MEMTOP:
 | 
						|
    case DJMEMC_CONFIG:
 | 
						|
    case DJMEMC_REFRESH:
 | 
						|
        val = s->regs[addr >> 2];
 | 
						|
        break;
 | 
						|
    default:
 | 
						|
        qemu_log_mask(LOG_UNIMP, "djMEMC: unimplemented read addr=0x%"PRIx64
 | 
						|
                                 " val=0x%"PRIx64 " size=%d\n",
 | 
						|
                                 addr, val, size);
 | 
						|
    }
 | 
						|
 | 
						|
    trace_djmemc_read(addr, val, size);
 | 
						|
    return val;
 | 
						|
}
 | 
						|
 | 
						|
static void djmemc_write(void *opaque, hwaddr addr, uint64_t val,
 | 
						|
                         unsigned size)
 | 
						|
{
 | 
						|
    DJMEMCState *s = opaque;
 | 
						|
 | 
						|
    trace_djmemc_write(addr, val, size);
 | 
						|
 | 
						|
    switch (addr) {
 | 
						|
    case DJMEMC_INTERLEAVECONF:
 | 
						|
    case DJMEMC_BANK0CONF ... DJMEMC_BANK9CONF:
 | 
						|
    case DJMEMC_MEMTOP:
 | 
						|
    case DJMEMC_CONFIG:
 | 
						|
    case DJMEMC_REFRESH:
 | 
						|
        s->regs[addr >> 2] = val;
 | 
						|
        break;
 | 
						|
    default:
 | 
						|
        qemu_log_mask(LOG_UNIMP, "djMEMC: unimplemented write addr=0x%"PRIx64
 | 
						|
                                 " val=0x%"PRIx64 " size=%d\n",
 | 
						|
                                 addr, val, size);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static const MemoryRegionOps djmemc_mmio_ops = {
 | 
						|
    .read = djmemc_read,
 | 
						|
    .write = djmemc_write,
 | 
						|
    .impl = {
 | 
						|
        .min_access_size = 4,
 | 
						|
        .max_access_size = 4,
 | 
						|
    },
 | 
						|
    .endianness = DEVICE_BIG_ENDIAN,
 | 
						|
};
 | 
						|
 | 
						|
static void djmemc_init(Object *obj)
 | 
						|
{
 | 
						|
    DJMEMCState *s = DJMEMC(obj);
 | 
						|
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 | 
						|
 | 
						|
    memory_region_init_io(&s->mem_regs, obj, &djmemc_mmio_ops, s, "djMEMC",
 | 
						|
                          DJMEMC_SIZE);
 | 
						|
    sysbus_init_mmio(sbd, &s->mem_regs);
 | 
						|
}
 | 
						|
 | 
						|
static void djmemc_reset_hold(Object *obj)
 | 
						|
{
 | 
						|
    DJMEMCState *s = DJMEMC(obj);
 | 
						|
 | 
						|
    memset(s->regs, 0, sizeof(s->regs));
 | 
						|
}
 | 
						|
 | 
						|
static const VMStateDescription vmstate_djmemc = {
 | 
						|
    .name = "djMEMC",
 | 
						|
    .version_id = 1,
 | 
						|
    .minimum_version_id = 1,
 | 
						|
    .fields = (VMStateField[]) {
 | 
						|
        VMSTATE_UINT32_ARRAY(regs, DJMEMCState, DJMEMC_NUM_REGS),
 | 
						|
        VMSTATE_END_OF_LIST()
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
static void djmemc_class_init(ObjectClass *oc, void *data)
 | 
						|
{
 | 
						|
    DeviceClass *dc = DEVICE_CLASS(oc);
 | 
						|
    ResettableClass *rc = RESETTABLE_CLASS(oc);
 | 
						|
 | 
						|
    dc->vmsd = &vmstate_djmemc;
 | 
						|
    rc->phases.hold = djmemc_reset_hold;
 | 
						|
}
 | 
						|
 | 
						|
static const TypeInfo djmemc_info_types[] = {
 | 
						|
    {
 | 
						|
        .name          = TYPE_DJMEMC,
 | 
						|
        .parent        = TYPE_SYS_BUS_DEVICE,
 | 
						|
        .instance_size = sizeof(DJMEMCState),
 | 
						|
        .instance_init = djmemc_init,
 | 
						|
        .class_init    = djmemc_class_init,
 | 
						|
    },
 | 
						|
};
 | 
						|
 | 
						|
DEFINE_TYPES(djmemc_info_types)
 |