1 // license:BSD-3-Clause
2 // copyright-holders:Fabio Priuli
3 /***********************************************************************************************************
4 
5 
6  NES/Famicom cartridge emulation for Nintendo NES-EVENT PCB
7 
8 
9  Here we emulate the following PCBs
10 
11  * Nintendo NES-EVENT [mapper 105]
12 
13  ***********************************************************************************************************/
14 
15 
16 #include "emu.h"
17 #include "event.h"
18 
19 
20 #ifdef NES_PCB_DEBUG
21 #define VERBOSE 1
22 #else
23 #define VERBOSE 0
24 #endif
25 
26 #define LOG_MMC(x) do { if (VERBOSE) logerror x; } while (0)
27 
28 
29 //-------------------------------------------------
30 //  constructor
31 //-------------------------------------------------
32 
33 DEFINE_DEVICE_TYPE(NES_EVENT, nes_event_device, "nes_event", "NES Cart Event PCB")
34 
35 
nes_event_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)36 nes_event_device::nes_event_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
37 	: nes_sxrom_device(mconfig, NES_EVENT, tag, owner, clock)
38 	, m_dsw(*this, "DIPSW")
39 	, m_nwc_init(0)
40 	, event_timer(nullptr)
41 	, m_timer_count(0)
42 	, m_timer_on(0)
43 	, m_timer_enabled(0)
44 {
45 }
46 
47 
device_start()48 void nes_event_device::device_start()
49 {
50 	common_start();
51 	event_timer = timer_alloc(TIMER_EVENT);
52 	event_timer->adjust(attotime::never);
53 	timer_freq = clocks_to_attotime(1);
54 
55 	save_item(NAME(m_latch));
56 	save_item(NAME(m_count));
57 	save_item(NAME(m_reg));
58 	save_item(NAME(m_reg_write_enable));
59 	save_item(NAME(m_nwc_init));
60 
61 	save_item(NAME(m_timer_count));
62 	save_item(NAME(m_timer_on));
63 	save_item(NAME(m_timer_enabled));
64 }
65 
pcb_reset()66 void nes_event_device::pcb_reset()
67 {
68 	m_latch = 0;
69 	m_count = 0;
70 	m_reg[0] = 0x0f;
71 	m_reg[1] = m_reg[2] = m_reg[3] = 0;
72 	m_reg_write_enable = 1;
73 	m_nwc_init = 2;
74 
75 	set_nt_mirroring(PPU_MIRROR_HORZ);
76 	chr8(0, CHRRAM);
77 	prg32(0);
78 	m_timer_count = 0;
79 	m_timer_enabled = 0;
80 	m_timer_on = 0;
81 }
82 
83 
84 
85 /*-------------------------------------------------
86  mapper specific handlers
87  -------------------------------------------------*/
88 
89 /*-------------------------------------------------
90 
91  Event PCB
92 
93  Games: Nintento World Championships
94 
95  MMC-1 variant with repurposed register at $a000 and a
96  lot of discrete components
97 
98  iNES: mapper 105
99 
100  In MESS: Supported.
101 
102  -------------------------------------------------*/
103 
set_chr()104 void nes_event_device::set_chr()
105 {
106 	// no CHR switching, there are only 8KB VRAM from the cart
107 }
108 
set_prg()109 void nes_event_device::set_prg()
110 {
111 //  printf("enter with %d and reg1 0x%x - reg3 0x%x\n", m_nwc_init, m_reg[1], m_reg[3]);
112 	// reg[1] is different from base MMC-1!
113 	// bit 0 is ignored, bit1/bit3 are used for PRG switch, bit4 is used for the timer
114 	uint8_t temp = (m_reg[1] >> 1) & 7;
115 
116 	// initially PRG is fixed, until bit4 of reg1 is set to 1 and then to 0
117 	switch (m_nwc_init)
118 	{
119 		case 2:
120 			if (m_reg[1] & 0x10) m_nwc_init--;
121 			return;
122 		case 1:
123 			if (~m_reg[1] & 0x10) m_nwc_init--;
124 			return;
125 	}
126 
127 	if (temp < 4)
128 		prg32(temp);
129 	else
130 	{
131 		// else PRG works similarly to base MMC-1, but only acts on the higher 128KB (2nd PRG ROM)
132 		switch (m_reg[0] & 0x0c)
133 		{
134 			case 0x00:
135 			case 0x04:
136 				prg32(0x04 | ((m_reg[3] >> 1) & 0x03));
137 				break;
138 			case 0x08:
139 				prg16_89ab(0x08 | 0x00);
140 				prg16_cdef(0x08 | (m_reg[3] & 0x07));
141 				break;
142 			case 0x0c:
143 				prg16_89ab(0x08 | (m_reg[3] & 0x07));
144 				prg16_cdef(0x08 | 0x07);
145 				break;
146 		}
147 	}
148 
149 	// after the init procedure above, bit4 of m_reg[1] is used to init IRQ, by setting and then clearing the bit
150 	// however, there are (bankswitch related?) writes with bit4 cleared before the one 'enabling' the timer, so
151 	// we need the additional m_timer_enabled variable, to avoid starting the timer before its time...
152 	if (m_reg[1] & 0x10)
153 	{
154 		m_timer_enabled = 1;
155 		set_irq_line(CLEAR_LINE);
156 	}
157 	else
158 	{
159 		if (!m_timer_on && m_timer_enabled)
160 		{
161 			m_timer_count = 0x20000000 | ((m_dsw->read() & 0x0f) << 25);
162 			event_timer->adjust(attotime::zero, 0, timer_freq);
163 			m_timer_on = 1;
164 		}
165 	}
166 }
167 
update_regs(int reg)168 void nes_event_device::update_regs(int reg)
169 {
170 	switch (reg)
171 	{
172 		case 0:
173 			switch (m_reg[0] & 0x03)
174 			{
175 				case 0: set_nt_mirroring(PPU_MIRROR_LOW); break;
176 				case 1: set_nt_mirroring(PPU_MIRROR_HIGH); break;
177 				case 2: set_nt_mirroring(PPU_MIRROR_VERT); break;
178 				case 3: set_nt_mirroring(PPU_MIRROR_HORZ); break;
179 			}
180 			set_prg();
181 			break;
182 		case 1:
183 			set_prg();
184 			break;
185 		case 2:
186 			set_chr();
187 			break;
188 		case 3:
189 			set_prg();
190 			break;
191 	}
192 }
193 
194 //-------------------------------------------------
195 //  Dipswitch
196 //-------------------------------------------------
197 
198 static INPUT_PORTS_START( nwc_dsw )
199 	PORT_START("DIPSW")
200 	PORT_DIPNAME( 0x0f, 0x04, "Timer" ) PORT_DIPLOCATION("SW:!1,!2,!3,!4")
201 	PORT_DIPSETTING( 0x00, "5:00.4" )
202 	PORT_DIPSETTING( 0x01, "5:19.2" )
203 	PORT_DIPSETTING( 0x02, "5:38.0" )
204 	PORT_DIPSETTING( 0x03, "5:56.7" )
205 	PORT_DIPSETTING( 0x04, "6:15.5" )
206 	PORT_DIPSETTING( 0x05, "6:34.3" )
207 	PORT_DIPSETTING( 0x06, "6:53.1" )
208 	PORT_DIPSETTING( 0x07, "7:11.9" )
209 	PORT_DIPSETTING( 0x08, "7:30.6" )
210 	PORT_DIPSETTING( 0x09, "7:49.4" )
211 	PORT_DIPSETTING( 0x0a, "8:08.2" )
212 	PORT_DIPSETTING( 0x0b, "8:27.0" )
213 	PORT_DIPSETTING( 0x0c, "8:45.8" )
214 	PORT_DIPSETTING( 0x0d, "9:04.5" )
215 	PORT_DIPSETTING( 0x0e, "9:23.3" )
216 	PORT_DIPSETTING( 0x0f, "9:42.1" )
217 INPUT_PORTS_END
218 
219 
220 
device_input_ports() const221 ioport_constructor nes_event_device::device_input_ports() const
222 {
223 	return INPUT_PORTS_NAME( nwc_dsw );
224 }
225 
226 
227 //-------------------------------------------------
228 //  device_timer - handler timer events
229 //-------------------------------------------------
230 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)231 void nes_event_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
232 {
233 	if (id == TIMER_EVENT)
234 	{
235 		m_timer_count--;
236 		if (!m_timer_count)
237 		{
238 			hold_irq_line();
239 			event_timer->reset();
240 		}
241 	}
242 }
243