commit e31915a5c2d014b57347b388de316ed9d8b5727a
parent 338d24a611c0c8f6be6f04d18b03015b02d1132d
Author: Ryan Jeffrey <ryan@ryanmj.xyz>
Date: Mon, 13 Jun 2022 01:58:46 -0700
Docucomments
Diffstat:
M | src/config.rs | | | 39 | +++++++++++++++++++++++++++++++++++++++ |
M | src/cpu.rs | | | 69 | +++++++++++++++++++++++++++++++++++++++------------------------------ |
M | src/instruction.rs | | | 47 | +++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/util.rs | | | 45 | +++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 170 insertions(+), 30 deletions(-)
diff --git a/src/config.rs b/src/config.rs
@@ -54,6 +54,7 @@ pub struct Config {
// Struct impls.
impl Config {
+ /// Create a new configuration object (with default settings) on success and a string on error.
pub fn new() -> Result<Config, String> {
let home_dir = util::get_home_nofail();
// Find a configuration path specified on the command line.
@@ -75,6 +76,7 @@ impl Config {
})
}
+ /// Create an initialized configuration object on success and a string on error.
pub fn init() -> Result<Config, String> {
let mut config = Self::new()?;
let args: Vec<String> = env::args().collect();
@@ -91,6 +93,9 @@ impl Config {
Ok(config)
}
+ /// Read the user's configuration file and update configuration state
+ /// (default ~/.config/riscii/config.toml). Return void on success and a
+ /// string on error.
fn read_config_file(&mut self) -> Result<(), String> {
// TODO do not exit if config.toml does not exist
// TODO get ~ in paths to expand
@@ -114,6 +119,10 @@ impl Config {
Ok(())
}
+ /// Parse CMD arguments for configuration file path. Return path on
+ /// success and string on error.
+ /// # Arguments
+ /// * `args` - CMD argument vector.
fn find_cmd_config_path(&self, args: &Vec<String>) -> Result<Option<String>, String> {
for (i, arg) in args.iter().enumerate() {
match arg.as_str() {
@@ -128,6 +137,10 @@ impl Config {
Ok(None)
}
+ /// Parse CMD args and update configuration state. Return void on success
+ /// and a string on error.
+ /// # Arguments
+ /// * `args` - CMD argument vector.
fn parse_cmd_args(&mut self, args: &Vec<String>) -> Result<(), String> {
let mut skips = 1i32;
for (i, arg) in args.iter().enumerate() {
@@ -180,21 +193,35 @@ impl Config {
// Getters.
+ /// Get the user's configured window width.
pub fn get_win_width(&self) -> u32 {
self.win_width
}
+ /// Get the user's configured window height.
pub fn get_win_height(&self) -> u32 {
self.win_height
}
+ /// Get the user's configured memory size.
pub fn get_mem_size(&self) -> u32 {
self.mem
}
+
+ /// Get the user's configured number of CPUs.
+ pub fn get_ncpus(&self) -> u32 {
+ self.ncpu
+ }
}
// Local functions.
+/// Check the argument vector to make sure it has at least one more string
+/// after the current argument. Return void on success and a string on error.
+/// # Arguments
+/// * `args` - CMD argument vector.
+/// * `i` - Index of the current argument.
+/// * `what` - String describing the current argument (for error message).
fn args_check_size(args: &Vec<String>, i: usize, what: &String) -> Result<(), String> {
if i >= args.len() {
Err(format!(
@@ -206,6 +233,12 @@ fn args_check_size(args: &Vec<String>, i: usize, what: &String) -> Result<(), St
}
}
+/// Get the next argument in the argument vector as a string. Return next
+/// string on success and a string on error.
+/// # Arguments
+/// * `args` - CMD argument vector.
+/// * `i` - Index of the current argument.
+/// * `what` - String describing the current argument (for error message).
fn args_get_next_arg<'a>(
args: &'a Vec<String>,
i: usize,
@@ -215,6 +248,12 @@ fn args_get_next_arg<'a>(
Ok(&args[i + 1])
}
+/// Get the next argument in the argument vector as a u32. Return
+/// u32 on success and a string on error.
+/// # Arguments
+/// * `args` - CMD argument vector.
+/// * `i` - Index of the current argument.
+/// * `what` - String describing the current argument (for error message).
fn args_get_next_uint(args: &Vec<String>, i: usize, what: &String) -> Result<u32, String> {
args_check_size(&args, i, &what)?;
Ok(match args[i + 1].parse::<u32>() {
diff --git a/src/cpu.rs b/src/cpu.rs
@@ -65,15 +65,23 @@ pub struct RegisterFile {
window_regs: [Register; NUM_WINDOW_REGISTERS], // TODO test, there should be 138 regs.
}
-///
+/// Load/Store queries. Specifies the register and the value to set it to (if store).
pub enum LoadStore {
- NXTPC { val: u32 },
- PC { val: u32 },
- LSTPC { val: u32 },
- CWP { val: u32 },
- SWP { val: u32 },
- Global { which: u32, val: u32 },
- Window { which: u32, val: u32 },
+ /// Global register.
+ Global {
+ /// Which global register. g0 is special and will always return 0,
+ /// attempts to store to it are ignored. Values above 10 throw an error.
+ which: u32,
+ /// Value to set register to (ignored owhen loading).
+ val: u32,
+ },
+ /// Window register.
+ Window {
+ /// Which window register. Values above 22 throw an error.
+ which: u32,
+ /// Value to set register to (ignored owhen loading).
+ val: u32,
+ },
}
// Struct implementations.
@@ -91,7 +99,7 @@ impl RegisterFile {
/// Create a register state from a buffer.
/// # Arguments
- /// * `buffer` - A byte buffer that is the size of the sum of of register::RegisterFile's
+ /// * `buf` - A byte buffer that is the size of the sum of of register::RegisterFile's
/// members (in bytes) (see `SIZEOF_STATE`).
/// The registers should appear in the following order:
/// - NXTPC
@@ -133,6 +141,7 @@ impl RegisterFile {
}
}
+ /// Convert self to a byte buffer of all of the register values.
pub fn to_buf(&self) -> [u8; SIZEOF_STATE] {
let mut result = [0u8; SIZEOF_STATE];
result[0..4].copy_from_slice(&self.cwp.to_be_bytes());
@@ -159,6 +168,8 @@ impl RegisterFile {
result
}
+ /// Push the register window stack. Increment CWP by 1 and flush the bottom
+ /// windows to memory if necessary and change SWP.
pub fn push_reg_window(&mut self) {
self.cwp += 1;
while self.cwp >= self.swp {
@@ -167,6 +178,8 @@ impl RegisterFile {
}
}
+ /// Pop the register window stack. Decrement CWP by 1 and pull the bottom
+ /// windows from memory if necessary and change SWP.
pub fn pop_reg_window(&mut self) {
self.cwp -= 1;
while self.swp >= self.cwp {
@@ -175,14 +188,13 @@ impl RegisterFile {
}
}
- pub fn load(&self, ls: LoadStore) -> Result<u32, String> {
+ /// Load from a register (unsigned). Return the register's value
+ /// on success and a string message on error.
+ /// # Arguments
+ /// * `ls` - Load/Store instruction. Will error if `which` is out of range.
+ pub fn load_u(&self, ls: LoadStore) -> Result<u32, String> {
type LS = LoadStore;
Ok(match ls {
- LS::NXTPC { val: _ } => self.nxtpc,
- LS::PC { val: _ } => self.pc,
- LS::LSTPC { val: _ } => self.lstpc,
- LS::CWP { val: _ } => self.cwp,
- LS::SWP { val: _ } => self.swp,
LS::Global { which: rd, val: _ } => {
if rd <= NUM_GLOBALS {
self.globals[rd]
@@ -204,24 +216,21 @@ impl RegisterFile {
})
}
+ /// Load from a register (signed). Return the register's value
+ /// on success and a string message on error.
+ /// # Arguments
+ /// * `ls` - Load/Store instruction. `val` is ignored.
+ pub fn load_s(&self, ls: LoadStore) -> Result<i32, String> {
+ self.load_u(ls)? as i32
+ }
+
+ /// Store to a register. Return void on success and a string message on
+ /// failure.
+ /// # Arguments
+ /// * `ls` - Load/Store instruction. Will error if `which` is out of range.
pub fn store(&mut self, ls: LoadStore) -> Result<(), String> {
type LS = LoadStore;
Ok(match ls {
- LS::NXTPC { val: v } => {
- self.nxtpc = v;
- }
- LS::PC { val: v } => {
- self.pc = v;
- }
- LS::LSTPC { val: v } => {
- self.lstpc = v;
- }
- LS::CWP { val: v } => {
- self.cwp = v;
- }
- LS::SWP { val: v } => {
- self.swp = v;
- }
LS::Global { which: rd, val: v } => {
if rd <= NUM_GLOBALS && rd > 0 {
self.globals[rd] = val;
diff --git a/src/instruction.rs b/src/instruction.rs
@@ -64,33 +64,51 @@ pub enum ShortSource {
SImm13(i32),
}
+/// Short instruction format data.
#[derive(PartialEq, Eq, Copy, Clone)]
pub struct ShortInstruction {
+ /// Update CC bit.
scc: bool,
+ /// Destination register.
dest: u8,
+ /// Source register.
rs1: u8,
+ /// Short source data.
short_source: ShortSource,
}
+/// Long instruction format data.
#[derive(PartialEq, Eq, Copy, Clone)]
pub struct LongInstruction {
+ /// Update CC bit.
scc: bool,
+ /// Destination register.
dest: u8,
+ /// 19 bit constant.
imm19: u32,
}
+/// Short conditional instruction format data.
#[derive(PartialEq, Eq, Copy, Clone)]
pub struct ShortConditional {
+ /// Update CC bit.
scc: bool,
+ /// Destination register.
dest: Conditional,
+ /// Source register.
rs1: u8,
+ /// Short source data.
short_source: ShortSource,
}
+/// Long conditional instruction format data.
#[derive(PartialEq, Eq, Copy, Clone)]
pub struct LongConditional {
+ /// Update CC bit.
scc: bool,
+ /// Destination register.
dest: Conditional,
+ /// 19 bit constant.
imm19: u32,
}
@@ -252,6 +270,11 @@ pub enum Instruction {
// Impls.
impl ShortSource {
+ /// Create a new short source.
+ /// # Arguments
+ /// * `opcode` - The current opcode being executed.
+ /// * `signed` - True if `self` is a 13 bit constant and signed. This
+ /// is ignored if `self` is not a constant.
pub fn new(opcode: u32, signed: bool) -> Self {
// Short source immediate-mode bottom 13 bits <12-0> or rs1 <4-0>.
if opcode & 0x2000 != 0 {
@@ -266,6 +289,8 @@ impl ShortSource {
}
}
+ /// Create a new short source. If `self` is an unsigned constant,
+ /// convert it a signed constant. Else, return `self`.
pub fn uimm_to_simm(&self) -> Self {
match *self {
Self::UImm13(u) => {
@@ -303,6 +328,11 @@ impl LowerHex for ShortSource {
}
impl LongInstruction {
+ /// Create a new long instruction.
+ /// # Arguments
+ /// * `scc` - Should update CC's.
+ /// * `dest` - Destination register.
+ /// * `imm19` - 19 bit constant.
pub fn new(scc: bool, dest: u8, imm19: u32) -> Self {
Self {
scc: scc,
@@ -323,6 +353,11 @@ impl fmt::Display for LongInstruction {
}
impl LongConditional {
+ /// Create a new long conditional instruction.
+ /// # Arguments
+ /// * `scc` - Should update CC's.
+ /// * `dest` - Conditional.
+ /// * `imm19` - 19 bit constant.
pub fn new(scc: bool, dest: Conditional, imm19: u32) -> Self {
Self {
scc: scc,
@@ -343,6 +378,12 @@ impl fmt::Display for LongConditional {
}
impl ShortInstruction {
+ /// Create a new long conditional instruction.
+ /// # Arguments
+ /// * `scc` - Should update CC's.
+ /// * `dest` - Destination register.
+ /// * `rs1` - Source register.
+ /// * `short_source` - Short source.
pub fn new(scc: bool, dest: u8, rs1: u8, short_source: ShortSource) -> Self {
Self {
scc: scc,
@@ -364,6 +405,12 @@ impl fmt::Display for ShortInstruction {
}
impl ShortConditional {
+ /// Create a new long conditional instruction.
+ /// # Arguments
+ /// * `scc` - Should update CC's.
+ /// * `dest` - Conditional.
+ /// * `rs1` - Source register.
+ /// * `short_source` - Short source.
pub fn new(scc: bool, dest: Conditional, rs1: u8, short_source: ShortSource) -> Self {
Self {
scc: scc,
diff --git a/src/util.rs b/src/util.rs
@@ -23,17 +23,27 @@ use std::time::{Duration, SystemTime, SystemTimeError, UNIX_EPOCH};
// Public struct definitions.
+/// File object. Wrapper around fs::File but caches more data.
pub struct File {
+ /// Underlying file object.
file: fs::File,
+ /// Path to the object.
path: String,
}
// Public function definitions.
+/// Return a file's contents as a byte vector on success and a string on error.
+/// # Arguments
+/// * `path` - Path to the file.
pub fn read_file_path(path: &String) -> Result<Vec<u8>, String> {
File::open(&path)?.read_file()
}
+/// Return two paths concatenated together on success and a string on error.
+/// # Arguments
+/// * `base` - Base path.
+/// * `rest` - Rest of the path.
pub fn concat_paths(base: &String, rest: &String) -> Result<String, String> {
let p = Path::new(&base).join(&rest);
match p.to_str() {
@@ -42,6 +52,7 @@ pub fn concat_paths(base: &String, rest: &String) -> Result<String, String> {
}
}
+/// Get the current unix timestamp on success and a string on error.
pub fn get_unix_timestamp() -> Result<Duration, String> {
match SystemTime::now().duration_since(UNIX_EPOCH) {
Ok(r) => Ok(r),
@@ -49,6 +60,9 @@ pub fn get_unix_timestamp() -> Result<Duration, String> {
}
}
+/// Convert a `Result<OsString, String>` to a `Result<String, String>`.
+/// # Arguments
+/// * `r` - Result to convert.
pub fn os_string_result_to_strings(r: Result<String, OsString>) -> Result<String, String> {
match r {
Err(e) => Err(match e.into_string() {
@@ -59,6 +73,8 @@ pub fn os_string_result_to_strings(r: Result<String, OsString>) -> Result<String
}
}
+/// Get the user's home directory. If that fails, get the current directory.
+/// If that fails, return an empty string.
pub fn get_home_nofail() -> String {
match env::var("HOME") {
Ok(v) => format!("{}", v),
@@ -84,6 +100,9 @@ pub fn get_home_nofail() -> String {
// Struct impls.
impl File {
+ /// Open a file from a path. Return File on success and a string on error.
+ /// # Arguments
+ /// * `path` - Path to file.
pub fn open(path: &String) -> Result<Self, String> {
match fs::File::open(&path) {
Ok(r) => Ok(Self {
@@ -94,6 +113,10 @@ impl File {
}
}
+ /// Open a file from a path with options. Return File on success and a string on error.
+ /// # Arguments
+ /// * `path` - Path to file.
+ /// * `ops` - File open options.
pub fn open_ops(path: &String, ops: &OpenOptions) -> Result<Self, String> {
match ops.open(&path) {
Ok(r) => Ok(Self {
@@ -104,6 +127,11 @@ impl File {
}
}
+ /// Read `self`'s contents into a byte vector, reading as many bytes as
+ /// necessary to fill that vector. Return void on success and
+ /// a string on error.
+ /// # Arguments
+ /// * `buf` - Byte vector to read `self` into.
pub fn read_into_vec(&mut self, buf: &mut Vec<u8>) -> Result<(), String> {
match self.file.read_exact(&mut buf[..]) {
Ok(r) => Ok(()),
@@ -111,6 +139,8 @@ impl File {
}
}
+ /// Read `self`'s contents into a byte vector. Return byte vector on success and
+ /// a string on error.
pub fn read_file(&mut self) -> Result<Vec<u8>, String> {
let metadata = self.get_metadata()?;
let mut result = vec![0u8; metadata.len() as usize];
@@ -119,6 +149,8 @@ impl File {
Ok(result)
}
+ /// Read `self`'s contents into a byte vector. Return byte vector on success and
+ /// a string on error.
pub fn get_metadata(&mut self) -> Result<Metadata, String> {
match self.file.metadata() {
Ok(r) => Ok(r),
@@ -126,6 +158,11 @@ impl File {
}
}
+ /// Read `self`'s contents into a byte buffer, reading as many bytes as
+ /// necessary to fill that buffer. Return void on success and
+ /// a string on error.
+ /// # Arguments
+ /// * `buf` - Byte buffer to read `self` into.
pub fn read(&mut self, buf: &mut [u8]) -> Result<(), String> {
match self.file.read_exact(buf) {
Ok(r) => Ok(()),
@@ -133,6 +170,10 @@ impl File {
}
}
+ /// Write `buf`'s contents into a self (as binary data).
+ /// Return void on success and string on error.
+ /// # Arguments
+ /// * `buf` - Byte buffer to write to `self`.
pub fn write_buf(&mut self, buf: &[u8]) -> Result<(), String> {
match self.file.write_all(buf) {
Ok(r) => Ok(()),
@@ -143,6 +184,10 @@ impl File {
}
}
+ /// Write `buf`'s contents into a self (as binary data).
+ /// Return void on success and string on error.
+ /// # Arguments
+ /// * `buf` - Byte vector to write to `self`.
pub fn write_vec(&mut self, buf: &Vec<u8>) -> Result<(), String> {
match self.file.write_all(&buf[..]) {
Ok(r) => Ok(()),