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