yosys/techlibs/rapidflex/util/pcounter_ip_template_genera...

483 lines
18 KiB
Python

import time
import logging
import yaml
import os
import re
import subprocess
from datetime import timedelta
from datetime import datetime
import threading
import csv
# Constants
CLK_TYPE_RISE = "RISING"
CLK_TYPE_FALL = "FALLING"
RST_TYPE_SYNC = "SYNCHRONOUS"
RST_TYPE_ASYNC = "ASYNCHRONOUS"
RST_POLARITY_L = "ACTIVE-LOW"
RST_POLARITY_H = "ACTIVE-HIGH"
EVENT_TYPE_LOAD = "LOAD"
EVENT_TYPE_ADD = "ADD"
EVENT_TYPE_SUB = "SUBTRACT"
EVENT_TYPE_SR = "SHIFT-RIGHT"
EVENT_TYPE_SL = "SHIFT-LEFT"
# Class of an mini pin table
class PcounterIpTemplateGenerator:
def __init__(self):
# Constants
self.__CLK_TYPES_ = [CLK_TYPE_RISE, CLK_TYPE_FALL]
self.__RST_TYPES_ = [RST_TYPE_SYNC, RST_TYPE_ASYNC]
self.__RST_POLARITIES_ = [RST_POLARITY_L, RST_POLARITY_H]
self.__EVENT_TYPES_ = [
EVENT_TYPE_LOAD,
EVENT_TYPE_ADD,
EVENT_TYPE_SUB,
EVENT_TYPE_SR,
EVENT_TYPE_SL,
]
self.__MAX_DATA_SIZE_ = 32
self.__CCB_POSTFIX_ = "_ccb"
# Internal switches
self.__include_q_ = False
# Create a new row
def clock_types(self):
return self.__CLK_TYPES_
def reset_types(self):
return self.__RST_TYPES_
def reset_polarities(self):
return self.__RST_POLARITIES_
def event_types(self):
return self.__EVENT_TYPES_
def data_sizes(self):
return range(1, self.__MAX_DATA_SIZE_ + 1)
def max_data_size(self):
return self.__MAX_DATA_SIZE_
def __verilog_clock_edge(self, edge_type):
if edge_type == CLK_TYPE_RISE:
return "posedge"
elif edge_type == CLK_TYPE_FALL:
return "negedge"
else:
raise Exception(f"Invalid clock type '{edge_type}'. Expect {self.__CLK_TYPES_}\n")
def __verilog_reset_edge(self, edge_type):
if edge_type == RST_POLARITY_H:
return "posedge"
elif edge_type == RST_POLARITY_L:
return "negedge"
else:
raise Exception(f"Invalid reset type '{edge_type}'. Expect {self.__RST_POLARITIES_}\n")
def __verilog_reset_polarity(self, polarity_type):
if polarity_type == RST_POLARITY_L:
return "~"
elif polarity_type == RST_POLARITY_H:
return ""
else:
raise Exception(
f"Invalid reset type '{polarity_type}'. Expect {self.__RST_POLARITIES}\n"
)
def __verilog_event_op_ccb(self, event_type):
if event_type == EVENT_TYPE_LOAD:
return "ccb_load_val_i"
elif event_type == EVENT_TYPE_ADD:
return "q_o + ccb_load_val_i"
elif event_type == EVENT_TYPE_SUB:
return "q_o - ccb_load_val_i"
elif event_type == EVENT_TYPE_SL:
return "q_o << ccb_load_val_i"
elif event_type == EVENT_TYPE_SR:
return "q_o >> ccb_load_val_i"
else:
raise Exception(f"Invalid event type '{event_type}'. Expect {self.__EVENT_TYPES_}\n")
def __verilog_event_op(self, event_type):
if event_type == EVENT_TYPE_LOAD:
return "LOAD_VAL"
elif event_type == EVENT_TYPE_ADD:
return "q_o + LOAD_VAL"
elif event_type == EVENT_TYPE_SUB:
return "q_o - LOAD_VAL"
elif event_type == EVENT_TYPE_SL:
return "q_o << LOAD_VAL"
elif event_type == EVENT_TYPE_SR:
return "q_o >> LOAD_VAL"
else:
raise Exception(f"Invalid event type '{event_type}'. Expect {self.__EVENT_TYPES_}\n")
def __clock_type_str(self, edge_type):
if edge_type == CLK_TYPE_RISE:
return "clkp"
elif edge_type == CLK_TYPE_FALL:
return "clkn"
else:
raise Exception(f"Invalid clock type '{edge_type}'. Expect {self.__CLK_TYPES_}\n")
def __reset_type_str(self, edge_type, polarity_type):
ret = ""
if edge_type == RST_TYPE_ASYNC:
ret = "arst"
elif edge_type == RST_TYPE_SYNC:
ret = "srst"
else:
raise Exception(f"Invalid reset type '{edge_type}'. Expect {self.__RST_TYPES_}\n")
if polarity_type == RST_POLARITY_L:
ret += "n"
elif polarity_type == RST_POLARITY_H:
ret += "p"
else:
raise Exception(
f"Invalid reset type '{polarity_type}'. Expect {self.__RST_POLARITIES}\n"
)
return ret
def __event_type_str(self, event_type):
if event_type == EVENT_TYPE_LOAD:
return "load"
elif event_type == EVENT_TYPE_ADD:
return "add"
elif event_type == EVENT_TYPE_SUB:
return "sub"
elif event_type == EVENT_TYPE_SL:
return "sl"
elif event_type == EVENT_TYPE_SR:
return "sr"
else:
raise Exception(f"Invalid event type '{event_type}'. Expect {self.__EVENT_TYPES_}\n")
def ccb_ip_template_name(self, c_type, r_type, r_polar, e_type):
return (
"pcounterN_"
+ self.__clock_type_str(c_type)
+ "_"
+ self.__reset_type_str(r_type, r_polar)
+ "_"
+ self.__event_type_str(e_type)
+ self.__CCB_POSTFIX_
)
def ip_template_name(self, c_type, r_type, r_polar, e_type):
return (
"pcounterN_"
+ self.__clock_type_str(c_type)
+ "_"
+ self.__reset_type_str(r_type, r_polar)
+ "_"
+ self.__event_type_str(e_type)
)
def ip_name(self, c_type, r_type, r_polar, e_type, d_size):
return (
"pcounter"
+ str(d_size)
+ "_"
+ self.__clock_type_str(c_type)
+ "_"
+ self.__reset_type_str(r_type, r_polar)
+ "_"
+ self.__event_type_str(e_type)
)
def ccb_ip_name(self, c_type, r_type, r_polar, e_type, d_size):
return (
"pcounter"
+ str(d_size)
+ "_"
+ self.__clock_type_str(c_type)
+ "_"
+ self.__reset_type_str(r_type, r_polar)
+ "_"
+ self.__event_type_str(e_type)
+ self.__CCB_POSTFIX_
)
def write_ccb_ip_template(self, f0, c_type, r_type, r_polar, e_type):
f0.write("//-------------------------------------------------\n\n")
f0.write(
"// Template of Programmable counter to be counting up or down as well as paused\n\n"
)
f0.write(f"// triggered by {c_type.lower()} edge clock\n\n")
f0.write(f"// with {r_type.lower()} {r_polar.lower()} reset\n\n")
f0.write(f"// Capable of {e_type.lower()} values from inputs\n\n")
f0.write("`default_nettype none\n\n")
f0.write(f"module {self.ccb_ip_template_name(c_type, r_type, r_polar, e_type)} #(\n")
f0.write(f" parameter integer DATA_WIDTH = {self.__MAX_DATA_SIZE_}\n")
f0.write(")(\n")
f0.write(" input clk_i,\n")
f0.write(" input rst_i,\n")
f0.write(" input up_down_i,\n")
f0.write(" input event_i,\n")
f0.write(" input enable_i,\n")
f0.write(" input [0 : DATA_WIDTH - 1] ccb_match0_ref_i,\n")
f0.write(" input [0 : DATA_WIDTH - 1] ccb_match1_ref_i,\n")
f0.write(" input [0 : DATA_WIDTH - 1] ccb_load_val_i,\n")
f0.write(" output match0_o,\n")
f0.write(" output match1_o,\n")
f0.write(" output zero_o,\n")
f0.write(" output [0 : DATA_WIDTH - 1] q_o\n")
f0.write(");\n")
f0.write(" reg [0 : DATA_WIDTH - 1] q_o;\n")
if r_type == RST_TYPE_ASYNC:
f0.write(
f" always@({self.__verilog_clock_edge(c_type)} clk_i or {self.__verilog_reset_edge(r_polar)} rst_i) \n"
)
elif r_type == RST_TYPE_SYNC:
f0.write(f" always@({self.__verilog_clock_edge(c_type)} clk_i) \n")
else:
raise Exception(f"Invalid reset type '{edge_type}'. Expect {self.__RST_TYPES_}\n")
f0.write(" begin\n")
f0.write(
f" if ({self.__verilog_reset_polarity(r_polar)}rst_i) //Set Counter to Zero\n"
)
f0.write(" q_o <= 0;\n")
f0.write(" else if(event_i)\n")
f0.write(f" q_o <= {self.__verilog_event_op_ccb(e_type)};\n")
f0.write(" else if (~enable_i)\n")
f0.write(" q_o <= q_o; // pause\n")
f0.write(" else if(up_down_i) //count down\n")
f0.write(" q_o <= q_o - 1;\n")
f0.write(" else //count up\n")
f0.write(" q_o <= q_o + 1;\n")
f0.write(" end\n")
f0.write(" assign zero_o = (q_o == 0) ? 1 : 0;\n")
f0.write(" assign match0_o = (q_o == ccb_match0_ref_i) ? 1 : 0;\n")
f0.write(" assign match1_o = (q_o == ccb_match1_ref_i) ? 1 : 0;\n")
f0.write("endmodule\n")
f0.write("`default_nettype wire\n")
def write_ip_template(self, f0, c_type, r_type, r_polar, e_type):
f0.write("//-------------------------------------------------\n\n")
f0.write(
"// Template of Programmable counter to be counting up or down as well as paused\n\n"
)
f0.write(f"// triggered by {c_type.lower()} edge clock\n\n")
f0.write(f"// with {r_type.lower()} {r_polar.lower()} reset\n\n")
f0.write(f"// Capable of {e_type.lower()} values from inputs\n\n")
f0.write("`default_nettype none\n\n")
f0.write(f"module {self.ip_template_name(c_type, r_type, r_polar, e_type)} #(\n")
f0.write(f" parameter integer DATA_WIDTH = {self.__MAX_DATA_SIZE_},\n")
f0.write(" parameter [0 : DATA_WIDTH - 1] LOAD_VAL = {DATA_WIDTH{1'b0}},\n")
f0.write(" parameter [0 : DATA_WIDTH - 1] MATCH0_REF = {DATA_WIDTH{1'b0}},\n")
f0.write(" parameter [0 : DATA_WIDTH - 1] MATCH1_REF = {DATA_WIDTH{1'b0}}\n")
f0.write(")(\n")
f0.write(" input clk_i,\n")
f0.write(" input rst_i,\n")
f0.write(" input up_down_i,\n")
f0.write(" input event_i,\n")
f0.write(" input enable_i,\n")
f0.write(" output match0_o,\n")
f0.write(" output match1_o,\n")
f0.write(" output zero_o")
if self.__include_q_:
f0.write(",\n")
f0.write(" output [0 : DATA_WIDTH - 1] q_o\n")
f0.write(");\n")
f0.write(" reg [0 : DATA_WIDTH - 1] q_o;\n")
if r_type == RST_TYPE_ASYNC:
f0.write(
f" always@({self.__verilog_clock_edge(c_type)} clk_i or {self.__verilog_reset_edge(r_polar)} rst_i) \n"
)
elif r_type == RST_TYPE_SYNC:
f0.write(f" always@({self.__verilog_clock_edge(c_type)} clk_i) \n")
else:
raise Exception(f"Invalid reset type '{edge_type}'. Expect {self.__RST_TYPES_}\n")
f0.write(" begin\n")
f0.write(
f" if ({self.__verilog_reset_polarity(r_polar)}rst_i) //Set Counter to Zero\n"
)
f0.write(" q_o <= 0;\n")
f0.write(" else if(event_i)\n")
f0.write(f" q_o <= {self.__verilog_event_op(e_type)};\n")
f0.write(" else if (~enable_i)\n")
f0.write(" q_o <= q_o; // pause\n")
f0.write(" else if(up_down_i) //count down\n")
f0.write(" q_o <= q_o - 1;\n")
f0.write(" else //count up\n")
f0.write(" q_o <= q_o + 1;\n")
f0.write(" end\n")
f0.write(" assign zero_o = (q_o == 0) ? 1 : 0;\n")
f0.write(" assign match0_o = (q_o == MATCH0_REF) ? 1 : 0;\n")
f0.write(" assign match1_o = (q_o == MATCH1_REF) ? 1 : 0;\n")
f0.write("endmodule\n")
f0.write("`default_nettype wire\n")
def write_ccb_ip(self, f0, c_type, r_type, r_polar, e_type, d_size, require_padding=False):
d_msb = d_size - 1
f0.write("`default_nettype none\n\n")
f0.write(f"module {self.ccb_ip_name(c_type, r_type, r_polar, e_type, d_size)} # (\n")
f0.write(" // Location constraints\n")
f0.write(" parameter FPGA_LOC_X = 0,\n")
f0.write(" parameter FPGA_LOC_Y = 0,\n")
f0.write(" parameter FPGA_LOC_Z = 0)(\n")
f0.write(" input clk_i,\n")
f0.write(" input rst_i,\n")
f0.write(" input up_down_i,\n")
f0.write(" input event_i,\n")
f0.write(" input enable_i,\n")
f0.write(f" input [0 : {d_msb}] ccb_match0_ref_i,\n")
f0.write(f" input [0 : {d_msb}] ccb_match1_ref_i,\n")
f0.write(f" input [0 : {d_msb}] ccb_load_val_i,\n")
f0.write(" output match0_o,\n")
f0.write(" output match1_o,\n")
f0.write(" output zero_o,\n")
f0.write(f" output [0 : {d_msb}] q_o\n")
f0.write(");\n")
# Local wire
padding_size = self.__MAX_DATA_SIZE_ - d_size
# Padding
# q_padding_str = "q_o"
# if require_padding:
# if padding_size:
# q_padding_str = "{ q_o, {" + str(padding_size) + "{1'b0}} }"
# f0.write(f"wire [0: {self.__MAX_DATA_SIZE_ - 1}] q_wire;\n")
# f0.write(f"assign q_wire = {q_padding_str};\n")
# else:
# f0.write(f"wire [0: {d_size - 1}] q_wire;\n")
# f0.write(f"assign q_wire = q_o;\n")
f0.write(f" {self.ccb_ip_template_name(c_type, r_type, r_polar, e_type)} #(\n")
if require_padding:
f0.write(f" .DATA_WIDTH({self.__MAX_DATA_SIZE_})\n")
else:
f0.write(f" .DATA_WIDTH({d_size})\n")
load_val_padding_str = "ccb_load_val_i"
if require_padding:
if padding_size:
load_val_padding_str = "{ ccb_load_val_i, {" + str(padding_size) + "{1'b0}} }"
match0_padding_str = "ccb_match0_ref_i"
if require_padding:
if padding_size:
match0_padding_str = "{ ccb_match0_ref_i, {" + str(padding_size) + "{1'b0}} }"
match1_padding_str = "ccb_match1_ref_i"
if require_padding:
if padding_size:
match1_padding_str = "{ ccb_match1_ref_i, {" + str(padding_size) + "{1'b0}} }"
f0.write(" ) core (\n")
f0.write(" .clk_i(clk_i),\n")
f0.write(" .rst_i(rst_i),\n")
f0.write(" .up_down_i(up_down_i),\n")
f0.write(" .event_i(event_i),\n")
f0.write(" .enable_i(enable_i),\n")
f0.write(f" .ccb_load_val_i({load_val_padding_str}),\n")
f0.write(f" .ccb_match0_ref_i({match0_padding_str}),\n")
f0.write(f" .ccb_match1_ref_i({match1_padding_str}),\n")
f0.write(" .match0_o(match0_o),\n")
f0.write(" .match1_o(match1_o),\n")
f0.write(" .zero_o(zero_o),\n")
f0.write(f" .q_o(q_o)\n")
f0.write(" );\n")
f0.write("endmodule\n")
f0.write("`default_nettype wire\n")
def write_ip(self, f0, c_type, r_type, r_polar, e_type, d_size, require_padding=False):
d_msb = d_size - 1
f0.write("`default_nettype none\n\n")
f0.write(f"module {self.ip_name(c_type, r_type, r_polar, e_type, d_size)} #(\n")
f0.write(" // Location constraints\n")
f0.write(" parameter FPGA_LOC_X = 0,\n")
f0.write(" parameter FPGA_LOC_Y = 0,\n")
f0.write(" parameter FPGA_LOC_Z = 0,\n")
f0.write(" parameter [0 : " + str(d_msb) + "] LOAD_VAL = {" + str(d_size) + "{1'b0}},\n")
f0.write(" parameter [0 : " + str(d_msb) + "] MATCH0_REF = {" + str(d_size) + "{1'b0}},\n")
f0.write(" parameter [0 : " + str(d_msb) + "] MATCH1_REF = {" + str(d_size) + "{1'b0}}\n")
f0.write(")(\n")
f0.write(" input clk_i,\n")
f0.write(" input rst_i,\n")
f0.write(" input up_down_i,\n")
f0.write(" input event_i,\n")
f0.write(" input enable_i,\n")
f0.write(" output match0_o,\n")
f0.write(" output match1_o,\n")
f0.write(" output zero_o")
if self.__include_q_:
f0.write(",\n")
f0.write(f" output [0 : {d_msb}] q_o\n")
else:
f0.write("\n")
f0.write(");\n")
# Local wire
padding_size = self.__MAX_DATA_SIZE_ - d_size
# if self.__include_q_:
# q_padding_str = "q_o"
# if require_padding:
# if padding_size:
# q_padding_str = "{ q_o, {" + str(padding_size) + "{1'b0}} }"
# f0.write(f"wire [0: {self.__MAX_DATA_SIZE_ - 1}] q_wire;\n")
# f0.write(f"assign q_wire = {q_padding_str};\n")
# else:
# f0.write(f"wire [0: {d_size - 1}] q_wire;\n")
# f0.write(f"assign q_wire = {q_padding_str};\n")
f0.write(f" {self.ip_template_name(c_type, r_type, r_polar, e_type)} #(\n")
if require_padding:
f0.write(f" .DATA_WIDTH({self.__MAX_DATA_SIZE_})\n")
else:
f0.write(f" .DATA_WIDTH({d_size}),\n")
load_val_padding_str = "LOAD_VAL"
if require_padding:
if padding_size:
load_val_padding_str = "{ LOAD_VAL, {" + str(padding_size) + "{1'b0}} }"
f0.write(f" .LOAD_VAL({load_val_padding_str}),\n")
match0_padding_str = "MATCH0_REF"
if require_padding:
if padding_size:
match0_padding_str = "{ MATCH0_REF, {" + str(padding_size) + "{1'b0}} }"
f0.write(f" .MATCH0_REF({match0_padding_str}),\n")
match1_padding_str = "MATCH1_REF"
if require_padding:
if padding_size:
match1_padding_str = "{ MATCH1_REF, {" + str(padding_size) + "{1'b0}} }"
f0.write(f" .MATCH1_REF({match1_padding_str})\n")
f0.write(" ) core (\n")
f0.write(" .clk_i(clk_i),\n")
f0.write(" .rst_i(rst_i),\n")
f0.write(" .up_down_i(up_down_i),\n")
f0.write(" .event_i(event_i),\n")
f0.write(" .enable_i(enable_i),\n")
f0.write(" .match0_o(match0_o),\n")
f0.write(" .match1_o(match1_o),\n")
f0.write(" .zero_o(zero_o)")
if self.__include_q_:
f0.write(",\n")
f0.write(f" .q_o(q_o)\n")
else:
f0.write("\n")
f0.write(" );\n")
f0.write("endmodule\n")
f0.write("`default_nettype wire\n")
# Clear all the data
def clear(self):
self.__init__()