Trait spectrusty_core::video::VideoFrame
source · 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§
sourcetype BorderHtsIter: Iterator<Item = Ts>
type BorderHtsIter: Iterator<Item = Ts>
An iterator for rendering borders.
Required Associated Constants§
sourceconst VSL_BORDER_TOP: Ts
const VSL_BORDER_TOP: Ts
The first visible video scan line index of the top border.
sourceconst VSL_PIXELS: Range<Ts>
const VSL_PIXELS: Range<Ts>
A range of video scan line indexes where pixel data is being drawn.
sourceconst VSL_BORDER_BOT: Ts
const VSL_BORDER_BOT: Ts
The last visible video scan line index of the bottom border.
Provided Associated Constants§
sourceconst FRAME_TSTATES_COUNT: FTs = _
const FRAME_TSTATES_COUNT: FTs = _
The total number of T-states per frame.
Required Methods§
sourcefn border_whole_line_hts_iter(border_size: BorderSize) -> Self::BorderHtsIter
fn border_whole_line_hts_iter(border_size: BorderSize) -> Self::BorderHtsIter
Returns an iterator of border latch horizontal T-states.
sourcefn border_left_hts_iter(border_size: BorderSize) -> Self::BorderHtsIter
fn border_left_hts_iter(border_size: BorderSize) -> Self::BorderHtsIter
Returns an iterator of left border latch horizontal T-states.
sourcefn border_right_hts_iter(border_size: BorderSize) -> Self::BorderHtsIter
fn border_right_hts_iter(border_size: BorderSize) -> Self::BorderHtsIter
Returns an iterator of right border latch horizontal T-states.
sourcefn contention(hc: Ts) -> Ts
fn contention(hc: Ts) -> Ts
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§
sourcefn border_size_pixels(border_size: BorderSize) -> u32
fn border_size_pixels(border_size: BorderSize) -> u32
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?
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
}
sourcefn screen_size_pixels(border_size: BorderSize) -> (u32, u32)
fn screen_size_pixels(border_size: BorderSize) -> (u32, u32)
Returns output screen pixel size (horizontal, vertical), including the border area, measured in low-resolution pixels.
The size depends on the given border_size
.
sourcefn border_top_vsl_iter(border_size: BorderSize) -> Range<Ts>
fn border_top_vsl_iter(border_size: BorderSize) -> Range<Ts>
Returns an iterator of the top border low-resolution scan line indexes.
sourcefn border_bot_vsl_iter(border_size: BorderSize) -> Range<Ts>
fn border_bot_vsl_iter(border_size: BorderSize) -> Range<Ts>
Returns an iterator of the bottom border low-resolution scan line indexes.
sourcefn floating_bus_offset(_hc: Ts) -> Option<u16>
fn floating_bus_offset(_hc: Ts) -> Option<u16>
Returns an optional floating bus horizontal offset for the given horizontal timestamp.
Examples found in repository?
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
}
}
sourcefn floating_bus_screen_address(_: VideoTs) -> Option<u16>
fn floating_bus_screen_address(_: VideoTs) -> Option<u16>
Returns an optional floating bus screen address (in the screen address space) for the given timestamp.
The returned screen address range is: [0x0000, 0x1B00).
sourcefn snow_interference_coords(_ts: VideoTs) -> Option<CellCoords>
fn snow_interference_coords(_ts: VideoTs) -> Option<CellCoords>
Returns an optional cell coordinates of a “snow effect” interference.
sourcefn is_contended_line_mreq(vsl: Ts) -> bool
fn is_contended_line_mreq(vsl: Ts) -> bool
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?
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()
}
sourcefn is_contended_line_no_mreq(vsl: Ts) -> bool
fn is_contended_line_no_mreq(vsl: Ts) -> bool
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?
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()
}
sourcefn vc_hc_to_tstates(vc: Ts, hc: Ts) -> FTs
fn vc_hc_to_tstates(vc: Ts, hc: Ts) -> FTs
Converts video scan line and horizontal T-state counters to the frame T-state count without any normalization.