euphrates/hardware/sms_vdp/
line.rs

1use super::*;
2
3pub trait SmsVdpLineImpler: SmsVdpGraphics {
4    type Vdp: SmsVdpInternal;
5
6    fn vdp(&mut self) -> &mut Self::Vdp;
7}
8
9impl<'a, V: 'a, G: 'a> SmsVdpLineImpler for SmsVdpGraphicsImpler<'a, V, G>
10where
11    V: SmsVdpInternal,
12    Self: SmsVdpGraphics,
13{
14    type Vdp = V;
15
16    #[inline(always)]
17    fn vdp(&mut self) -> &mut Self::Vdp {
18        self.vdp
19    }
20}
21
22pub fn line<V>(x: &mut V) -> Result<(), SmsVdpGraphicsError>
23where
24    V: SmsVdpLineImpler,
25{
26    x.draw_line()?;
27
28    let vdp = x.vdp();
29
30    let v = vdp.v();
31
32    if v == vdp.active_lines() {
33        // YYY - it's not completely clear to me whether this is the right
34        // line on which to trigger a frame interrupt.
35        let flags = vdp.status_flags();
36        vdp.set_status_flags(flags | FRAME_INTERRUPT_FLAG);
37        vdp.set_new_irq(true);
38    }
39
40    let new_v = (v + 1) % vdp.total_lines();
41
42    vdp.set_v(new_v);
43
44    if new_v <= vdp.active_lines() {
45        // yes, according to VDPTEST.sms, this really should be <=
46        let line_counter = vdp.line_counter();
47        vdp.set_line_counter(line_counter.wrapping_sub(1));
48        if vdp.line_counter() == 0xFF {
49            let reg_line_counter = vdp.reg_line_counter();
50            vdp.set_line_counter(reg_line_counter);
51            vdp.set_line_interrupt_pending(true);
52            vdp.set_new_irq(true);
53        }
54    } else {
55        let reg_line_counter = vdp.reg_line_counter();
56        vdp.set_line_counter(reg_line_counter);
57    }
58
59    if new_v == 0 {
60        let reg9 = unsafe { vdp.register_unchecked(9) };
61        vdp.set_y_scroll(reg9);
62    }
63
64    let cycles = vdp.cycles();
65    vdp.set_cycles(cycles + 342);
66
67    return Ok(());
68}