Croissant Runtime
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
crsn/launcher/src/main.rs

158 lines
4.3 KiB

4 years ago
#[macro_use]
extern crate log;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use clappconfig::{AppConfig, clap};
use clappconfig::clap::ArgMatches;
use serde::{Deserialize, Serialize};
4 years ago
use crsn::asm::data::literal::Addr;
use crsn::module::OpTrait;
use crsn::runtime::run_thread::{RunThread, ThreadToken};
use crsn_arith::ArithOps;
use crsn_screen::ScreenOps;
use crsn_stacks::StackOps;
mod read_file;
mod serde_duration_millis;
#[derive(Debug, Clone, Serialize, Deserialize)]
struct LogConfig {
level: String,
modules: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
struct Config {
log: LogConfig,
#[serde(skip)]
program_file: String,
#[serde(skip)]
asm_only: bool,
#[serde(with = "serde_duration_millis")]
cycle_time: Duration,
}
impl Default for Config {
fn default() -> Self {
Self {
log: LogConfig {
level: "info".to_string(),
modules: Default::default(),
},
program_file: "".to_string(),
asm_only: false,
cycle_time: Duration::default(),
}
}
}
impl AppConfig for Config {
type Init = Self;
fn logging(&self) -> &str {
&self.log.level
}
fn logging_mod_levels(&self) -> Option<&HashMap<String, String>> {
Some(&self.log.modules)
}
/// Add args to later use in the `configure` method.
fn add_args<'a: 'b, 'b>(clap: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
// Default impl
clap
.arg(
clap::Arg::with_name("input")
.value_name("FILE")
.help("Program to run")
.required_unless("default-config")
.takes_value(true),
)
.arg(
clap::Arg::with_name("asm-only")
.short("P")
.long("asm")
.help("Only assemble, do not run."),
)
.arg(
clap::Arg::with_name("cycle")
.long("cycle")
.short("C")
.value_name("MILLIS")
.help("Cycle time (ms)")
.validator(|s| {
let t = s.trim();
if t.is_empty() {
Err("cycle time requires an argument".into())
} else {
if t.chars()
.find(|c| !c.is_ascii_digit())
.is_some() {
Err("cycle time requires an integer number".into())
} else {
Ok(())
}
}
})
.takes_value(true),
)
}
fn configure(mut self, clap: &ArgMatches) -> anyhow::Result<Self> {
self.program_file = clap.value_of("input").unwrap().to_string();
self.asm_only = clap.is_present("asm-only");
if let Some(c) = clap.value_of("cycle") {
self.cycle_time = Duration::from_millis(c.parse().unwrap());
}
Ok(self)
}
}
fn main() -> anyhow::Result<()> {
let config = Config::init("crsn", "crsn.json5", env!("CARGO_PKG_VERSION"))?;
info!("Loading {}", config.program_file);
let source = read_file::read_file(&config.program_file)?;
4 years ago
let parsers = Arc::new(vec![
ArithOps::new(),
StackOps::new(),
ScreenOps::new(),
]);
let parsed = crsn::asm::assemble(&source, parsers)?;
4 years ago
if config.asm_only {
for (n, op) in parsed.ops.iter().enumerate() {
println!("{:04} : {}", n, op.to_sexp());
}
return Ok(());
} else {
trace!("--- Compiled program ---");
for (n, op) in parsed.ops.iter().enumerate() {
trace!("{:04} : {}", n, op.to_sexp());
}
trace!("------------------------");
}
info!("Start runtime");
let args = &[];
let mut thread = RunThread::new(ThreadToken(0), None, parsed.clone(), Addr(0), args);
thread.set_speed(config.cycle_time);
// run without spawning, so it is on the main thread - required by some extensions
thread.run();
info!("Runtime shut down.");
4 years ago
Ok(())
4 years ago
}