pub trait VideoFrame: Copy + Debug {
    type BorderHtsIter: Iterator<Item = Ts>;

    const HTS_RANGE: Range<Ts>;
    const VSL_BORDER_TOP: Ts;
    const VSL_PIXELS: Range<Ts>;
    const VSL_BORDER_BOT: Ts;
    const VSL_COUNT: Ts;
    const HTS_COUNT: Ts = _;
    const FRAME_TSTATES_COUNT: FTs = _;
Show 14 methods fn border_whole_line_hts_iter(
        border_size: BorderSize
    ) -> Self::BorderHtsIter; fn border_left_hts_iter(border_size: BorderSize) -> Self::BorderHtsIter; fn border_right_hts_iter(border_size: BorderSize) -> Self::BorderHtsIter; fn contention(hc: Ts) -> Ts; fn border_size_pixels(border_size: BorderSize) -> u32 { ... } fn screen_size_pixels(border_size: BorderSize) -> (u32, u32) { ... } fn border_top_vsl_iter(border_size: BorderSize) -> Range<Ts> { ... } fn border_bot_vsl_iter(border_size: BorderSize) -> Range<Ts> { ... } fn floating_bus_offset(_hc: Ts) -> Option<u16> { ... } fn floating_bus_screen_address(_: VideoTs) -> Option<u16> { ... } fn snow_interference_coords(_ts: VideoTs) -> Option<CellCoords> { ... } fn is_contended_line_mreq(vsl: Ts) -> bool { ... } fn is_contended_line_no_mreq(vsl: Ts) -> bool { ... } fn vc_hc_to_tstates(vc: Ts, hc: Ts) -> FTs { ... }
}
Expand description

A collection of static methods and constants related to video parameters.

                              - 0
    +-------------------------+ VSL_BORDER_TOP
    |                         |
    |  +-------------------+  | -
    |  |                   |  | |
    |  |                   |  |  
    |  |                   |  | VSL_PIXELS
    |  |                   |  |  
    |  |                   |  | |
    |  +-------------------+  | -
    |                         |
    +-------------------------+ VSL_BORDER_BOT
                              - VSL_COUNT
|----- 0 -- HTS_RANGE ---------|
|           HTS_COUNT          |

Required Associated Types§

An iterator for rendering borders.

Required Associated Constants§

A range of horizontal T-states, 0 should be where the frame starts.

The first visible video scan line index of the top border.

A range of video scan line indexes where pixel data is being drawn.

The last visible video scan line index of the bottom border.

The total number of video scan lines including the beam retrace.

Provided Associated Constants§

The number of horizontal T-states.

The total number of T-states per frame.

Required Methods§

Returns an iterator of border latch horizontal T-states.

Returns an iterator of left border latch horizontal T-states.

Returns an iterator of right border latch horizontal T-states.

Returns a horizontal T-state counter after adding an additional T-states required for emulating a memory contention, while rendering lines that require reading video memory.

Provided Methods§

A rendered screen border size in pixels depending on the border size selection.

NOTE: The upper and lower border size may be lower than the value returned here e.g. in the NTSC video frame.

Examples found in repository?
src/video.rs (line 202)
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
    fn screen_size_pixels(border_size: BorderSize) -> (u32, u32) {
        let border = 2 * Self::border_size_pixels(border_size);
        let w = PAL_HC - 2*MAX_BORDER_SIZE + border;
        let h = (PAL_VC - 2*MAX_BORDER_SIZE + border)
                .min((Self::VSL_BORDER_BOT + 1 - Self::VSL_BORDER_TOP) as u32);
        (w, h)
    }
    /// Returns an iterator of the top border low-resolution scan line indexes.
    fn border_top_vsl_iter(border_size: BorderSize) -> Range<Ts> {
        let border = Self::border_size_pixels(border_size) as Ts;
        let top = (Self::VSL_PIXELS.start - border).max(Self::VSL_BORDER_TOP);
        top..Self::VSL_PIXELS.start
    }
    /// Returns an iterator of the bottom border low-resolution scan line indexes.
    fn border_bot_vsl_iter(border_size: BorderSize) -> Range<Ts> {
        let border = Self::border_size_pixels(border_size) as Ts;
        let bot = (Self::VSL_PIXELS.end + border).min(Self::VSL_BORDER_BOT);
        Self::VSL_PIXELS.end..bot
    }

