pub struct UlaFrameCache<V> {
    pub frame_pixels: [(u32, [u8; 32]); 192],
    pub frame_colors: [(u32, [u8; 32]); 192],
    pub frame_colors_coarse: [(u32, [u8; 32]); 24],
    /* private fields */
}
Expand description

Spectrum’s video data frame cache.

When a byte is being written to the video memory and the video beam position has already passed the referenced screen cell, the cell value is being cached from memory before the data in memory is being modified.

The caching is performed only once per frame for each potential cell so subsequent writes to the same memory address won’t modify the cached cell value.

When a screen is being drawn the data stored in cache will override any value currently residing in video memory.

Fields§

§frame_pixels: [(u32, [u8; 32]); 192]§frame_colors: [(u32, [u8; 32]); 192]§frame_colors_coarse: [(u32, [u8; 32]); 24]

Implementations§

Examples found in repository?
src/chip/ula/video.rs (line 178)
175
176
177
178
179
    pub(super) fn cleanup_video_frame_data(&mut self) {
        self.border = self.last_border;
        self.border_out_changes.clear();
        self.frame_cache.clear();
    }
More examples
Hide additional examples
src/chip/ula3.rs (line 447)
441
442
443
444
445
446
447
448
449
450
    fn prepare_next_frame<C: MemoryContention>(
            &mut self,
            vtsc: VFrameTsCounter<Ula3VidFrame, C>
        ) -> VFrameTsCounter<Ula3VidFrame, C>
    {
        self.beg_screen_shadow = self.cur_screen_shadow;
        self.shadow_frame_cache.clear();
        self.screen_changes.clear();
        self.ula.prepare_next_frame(vtsc)
    }
src/chip/scld.rs (line 378)
372
373
374
375
376
377
378
379
380
381
382
    fn prepare_next_frame<C: MemoryContention>(
            &mut self,
            vtsc: VFrameTsCounter<V, C>
        ) -> VFrameTsCounter<V, C>
    {
        self.beg_ctrl_flags = self.cur_ctrl_flags;
        self.sec_frame_cache.clear();
        self.mode_changes.clear();
        self.source_changes.clear();
        self.ula.prepare_next_frame(vtsc)
    }
src/chip/ula128.rs (line 366)
359
360
361
362
363
364
365
366
367
368
369
    fn prepare_next_frame<C: MemoryContention>(
            &mut self,
            vtsc: VFrameTsCounter<Ula128VidFrame, C>
        ) -> VFrameTsCounter<Ula128VidFrame, C>
    {
        // println!("vis: {} nxt: {} p3: {}", self.beg_screen_shadow, self.cur_screen_shadow, self.mem_page3_bank);
        self.beg_screen_shadow = self.cur_screen_shadow;
        self.shadow_frame_cache.clear();
        self.screen_changes.clear();
        self.ula.prepare_next_frame(vtsc)
    }
src/chip/plus.rs (line 586)
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
    fn prepare_next_frame<C: MemoryContention>(
            &mut self,
            vtsc: VFrameTsCounter<U::VideoFrame, C>
        ) -> VFrameTsCounter<U::VideoFrame, C>
    {
        self.beg_render_mode = self.cur_render_mode;
        self.beg_source_mode = self.cur_source_mode;
        self.beg_palette = self.cur_palette;

        self.sec_frame_cache.clear();
        self.shadow_sec_frame_cache.clear();
        self.palette_changes.clear();
        self.source_changes.clear();
        self.mode_changes.clear();
        self.ula.prepare_next_frame(vtsc)
    }

Compares the given bitmap cell coordinates with the video timestamp and depending on the result of that comparison caches (or not) the bitmap cell with the value from the memory at the given address.

Examples found in repository?
src/chip/ula/video.rs (line 153)
149
150
151
152
153
154
155
156
157
158
159
160
161
    pub(super) fn update_frame_cache(&mut self, addr: u16, ts: VideoTs) {
        match addr {
            0x4000..=0x57FF => {
                let coords = pixel_address_coords(addr);
                self.frame_cache.update_frame_pixels(&self.memory, coords, addr, ts);
            }
            0x5800..=0x5AFF => {
                let coords = color_address_coords(addr);
                self.frame_cache.update_frame_colors(&self.memory, coords, addr, ts);
            }
            _ => {}
        }
    }
More examples
Hide additional examples
src/chip/scld/video.rs (line 87)
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    pub(super) fn update_frame_cache(&mut self, addr: u16, ts: VideoTs) {
        let frame_cache = match addr {
            0x4000..=0x5AFF if self.mem_paged & 4 == 0 => &mut self.ula.frame_cache,
            0x6000..=0x7AFF if self.mem_paged & 8 == 0 => &mut self.sec_frame_cache,
            _ => return
        };

        if addr & 0x1800 != 0x1800 {
            let coords = pixel_address_coords(addr);
            frame_cache.update_frame_pixels(&self.ula.memory, coords, addr, ts);
        }
        else {
            let coords = color_address_coords(addr);
            frame_cache.update_frame_colors(&self.ula.memory, coords, addr, ts);
        }
    }
