ppc750cl/genisa/src/isa.rs

417 lines
11 KiB
Rust

use std::collections::HashMap;
use std::{fs::File, path::Path, str::FromStr};
use anyhow::{Context, Result};
use num_traits::PrimInt;
use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, ToTokens};
use serde::{Deserialize, Deserializer, Serialize};
pub fn load_isa(path: &Path) -> Result<Isa> {
let yaml_file =
File::open(path).with_context(|| format!("Failed to open file {}", path.display()))?;
let isa: Isa = serde_yaml::from_reader(yaml_file)
.with_context(|| format!("While parsing file {}", path.display()))?;
Ok(isa)
}
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
#[serde(default)]
pub struct Isa {
pub fields: Vec<Field>,
pub modifiers: Vec<Modifier>,
pub opcodes: Vec<Opcode>,
pub mnemonics: Vec<Mnemonic>,
}
impl Isa {
pub fn find_field(&self, name: &str) -> Option<&Field> {
self.fields.iter().find(|f| f.name == name)
}
pub fn find_modifier(&self, name: &str) -> Option<&Modifier> {
self.modifiers.iter().find(|m| m.name == name)
}
pub fn find_opcode(&self, name: &str) -> Option<&Opcode> {
self.opcodes.iter().find(|o| o.name == name)
}
}
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
#[serde(default)]
pub struct Field {
pub name: String,
pub desc: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub bits: Option<BitRange>,
pub signed: bool,
pub split: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub arg: Option<String>,
pub shift_left: u8,
}
impl Field {
/// Calculate the field mask from its bit range
pub fn mask(&self) -> u32 {
self.bits.map(|b| b.mask()).unwrap_or(0)
}
/// Shift and mask a value according to the field
pub fn shift_value(&self, mut value: u32) -> u32 {
if self.split {
// Swap 5-bit halves (SPR, TBR)
value = ((value & 0b11111_00000u32) >> 5) | ((value & 0b00000_11111u32) << 5);
}
self.bits.map(|b| b.shift_value(value >> self.shift_left)).unwrap_or(0)
}
pub fn ident(&self) -> Ident {
format_ident!("field_{}", to_ident(&self.name))
}
pub fn doc(&self) -> String {
if self.desc.is_empty() {
format!(" {}", self.name)
} else {
format!(" {}: {}", self.name, self.desc)
}
}
}
impl ToTokens for Field {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.ident().to_tokens(tokens)
}
}
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
#[serde(default)]
pub struct Opcode {
pub name: String,
pub desc: String,
pub bitmask: u32,
pub pattern: u32,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub modifiers: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub args: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub defs: Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub uses: Vec<String>,
}
impl Opcode {
/// Calculate the opcode mask from its fields and modifiers
pub fn mask(&self, isa: &Isa) -> u32 {
let mut calc_bitmask = 0u32;
for arg_n in &self.args {
let Some(field) = isa.find_field(arg_n) else {
continue;
};
calc_bitmask |= field.mask();
}
for modifier_n in &self.modifiers {
let Some(modifier) = isa.find_modifier(modifier_n) else {
continue;
};
calc_bitmask |= modifier.mask();
}
!calc_bitmask
}
pub fn ident(&self) -> Ident {
Ident::new(&to_ident(&self.name), Span::call_site())
}
pub fn variant(&self) -> Ident {
Ident::new(&to_variant(&self.name), Span::call_site())
}
pub fn doc(&self) -> String {
if self.desc.is_empty() {
format!(" {}", self.name)
} else {
format!(" {}: {}", self.name, self.desc)
}
}
}
impl ToTokens for Opcode {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.ident().to_tokens(tokens)
}
}
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
#[serde(default)]
pub struct Mnemonic {
pub name: String,
pub desc: String,
pub opcode: String,
#[serde(skip_serializing_if = "Option::is_none")]
// Overrides modifier list from opcode
pub modifiers: Option<Vec<String>>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub args: Vec<String>,
pub condition: String,
#[serde(skip_serializing_if = "HashMap::is_empty")]
pub replace: HashMap<String, String>,
#[serde(skip_serializing_if = "HashMap::is_empty")]
pub replace_assemble: HashMap<String, String>,
}
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
#[serde(default)]
pub struct Modifier {
pub name: String,
pub desc: String,
pub suffix: char,
pub bit: u8,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub defs: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub condition: Option<String>,
}
impl Modifier {
/// Calculate the modifier mask from its bit
pub fn mask(&self) -> u32 {
1 << (31 - self.bit)
}
pub fn ident(&self) -> Ident {
format_ident!("field_{}", to_ident(&self.name))
}
pub fn doc(&self) -> String {
if self.desc.is_empty() {
format!(" {}", self.name)
} else {
format!(" {}: {}", self.name, self.desc)
}
}
}
impl ToTokens for Modifier {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.ident().to_tokens(tokens)
}
}
/// A collection of modifiers
type Modifiers<'a> = Vec<&'a Modifier>;
/// Whether a collection of modifiers is valid (all bits are unique)
pub fn modifiers_valid(modifiers: &Modifiers) -> bool {
let bits = modifiers.iter().map(|m| m.bit).collect::<Vec<_>>();
bits.iter().all(|&b| bits.iter().filter(|&&x| x == b).count() == 1)
}
/// Iterate over all possible combinations of modifiers
pub fn modifiers_iter<'a>(
modifiers: &'a [String],
isa: &'a Isa,
) -> impl Iterator<Item = Modifiers<'a>> {
(0..=(1 << modifiers.len()) - 1).map(move |b| {
modifiers
.iter()
.enumerate()
.filter(|(i, _)| b & (1 << i) != 0)
.map(|(_, m)| isa.find_modifier(m).unwrap())
.collect::<Vec<_>>()
})
}
#[derive(Copy, Clone, Debug, Default)]
pub struct BitRange(pub (u8, u8));
impl BitRange {
#[inline]
pub fn new(start: u8, end: u8) -> Self {
Self((start, end))
}
#[inline]
pub fn start(&self) -> u8 {
self.0 .0
}
#[inline]
pub fn end(&self) -> u8 {
self.0 .1
}
/// Calculate the mask from the range
#[inline]
pub fn mask(&self) -> u32 {
self.max_value() << self.shift()
}
/// Number of bits to shift
#[inline]
pub fn shift(&self) -> u8 {
32 - self.end()
}
/// Number of bits in the range
#[inline]
pub fn len(&self) -> u8 {
self.end() - self.start()
}
/// Shift and mask a value according to the range
#[inline]
pub fn shift_value(&self, value: u32) -> u32 {
(value & self.max_value()) << self.shift()
}
/// Calculate the maximum value that can be represented by the range
#[inline]
pub fn max_value(&self) -> u32 {
(1 << self.len()) - 1
}
}
impl<'de> Deserialize<'de> for BitRange {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let range_str: String = Deserialize::deserialize(deserializer)?;
if let Some((start_str, end_str)) = range_str.split_once("..") {
let start = start_str.parse::<u8>().map_err(serde::de::Error::custom)?;
let end = end_str.parse::<u8>().map_err(serde::de::Error::custom)?;
Ok(Self::new(start, end))
} else {
let bit_idx = range_str.parse::<u8>().map_err(serde::de::Error::custom)?;
Ok(Self::new(bit_idx, bit_idx))
}
}
}
impl Serialize for BitRange {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if self.start() == self.end() {
self.start().serialize(serializer)
} else {
format!("{}..{}", self.start(), self.end()).serialize(serializer)
}
}
}
pub fn to_ident(key: &str) -> String {
key.to_ascii_lowercase().replace('.', "_").replace('+', "p").replace('-', "m")
}
pub fn to_variant(key: &str) -> String {
let mut s = String::new();
let mut chars = key.chars();
loop {
// Make first char uppercase.
let c = match chars.next() {
None => return s,
Some(c) => c,
};
s.push(match c {
'a'..='z' => c.to_ascii_uppercase(),
'A'..='Z' => c,
_ => panic!("invalid identifier: {}", key),
});
loop {
let c = match chars.next() {
None => return s,
Some(c) => c,
};
match c.to_ascii_lowercase() {
'0'..='9' | 'a'..='z' => s.push(c),
'_' => break,
'.' => {
s.push('_');
break;
}
_ => panic!("invalid character in variant: {}", key),
}
}
}
}
/// Parse an unsigned number in decimal, binary, or hexadecimal format.
pub fn parse_unsigned(mask: &str) -> Result<u32, std::num::ParseIntError> {
if let Some(mask) = mask.strip_prefix("0b") {
u32::from_str_radix(mask, 2)
} else if let Some(mask) = mask.strip_prefix("0x") {
u32::from_str_radix(mask, 16)
} else {
mask.parse::<u32>()
}
}
/// Parse a signed number in decimal, binary, or hexadecimal format.
pub fn parse_signed(mask: &str) -> Result<i32, std::num::ParseIntError> {
if let Some(mask) = mask.strip_prefix('-') {
if let Some(mask) = mask.strip_prefix("0b") {
i32::from_str_radix(mask, 2).map(|n| -n)
} else if let Some(mask) = mask.strip_prefix("0x") {
i32::from_str_radix(mask, 16).map(|n| -n)
} else {
mask.parse::<i32>().map(|n| -n)
}
} else {
parse_unsigned(mask).map(|n| n as i32)
}
}
pub struct HexLiteral<T>(pub T);
impl<T> std::fmt::LowerHex for HexLiteral<T>
where
T: std::fmt::LowerHex,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::LowerHex::fmt(&self.0, f)
}
}
impl<T> ToTokens for HexLiteral<T>
where
T: std::fmt::LowerHex,
{
fn to_tokens(&self, tokens: &mut TokenStream) {
let s = format!("{:#x}", self);
tokens.extend(TokenStream::from_str(&s).unwrap());
}
}
pub struct SignedHexLiteral<T>(pub T);
impl<T> std::fmt::LowerHex for SignedHexLiteral<T>
where
T: PrimInt + std::fmt::LowerHex,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.0 < T::zero() {
write!(f, "-")?;
let int = self.0.to_i64().unwrap_or_default();
std::fmt::LowerHex::fmt(&-int, f)
} else {
std::fmt::LowerHex::fmt(&self.0, f)
}
}
}
impl<T> ToTokens for SignedHexLiteral<T>
where
T: PrimInt + std::fmt::LowerHex,
{
fn to_tokens(&self, tokens: &mut TokenStream) {
let s = format!("{:#x}", self);
tokens.extend(TokenStream::from_str(&s).unwrap());
}
}