forked from MightyPork/crsn
parent
4cf24f0382
commit
7efa04054c
@ -0,0 +1,21 @@ |
||||
[package] |
||||
name = "launcher_nox" |
||||
version = "0.1.0" |
||||
authors = ["Ondřej Hruška <ondra@ondrovo.com>"] |
||||
edition = "2018" |
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||
|
||||
[dependencies] |
||||
crsn = { path = "../crsn" } |
||||
crsn_arith = { path = "../crsn_arith" } |
||||
crsn_buf = { path = "../crsn_buf" } |
||||
crsn_stdio = { path = "../crsn_stdio" } |
||||
|
||||
simple_logger = "1.9.0" |
||||
log = "0.4.11" |
||||
thiserror = "1.0.20" |
||||
anyhow = "1.0.32" |
||||
clappconfig = "0.4.0" |
||||
|
||||
serde = { version = "1.0.116", features = ["derive"] } |
@ -0,0 +1,172 @@ |
||||
#[macro_use] |
||||
extern crate log; |
||||
|
||||
use std::collections::HashMap; |
||||
|
||||
use std::time::Duration; |
||||
|
||||
use clappconfig::{AppConfig, clap}; |
||||
use clappconfig::clap::ArgMatches; |
||||
use serde::{Deserialize, Serialize}; |
||||
|
||||
use crsn::asm::data::literal::Addr; |
||||
use crsn::module::{OpTrait, CrsnUniq}; |
||||
use crsn::runtime::run_thread::{RunThread, ThreadToken, ThreadParams}; |
||||
use crsn_arith::ArithOps; |
||||
use crsn_stdio::StdioOps; |
||||
use crsn_buf::BufOps; |
||||
|
||||
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)] |
||||
assemble_only: bool, |
||||
#[serde(with = "serde_duration_millis")] |
||||
cycle_time: Duration, |
||||
} |
||||
|
||||
impl Default for Config { |
||||
fn default() -> Self { |
||||
Self { |
||||
log: LogConfig { |
||||
level: "warn".to_string(), |
||||
modules: Default::default(), |
||||
}, |
||||
program_file: "".to_string(), |
||||
assemble_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) |
||||
} |
||||
|
||||
fn pre_log_println(_message: String) { |
||||
// shut up
|
||||
} |
||||
|
||||
fn print_banner(_name: &str, _version: &str) { |
||||
// No banner
|
||||
} |
||||
|
||||
/// 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("MICROS") |
||||
.help("Cycle time (us, append \"s\" or \"ms\" for coarser time)") |
||||
.takes_value(true), |
||||
) |
||||
} |
||||
|
||||
fn configure(mut self, clap: &ArgMatches) -> anyhow::Result<Self> { |
||||
self.program_file = clap.value_of("input").unwrap().to_string(); |
||||
self.assemble_only = clap.is_present("asm-only"); |
||||
if let Some(t) = clap.value_of("cycle") { |
||||
let (t, mul) = if t.ends_with("us") { |
||||
(&t[..(t.len()-2)], 1) |
||||
} else if t.ends_with("ms") { |
||||
(&t[..(t.len()-2)], 1000) |
||||
} else if t.ends_with("m") { |
||||
(&t[..(t.len()-1)], 1000) |
||||
} else if t.ends_with("u") { |
||||
(&t[..(t.len()-1)], 1) |
||||
} else if t.ends_with("s") { |
||||
(&t[..(t.len()-1)], 1000_000) |
||||
} else { |
||||
(t, 1) |
||||
}; |
||||
|
||||
self.cycle_time = Duration::from_micros(t.parse::<u64>().expect("parse -C value") * mul); |
||||
println!("ct = {:?}", self.cycle_time); |
||||
} |
||||
Ok(self) |
||||
} |
||||
} |
||||
|
||||
|
||||
fn main() -> anyhow::Result<()> { |
||||
let config = Config::init("crsn", "crsn.json5", env!("CARGO_PKG_VERSION"))?; |
||||
|
||||
debug!("Loading {}", config.program_file); |
||||
|
||||
let source = read_file::read_file(&config.program_file)?; |
||||
|
||||
let uniq = CrsnUniq::new(); |
||||
|
||||
let parsed = crsn::asm::assemble(&source, &uniq, vec![ |
||||
ArithOps::new(), |
||||
BufOps::new(), |
||||
StdioOps::new(), |
||||
])?; |
||||
|
||||
if config.assemble_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!("------------------------"); |
||||
} |
||||
|
||||
debug!("Start runtime"); |
||||
|
||||
let args = &[]; |
||||
let thread = RunThread::new(ThreadParams { |
||||
id: ThreadToken(0), |
||||
uniq, |
||||
program: parsed, |
||||
pc: Addr(0), |
||||
cycle_time: config.cycle_time, |
||||
args |
||||
}); |
||||
|
||||
// run without spawning, so it is on the main thread - required by some extensions
|
||||
thread.run(); |
||||
|
||||
debug!("Runtime shut down."); |
||||
|
||||
Ok(()) |
||||
} |
@ -0,0 +1,14 @@ |
||||
use std::fs::File; |
||||
use std::io; |
||||
use std::io::Read; |
||||
use std::path::Path; |
||||
|
||||
/// Read a file to string
|
||||
pub fn read_file<P: AsRef<Path>>(path: P) -> io::Result<String> { |
||||
let path = path.as_ref(); |
||||
let mut file = File::open(path)?; |
||||
|
||||
let mut buf = String::new(); |
||||
file.read_to_string(&mut buf)?; |
||||
Ok(buf) |
||||
} |
@ -0,0 +1,18 @@ |
||||
use std::time::Duration; |
||||
|
||||
use serde::{self, Deserialize, Deserializer, Serializer}; |
||||
|
||||
pub fn serialize<S>(value: &Duration, se: S) -> Result<S::Ok, S::Error> |
||||
where |
||||
S: Serializer, |
||||
{ |
||||
se.serialize_u64(value.as_secs() * 1000 + value.subsec_millis() as u64) |
||||
} |
||||
|
||||
pub fn deserialize<'de, D>(de: D) -> Result<Duration, D::Error> |
||||
where |
||||
D: Deserializer<'de>, |
||||
{ |
||||
let s: u64 = u64::deserialize(de)?; |
||||
Ok(Duration::from_millis(s)) |
||||
} |
Loading…
Reference in new issue