Returns output screen pixel size (horizontal, vertical), including the border area, measured in low-resolution pixels.

The size depends on the given border_size.

Examples found in repository?
src/video.rs (line 126)
125
126
127
128
    fn render_size_pixels(border_size: BorderSize) -> (u32, u32) {
        let (width, height) = Self::VideoFrame::screen_size_pixels(border_size);
        (width * Self::pixel_density(), height)
    }

Returns an iterator of the top border low-resolution scan line indexes.

Returns an iterator of the bottom border low-resolution scan line indexes.

Returns an optional floating bus horizontal offset for the given horizontal timestamp.

Examples found in repository?
src/video.rs (line 244)
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
    fn floating_bus_screen_address(VideoTs { vc, hc }: VideoTs) -> Option<u16> {
        let line = vc - Self::VSL_PIXELS.start;
        if line >= 0 && vc < Self::VSL_PIXELS.end {
            Self::floating_bus_offset(hc).map(|offs| {
                let y = line as u16;
                let col = (offs >> 3) << 1;
                // println!("got offs: {} col:{} y:{}", offs, col, y);
                match offs & 3 {
                    0 =>          pixel_line_offset(y) + col,
                    1 => 0x1800 + color_line_offset(y) + col,
                    2 => 0x0001 + pixel_line_offset(y) + col,
                    3 => 0x1801 + color_line_offset(y) + col,
                    _ => unsafe { core::hint::unreachable_unchecked() }
                }
            })
        }
        else {
            None
        }
    }

Returns an optional floating bus screen address (in the screen address space) for the given timestamp.

The returned screen address range is: [0x0000, 0x1B00).

Returns an optional cell coordinates of a “snow effect” interference.

Returns true if the given scan line index is contended for MREQ (memory request) access.

This indicates if the contention should be applied during the indicated video scan line.

Examples found in repository?
src/clock.rs (line 436)
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
    fn add_m1(&mut self, address: u16) -> Self::Timestamp {
        // match address {
        //     // 0x8043 => println!("0x{:04x}: {} {:?}", address, self.as_tstates(), self.tsc),
        //     0x806F..=0x8078 => println!("0x{:04x}: {} {:?}", address, self.as_tstates(), self.tsc),
        //     // 0xC008..=0xC011 => println!("0x{:04x}: {} {:?}", address, self.as_tstates(), self.tsc),
        //     _ => {}
        // }
        let hc = if V::is_contended_line_mreq(self.vc) && self.contention.is_contended_address(address) {
            V::contention(self.hc)
        }
        else {
            self.hc
        };
        self.vts.set_hc_after_small_increment(hc + M1_CYCLE_TS as Ts);
        self.as_timestamp()
    }

    #[inline(always)]
    fn add_mreq(&mut self, address: u16) -> Self::Timestamp {
        let hc = if V::is_contended_line_mreq(self.vc) && self.contention.is_contended_address(address) {
            V::contention(self.hc)
        }
        else {
            self.hc
        };
        self.vts.set_hc_after_small_increment(hc + MEMRW_CYCLE_TS as Ts);
        self.as_timestamp()
    }

Returns true if the given scan line index is contended for other than MREQ (memory request) access.

This indicates if the contention should be applied during the indicated video scan line. Other accesses include IORQ and instruction cycles not requiring memory access.

