commit
93466defd0
6 changed files with 243 additions and 0 deletions
@ -0,0 +1,39 @@
|
||||
# This file is automatically @generated by Cargo. |
||||
# It is not intended for manual editing. |
||||
version = 3 |
||||
|
||||
[[package]] |
||||
name = "futilehdl" |
||||
version = "0.1.0" |
||||
dependencies = [ |
||||
"nom", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "memchr" |
||||
version = "2.4.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" |
||||
|
||||
[[package]] |
||||
name = "minimal-lexical" |
||||
version = "0.2.1" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" |
||||
|
||||
[[package]] |
||||
name = "nom" |
||||
version = "7.1.0" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" |
||||
dependencies = [ |
||||
"memchr", |
||||
"minimal-lexical", |
||||
"version_check", |
||||
] |
||||
|
||||
[[package]] |
||||
name = "version_check" |
||||
version = "0.9.4" |
||||
source = "registry+https://github.com/rust-lang/crates.io-index" |
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" |
@ -0,0 +1,9 @@
|
||||
[package] |
||||
name = "futilehdl" |
||||
version = "0.1.0" |
||||
edition = "2021" |
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html |
||||
|
||||
[dependencies] |
||||
nom = "7.1.0" |
@ -0,0 +1,4 @@
|
||||
module top ( input wire x, output wire y ) |
||||
{ |
||||
assign x = y; |
||||
} |
@ -0,0 +1,46 @@
|
||||
use nom::{ |
||||
bytes::complete::tag, |
||||
character::complete::{char, one_of}, |
||||
combinator::{map_res, recognize}, |
||||
multi::{many0, many1}, |
||||
sequence::{preceded, terminated}, |
||||
}; |
||||
|
||||
use crate::IResult; |
||||
|
||||
pub fn decimal(input: &str) -> IResult<&str, u64> { |
||||
map_res( |
||||
recognize(many1(terminated(one_of("0123456789"), many0(char('_'))))), |
||||
|out: &str| out.parse::<u64>(), |
||||
)(input) |
||||
} |
||||
|
||||
pub fn hexadecimal(input: &str) -> IResult<&str, u64> { |
||||
map_res( |
||||
preceded( |
||||
tag("h"), |
||||
recognize(many1(terminated( |
||||
one_of("0123456789abcdefABCDEF"), |
||||
many0(char('_')), |
||||
))), |
||||
), |
||||
|out: &str| u64::from_str_radix(&str::replace(&out, "_", ""), 16), |
||||
)(input) |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod test { |
||||
use super::*; |
||||
|
||||
#[test] |
||||
fn test_dec() { |
||||
assert_eq!(decimal("123").unwrap().1, 123); |
||||
assert_eq!(decimal("0123").unwrap().1, 123); |
||||
} |
||||
|
||||
#[test] |
||||
fn test_hex() { |
||||
assert_eq!(hexadecimal("hfF").unwrap().1, 0xff); |
||||
assert_eq!(hexadecimal("hF").unwrap().1, 0xf); |
||||
} |
||||
} |
@ -0,0 +1,144 @@
|
||||
mod literals; |
||||
|
||||
use nom::{ |
||||
self, |
||||
branch::alt, |
||||
bytes::complete::tag, |
||||
character::complete::{alpha1, alphanumeric1, char, multispace0}, |
||||
combinator::{map, opt, recognize}, |
||||
error::ParseError, |
||||
error::{context, convert_error, VerboseError}, |
||||
multi::{many0, separated_list1}, |
||||
sequence::{delimited, pair, preceded, terminated, tuple}, |
||||
}; |
||||
|
||||
use crate::literals::{decimal, hexadecimal}; |
||||
|
||||
const REG_EXAMPLE: &'static str = "reg [0:15] msg = 16'hAAAA;"; |
||||
|
||||
// custom IResult type for verboseerror
|
||||
pub type IResult<I, O, E = VerboseError<I>> = nom::IResult<I, O, E>; |
||||
|
||||
fn ws0<'a, F: 'a, O, E: ParseError<&'a str>>( |
||||
inner: F, |
||||
) -> impl FnMut(&'a str) -> IResult<&'a str, O, E> |
||||
where |
||||
F: FnMut(&'a str) -> IResult<&'a str, O, E>, |
||||
{ |
||||
delimited(multispace0, inner, multispace0) |
||||
} |
||||
fn identifier(input: &str) -> IResult<&str, &str> { |
||||
recognize(pair( |
||||
alt((alpha1, tag("_"))), |
||||
many0(alt((alphanumeric1, tag("_")))), |
||||
))(input) |
||||
} |
||||
|
||||
fn widthspec(input: &str) -> IResult<&str, u64> { |
||||
delimited(char('['), ws0(decimal), char(']'))(input) |
||||
} |
||||
|
||||
fn intliteral(input: &str) -> IResult<&str, (u64, u64)> { |
||||
tuple((terminated(decimal, char('\'')), alt((decimal, hexadecimal))))(input) |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
struct NetDecl { |
||||
name: String, |
||||
width: Option<u64>, |
||||
value: Option<(u64, u64)>, |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
enum PortDirection { |
||||
Input, |
||||
Output, |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
struct PortDecl { |
||||
direction: PortDirection, |
||||
net: NetDecl, |
||||
} |
||||
|
||||
#[derive(Debug)] |
||||
struct Module { |
||||
name: String, |
||||
ports: Vec<PortDecl>, |
||||
} |
||||
|
||||
fn declaration(i: &str) -> IResult<&str, NetDecl> { |
||||
let (i, (_, width, ident, value)) = tuple(( |
||||
ws0(alt((tag("reg"), tag("wire")))), |
||||
opt(ws0(widthspec)), |
||||
identifier, |
||||
opt(preceded(ws0(char('=')), intliteral)), |
||||
))(i)?; |
||||
Ok(( |
||||
i, |
||||
NetDecl { |
||||
name: ident.into(), |
||||
width, |
||||
value, |
||||
}, |
||||
)) |
||||
} |
||||
|
||||
fn port_decl(i: &str) -> IResult<&str, PortDecl> { |
||||
map( |
||||
tuple(( |
||||
alt(( |
||||
map(tag("input"), |_| PortDirection::Input), |
||||
map(tag("output"), |_| PortDirection::Output), |
||||
)), |
||||
declaration, |
||||
)), |
||||
|(direction, net)| PortDecl { direction, net }, |
||||
)(i) |
||||
} |
||||
|
||||
fn ports_list(input: &str) -> IResult<&str, Vec<PortDecl>> { |
||||
context( |
||||
"port declaration", |
||||
separated_list1(ws0(char(',')), ws0(port_decl)), |
||||
)(input) |
||||
} |
||||
|
||||
fn module(input: &str) -> IResult<&str, Module> { |
||||
context( |
||||
"module", |
||||
map( |
||||
tuple(( |
||||
tag("module"), |
||||
ws0(identifier), |
||||
ws0(delimited(char('('), ws0(ports_list), char(')'))), |
||||
)), |
||||
|(_, name, ports)| Module { |
||||
name: name.into(), |
||||
ports, |
||||
}, |
||||
), |
||||
)(input) |
||||
} |
||||
|
||||
fn main() { |
||||
let input = include_str!("../identity.fut"); |
||||
let parsed = module(input); |
||||
match parsed { |
||||
Err(nom::Err::Error(err) | nom::Err::Failure(err)) => { |
||||
print!("{}", convert_error(input, err)) |
||||
} |
||||
Err(_) => (), |
||||
Ok(res) => println!("{:#?}", res), |
||||
} |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod test { |
||||
use super::*; |
||||
|
||||
#[test] |
||||
fn test_decl() { |
||||
declaration("input reg abcd").unwrap(); |
||||
} |
||||
} |
Loading…
Reference in new issue