summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/vic_pl192.cpp
blob: 5c37d03abee0de602a7d78c210c990006103f248 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// license:BSD-3-Clause
// copyright-holders:Melissa Goad

// ARM PrimeCell PL192 VIC emulation

#include "emu.h"
#include "machine/bankdev.h"
#include "machine/vic_pl192.h"

#define LOG_GENERAL (1U << 0)

#define VERBOSE (LOG_GENERAL)
#include "logmacro.h"

void vic_pl192_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	if(u32 intrs = (raw_intr | soft_intr) & intr_en)
	{
		if(intrs & intr_select) m_out_fiq_func(1);
		else m_out_fiq_func(0);

		if(intrs & ~intr_select) m_out_irq_func(1);
		else m_out_irq_func(0);
	}
}

void vic_pl192_device::set_irq_line(int irq, int state)
{
	u32 mask = (1 << irq);

	if(state)
	{
		raw_intr |= mask;
	}
	else
	{
		raw_intr &= ~mask;
	}

	timer_set(attotime::zero, TIMER_CHECK_IRQ);
}

void vic_pl192_device::map(address_map &map)
{
	map(0x000, 0x003).lr32([this](offs_t offset){ return raw_intr & ~intr_select; }, "irq_status"); //IRQ_STATUS
	map(0x004, 0x007).lr32([this](offs_t offset){ return raw_intr & intr_select; }, "fiq_status"); //FIQ_STATUS
	map(0x008, 0x00b).lr32([this](offs_t offset){ return raw_intr; }, "raw_intr");
	map(0x00c, 0x00f).lrw32(NAME([this](offs_t offset){ return intr_select; }), NAME([this](offs_t offset, u32 data){ intr_select = data; timer_set(attotime::zero, TIMER_CHECK_IRQ); }));
	map(0x010, 0x013).lrw32(NAME([this](offs_t offset){ return intr_en; }), NAME([this](offs_t offset, u32 data){ intr_en = data; timer_set(attotime::zero, TIMER_CHECK_IRQ); }));
	map(0x014, 0x017).lw32([this](u32 data){ intr_en &= ~data; }, "intr_en_clear");
	map(0x018, 0x01b).lrw32(NAME([this](offs_t offset){ return soft_intr; }), NAME([this](offs_t offset, u32 data){ soft_intr = data; timer_set(attotime::zero, TIMER_CHECK_IRQ); }));
	map(0x01c, 0x01f).lw32([this](u32 data){ soft_intr &= ~data; }, "soft_intr_clear");
	map(0x020, 0x020).lrw8(NAME([this](offs_t offset){ return protection; }), NAME([this](offs_t offset, u8 data){ protection = data & 1; })).umask32(0x000000ff);
	map(0x024, 0x025).lrw8(NAME([this](offs_t offset){ return sw_priority_mask; }), NAME([this](offs_t offset, u16 data){ sw_priority_mask = data; })).umask32(0x0000ffff);
	map(0x028, 0x028).lrw8(NAME([this](offs_t offset){ return daisy_priority; }), NAME([this](offs_t offset, u8 data){ daisy_priority = data & 0xf; })).umask32(0x000000ff);
	map(0x100, 0x17f).lrw32(NAME([this](offs_t offset){ return vectaddr[(offset & 0x7c) >> 2]; }), NAME([this](offs_t offset, u32 data){ vectaddr[(offset & 0x7c) >> 2] = data; }));
	map(0x200, 0x27f).lrw8(NAME([this](offs_t offset){ return vectprio[(offset & 0x7c) >> 2]; }), NAME([this](offs_t offset, u32 data){ vectprio[(offset & 0x7c) >> 2] = data & 0xf; }));
	map(0xf00, 0xf03).lrw32(NAME([this](offs_t offset){ return vicaddress; }), NAME([this](offs_t offset, u32 data){ vectaddr[(offset & 0x7c) >> 2] = data; }));
	map(0xfe0, 0xfe0).lr8([this](offs_t offset){ return periph_id[0]; }, "periph_id0").umask32(0x000000ff);
	map(0xfe4, 0xfe4).lr8([this](offs_t offset){ return periph_id[1]; }, "periph_id1").umask32(0x000000ff);
	map(0xfe8, 0xfe8).lr8([this](offs_t offset){ return periph_id[2]; }, "periph_id2").umask32(0x000000ff);
	map(0xfec, 0xfec).lr8([this](offs_t offset){ return periph_id[3]; }, "periph_id3").umask32(0x000000ff);
	map(0xff0, 0xff0).lr8([this](offs_t offset){ return pcell_id[0]; }, "pcell_id0").umask32(0x000000ff);
	map(0xff4, 0xff4).lr8([this](offs_t offset){ return pcell_id[1]; }, "pcell_id1").umask32(0x000000ff);
	map(0xff8, 0xff8).lr8([this](offs_t offset){ return pcell_id[2]; }, "pcell_id2").umask32(0x000000ff);
	map(0xffc, 0xffc).lr8([this](offs_t offset){ return pcell_id[3]; }, "pcell_id3").umask32(0x000000ff);
}

device_memory_interface::space_config_vector vic_pl192_device::memory_space_config() const
{
	return space_config_vector{
		std::make_pair(0, &m_mmio_config)
	};
}

void vic_pl192_device::device_resolve_objects()
{
	// resolve callbacks
	m_out_irq_func.resolve_safe();
	m_out_fiq_func.resolve_safe();
}

void vic_pl192_device::device_start()
{
	save_item(NAME(raw_intr));
	save_item(NAME(intr_select));
	save_item(NAME(intr_en));
	save_item(NAME(soft_intr));
	save_item(NAME(vectaddr));
	save_item(NAME(vicaddress));
	save_item(NAME(protection));
	save_item(NAME(sw_priority_mask));
	save_item(NAME(daisy_priority));
	save_item(NAME(vectprio));
}

void vic_pl192_device::device_reset()
{
	raw_intr = intr_select = intr_en = soft_intr = vicaddress = protection = 0;
	sw_priority_mask = 0xffff;
	daisy_priority = 0xf;

	for(int i = 0; i < 32; i++)
	{
		vectaddr[i] = 0;
	}

	for(int i = 0; i < 32; i++)
	{
		vectprio[i] = 0xf;
	}
}

DEFINE_DEVICE_TYPE(PL192_VIC, vic_pl192_device, "vic_pl192", "ARM PL192 VIC")

vic_pl192_device::vic_pl192_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, type, tag, owner, clock)
	, device_memory_interface(mconfig, *this)
	, m_mmio_config("mmio", ENDIANNESS_LITTLE, 32, 32, 0)
	, m_out_irq_func(*this)
	, m_out_fiq_func(*this)
	, periph_id{0x92, 0x11, 0x04, 0x00}
	, pcell_id{0x0d, 0xf0, 0x05, 0xb1}
{
}

vic_pl192_device::vic_pl192_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: vic_pl192_device(mconfig, PL192_VIC, tag, owner, clock)
{
}