src/chip/ula128/video.rs (line 165)
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    pub(super) fn update_frame_cache(&mut self, addr: u16, ts: VideoTs) {
        let frame_cache = match addr {
            0x4000..=0x5AFF => &mut self.ula.frame_cache,
            0xC000..=0xDAFF => match self.page3_screen_shadow_bank() {
                Some(false) => &mut self.ula.frame_cache,
                Some(true)  => &mut self.shadow_frame_cache,
                None => return
            }
            _ => return
        };
        if addr & 0x1800 != 0x1800 {
            let coords = pixel_address_coords(addr);
            frame_cache.update_frame_pixels(&self.ula.memory, coords, addr, ts);
        }
        else {
            let coords = color_address_coords(addr);
            frame_cache.update_frame_colors(&self.ula.memory, coords, addr, ts);
        }
    }
src/chip/ula3/video.rs (line 139)
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
    pub(super) fn update_frame_cache(&mut self, addr: u16, ts: VideoTs) {
        let maybe_shadow = match addr {
            0x4000..=0x5AFF => self.page1_screen_shadow_bank(),
            0xC000..=0xDAFF => self.page3_screen_shadow_bank(),
            _ => return
        };
        let frame_cache = match maybe_shadow {
            Some(false) => &mut self.ula.frame_cache,
            Some(true)  => &mut self.shadow_frame_cache,
            None => return
        };
        if addr & 0x1800 != 0x1800 {
            let coords = pixel_address_coords(addr);
            frame_cache.update_frame_pixels(&self.ula.memory, coords, addr, ts);
        }
        else {
            let coords = color_address_coords(addr);
            frame_cache.update_frame_colors(&self.ula.memory, coords, addr, ts);
        }
    }
src/chip/plus/video.rs (line 103)
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    pub(super) fn update_frame_cache(&mut self, addr: u16, ts: VideoTs) {
        let (frame_cache, memory_ref): (&mut UlaFrameCache<_>, _) = match addr {
            0x4000..=0x5AFF => match self.ula.page1_screen0_shadow_bank() {
                Some(false) => self.ula.frame_cache_mut_mem_ref(),
                Some(true) => self.ula.shadow_frame_cache_mut_mem_ref(),
                None => return
            }
            0x6000..=0x7AFF => match self.ula.page1_screen1_shadow_bank() {
                Some(false) => (&mut self.sec_frame_cache, self.ula.memory_ref()),
                Some(true) => (&mut self.shadow_sec_frame_cache, self.ula.memory_ref()),
                None => return
            }
            0xC000..=0xDAFF => match self.ula.page3_screen0_shadow_bank() {
                Some(false) => self.ula.frame_cache_mut_mem_ref(),
                Some(true) => self.ula.shadow_frame_cache_mut_mem_ref(),
                None => return
            }
            0xE000..=0xFAFF => match self.ula.page3_screen1_shadow_bank() {
                Some(false) => (&mut self.sec_frame_cache, self.ula.memory_ref()),
                Some(true) => (&mut self.shadow_sec_frame_cache, self.ula.memory_ref()),
                None => return
            }
            _ => return
        };

        if addr & 0x1800 != 0x1800 {
            let coords = pixel_address_coords(addr);
            frame_cache.update_frame_pixels(memory_ref, coords, addr, ts);
        }
        else {
            let coords = color_address_coords(addr);
            frame_cache.update_frame_colors(memory_ref, coords, addr, ts);
        }
    }

Compares the given attribute cell coordinates with the video timestamp and depending on the result of that comparison caches (or not) the attribute cell or cells with the value from the memory at the given address.

Examples found in repository?
src/chip/ula/video.rs (line 157)
149
150
151
152
153
154
155
156
157
158
159
160
161
    pub(super) fn update_frame_cache(&mut self, addr: u16, ts: VideoTs) {
        match addr {
            0x4000..=0x57FF => {
                let coords = pixel_address_coords(addr);
                self.frame_cache.update_frame_pixels(&self.memory, coords, addr, ts);
            }
            0x5800..=0x5AFF => {
                let coords = color_address_coords(addr);
                self.frame_cache.update_frame_colors(&self.memory, coords, addr, ts);
            }
            _ => {}
        }
    }
More examples
Hide additional examples
src/chip/scld/video.rs (line 91)
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    pub(super) fn update_frame_cache(&mut self, addr: u16, ts: VideoTs) {
        let frame_cache = match addr {
            0x4000..=0x5AFF if self.mem_paged & 4 == 0 => &mut self.ula.frame_cache,
            0x6000..=0x7AFF if self.mem_paged & 8 == 0 => &mut self.sec_frame_cache,
            _ => return
        };

        if addr & 0x1800 != 0x1800 {
            let coords = pixel_address_coords(addr);
            frame_cache.update_frame_pixels(&self.ula.memory, coords, addr, ts);
        }
        else {
            let coords = color_address_coords(addr);
            frame_cache.update_frame_colors(&self.ula.memory, coords, addr, ts);
        }
    }
src/chip/ula128/video.rs (line 169)
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
    pub(super) fn update_frame_cache(&mut self, addr: u16, ts: VideoTs) {
        let frame_cache = match addr {
            0x4000..=0x5AFF => &mut self.ula.frame_cache,
            0xC000..=0xDAFF => match self.page3_screen_shadow_bank() {
                Some(false) => &mut self.ula.frame_cache,
                Some(true)  => &mut self.shadow_frame_cache,
                None => return
            }
            _ => return
        };
        if addr & 0x1800 != 0x1800 {
            let coords = pixel_address_coords(addr);
            frame_cache.update_frame_pixels(&self.ula.memory, coords, addr, ts);
        }
        else {
            let coords = color_address_coords(addr);
            frame_cache.update_frame_colors(&self.ula.memory, coords, addr, ts);
        }
    }
src/chip/ula3/video.rs (line 143)
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
    pub(super) fn update_frame_cache(&mut self, addr: u16, ts: VideoTs) {
        let maybe_shadow = match addr {
            0x4000..=0x5AFF => self.page1_screen_shadow_bank(),
            0xC000..=0xDAFF => self.page3_screen_shadow_bank(),
            _ => return
        };
        let frame_cache = match maybe_shadow {
            Some(false) => &mut self.ula.frame_cache,
            Some(true)  => &mut self.shadow_frame_cache,
            None => return
        };
        if addr & 0x1800 != 0x1800 {
            let coords = pixel_address_coords(addr);
            frame_cache.update_frame_pixels(&self.ula.memory, coords, addr, ts);
        }
        else {
            let coords = color_address_coords(addr);
            frame_cache.update_frame_colors(&self.ula.memory, coords, addr, ts);
        }
    }
src/chip/plus/video.rs (line 107)
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    pub(super) fn update_frame_cache(&mut self, addr: u16, ts: VideoTs) {
        let (frame_cache, memory_ref): (&mut UlaFrameCache<_>, _) = match addr {
            0x4000..=0x5AFF => match self.ula.page1_screen0_shadow_bank() {
                Some(false) => self.ula.frame_cache_mut_mem_ref(),
                Some(true) => self.ula.shadow_frame_cache_mut_mem_ref(),
                None => return
            }
            0x6000..=0x7AFF => match self.ula.page1_screen1_shadow_bank() {
                Some(false) => (&mut self.sec_frame_cache, self.ula.memory_ref()),
                Some(true) => (&mut self.shadow_sec_frame_cache, self.ula.memory_ref()),
                None => return
            }
            0xC000..=0xDAFF => match self.ula.page3_screen0_shadow_bank() {
                Some(false) => self.ula.frame_cache_mut_mem_ref(),
                Some(true) => self.ula.shadow_frame_cache_mut_mem_ref(),
                None => return
            }
            0xE000..=0xFAFF => match self.ula.page3_screen1_shadow_bank() {
                Some(false) => (&mut self.sec_frame_cache, self.ula.memory_ref()),
                Some(true) => (&mut self.shadow_sec_frame_cache, self.ula.memory_ref()),
                None => return
            }
            _ => return
        };

        if addr & 0x1800 != 0x1800 {
            let coords = pixel_address_coords(addr);
            frame_cache.update_frame_pixels(memory_ref, coords, addr, ts);
        }
        else {
            let coords = color_address_coords(addr);
            frame_cache.update_frame_colors(memory_ref, coords, addr, ts);
        }
    }

Caches the bitmap and attribute cell at the given coordinates with the snow distortion applied.

Examples found in repository?
src/chip/ula/video.rs (line 168)
164
165
166
167
168
169
170
171
    pub(super) fn update_snow_interference(&mut self, ts: VideoTs, ir: u16) {
        if UlaMemoryContention.is_contended_address(ir) {
            if let Some(coords) = V::snow_interference_coords(ts) {
                let screen = self.memory.screen_ref(0).unwrap();
                self.frame_cache.apply_snow_interference(screen, coords, ir as u8)
            }
        }
    }
More examples
Hide additional examples
src/chip/ula128/video.rs (line 183)
174
175
176
177
178
179
180
181
182
183
184
185
186
    pub(super) fn update_snow_interference(&mut self, ts: VideoTs, ir: u16) {
        if self.memory_contention().is_contended_address(ir) {
            if let Some(coords) = Ula128VidFrame::snow_interference_coords(ts) {
                let (screen, frame_cache) = if self.cur_screen_shadow {
                    (self.ula.memory.screen_ref(1).unwrap(), &mut self.shadow_frame_cache)
                }
                else {
                    (self.ula.memory.screen_ref(0).unwrap(), &mut self.ula.frame_cache)
                };
                frame_cache.apply_snow_interference(screen, coords, ir as u8);
            }
        }
    }

Trait Implementations§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when Debug-formatted. Read more
Causes self to use its LowerExp implementation when Debug-formatted. Read more
Causes self to use its LowerHex implementation when Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when Debug-formatted. Read more
Causes self to use its UpperExp implementation when Debug-formatted. Read more
Causes self to use its UpperHex implementation when Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Convert to S a sample type from self.
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.