forked from MightyPork/crsn
7 changed files with 255 additions and 1 deletions
@ -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