Examples found in repository?
src/clock.rs (line 417)
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
    fn add_no_mreq(&mut self, address: u16, add_ts: NonZeroU8) {
        let mut hc = self.hc;
        if V::is_contended_line_no_mreq(self.vc) && self.contention.is_contended_address(address) {
            for _ in 0..add_ts.get() {
                hc = V::contention(hc) + 1;
            }
        }
        else {
            hc += add_ts.get() as Ts;
        }
        self.vts.set_hc_after_small_increment(hc);
    }

    #[inline(always)]
    fn add_m1(&mut self, address: u16) -> Self::Timestamp {
        // match address {
        //     // 0x8043 => println!("0x{:04x}: {} {:?}", address, self.as_tstates(), self.tsc),
        //     0x806F..=0x8078 => println!("0x{:04x}: {} {:?}", address, self.as_tstates(), self.tsc),
        //     // 0xC008..=0xC011 => println!("0x{:04x}: {} {:?}", address, self.as_tstates(), self.tsc),
        //     _ => {}
        // }
        let hc = if V::is_contended_line_mreq(self.vc) && self.contention.is_contended_address(address) {
            V::contention(self.hc)
        }
        else {
            self.hc
        };
        self.vts.set_hc_after_small_increment(hc + M1_CYCLE_TS as Ts);
        self.as_timestamp()
    }

    #[inline(always)]
    fn add_mreq(&mut self, address: u16) -> Self::Timestamp {
        let hc = if V::is_contended_line_mreq(self.vc) && self.contention.is_contended_address(address) {
            V::contention(self.hc)
        }
        else {
            self.hc
        };
        self.vts.set_hc_after_small_increment(hc + MEMRW_CYCLE_TS as Ts);
        self.as_timestamp()
    }

    // fn add_io(&mut self, port: u16) -> Self::Timestamp {
    //     let VideoTs{ vc, hc } = self.tsc;
    //     let hc = if V::is_contended_line_no_mreq(vc) {
    //         if self.contention.is_contended_address(port) {
    //             let hc = V::contention(hc) + 1;
    //             if port & 1 == 0 { // C:1, C:3
    //                 V::contention(hc) + (IO_CYCLE_TS - 1) as Ts
    //             }
    //             else { // C:1, C:1, C:1, C:1
    //                 let mut hc1 = hc;
    //                 for _ in 1..IO_CYCLE_TS {
    //                     hc1 = V::contention(hc1) + 1;
    //                 }
    //                 hc1
    //             }
    //         }
    //         else {
    //             if port & 1 == 0 { // N:1 C:3
    //                 V::contention(hc + 1) + (IO_CYCLE_TS - 1) as Ts
    //             }
    //             else { // N:4
    //                 hc + IO_CYCLE_TS as Ts
    //             }
    //         }
    //     }
    //     else { // N:4
    //         hc + IO_CYCLE_TS as Ts
    //     };
    //     self.vts.set_hc_after_small_increment(hc);
    //     Self::new(vc, hc - 1).as_timestamp() // data read at last cycle
    // }

    fn add_io(&mut self, port: u16) -> Self::Timestamp {
        let VideoTs{ vc, mut hc } = self.as_timestamp();
        // if port == 0x7ffd {
        //     println!("0x{:04x}: {} {:?}", port, self.as_tstates(), self.tsc);
        // }
        let hc1 = if V::is_contended_line_no_mreq(vc) {
            ula_io_contention!(self.contention, port, hc, V::contention)
            // if is_contended_address(self.contention_mask, port) {
            //     hc = V::contention(hc) + IO_IORQ_LOW_TS as Ts;
            //     if port & 1 == 0 { // C:1, C:3
            //         V::contention(hc) + (IO_CYCLE_TS - IO_IORQ_LOW_TS) as Ts
            //     }
            //     else { // C:1, C:1, C:1, C:1
            //         let mut hc1 = hc;
            //         for _ in 0..(IO_CYCLE_TS - IO_IORQ_LOW_TS) {
            //             hc1 = V::contention(hc1) + 1;
            //         }
            //         hc1
            //     }
            // }
            // else {
            //     hc += IO_IORQ_LOW_TS as Ts;
            //     if port & 1 == 0 { // N:1 C:3
            //         V::contention(hc) + (IO_CYCLE_TS - IO_IORQ_LOW_TS) as Ts
            //     }
            //     else { // N:4
            //         hc + (IO_CYCLE_TS - IO_IORQ_LOW_TS) as Ts
            //     }
            // }
        }
        else {
            hc += IO_IORQ_LOW_TS as Ts;
            hc + (IO_CYCLE_TS - IO_IORQ_LOW_TS) as Ts
        };
        let mut vtsc = *self;
        vtsc.vts.set_hc_after_small_increment(hc);
        self.vts.set_hc_after_small_increment(hc1);
        vtsc.as_timestamp()
    }

Converts video scan line and horizontal T-state counters to the frame T-state count without any normalization.

Examples found in repository?
src/clock.rs (line 220)
218
219
220
221
    pub fn into_tstates(self) -> FTs {
        let VideoTs { vc, hc } = self.ts;
        V::vc_hc_to_tstates(vc, hc)
    }

Implementors§