1mod debug;
2
3use crate::WhichCpu;
4use crate::vdp::Vdp;
5use bincode::{Decode, Encode};
6use jgenesis_common::define_bit_enum;
7use jgenesis_common::num::{GetBit, U16Ext, U24Ext};
8use std::array;
9use std::fmt::{Display, Formatter};
10
11define_bit_enum!(Access, [M68k, Sh2]);
12
13impl Display for Access {
14    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
15        match self {
16            Self::M68k => write!(f, "68000"),
17            Self::Sh2 => write!(f, "SH-2"),
18        }
19    }
20}
21
22#[derive(Debug, Clone, Default, Encode, Decode)]
23pub struct Sh2Interrupts {
24    pub reset_pending: bool,
25    pub v_pending: bool,
26    pub v_enabled: bool,
27    pub h_pending: bool,
28    pub h_enabled: bool,
29    pub command_pending: bool,
30    pub command_enabled: bool,
31    pub pwm_pending: bool,
32    pub pwm_enabled: bool,
33    pub current_interrupt_level: u8,
34}
35
36impl Sh2Interrupts {
37    fn mask_bits(&self) -> u16 {
38        (u16::from(self.v_enabled) << 3)
39            | (u16::from(self.h_enabled) << 2)
40            | (u16::from(self.command_enabled) << 1)
41            | u16::from(self.pwm_enabled)
42    }
43
44    fn write_mask_bits(&mut self, value: u16) {
45        self.v_enabled = value.bit(3);
46        self.h_enabled = value.bit(2);
47        self.command_enabled = value.bit(1);
48        self.pwm_enabled = value.bit(0);
49
50        self.update_interrupt_level();
51    }
52
53    fn clear_reset(&mut self) {
54        self.reset_pending = false;
55        self.update_interrupt_level();
56    }
57
58    fn clear_v(&mut self) {
59        // Clear pending flag only if VINTs are enabled (verified on hardware)
60        // TODO do the other interrupt types also work this way?
61        self.v_pending &= !self.v_enabled;
62        self.update_interrupt_level();
63    }
64
65    fn clear_h(&mut self) {
66        self.h_pending = false;
67        self.update_interrupt_level();
68    }
69
70    fn clear_command(&mut self) {
71        self.command_pending = false;
72        self.update_interrupt_level();
73    }
74
75    fn clear_pwm(&mut self) {
76        self.pwm_pending = false;
77        self.update_interrupt_level();
78    }
79
80    fn update_interrupt_level(&mut self) {
81        self.current_interrupt_level = if self.reset_pending {
82            14
83        } else if self.v_pending && self.v_enabled {
84            12
85        } else if self.h_pending {
86            10
87        } else if self.command_pending && self.command_enabled {
88            8
89        } else if self.pwm_pending {
90            6
91        } else {
92            0
93        };
94    }
95}
96
97const DMA_FIFO_LEN: usize = 4;
98
99#[derive(Debug, Clone, Default, Encode, Decode)]
100pub struct DmaFifo {
101    blocks: [[u16; 4]; 2],
102    ready: [bool; 2],
103    m68k_block: usize,
104    m68k_idx: usize,
105    sh2_block: usize,
106    sh2_idx: usize,
107}
108
109impl DmaFifo {
110    pub fn push(&mut self, value: u16) {
111        log::trace!("DMA FIFO push: {value:04X}");
112
113        self.blocks[self.m68k_block][self.m68k_idx] = value;
114        self.m68k_idx += 1;
115
116        if self.m68k_idx == DMA_FIFO_LEN {
117            self.ready[self.m68k_block] = true;
118            self.m68k_block ^= 1;
119            self.m68k_idx = 0;
120        }
121    }
122
123    pub fn pop(&mut self) -> u16 {
124        let value = self.blocks[self.sh2_block][self.sh2_idx];
125        self.sh2_idx += 1;
126
127        if self.sh2_idx == DMA_FIFO_LEN {
128            self.ready[self.sh2_block] = false;
129            self.sh2_block ^= 1;
130            self.sh2_idx = 0;
131        }
132
133        log::trace!("DMA FIFO pop: {value:04X}");
134
135        value
136    }
137
138    pub fn sh2_is_empty(&self) -> bool {
139        !self.ready[self.sh2_block]
140    }
141
142    pub fn is_full(&self) -> bool {
143        self.ready[self.m68k_block]
144    }
145
146    pub fn clear(&mut self) {
147        self.ready.fill(false);
148    }
149}
150
151#[derive(Debug, Clone, Encode, Decode)]
152pub struct DmaRegisters {
153    pub rom_to_vram: bool,
154    // TODO not sure what this does
155    pub bit_1: bool,
156    pub active: bool,
157    pub source_address: u32,
158    pub destination_address: u32,
159    pub length: u16,
160    pub fifo: DmaFifo,
161}
162
163impl Default for DmaRegisters {
164    fn default() -> Self {
165        Self {
166            rom_to_vram: false,
167            bit_1: false,
168            active: false,
169            source_address: 0,
170            destination_address: 0,
171            length: 0xFFFF,
172            fifo: DmaFifo::default(),
173        }
174    }
175}
176
177#[derive(Debug, Clone, Encode, Decode)]
178pub struct SystemRegisters {
179    pub adapter_enabled: bool,
180    pub reset_sh2: bool,
181    pub vdp_access: Access,
182    pub m68k_rom_bank: u8,
183    pub communication_ports: [u16; 8],
184    pub master_interrupts: Sh2Interrupts,
185    pub slave_interrupts: Sh2Interrupts,
186    pub dma: DmaRegisters,
187    pub cartridge_present: bool,
188    // Functionality not emulated, only bits 0 and 8 being R/W
189    pub sega_tv_bits: u16,
190}
191
192impl SystemRegisters {
193    pub fn new(cartridge_present: bool) -> Self {
194        Self {
195            adapter_enabled: false,
196            reset_sh2: false,
197            vdp_access: Access::M68k,
198            m68k_rom_bank: 0,
199            communication_ports: array::from_fn(|_| 0),
200            master_interrupts: Sh2Interrupts::default(),
201            slave_interrupts: Sh2Interrupts::default(),
202            dma: DmaRegisters::default(),
203            cartridge_present,
204            sega_tv_bits: 0,
205        }
206    }
207
208    pub fn notify_vblank_start(&mut self) {
209        self.master_interrupts.v_pending = true;
210        self.slave_interrupts.v_pending = true;
211
212        self.master_interrupts.update_interrupt_level();
213        self.slave_interrupts.update_interrupt_level();
214    }
215
216    pub fn notify_vblank_end(&mut self) {
217        self.master_interrupts.v_pending = false;
218        self.slave_interrupts.v_pending = false;
219
220        self.master_interrupts.update_interrupt_level();
221        self.slave_interrupts.update_interrupt_level();
222    }
223
224    pub fn notify_h_interrupt(&mut self) {
225        self.master_interrupts.h_pending |= self.master_interrupts.h_enabled;
226        self.slave_interrupts.h_pending |= self.slave_interrupts.h_enabled;
227
228        self.master_interrupts.update_interrupt_level();
229        self.slave_interrupts.update_interrupt_level();
230    }
231
232    pub fn either_h_interrupt_enabled(&self) -> bool {
233        self.master_interrupts.h_enabled || self.slave_interrupts.h_enabled
234    }
235
236    pub fn notify_pwm_timer(&mut self) {
237        self.master_interrupts.pwm_pending |= self.master_interrupts.pwm_enabled;
238        self.slave_interrupts.pwm_pending |= self.slave_interrupts.pwm_enabled;
239
240        self.master_interrupts.update_interrupt_level();
241        self.slave_interrupts.update_interrupt_level();
242    }
243
244    pub fn reset(&mut self) {
245        self.master_interrupts.reset_pending = true;
246        self.slave_interrupts.reset_pending = true;
247
248        self.master_interrupts.update_interrupt_level();
249        self.slave_interrupts.update_interrupt_level();
250
251        self.adapter_enabled = false;
252    }
253
254    pub fn m68k_read(&mut self, address: u32) -> u16 {
255        match address {
256            0xA15100 => self.read_adapter_control(),
257            0xA15102 => self.read_interrupt_control(),
258            0xA15104 => self.read_68k_rom_bank(),
259            0xA15106 => self.m68k_read_dreq_control(),
260            0xA15108 => self.read_dreq_source_high(),
261            0xA1510A => self.read_dreq_source_low(),
262            0xA1510C => self.read_dreq_destination_high(),
263            0xA1510E => self.read_dreq_destination_low(),
264            0xA15110 => self.dma.length,
265            0xA1511A => self.sega_tv_bits,
266            0xA15120..=0xA1512F => self.read_communication_port(address),
267            _ => {
268                log::warn!("M68K invalid register read: {address:06X}");
269                0
270            }
271        }
272    }
273
274    pub fn m68k_write_byte(&mut self, address: u32, value: u8) {
275        let mut word = self.m68k_read(address & !1);
276        if !address.bit(0) {
277            word.set_msb(value);
278        } else {
279            word.set_lsb(value);
280        }
281        self.m68k_write(address & !1, word);
282    }
283
284    pub fn m68k_write(&mut self, address: u32, value: u16) {
285        match address {
286            0xA15100 => self.write_adapter_control(value),
287            0xA15102 => self.write_interrupt_control(value),
288            0xA15104 => self.write_68k_rom_bank(value),
289            0xA15106 => self.write_dreq_control(value),
290            0xA15108 => self.write_dreq_source_high(value),
291            0xA1510A => self.write_dreq_source_low(value),
292            0xA1510C => self.write_dreq_destination_high(value),
293            0xA1510E => self.write_dreq_destination_low(value),
294            0xA15110 => self.write_dreq_length(value),
295            0xA15112 => self.write_dreq_fifo(value),
296            0xA1511A => {
297                // Only bits 0 and 8 are writable per testpico
298                // TODO is this actually a single bit mirrored?
299                self.sega_tv_bits = value & 0x0101;
300            }
301            0xA15120..=0xA1512F => self.write_communication_port(address, value),
302            _ => log::warn!("M68K invalid register write: {address:06X} {value:04X}"),
303        }
304    }
305
306    pub fn sh2_read(&mut self, address: u32, which: WhichCpu, vdp: &Vdp) -> u16 {
307        match address {
308            0x4000 => self.read_interrupt_mask(which, vdp),
309            0x4004 => vdp.h_interrupt_interval(),
310            0x4006 => self.sh2_read_dreq_control(),
311            0x4008 => self.read_dreq_source_high(),
312            0x400A => self.read_dreq_source_low(),
313            0x400C => self.read_dreq_destination_high(),
314            0x400E => self.read_dreq_destination_low(),
315            0x4010 => self.dma.length,
316            0x4012 => self.read_dreq_fifo(),
317            // TODO these registers shouldn't be readable? (interrupt clear)
318            0x4014 | 0x4016 | 0x4018 | 0x401A | 0x401C => 0,
319            0x4020..=0x402F => self.read_communication_port(address),
320            _ => {
321                log::warn!("SH-2 invalid register read: {address:08X} {which:?}");
322                0
323            }
324        }
325    }
326
327    pub fn sh2_write(&mut self, address: u32, value: u16, which: WhichCpu, vdp: &mut Vdp) {
328        match address {
329            0x4000 => self.write_interrupt_mask(value, which, vdp),
330            0x4002 => {
331                // The master SH-2 writes to this register when it resets while the 32X adapter is
332                // not enabled, after which it executes a SLEEP instruction and waits for a reset
333                log::debug!("SH-2 {which:?} wrote to standby register $4002");
334            }
335            0x4004 => vdp.write_h_interrupt_interval(value),
336            0x4014 => self.clear_reset_interrupt(which),
337            0x4016 => self.clear_v_interrupt(which),
338            0x4018 => self.clear_h_interrupt(which),
339            0x401A => self.clear_command_interrupt(which),
340            0x401C => self.clear_pwm_interrupt(which),
341            0x4020..=0x402F => self.write_communication_port(address, value),
342            _ => log::warn!("SH-2 invalid register write: {address:08X} {value:04X} {which:?}"),
343        }
344    }
345
346    // 68000: $A15100
347    fn read_adapter_control(&self) -> u16 {
348        // TODO bit 7? (REN / reset enabled)
349        ((self.vdp_access as u16) << 15)
350            | (1 << 7)
351            | (u16::from(!self.reset_sh2) << 1)
352            | u16::from(self.adapter_enabled)
353    }
354
355    // 68000: $A15100
356    fn write_adapter_control(&mut self, value: u16) {
357        self.adapter_enabled = value.bit(0);
358        self.reset_sh2 = !value.bit(1);
359        self.vdp_access = Access::from_bit(value.bit(15));
360
361        log::trace!("Adapter control write: {value:04X}");
362        log::trace!("  32X adapter enabled: {}", self.adapter_enabled);
363        log::trace!("  Reset SH-2: {}", self.reset_sh2);
364        log::trace!("  32X VDP access: {}", self.vdp_access);
365    }
366
367    // 68000: $A15102
368    fn read_interrupt_control(&self) -> u16 {
369        (u16::from(self.slave_interrupts.command_pending) << 1)
370            | u16::from(self.master_interrupts.command_pending)
371    }
372
373    // 68000: $A15102
374    fn write_interrupt_control(&mut self, value: u16) {
375        self.master_interrupts.command_pending = value.bit(0);
376        self.slave_interrupts.command_pending = value.bit(1);
377
378        self.master_interrupts.update_interrupt_level();
379        self.slave_interrupts.update_interrupt_level();
380
381        log::trace!("Interrupt control write: {value:04X}");
382        log::trace!("  Master command interrupt: {}", self.master_interrupts.command_pending);
383        log::trace!("  Slave command interrupt: {}", self.slave_interrupts.command_pending);
384    }
385
386    // 68000: $A15104
387    fn read_68k_rom_bank(&self) -> u16 {
388        self.m68k_rom_bank.into()
389    }
390
391    // 68000: $A15104
392    fn write_68k_rom_bank(&mut self, value: u16) {
393        self.m68k_rom_bank = (value & 0x03) as u8;
394        log::trace!("68000 ROM bank: {}", self.m68k_rom_bank);
395    }
396
397    // 68000: $A15106
398    fn m68k_read_dreq_control(&self) -> u16 {
399        (u16::from(self.dma.fifo.is_full()) << 7)
400            | (u16::from(self.dma.active) << 2)
401            | (u16::from(self.dma.bit_1) << 1)
402            | u16::from(self.dma.rom_to_vram)
403    }
404
405    // SH-2: $4006
406    fn sh2_read_dreq_control(&self) -> u16 {
407        (u16::from(self.dma.fifo.is_full()) << 15)
408            | (u16::from(self.dma.fifo.sh2_is_empty()) << 14)
409            | (u16::from(self.dma.active) << 2)
410            | (u16::from(self.dma.bit_1) << 1)
411            | u16::from(self.dma.rom_to_vram)
412    }
413
414    // 68000: $A15106
415    fn write_dreq_control(&mut self, value: u16) {
416        self.dma.rom_to_vram = value.bit(0);
417        self.dma.bit_1 = value.bit(1);
418        self.dma.active = value.bit(2);
419
420        if !self.dma.active {
421            self.dma.fifo.clear();
422        }
423
424        log::trace!("DREQ control write: {value:04X}");
425        log::trace!("  ROM-to-VRAM DMA active: {}", self.dma.rom_to_vram);
426        log::trace!("  DMA active: {}", self.dma.active);
427    }
428
429    // 68000: $A15108
430    // SH-2: $4008
431    fn read_dreq_source_high(&self) -> u16 {
432        (self.dma.source_address >> 16) as u16
433    }
434
435    // 68000: $A1510A
436    // SH-2: $400A
437    fn read_dreq_source_low(&self) -> u16 {
438        self.dma.source_address as u16
439    }
440
441    // 68000: $A15108
442    fn write_dreq_source_high(&mut self, value: u16) {
443        self.dma.source_address.set_high_byte(value as u8);
444
445        log::trace!("DREQ source address high write: {value:04X}");
446        log::trace!("  New address: {:06X}", self.dma.source_address);
447    }
448
449    // 68000: $A1510A
450    fn write_dreq_source_low(&mut self, value: u16) {
451        self.dma.source_address = (self.dma.source_address & 0xFFFF0000) | u32::from(value & !1);
452
453        log::trace!("DREQ source address low write: {value:04X}");
454        log::trace!("  New address: {:06X}", self.dma.source_address);
455    }
456
457    // 68000: $A1510C
458    // SH-2: $410C
459    fn read_dreq_destination_high(&self) -> u16 {
460        (self.dma.destination_address >> 16) as u16
461    }
462
463    // 68000: $A1510E
464    // SH-2: $410E
465    fn read_dreq_destination_low(&self) -> u16 {
466        self.dma.destination_address as u16
467    }
468
469    // 68000: $A1510C
470    fn write_dreq_destination_high(&mut self, value: u16) {
471        self.dma.destination_address.set_high_byte(value as u8);
472
473        log::trace!("DREQ destination address high write: {value:04X}");
474        log::trace!("  New address: {:06X}", self.dma.destination_address);
475    }
476
477    // 68000: $A1510E
478    fn write_dreq_destination_low(&mut self, value: u16) {
479        self.dma.destination_address =
480            (self.dma.destination_address & 0xFFFF0000) | u32::from(value);
481
482        log::trace!("DREQ destination address low write: {value:04X}");
483        log::trace!("  New address: {:06X}", self.dma.destination_address);
484    }
485
486    // 68000: $A15110
487    fn write_dreq_length(&mut self, value: u16) {
488        // Lowest 2 bits are forced to 0
489        self.dma.length = value & !3;
490        log::trace!("DREQ length: {:04X}", self.dma.length);
491    }
492
493    // SH-2: $4012
494    fn read_dreq_fifo(&mut self) -> u16 {
495        self.dma.length = self.dma.length.wrapping_sub(1);
496        if self.dma.length == 0 {
497            self.dma.active = false;
498        }
499
500        self.dma.fifo.pop()
501    }
502
503    // 68000: $A15112
504    fn write_dreq_fifo(&mut self, value: u16) {
505        // Only push to the DMA FIFO if 68000-to-32X DMA is currently active. Virtua Racing Deluxe
506        // depends on this or else it will crash after the title screen.
507        // It does 68000-to-32X DMAs of length 64 while consistently pushing 65 words into the FIFO
508        // for each DMA, and it depends on the 65th word never getting transferred.
509        if self.dma.active {
510            self.dma.fifo.push(value);
511        }
512    }
513
514    // SH-2: $4000
515    fn read_interrupt_mask(&self, which: WhichCpu, vdp: &Vdp) -> u16 {
516        let mask_bits: u16 = match which {
517            WhichCpu::Master => self.master_interrupts.mask_bits(),
518            WhichCpu::Slave => self.slave_interrupts.mask_bits(),
519        };
520
521        ((self.vdp_access as u16) << 15)
522            | (u16::from(self.adapter_enabled) << 9)
523            | (u16::from(!self.cartridge_present) << 8)
524            | (u16::from(vdp.hen_bit()) << 7)
525            | mask_bits
526    }
527
528    // SH-2: $4000
529    pub fn write_interrupt_mask(&mut self, value: u16, which: WhichCpu, vdp: &mut Vdp) {
530        self.vdp_access = Access::from_bit(value.bit(15));
531
532        vdp.write_hen_bit(value.bit(7));
533
534        match which {
535            WhichCpu::Master => self.master_interrupts.write_mask_bits(value),
536            WhichCpu::Slave => self.slave_interrupts.write_mask_bits(value),
537        }
538
539        log::trace!("Interrupt mask write ({which:?}): {value:04X}");
540        log::trace!("  VDP access: {:?}", self.vdp_access);
541        log::trace!("  HINT during VBlank: {}", vdp.hen_bit());
542
543        if log::log_enabled!(log::Level::Trace) {
544            let interrupts = match which {
545                WhichCpu::Master => &self.master_interrupts,
546                WhichCpu::Slave => &self.slave_interrupts,
547            };
548
549            log::trace!("  V interrupt enabled: {}", interrupts.v_enabled);
550            log::trace!("  H interrupt enabled: {}", interrupts.h_enabled);
551            log::trace!("  Command interrupt enabled: {}", interrupts.command_enabled);
552            log::trace!("  PWM interrupt enabled: {}", interrupts.pwm_enabled);
553        }
554    }
555
556    // SH-2: $4014
557    fn clear_reset_interrupt(&mut self, which: WhichCpu) {
558        match which {
559            WhichCpu::Master => self.master_interrupts.clear_reset(),
560            WhichCpu::Slave => self.slave_interrupts.clear_reset(),
561        }
562        log::trace!("VRESINT cleared");
563    }
564
565    // SH-2: $4016
566    fn clear_v_interrupt(&mut self, which: WhichCpu) {
567        match which {
568            WhichCpu::Master => self.master_interrupts.clear_v(),
569            WhichCpu::Slave => self.slave_interrupts.clear_v(),
570        }
571        log::trace!("VINT cleared");
572    }
573
574    // SH-2: $4018
575    fn clear_h_interrupt(&mut self, which: WhichCpu) {
576        match which {
577            WhichCpu::Master => self.master_interrupts.clear_h(),
578            WhichCpu::Slave => self.slave_interrupts.clear_h(),
579        }
580    }
581
582    // SH-2: $401A
583    fn clear_command_interrupt(&mut self, which: WhichCpu) {
584        match which {
585            WhichCpu::Master => self.master_interrupts.clear_command(),
586            WhichCpu::Slave => self.slave_interrupts.clear_command(),
587        }
588        log::trace!("CMDINT cleared");
589    }
590
591    // SH-2: $401C
592    fn clear_pwm_interrupt(&mut self, which: WhichCpu) {
593        match which {
594            WhichCpu::Master => self.master_interrupts.clear_pwm(),
595            WhichCpu::Slave => self.slave_interrupts.clear_pwm(),
596        }
597        log::trace!("PWMINT cleared");
598    }
599
600    // 68000: $A15120-$A1512F
601    // SH-2: $4020-$402F
602    fn read_communication_port(&self, address: u32) -> u16 {
603        let idx = (address >> 1) & 0x7;
604        self.communication_ports[idx as usize]
605    }
606
607    // 68000: $A15120-$A1512F
608    // SH-2: $4020-$402F
609    fn write_communication_port(&mut self, address: u32, value: u16) {
610        let idx = (address >> 1) & 0x7;
611        self.communication_ports[idx as usize] = value;
612    }
613}