Some scaffolding for an assembler (bad)
This commit is contained in:
parent
9ae36eef34
commit
3af08db591
|
@ -276,6 +276,44 @@ dependencies = [
|
|||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_codegen"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770"
|
||||
dependencies = [
|
||||
"phf_generator",
|
||||
"phf_shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_generator"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf"
|
||||
dependencies = [
|
||||
"phf_shared",
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "phf_shared"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676"
|
||||
dependencies = [
|
||||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppc750cl"
|
||||
version = "0.2.0"
|
||||
|
@ -284,6 +322,13 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppc750cl-asm"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"phf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppc750cl-flow-graph"
|
||||
version = "0.2.0"
|
||||
|
@ -310,6 +355,9 @@ name = "ppc750cl-genisa"
|
|||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"phf",
|
||||
"phf_codegen",
|
||||
"pratt",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
|
@ -340,6 +388,12 @@ version = "0.2.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "pratt"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17e0a4425d076f0718b820673a38fbf3747080c61017eeb0dd79bc7e472b8bb8"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.37"
|
||||
|
@ -511,6 +565,12 @@ dependencies = [
|
|||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.8.0"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
[workspace]
|
||||
members = [
|
||||
"asm",
|
||||
"disasm",
|
||||
"disasm-py",
|
||||
"dol",
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "ppc750cl-asm"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
license = "GPL-3.0-or-later"
|
||||
description = "Assembler for PowerPC 750CL"
|
||||
keywords = ["powerpc", "wii", "gamecube"]
|
||||
repository = "https://github.com/encounter/ppc750cl"
|
||||
|
||||
[dependencies]
|
||||
phf = "0.11.1"
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,8 @@
|
|||
mod generated;
|
||||
|
||||
pub mod prelude {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
}
|
|
@ -15,3 +15,7 @@ quote = "1.0"
|
|||
syn = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_yaml = "0.8"
|
||||
phf = "0.11.1"
|
||||
phf_codegen = "0.11.1"
|
||||
pratt = "0.4.0"
|
||||
|
||||
|
|
|
@ -0,0 +1,483 @@
|
|||
use std::{
|
||||
collections::{hash_map::Entry, HashMap},
|
||||
fs::File,
|
||||
io::Write,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use pratt::{Affix, Associativity, PrattParser, Precedence, Result as PrattResult};
|
||||
use proc_macro2::{token_stream, Ident, Literal, Spacing, Span, TokenStream, TokenTree};
|
||||
use quote::{__private::ext::RepToTokensExt, quote, ToTokens};
|
||||
use syn::{parse::Parser, LitInt};
|
||||
|
||||
use crate::{load_isa, rustfmt, to_rust_variant, Field, Isa, Modifier, Opcode};
|
||||
|
||||
type Error = Box<dyn std::error::Error>;
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
macro_rules! token_stream {
|
||||
($stream:ident) => {
|
||||
TokenStream::from_iter($stream.into_iter())
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn asm_main() -> Result<()> {
|
||||
let isa = load_isa()?;
|
||||
|
||||
let mut unformatted_code = Vec::<u8>::new();
|
||||
writeln!(&mut unformatted_code, "{}", quote! {
|
||||
use crate::prelude::*;
|
||||
})?;
|
||||
writeln!(&mut unformatted_code, "{}", gen_fields(&isa)?)?;
|
||||
writeln!(&mut unformatted_code, "{}", gen_opcode_from_str(&isa)?)?;
|
||||
|
||||
let formatted_code = rustfmt(unformatted_code);
|
||||
File::create("./asm/src/generated.rs")?.write_all(&formatted_code)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn gen_apply_field(field: &Field) -> Result<TokenStream> {
|
||||
let mut val = quote! { value as u32 };
|
||||
|
||||
let val_shift = field.shift_left;
|
||||
if field.shift_left > 0 {
|
||||
val = quote!((#val >> #val_shift));
|
||||
}
|
||||
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend
|
||||
if field.signed {
|
||||
// let mask2 = 1u32 << (self.bits.0.len() - 1);
|
||||
// let mask2 = LitInt::new(&format!("0x{:x}", mask2), Span::call_site());
|
||||
// val = quote!((((#val ^ #mask2).wrapping_sub(#mask2)) as i32))
|
||||
} else {
|
||||
// val = quote! { #val };
|
||||
}
|
||||
|
||||
if field.split {
|
||||
val = quote!((((#val & 0b11111_00000u32) >> 5u32) | ((#val & 0b00000_11111u32) << 5u32)) as u32);
|
||||
}
|
||||
|
||||
let mask = (1u32 << field.bits.0.len()) - 1;
|
||||
if mask != 0xFFFF_FFFF {
|
||||
let mask = LitInt::new(&format!("0x{:x}", mask), Span::call_site());
|
||||
val = quote!((#val & #mask));
|
||||
}
|
||||
|
||||
let shift = 32 - field.bits.0.end;
|
||||
if shift > 0 {
|
||||
val = quote!((#val << #shift));
|
||||
}
|
||||
|
||||
let ident = to_rust_variant(&field.name)?;
|
||||
Ok(quote! {
|
||||
Field::#ident => code | #val,
|
||||
})
|
||||
}
|
||||
|
||||
fn gen_fields(isa: &Isa) -> Result<TokenStream> {
|
||||
let fields = TokenStream::from_iter(
|
||||
isa.fields
|
||||
.iter()
|
||||
.filter(|field| !field.bits.0.is_empty())
|
||||
.map(|field| -> Result<TokenStream> {
|
||||
let ident = to_rust_variant(field.name.as_str())?;
|
||||
Ok(quote! { #ident, })
|
||||
})
|
||||
.try_collect::<TokenStream>()?,
|
||||
);
|
||||
let field_match = TokenStream::from_iter(
|
||||
isa.fields
|
||||
.iter()
|
||||
.filter(|field| !field.bits.0.is_empty())
|
||||
.map(|field| gen_apply_field(field))
|
||||
.try_collect::<TokenStream>()?,
|
||||
);
|
||||
return Ok(quote! {
|
||||
pub enum Field {
|
||||
#fields
|
||||
}
|
||||
pub const fn apply_field(code: u32, field: Field, value: i32) -> u32 {
|
||||
match field {
|
||||
#field_match
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_gpr() {
|
||||
assert_eq!(parse_gpr("r0").unwrap(), (0, ""));
|
||||
assert_eq!(parse_gpr("r31").unwrap(), (31, ""));
|
||||
assert_eq!(parse_gpr("1234").unwrap(), (1234, ""));
|
||||
}
|
||||
}
|
||||
|
||||
struct OpcodeInfo {
|
||||
code: u32,
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
fn gen_opcode_from_str(isa: &Isa) -> Result<TokenStream> {
|
||||
let mut map_builder = phf_codegen::Map::<String>::new();
|
||||
let mut opcode_map = HashMap::<String, Vec<Option<OpcodeInfo>>>::new();
|
||||
for opcode in &isa.opcodes {
|
||||
let mut modifiers = Vec::<Modifier>::with_capacity(opcode.modifiers.len());
|
||||
for modifier_name in &opcode.modifiers {
|
||||
modifiers.push(match isa.modifiers.iter().find(|m| m.name == *modifier_name) {
|
||||
Some(modifier) => modifier.clone(),
|
||||
None => return Err(Error::from(format!("Modifier {} not found", modifier_name))),
|
||||
});
|
||||
}
|
||||
'outer: for bits in 0..(1 << modifiers.len()) {
|
||||
let mut suffix = String::new();
|
||||
let mut set_bits = 0u32;
|
||||
for (idx, modifier) in modifiers.iter().enumerate() {
|
||||
if bits & (1 << idx) != 0 {
|
||||
if set_bits & (1 << modifier.bit) != 0 {
|
||||
// Incompatible combination
|
||||
continue 'outer;
|
||||
}
|
||||
set_bits |= 1 << modifier.bit;
|
||||
suffix.push(modifier.suffix);
|
||||
}
|
||||
}
|
||||
let name = format!("{}{}", opcode.name, suffix);
|
||||
let info = OpcodeInfo { code: opcode.pattern, args: opcode.args.clone() };
|
||||
match opcode_map.entry(name) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
let vec = entry.get_mut();
|
||||
if vec.len() < opcode.args.len() + 1 {
|
||||
vec.resize_with(opcode.args.len() + 1, || None);
|
||||
}
|
||||
vec[opcode.args.len()] = Some(info);
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
let mut vec = Vec::<Option<OpcodeInfo>>::new();
|
||||
vec.resize_with(opcode.args.len() + 1, || None);
|
||||
vec[opcode.args.len()] = Some(info);
|
||||
entry.insert(vec);
|
||||
}
|
||||
}
|
||||
// println!("Adding opcode {}", name);
|
||||
// let quoted_name = format!("\"{}\"", name);
|
||||
// map_builder.entry(name, quoted_name.as_str());
|
||||
}
|
||||
}
|
||||
for mnemonic in &isa.mnemonics {
|
||||
let opcode = isa.opcodes.iter().find(|o| o.name == mnemonic.opcode).ok_or_else(|| {
|
||||
Error::from(format!("Opcode {} not found for {}", mnemonic.opcode, mnemonic.name))
|
||||
})?;
|
||||
let modifier_names = mnemonic.modifiers.as_ref().unwrap_or(&opcode.modifiers);
|
||||
let mut modifiers = Vec::<Modifier>::with_capacity(modifier_names.len());
|
||||
for modifier_name in modifier_names {
|
||||
modifiers.push(match isa.modifiers.iter().find(|m| m.name == *modifier_name) {
|
||||
Some(modifier) => modifier.clone(),
|
||||
None => return Err(Error::from(format!("Modifier {} not found", modifier_name))),
|
||||
});
|
||||
}
|
||||
'outer: for bits in 0..(1 << modifiers.len()) {
|
||||
let mut suffix = String::new();
|
||||
let mut set_bits = 0u32;
|
||||
for (idx, modifier) in modifiers.iter().enumerate() {
|
||||
if bits & (1 << idx) != 0 {
|
||||
if set_bits & (1 << modifier.bit) != 0 {
|
||||
// Incompatible combination
|
||||
continue 'outer;
|
||||
}
|
||||
set_bits |= 1 << modifier.bit;
|
||||
suffix.push(modifier.suffix);
|
||||
}
|
||||
}
|
||||
let name = format!("{}{}", mnemonic.name, suffix);
|
||||
let mut code = opcode.pattern;
|
||||
{
|
||||
let tokens: TokenStream = mnemonic.condition.parse()?;
|
||||
let mut iter = tokens.into_iter();
|
||||
let mut vec = Vec::<ParsedToken>::new();
|
||||
loop {
|
||||
match parse_token(&mut iter) {
|
||||
Some(token) => vec.push(token),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
let expr = ExprParser.parse(vec.into_iter()).unwrap();
|
||||
match apply_expr(code, expr, isa)? {
|
||||
ExprResult::Int(out) => {
|
||||
code = out;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
// for arg in mnemonic.args {
|
||||
// code = apply_field(code, )
|
||||
// }
|
||||
let info = OpcodeInfo { code, args: mnemonic.args.clone() };
|
||||
match opcode_map.entry(name) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
let vec = entry.get_mut();
|
||||
if vec.len() < mnemonic.args.len() + 1 {
|
||||
vec.resize_with(mnemonic.args.len() + 1, || None);
|
||||
}
|
||||
vec[mnemonic.args.len()] = Some(info);
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
let mut vec = Vec::<Option<OpcodeInfo>>::new();
|
||||
vec.resize_with(mnemonic.args.len() + 1, || None);
|
||||
vec[mnemonic.args.len()] = Some(info);
|
||||
entry.insert(vec);
|
||||
}
|
||||
}
|
||||
// println!("Adding mnemonic {}", name);
|
||||
// let quoted_name = format!("\"{}\"", name);
|
||||
// map_builder.entry(name, quoted_name.as_str());
|
||||
}
|
||||
}
|
||||
for (name, infos) in opcode_map {
|
||||
let opcodes = TokenStream::from_iter(infos.iter().map(|info| {
|
||||
if let Some(info) = info {
|
||||
let code = LitInt::new(&format!("0x{:x}", info.code), Span::call_site());
|
||||
let args = TokenStream::from_iter(info.args.iter().map(|arg| {
|
||||
let arg_s = arg.split_once('=').map(|(first, _)| first).unwrap_or(arg);
|
||||
let ident = to_rust_variant(arg_s).unwrap();
|
||||
quote! { Field::#ident, }
|
||||
}));
|
||||
quote! {
|
||||
Some(OpcodeInfo {
|
||||
code: #code,
|
||||
args: &[ #args ],
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
quote! { None, }
|
||||
}
|
||||
}));
|
||||
map_builder.entry(name, quote! { &[#opcodes] }.to_string().as_str());
|
||||
}
|
||||
let map: TokenStream = map_builder.build().to_string().parse()?;
|
||||
return Ok(quote! {
|
||||
struct OpcodeInfo {
|
||||
code: u32,
|
||||
args: &'static [Field],
|
||||
}
|
||||
static OPCODES: phf::Map<&'static str, &'static [Option<OpcodeInfo>]> = #map;
|
||||
fn opcode_from_str(str: &str) -> Option<&'static [Option<OpcodeInfo>]> {
|
||||
OPCODES.get(str).map(|x| *x)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn apply_field(code: u32, field: &Field, value: i32) -> u32 {
|
||||
let mut val = value as u32;
|
||||
|
||||
let val_shift = field.shift_left;
|
||||
if field.shift_left > 0 {
|
||||
val = val >> val_shift;
|
||||
}
|
||||
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html#VariableSignExtend
|
||||
if field.signed {
|
||||
// let mask2 = 1u32 << (self.bits.0.len() - 1);
|
||||
// let mask2 = LitInt::new(&format!("0x{:x}", mask2), Span::call_site());
|
||||
// val = quote!((((#val ^ #mask2).wrapping_sub(#mask2)) as i32))
|
||||
} else {
|
||||
// val = quote! { #val };
|
||||
}
|
||||
|
||||
if field.split {
|
||||
val = (((val & 0b11111_00000u32) >> 5u32) | ((val & 0b00000_11111u32) << 5u32)) as u32;
|
||||
}
|
||||
|
||||
let mask = (1u32 << field.bits.0.len()) - 1;
|
||||
if mask != 0xFFFF_FFFF {
|
||||
val = val & mask;
|
||||
}
|
||||
|
||||
let shift = 32 - field.bits.0.end;
|
||||
if shift > 0 {
|
||||
val = val << shift;
|
||||
}
|
||||
|
||||
code | val
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum Operator {
|
||||
BitAnd,
|
||||
LogicalAnd,
|
||||
Equal,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ParsedToken {
|
||||
Ident(Ident),
|
||||
Group(Vec<ParsedToken>),
|
||||
Literal(Literal),
|
||||
Operator(Operator),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Expr {
|
||||
BinOp(Box<Expr>, BinOpKind, Box<Expr>),
|
||||
// UnOp(UnOpKind, Box<Expr>),
|
||||
Literal(Literal),
|
||||
Ident(Ident),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BinOpKind {
|
||||
// &
|
||||
BitAnd,
|
||||
// &&
|
||||
LogicalAnd,
|
||||
// ==
|
||||
Eq,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UnOp {}
|
||||
|
||||
fn parse_token(iter: &mut token_stream::IntoIter) -> Option<ParsedToken> {
|
||||
match iter.next() {
|
||||
Some(TokenTree::Group(group)) => {
|
||||
let mut iter = group.stream().into_iter();
|
||||
let mut vec = Vec::<ParsedToken>::new();
|
||||
loop {
|
||||
match parse_token(&mut iter) {
|
||||
Some(token) => vec.push(token),
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
Some(ParsedToken::Group(vec))
|
||||
}
|
||||
Some(TokenTree::Punct(mut punct)) => {
|
||||
let mut str = String::new();
|
||||
str.push(punct.as_char());
|
||||
while punct.spacing() == Spacing::Joint {
|
||||
match iter.next() {
|
||||
Some(TokenTree::Punct(new_punct)) => {
|
||||
punct = new_punct;
|
||||
}
|
||||
token => panic!("unexpected token {:?}", token),
|
||||
}
|
||||
str.push(punct.as_char());
|
||||
}
|
||||
Some(ParsedToken::Operator(match str.as_str() {
|
||||
"&" => Operator::BitAnd,
|
||||
"&&" => Operator::LogicalAnd,
|
||||
"==" => Operator::Equal,
|
||||
op => todo!("operator {}", op),
|
||||
}))
|
||||
}
|
||||
Some(TokenTree::Ident(ident)) => Some(ParsedToken::Ident(ident)),
|
||||
Some(TokenTree::Literal(literal)) => Some(ParsedToken::Literal(literal)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
struct ExprParser;
|
||||
|
||||
impl<I> PrattParser<I> for ExprParser
|
||||
where I: Iterator<Item = ParsedToken>
|
||||
{
|
||||
type Error = pratt::NoError;
|
||||
type Input = ParsedToken;
|
||||
type Output = Expr;
|
||||
|
||||
fn query(&mut self, tree: &ParsedToken) -> PrattResult<Affix> {
|
||||
let affix = match tree {
|
||||
ParsedToken::Operator(Operator::BitAnd) => {
|
||||
Affix::Infix(Precedence(3), Associativity::Left)
|
||||
}
|
||||
ParsedToken::Operator(Operator::Equal) => {
|
||||
Affix::Infix(Precedence(2), Associativity::Left)
|
||||
}
|
||||
ParsedToken::Operator(Operator::LogicalAnd) => {
|
||||
Affix::Infix(Precedence(1), Associativity::Left)
|
||||
}
|
||||
ParsedToken::Group(_) | ParsedToken::Literal(_) | ParsedToken::Ident(_) => {
|
||||
Affix::Nilfix
|
||||
}
|
||||
};
|
||||
Ok(affix)
|
||||
}
|
||||
|
||||
// Construct a primary expression, e.g. a number
|
||||
fn primary(&mut self, tree: ParsedToken) -> PrattResult<Expr> {
|
||||
let expr = match tree {
|
||||
ParsedToken::Ident(num) => Expr::Ident(num),
|
||||
ParsedToken::Literal(literal) => Expr::Literal(literal),
|
||||
ParsedToken::Group(group) => self.parse(&mut group.into_iter()).unwrap(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
Ok(expr)
|
||||
}
|
||||
|
||||
// Construct a binary infix expression, e.g. 1+1
|
||||
fn infix(&mut self, lhs: Expr, tree: ParsedToken, rhs: Expr) -> PrattResult<Expr> {
|
||||
let op = match tree {
|
||||
ParsedToken::Operator(Operator::BitAnd) => BinOpKind::BitAnd,
|
||||
ParsedToken::Operator(Operator::LogicalAnd) => BinOpKind::LogicalAnd,
|
||||
ParsedToken::Operator(Operator::Equal) => BinOpKind::Eq,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
Ok(Expr::BinOp(Box::new(lhs), op, Box::new(rhs)))
|
||||
}
|
||||
|
||||
fn prefix(&mut self, _tree: ParsedToken, _rhs: Expr) -> PrattResult<Expr> { unreachable!() }
|
||||
|
||||
fn postfix(&mut self, _lhs: Expr, _tree: ParsedToken) -> PrattResult<Expr> { unreachable!() }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ExprResult {
|
||||
Int(u32),
|
||||
Ident(String),
|
||||
}
|
||||
|
||||
fn apply_expr(mut code: u32, expr: Expr, isa: &Isa) -> Result<ExprResult> {
|
||||
match expr {
|
||||
Expr::BinOp(lhs, kind, rhs) => match kind {
|
||||
BinOpKind::BitAnd => match *lhs {
|
||||
// ignoring rhs
|
||||
Expr::Ident(ident) => Ok(ExprResult::Ident(ident.to_string())),
|
||||
other => todo!("BitAnd {:?}", other),
|
||||
},
|
||||
BinOpKind::LogicalAnd => {
|
||||
code = match apply_expr(code, *lhs, isa)? {
|
||||
ExprResult::Int(code) => code,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
code = match apply_expr(code, *rhs, isa)? {
|
||||
ExprResult::Int(code) => code,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
Ok(ExprResult::Int(code))
|
||||
}
|
||||
BinOpKind::Eq => {
|
||||
let field_name = match apply_expr(code, *lhs, isa)? {
|
||||
ExprResult::Ident(ident) => ident,
|
||||
other => todo!("eq lhs {:?}", other),
|
||||
};
|
||||
let field = isa
|
||||
.fields
|
||||
.iter()
|
||||
.find(|field| field.name == field_name)
|
||||
.ok_or_else(|| Error::from(format!("Field {} not found", field_name)))?;
|
||||
let value = match apply_expr(code, *rhs, isa)? {
|
||||
ExprResult::Int(value) => value,
|
||||
// other => todo!("eq rhs {:?}", other),
|
||||
_ => return Ok(ExprResult::Int(code))
|
||||
};
|
||||
code = apply_field(code, field, value as i32);
|
||||
Ok(ExprResult::Int(code))
|
||||
}
|
||||
},
|
||||
Expr::Literal(lit) => Ok(ExprResult::Int(LitInt::from(lit).base10_parse()?)),
|
||||
Expr::Ident(id) => Ok(ExprResult::Ident(id.to_string())),
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
#![feature(iterator_try_collect)]
|
||||
|
||||
mod asm;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
@ -10,6 +14,7 @@ use proc_macro2::{Group, Ident, Literal, Span, TokenStream, TokenTree};
|
|||
use quote::quote;
|
||||
use serde::{Deserialize, Deserializer};
|
||||
use syn::{LitChar, LitInt, LitStr};
|
||||
use crate::asm::asm_main;
|
||||
|
||||
macro_rules! token_stream {
|
||||
($stream:ident) => {
|
||||
|
@ -22,6 +27,10 @@ fn main() {
|
|||
eprintln!("{}", err);
|
||||
std::process::exit(1);
|
||||
}
|
||||
// if let Err(err) = asm_main() {
|
||||
// eprintln!("{}", err);
|
||||
// std::process::exit(1);
|
||||
// }
|
||||
}
|
||||
|
||||
type Error = Box<dyn std::error::Error>;
|
||||
|
@ -238,7 +247,7 @@ pub(crate) struct Mnemonic {
|
|||
condition: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
#[derive(Deserialize, Default, Clone)]
|
||||
#[serde(default)]
|
||||
pub(crate) struct Modifier {
|
||||
name: String,
|
||||
|
@ -660,7 +669,7 @@ impl Isa {
|
|||
}
|
||||
|
||||
/// Converts the given key into an identifier.
|
||||
fn to_rust_ident(prefix: &str, key: &str) -> TokenTree {
|
||||
pub(crate) fn to_rust_ident(prefix: &str, key: &str) -> TokenTree {
|
||||
TokenTree::Ident(Ident::new(
|
||||
&(prefix.to_owned() + &key.replace('.', "_")),
|
||||
Span::call_site(),
|
||||
|
@ -668,7 +677,7 @@ fn to_rust_ident(prefix: &str, key: &str) -> TokenTree {
|
|||
}
|
||||
|
||||
/// Converts the given key into an enum variant key.
|
||||
fn to_rust_variant(key: &str) -> Result<TokenTree> {
|
||||
pub(crate) fn to_rust_variant(key: &str) -> Result<TokenTree> {
|
||||
Ok(TokenTree::Ident(Ident::new(
|
||||
&to_rust_variant_str(key)?,
|
||||
Span::call_site(),
|
||||
|
|
Loading…
Reference in New Issue