Skip to content
This repository was archived by the owner on Jul 6, 2019. It is now read-only.

Ioreg improvements #300

Merged
merged 3 commits into from
Jun 27, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions ioreg/src/builder/accessors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ impl<'a> node::RegVisitor for BuildAccessors<'a> {
let item = build_get_fn(self.cx, path, reg);
self.builder.push_item(item);
}
if fields.iter().any(|f| f.access != node::Access::ReadOnly) {
let item = build_ignoring_state_setter_fn(self.cx, path, reg);
self.builder.push_item(item);
}

for field in fields.iter() {
match build_field_accessors(self.cx, path, reg, field) {
Expand Down Expand Up @@ -121,6 +125,29 @@ fn build_get_fn(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg)
item.unwrap()
}

fn build_ignoring_state_setter_fn(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg)
-> P<ast::Item>
{
let reg_ty: P<ast::Ty> =
cx.ty_ident(reg.name.span, utils::path_ident(cx, path));
let setter_ty = utils::setter_name(cx, path);

let docstring = format!("Create new updater that ignores current value of the `{}` register",
reg.name.node);
let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

let item = quote_item!(cx,
impl $reg_ty {
$doc_attr
#[allow(dead_code)]
pub fn ignoring_state(&self) -> $setter_ty {
$setter_ty::new_ignoring_state(self)
}
}
);
item.unwrap()
}

fn build_field_set_fn(cx: &ExtCtxt, path: &Vec<String>,
reg: &node::Reg, field: &node::Field)
-> P<ast::ImplItem>
Expand Down
28 changes: 26 additions & 2 deletions ioreg/src/builder/setter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@ fn build_type(cx: &ExtCtxt, path: &Vec<String>,

let item = quote_item!(cx,
$doc_attr
#[allow(non_camel_case_types)]
#[allow(non_camel_case_types, dead_code)]
pub struct $name<'a> {
value: $packed_ty,
mask: $packed_ty,
write_only: bool,
reg: &'a $reg_ty,
}
);
Expand All @@ -100,6 +101,27 @@ fn build_new<'a>(cx: &'a ExtCtxt, path: &Vec<String>, reg: &node::Reg)
$setter_ident {
value: 0,
mask: 0,
write_only: false,
reg: reg,
}
}
}
).unwrap())
}

