switch more to sigspec, make processes work
This commit is contained in:
parent
b77fc1a1f9
commit
839287ec51
|
@ -4,9 +4,9 @@ module clockdiv_2 (
|
||||||
output wire out_clk
|
output wire out_clk
|
||||||
) {
|
) {
|
||||||
proc (clk) {
|
proc (clk) {
|
||||||
match (rst) {
|
match (not(rst)) {
|
||||||
0 => out_clk = 0,
|
0 => out_clk = 0,
|
||||||
1 => out_clk = ~out_clk
|
1 => out_clk = not(out_clk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,30 @@
|
||||||
use crate::frontend::{CallArgument, Callable, Type};
|
use crate::frontend::{CallArgument, Callable, Type};
|
||||||
use crate::rtlil;
|
use crate::rtlil;
|
||||||
|
use crate::rtlil::SigSpec;
|
||||||
|
|
||||||
|
fn instantiate_unop(celltype: &str, id: &str, args: &[SigSpec], ret: &SigSpec) -> rtlil::Cell {
|
||||||
|
let a = args
|
||||||
|
.get(0)
|
||||||
|
.expect("wrong argcount slipped through type check");
|
||||||
|
assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
fn builtin_unop_cell(celltype: &str, id: &str, a: &str, y: &str) -> rtlil::Cell {
|
|
||||||
let mut cell = rtlil::Cell::new(id, celltype);
|
let mut cell = rtlil::Cell::new(id, celltype);
|
||||||
cell.add_param("\\A_SIGNED", "0");
|
cell.add_param("\\A_SIGNED", "0");
|
||||||
cell.add_param("\\A_WIDTH", "1");
|
cell.add_param("\\A_WIDTH", "1");
|
||||||
cell.add_param("\\Y_WIDTH", "1");
|
cell.add_param("\\Y_WIDTH", "1");
|
||||||
cell.add_connection("\\A", a);
|
cell.add_connection("\\A", a);
|
||||||
cell.add_connection("\\Y", y);
|
cell.add_connection("\\Y", ret);
|
||||||
cell
|
cell
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instantiate_binop(celltype: &str, id: &str, args: &[String], ret: &str) -> rtlil::Cell {
|
fn instantiate_binop(celltype: &str, id: &str, args: &[SigSpec], ret: &SigSpec) -> rtlil::Cell {
|
||||||
let a = args
|
let a = args
|
||||||
.get(0)
|
.get(0)
|
||||||
.expect("wrong argcount slipped through type check");
|
.expect("wrong argcount slipped through type check");
|
||||||
let b = args
|
let b = args
|
||||||
.get(1)
|
.get(1)
|
||||||
.expect("wrong argcount slipped through type check");
|
.expect("wrong argcount slipped through type check");
|
||||||
|
assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
let mut cell = rtlil::Cell::new(id, celltype);
|
let mut cell = rtlil::Cell::new(id, celltype);
|
||||||
cell.add_param("\\A_SIGNED", "0");
|
cell.add_param("\\A_SIGNED", "0");
|
||||||
|
@ -50,11 +57,27 @@ fn make_binop_callable(name: &str, celltype: &'static str) -> Callable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_unnop_callable(name: &str, celltype: &'static str) -> Callable {
|
||||||
|
let args = vec![
|
||||||
|
CallArgument {
|
||||||
|
name: "A".to_owned(),
|
||||||
|
atype: Type::wire(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
Callable {
|
||||||
|
name: name.to_owned(),
|
||||||
|
args,
|
||||||
|
ret: Type::wire(),
|
||||||
|
instantiate: Box::new(move |id, args, ret| instantiate_unop(celltype, id, args, ret)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_builtins() -> Vec<Callable> {
|
pub fn get_builtins() -> Vec<Callable> {
|
||||||
vec![
|
vec![
|
||||||
make_binop_callable("and", "$and"),
|
make_binop_callable("and", "$and"),
|
||||||
make_binop_callable("or", "$or"),
|
make_binop_callable("or", "$or"),
|
||||||
make_binop_callable("xor", "$xor"),
|
make_binop_callable("xor", "$xor"),
|
||||||
make_binop_callable("xnor", "$xnor"),
|
make_binop_callable("xnor", "$xnor"),
|
||||||
|
make_unnop_callable("not", "$not"),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,9 @@ use crate::parser;
|
||||||
use crate::rtlil;
|
use crate::rtlil;
|
||||||
use crate::rtlil::RtlilWrite;
|
use crate::rtlil::RtlilWrite;
|
||||||
|
|
||||||
|
/// lots of code is still not width-aware, this constant keeps track of that
|
||||||
|
const TODO_WIDTH: u32 = 1;
|
||||||
|
|
||||||
fn make_pubid(id: &str) -> String {
|
fn make_pubid(id: &str) -> String {
|
||||||
"\\".to_owned() + id
|
"\\".to_owned() + id
|
||||||
}
|
}
|
||||||
|
@ -52,31 +55,82 @@ pub struct Callable {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub args: Vec<CallArgument>,
|
pub args: Vec<CallArgument>,
|
||||||
pub ret: Type,
|
pub ret: Type,
|
||||||
pub instantiate: Box<dyn Fn(&str, &[String], &str) -> rtlil::Cell>,
|
pub instantiate: Box<dyn Fn(&str, &[rtlil::SigSpec], &rtlil::SigSpec) -> rtlil::Cell>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Context {
|
struct Context {
|
||||||
callables: BTreeMap<String, Callable>,
|
callables: BTreeMap<String, Callable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lower_process_statement(
|
||||||
|
ctx: &Context,
|
||||||
|
module: &mut rtlil::Module,
|
||||||
|
updates: &mut Vec<(rtlil::SigSpec, rtlil::SigSpec)>,
|
||||||
|
stmt: &parser::proc::ProcStatement,
|
||||||
|
) -> Result<rtlil::CaseRule, CompileError> {
|
||||||
|
let rule = match stmt {
|
||||||
|
parser::proc::ProcStatement::IfElse(_) => todo!("if/else unimplemented"),
|
||||||
|
parser::proc::ProcStatement::Assign(assig) => {
|
||||||
|
// FIXME: actually store this
|
||||||
|
let next_gen_id = format!("${}$next", assig.lhs);
|
||||||
|
module.add_wire(rtlil::Wire::new(&next_gen_id, TODO_WIDTH, None));
|
||||||
|
|
||||||
|
let next_wire = rtlil::SigSpec::Wire(next_gen_id.clone());
|
||||||
|
updates.push((rtlil::SigSpec::Wire(assig.lhs.to_owned()), next_wire.clone()));
|
||||||
|
|
||||||
|
let next_expr_wire = lower_expression(ctx, module, &assig.expr)?;
|
||||||
|
|
||||||
|
rtlil::CaseRule {
|
||||||
|
assign: vec![(next_wire, next_expr_wire)],
|
||||||
|
switches: vec![]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parser::proc::ProcStatement::Match(match_block) => {
|
||||||
|
let match_sig = lower_expression(ctx, module, &match_block.expr)?;
|
||||||
|
let mut cases = vec![];
|
||||||
|
for arm in &match_block.arms {
|
||||||
|
let case = lower_process_statement(ctx, module, updates, &arm.1)?;
|
||||||
|
let compare_sig = lower_expression(ctx, module, &arm.0)?;
|
||||||
|
cases.push((compare_sig, case));
|
||||||
|
};
|
||||||
|
let switch_rule = rtlil::SwitchRule {
|
||||||
|
signal: match_sig,
|
||||||
|
cases,
|
||||||
|
};
|
||||||
|
rtlil::CaseRule {
|
||||||
|
assign: vec![],
|
||||||
|
switches: vec![switch_rule],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parser::proc::ProcStatement::Block(_) => todo!("blocks unimplemented"),
|
||||||
|
};
|
||||||
|
Ok(rule)
|
||||||
|
}
|
||||||
|
|
||||||
fn lower_process(
|
fn lower_process(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
module: &mut rtlil::Module,
|
module: &mut rtlil::Module,
|
||||||
process: &parser::proc::ProcBlock
|
process: &parser::proc::ProcBlock
|
||||||
) -> Result<(), CompileError> {
|
) -> Result<(), CompileError> {
|
||||||
|
let mut updates = vec![];
|
||||||
|
let mut cases = vec![];
|
||||||
|
for stmt in &process.items {
|
||||||
|
let case = lower_process_statement(ctx, module, &mut updates, &stmt)?;
|
||||||
|
cases.push(case);
|
||||||
|
}
|
||||||
|
|
||||||
let sync_cond = rtlil::SyncCond::Posedge((*process.net.fragment()).into());
|
let sync_cond = rtlil::SyncCond::Posedge((*process.net.fragment()).into());
|
||||||
let sync_rule = rtlil::SyncRule {
|
let sync_rule = rtlil::SyncRule {
|
||||||
cond: sync_cond,
|
cond: sync_cond,
|
||||||
assign: Vec::new()
|
assign: updates
|
||||||
};
|
|
||||||
let root_case = rtlil::CaseRule {
|
|
||||||
assign: vec![],
|
|
||||||
switches: vec![],
|
|
||||||
};
|
};
|
||||||
|
if cases.len() != 1 {
|
||||||
|
panic!("only one expression per block, for now")
|
||||||
|
}
|
||||||
|
assert_eq!(cases.len(), 1);
|
||||||
let ir_proc = rtlil::Process {
|
let ir_proc = rtlil::Process {
|
||||||
id: module.make_genid("proc"),
|
id: module.make_genid("proc"),
|
||||||
root_case,
|
root_case: cases.into_iter().next().unwrap(),
|
||||||
sync_rules: vec![sync_rule],
|
sync_rules: vec![sync_rule],
|
||||||
};
|
};
|
||||||
module.add_process(ir_proc);
|
module.add_process(ir_proc);
|
||||||
|
@ -87,12 +141,10 @@ fn lower_expression(
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
module: &mut rtlil::Module,
|
module: &mut rtlil::Module,
|
||||||
expr: &parser::Expression,
|
expr: &parser::Expression,
|
||||||
) -> Result<String, CompileError> {
|
) -> Result<rtlil::SigSpec, CompileError> {
|
||||||
match expr {
|
match expr {
|
||||||
parser::Expression::Ident(ident) => Ok(make_pubid(ident)),
|
parser::Expression::Ident(ident) => Ok(rtlil::SigSpec::Wire(make_pubid(ident))),
|
||||||
parser::Expression::Call(call) => {
|
parser::Expression::Call(call) => {
|
||||||
let output_gen_id = module.make_genid("cell");
|
|
||||||
module.add_wire(rtlil::Wire::new(&output_gen_id, 1, None));
|
|
||||||
|
|
||||||
let args_resolved = call
|
let args_resolved = call
|
||||||
.args
|
.args
|
||||||
|
@ -118,12 +170,18 @@ fn lower_expression(
|
||||||
|
|
||||||
let cell_id = module.make_genid(&callable.name);
|
let cell_id = module.make_genid(&callable.name);
|
||||||
|
|
||||||
let cell = (*callable.instantiate)(&cell_id, args_resolved.as_slice(), &output_gen_id);
|
let output_gen_id = format!("{}$out", &cell_id);
|
||||||
|
module.add_wire(rtlil::Wire::new(&output_gen_id, TODO_WIDTH, None));
|
||||||
|
let output_gen_wire = rtlil::SigSpec::Wire(output_gen_id);
|
||||||
|
|
||||||
|
let cell = (*callable.instantiate)(&cell_id, args_resolved.as_slice(), &output_gen_wire);
|
||||||
module.add_cell(cell);
|
module.add_cell(cell);
|
||||||
Ok(output_gen_id)
|
Ok(output_gen_wire)
|
||||||
}
|
}
|
||||||
parser::Expression::Operation(_op) => todo!(),
|
parser::Expression::Operation(_op) => todo!("operators not yet implemented"),
|
||||||
parser::Expression::Literal(_op) => todo!(),
|
parser::Expression::Literal(lit) => {
|
||||||
|
Ok(rtlil::SigSpec::Const(*lit as i64, TODO_WIDTH))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +190,7 @@ fn lower_assignment(
|
||||||
module: &mut rtlil::Module,
|
module: &mut rtlil::Module,
|
||||||
assignment: parser::Assign,
|
assignment: parser::Assign,
|
||||||
) -> Result<(), CompileError> {
|
) -> Result<(), CompileError> {
|
||||||
let target_id = make_pubid(assignment.lhs);
|
let target_id = rtlil::SigSpec::Wire(make_pubid(assignment.lhs));
|
||||||
let return_wire = lower_expression(ctx, module, &assignment.expr)?;
|
let return_wire = lower_expression(ctx, module, &assignment.expr)?;
|
||||||
module.add_connection(&target_id, &return_wire);
|
module.add_connection(&target_id, &return_wire);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -30,8 +30,8 @@ pub struct IfElseBlock {}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MatchBlock<'a> {
|
pub struct MatchBlock<'a> {
|
||||||
expr: Expression<'a>,
|
pub expr: Expression<'a>,
|
||||||
arms: Vec<(Expression<'a>, ProcStatement<'a>)>,
|
pub arms: Vec<(Expression<'a>, ProcStatement<'a>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_arm(input: Span) -> IResult<Span, (Expression, ProcStatement)> {
|
fn match_arm(input: Span) -> IResult<Span, (Expression, ProcStatement)> {
|
||||||
|
|
12
src/rtlil.rs
12
src/rtlil.rs
|
@ -48,9 +48,9 @@ pub trait RtlilWrite {
|
||||||
fn write_rtlil(&self, writer: &mut ILWriter);
|
fn write_rtlil(&self, writer: &mut ILWriter);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum SigSpec {
|
pub enum SigSpec {
|
||||||
Const(i32, u32),
|
Const(i64, u32),
|
||||||
Wire(String),
|
Wire(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,9 +143,9 @@ impl Module {
|
||||||
self.wires.push(wire)
|
self.wires.push(wire)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_connection(&mut self, target: &str, source: &str) {
|
pub fn add_connection(&mut self, target: &SigSpec, source: &SigSpec) {
|
||||||
self.connections
|
self.connections
|
||||||
.push((SigSpec::wire(target), SigSpec::wire(source)))
|
.push((target.clone(), source.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_cell(&mut self, cell: Cell) {
|
pub fn add_cell(&mut self, cell: Cell) {
|
||||||
|
@ -200,9 +200,9 @@ impl Cell {
|
||||||
self.parameters.push((name.into(), value.into()))
|
self.parameters.push((name.into(), value.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_connection(&mut self, from: &str, to: &str) {
|
pub fn add_connection(&mut self, from: &str, to: &SigSpec) {
|
||||||
self.connections
|
self.connections
|
||||||
.push((SigSpec::wire(from), SigSpec::wire(to)))
|
.push((SigSpec::wire(from), to.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ pub struct CaseRule {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SwitchRule {
|
pub struct SwitchRule {
|
||||||
signal: String,
|
pub signal: SigSpec,
|
||||||
cases: Vec<CaseRule>,
|
pub cases: Vec<(SigSpec, CaseRule)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -28,6 +28,7 @@ pub struct SyncRule {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SyncCond {
|
pub enum SyncCond {
|
||||||
Always,
|
Always,
|
||||||
|
Init,
|
||||||
Posedge(String),
|
Posedge(String),
|
||||||
Negedge(String),
|
Negedge(String),
|
||||||
}
|
}
|
||||||
|
@ -56,7 +57,12 @@ impl RtlilWrite for SwitchRule {
|
||||||
fn write_rtlil(&self, writer: &mut super::ILWriter) {
|
fn write_rtlil(&self, writer: &mut super::ILWriter) {
|
||||||
writer.write_line(&format!("switch {}", self.signal));
|
writer.write_line(&format!("switch {}", self.signal));
|
||||||
writer.indent();
|
writer.indent();
|
||||||
writer.write_iter(&self.cases);
|
for case in &self.cases {
|
||||||
|
writer.write_line(&format!("case {}", case.0));
|
||||||
|
writer.indent();
|
||||||
|
case.1.write_rtlil(writer);
|
||||||
|
writer.dedent();
|
||||||
|
}
|
||||||
writer.dedent();
|
writer.dedent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,6 +71,7 @@ impl RtlilWrite for SyncRule {
|
||||||
fn write_rtlil(&self, writer: &mut super::ILWriter) {
|
fn write_rtlil(&self, writer: &mut super::ILWriter) {
|
||||||
let sync_expr = match &self.cond {
|
let sync_expr = match &self.cond {
|
||||||
SyncCond::Always => "always".to_owned(),
|
SyncCond::Always => "always".to_owned(),
|
||||||
|
SyncCond::Init => "always".to_owned(),
|
||||||
SyncCond::Posedge(sig) => format!("posedge {}", sig),
|
SyncCond::Posedge(sig) => format!("posedge {}", sig),
|
||||||
SyncCond::Negedge(sig) => format!("negedge {}", sig),
|
SyncCond::Negedge(sig) => format!("negedge {}", sig),
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue