mos_hardware/
lib.rs

1// copyright 2022 mikael lund aka wombat
2//
3// licensed under the apache license, version 2.0 (the "license");
4// you may not use this file except in compliance with the license.
5// you may obtain a copy of the license at
6//
7//     http://www.apache.org/licenses/license-2.0
8//
9// unless required by applicable law or agreed to in writing, software
10// distributed under the license is distributed on an "as is" basis,
11// without warranties or conditions of any kind, either express or implied.
12// see the license for the specific language governing permissions and
13// limitations under the license.
14
15//! This crate contains hardware register tables and support functions for
16//! 8-bit retro computers like the Commodore 64, Commander X16, MEGA65 and others.
17//! Please check the `examples/` directory to see how Rust can be
18//! used generate basic graphics effects and interact with hardware.
19//!
20//! # Examples
21//!
22//! Read and write to labelled hardware registers:
23//! ~~~
24//! use mos_hardware::{c64,vic2};
25//! let old_border_color = c64::vic2.border_color.read();
26//! unsafe {
27//!     c64::vic2().border_color.write(vic2::LIGHT_RED);
28//! }
29//! ~~~
30//!
31//! Use bitflags to control hardware behaviour, _e.g._ where the VIC-II chip accesses
32//! screen memory and character sets:
33//! ~~~
34//! let bank = vic2::ScreenBank::AT_2C00.bits() | vic2::ScreenBank::AT_2000.bits();
35//! c64::vic2().screen_and_charset_bank.write(bank);
36//! ~~~
37//!
38//! Convenience functions to perform hardware-specific tasks, _e.g._ generate random numbers
39//! using noise from the C64's SID chip:
40//! ~~~
41//! c64::sid().start_random_generator();
42//! let value = c64::sid().random_byte();
43//! ~~~
44
45#![no_std]
46#![feature(const_option)]
47#![allow(incomplete_features)]
48#![feature(generic_const_exprs)]
49#![feature(error_in_core)]
50#![feature(iter_advance_by)]
51#![feature(iter_next_chunk)]
52#![feature(cfg_version)]
53#![allow(clippy::bad_bit_mask)]
54extern crate alloc;
55extern crate static_assertions;
56
57#[cfg(feature = "c64")]
58pub mod c64;
59pub mod cbm_kernal;
60#[cfg(feature = "cia")]
61pub mod cia;
62#[cfg(feature = "cx16")]
63pub mod cx16;
64#[cfg(feature = "mega65")]
65pub mod mega65;
66#[cfg(feature = "petscii")]
67pub mod petscii;
68#[cfg(feature = "sid")]
69pub mod sid;
70#[cfg(feature = "vera")]
71pub mod vera;
72#[cfg(feature = "vic2")]
73pub mod vic2;
74
75/// Peek into memory (volatile read)
76///
77/// # Examples
78/// ~~~
79/// let value = peek!(0xC000 as *mut u8);
80/// ~~~
81#[macro_export]
82macro_rules! peek {
83    ($address:expr) => {{
84        core::ptr::read_volatile($address)
85    }};
86}
87
88/// Poke into memory (volatile write)
89///
90/// # Examples
91/// ~~~
92/// poke!(0xD020 as *mut u8, vic2::LIGHT_GREEN);
93/// ~~~
94#[macro_export]
95macro_rules! poke {
96    ($address:expr, $value:expr) => {{
97        core::ptr::write_volatile($address, $value)
98    }};
99}
100
101/// Add two integers using wrapping
102#[macro_export]
103macro_rules! add {
104    ($value1:expr, $value2:expr) => {{
105        $value1.wrapping_add($value2)
106    }};
107}
108
109/// Subtract two integers using wrapping
110#[macro_export]
111macro_rules! sub {
112    ($value1:expr, $value2:expr) => {{
113        $value1.wrapping_sub($value2)
114    }};
115}
116
117/// Get high byte from a 16-bit integer using pointer arithmetic
118///
119/// # Examples
120/// ~~~
121/// let high = highbyte(0xABCD);
122/// let low = lowbyte(0xABCD);
123/// assert_eq!(high, 0xAB);
124/// assert_eq!(low, 0xCD);
125/// ~~~
126#[macro_export]
127macro_rules! highbyte {
128    ($word:expr) => {{
129        ((&$word as *const u16) as *const u8)
130            .offset(1)
131            .read_volatile()
132        // Can also be done using bit-shifting: ($word >> 8) as u8
133    }};
134}
135
136/// Get low byte from a 16-bit integer using pointer arithmetic
137///
138/// # Examples
139/// ~~~
140/// let word = 0xABCD;
141/// assert_eq!(highbyte!(word), 0xAB);
142/// assert_eq!(lowbyte!(word), 0xCD);
143/// ~~~
144#[macro_export]
145macro_rules! lowbyte {
146    ($word:expr) => {{
147        ((&$word as *const u16) as *const u8)
148            .offset(0)
149            .read_volatile()
150        // Can also be done using bit-shifting: ($word & 0xff) as u8
151    }};
152}
153
154/// Repeat each element n times
155///
156/// Convenience function currently used in the plasma examples.
157/// See more [here](https://stackoverflow.com/questions/66482699/how-to-repeat-each-element-of-iterator-n-times).
158pub fn repeat_element<T: Clone>(
159    it: impl Iterator<Item = T>,
160    cnt: usize,
161) -> impl Iterator<Item = T> {
162    it.flat_map(move |n| core::iter::repeat(n).take(cnt))
163}
164
165/// Returns constantly evaluated _scaled_ and _shifted_ sine table.
166///
167/// # Arguments
168///
169/// * `divide` - Number to divide with
170/// * `add`    - Number to add
171///
172/// # Examples
173/// ~~~
174/// const SINE: [u8; 256] = make_sine(1, 0);
175/// const SCALED_SINE: [u8; 256] = make_sine(4, 70);
176/// ~~~
177pub const fn make_sine(divide: u8, add: u8) -> [u8; SINETABLE.len()] {
178    let mut array = SINETABLE;
179    let mut i: usize = 0;
180    while i < array.len() {
181        array[i] = array[i] / divide + add;
182        i += 1;
183    }
184    array
185}
186
187/// Cyclic sine from 0x80..0..0xff..0x80
188pub const fn sine(index: u8) -> u8 {
189    SINETABLE[index as usize]
190}
191
192/// Tabulated, cyclic sine table
193pub const SINETABLE: [u8; 256] = [
194    0x80, 0x7d, 0x7a, 0x77, 0x74, 0x70, 0x6d, 0x6a, 0x67, 0x64, 0x61, 0x5e, 0x5b, 0x58, 0x55, 0x52,
195    0x4f, 0x4d, 0x4a, 0x47, 0x44, 0x41, 0x3f, 0x3c, 0x39, 0x37, 0x34, 0x32, 0x2f, 0x2d, 0x2b, 0x28,
196    0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a, 0x18, 0x16, 0x15, 0x13, 0x11, 0x10, 0x0f, 0x0d, 0x0c,
197    0x0b, 0x0a, 0x08, 0x07, 0x06, 0x06, 0x05, 0x04, 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
198    0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x0a,
199    0x0b, 0x0c, 0x0d, 0x0f, 0x10, 0x11, 0x13, 0x15, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24,
200    0x26, 0x28, 0x2b, 0x2d, 0x2f, 0x32, 0x34, 0x37, 0x39, 0x3c, 0x3f, 0x41, 0x44, 0x47, 0x4a, 0x4d,
201    0x4f, 0x52, 0x55, 0x58, 0x5b, 0x5e, 0x61, 0x64, 0x67, 0x6a, 0x6d, 0x70, 0x74, 0x77, 0x7a, 0x7d,
202    0x80, 0x83, 0x86, 0x89, 0x8c, 0x90, 0x93, 0x96, 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8, 0xab, 0xae,
203    0xb1, 0xb3, 0xb6, 0xb9, 0xbc, 0xbf, 0xc1, 0xc4, 0xc7, 0xc9, 0xcc, 0xce, 0xd1, 0xd3, 0xd5, 0xd8,
204    0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xeb, 0xed, 0xef, 0xf0, 0xf1, 0xf3, 0xf4,
205    0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfa, 0xfb, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff,
206    0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfb, 0xfa, 0xfa, 0xf9, 0xf8, 0xf6,
207    0xf5, 0xf4, 0xf3, 0xf1, 0xf0, 0xef, 0xed, 0xeb, 0xea, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0, 0xde, 0xdc,
208    0xda, 0xd8, 0xd5, 0xd3, 0xd1, 0xce, 0xcc, 0xc9, 0xc7, 0xc4, 0xc1, 0xbf, 0xbc, 0xb9, 0xb6, 0xb3,
209    0xb1, 0xae, 0xab, 0xa8, 0xa5, 0xa2, 0x9f, 0x9c, 0x99, 0x96, 0x93, 0x90, 0x8c, 0x89, 0x86, 0x83,
210];