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