fn build_new_ignoring_state<'a>(cx: &'a ExtCtxt, path: &Vec<String>,
reg: &node::Reg) -> P<ast::ImplItem> {
let reg_ty: P<ast::Ty> =
cx.ty_ident(reg.name.span, utils::path_ident(cx, path));
let setter_ident = utils::setter_name(cx, path);
utils::unwrap_impl_item(quote_item!(cx,
impl<'a> $setter_ident<'a> {
#[doc="Create a new updater that ignores current state"]
pub fn new_ignoring_state(reg: &'a $reg_ty) -> $setter_ident<'a> {
$setter_ident {
value: 0,
mask: 0,
write_only: true,
reg: reg,
}
}
Expand Down Expand Up @@ -132,7 +154,7 @@ fn build_drop(cx: &ExtCtxt, path: &Vec<String>,
if wo_reg {
quote_expr!(cx, 0)
} else {
quote_expr!(cx, self.reg.value.get())
quote_expr!(cx, if self.write_only { 0 } else { self.reg.value.get() })
};

let item = quote_item!(cx,
Expand Down Expand Up @@ -164,6 +186,7 @@ fn build_impl(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
fields: &Vec<node::Field>) -> P<ast::Item>
{
let new = build_new(cx, path, reg);
let new_is = build_new_ignoring_state(cx, path, reg);
let setter_ident = utils::setter_name(cx, path);
let methods: Vec<P<ast::ImplItem>> =
FromIterator::from_iter(
Expand All @@ -174,6 +197,7 @@ fn build_impl(cx: &ExtCtxt, path: &Vec<String>, reg: &node::Reg,
#[allow(dead_code)]
impl<'a> $setter_ident<'a> {
$new
$new_is
$methods
$done
}
Expand Down
15 changes: 14 additions & 1 deletion ioreg/src/builder/union.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,20 @@ impl<'a> BuildUnionTypes<'a> {
}
}
).unwrap();

let copy_impl = quote_item!(self.cx, impl ::core::marker::Copy for $name {}).unwrap();
vec!(struct_item, clone_impl, copy_impl)

let item_address = reg.address;
let item_getter = quote_item!(self.cx,
#[allow(non_snake_case, dead_code)]
pub fn $name() -> &'static $name {
unsafe { ::core::intrinsics::transmute($item_address as usize) }
}
).unwrap();
if item_address == 0 {
vec!(struct_item, clone_impl, copy_impl)
} else {
vec!(struct_item, clone_impl, copy_impl, item_getter)
}
}
}
5 changes: 2 additions & 3 deletions ioreg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,10 +327,9 @@ N => NAME

*/

#![feature(quote, plugin_registrar, rustc_private, collections, core)]
#![feature(convert)]
#![feature(plugin)]
#![feature(quote, plugin_registrar, rustc_private, collections, core, convert)]

#![feature(plugin)]
#![plugin(syntaxext_lint)]

extern crate rustc;
Expand Down
15 changes: 8 additions & 7 deletions ioreg/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ use syntax::codemap::{Spanned, Span};
use syntax::ast;

/// A variant of an enum field type
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Variant {
pub name: Spanned<String>,
pub value: Spanned<u64>,
pub docstring: Option<Spanned<ast::Ident>>,
}

/// A bit field type
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum FieldType {
/// A unsigned integer
UIntField,
Expand All @@ -40,7 +40,7 @@ pub enum FieldType {
},
}

#[derive(Copy, PartialEq, Eq, Clone)]
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
pub enum Access {
ReadWrite,
ReadOnly,
Expand All @@ -49,7 +49,7 @@ pub enum Access {
SetToClear,
}

#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Field {
pub name: Spanned<String>,
/// The index of the first (lowest order) bit of the field
Expand All @@ -71,7 +71,7 @@ impl Field {
}
}

#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
pub enum RegWidth {
/// A 32-bit wide register
Reg32,
Expand All @@ -92,7 +92,7 @@ impl RegWidth {
}
}

#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum RegType {
/// A primitive bitfield
RegPrim(Spanned<RegWidth>, Vec<Field>),
Expand All @@ -111,13 +111,14 @@ impl RegType {
}

/// A single register, either a union or primitive
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Reg {
pub offset: u64,
pub name: Spanned<String>,
pub ty: RegType,
pub count: Spanned<u32>,
pub docstring: Option<Spanned<ast::Ident>>,
pub address: usize,
}

impl Reg {
Expand Down
56 changes: 36 additions & 20 deletions ioreg/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ impl<'a> Parser<'a> {
Some(name) => respan(self.last_span, name),
None => return None,
};
let mut address: usize = 0;

if self.token == token::At {
self.bump();

// TODO(farcaller): expect_usize should return usize, no?
address = match self.expect_usize() {
Some(address) => address as usize,
None => return None,
};
}

if !self.expect(&token::Eq) {
return None;
Expand All @@ -99,6 +110,7 @@ impl<'a> Parser<'a> {
ty: RegType::RegUnion(Rc::new(regs)),
count: respan(mk_sp(sp_lo, self.span.hi), 1),
docstring: docstring,
address: address,
};

Some(Rc::new(group))
Expand Down Expand Up @@ -137,26 +149,29 @@ impl<'a> Parser<'a> {
regs.sort_by(|r1,r2| r1.offset.cmp(&r2.offset));

// Verify that registers don't overlap
let mut failed = false;
for (r1,r2) in regs.iter().zip(regs.iter().skip(1)) {
if r2.offset <= r1.last_byte() {
self.sess.span_diagnostic.span_err(
r1.name.span,
format!("The byte range of register ({} to {})",
r1.offset, r1.last_byte()).as_str());
self.sess.span_diagnostic.span_err(
r2.name.span,
format!("overlaps with the range of this register ({} to {})",
r2.offset, r2.last_byte()).as_str());
failed = true;
}
}

if failed {
None
} else {
Some(regs)
}
// TODO(farcaller): they actually can, which is a register union. We need
// a proper terminology and implementation for that.
// let mut failed = false;
// for (r1,r2) in regs.iter().zip(regs.iter().skip(1)) {
// if r2.offset <= r1.last_byte() {
// self.sess.span_diagnostic.span_err(
// r1.name.span,
// format!("The byte range of register ({} to {})",
// r1.offset, r1.last_byte()).as_slice());
// self.sess.span_diagnostic.span_err(
// r2.name.span,
// format!("overlaps with the range of this register ({} to {})",
// r2.offset, r2.last_byte()).as_slice());
// failed = true;
// }
// }

// if failed {
// None
// } else {
// Some(regs)
// }
Some(regs)
}

/// Parse the introduction of a register
Expand Down Expand Up @@ -260,6 +275,7 @@ impl<'a> Parser<'a> {
ty: ty,
count: count,
docstring: docstring,
address: 0,
})
}

Expand Down
10 changes: 5 additions & 5 deletions ioreg/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ mod test {
}
}

ioregs!(BASIC_TEST = {
ioregs!(BASIC_TEST @ 0 = {
0x0 => reg32 reg1 {
0 => field1,
1..3 => field2,
Expand Down Expand Up @@ -125,7 +125,7 @@ mod test {
);
*/

ioregs!(GROUP_TEST = {
ioregs!(GROUP_TEST @ 0 = {
0x0 => group regs[5] {
0x0 => reg32 reg1 {
0..31 => field1
Expand Down Expand Up @@ -172,7 +172,7 @@ mod test {
);
*/

ioregs!(FIELD_ARRAY_TEST = {
ioregs!(FIELD_ARRAY_TEST @ 0 = {
0x0 => reg32 reg1 {
0..31 => field[16]
}
Expand Down Expand Up @@ -208,7 +208,7 @@ mod test {
);
*/

ioregs!(GAP_TEST = {
ioregs!(GAP_TEST @ 0 = {
0x0 => reg32 reg1 {
0..31 => field,
}
Expand Down Expand Up @@ -268,7 +268,7 @@ mod test {
);
*/

ioregs!(MULTI_TEST = {
ioregs!(MULTI_TEST @ 0 = {
0x100 => reg32 reg1[8] {
0..31 => field[32],
}
Expand Down