RoCC SW Wrappers now handled by generate_wrapper.py

This commit is contained in:
Nathan Pemberton 2019-11-06 01:55:48 +00:00
parent 841aab0053
commit 2f19dd036e
4 changed files with 163 additions and 366 deletions

View File

@ -75,7 +75,11 @@ sub generate_accel{
system("perl run_chisel.pl ${PGM} ${FUNC} $prefix"); system("perl run_chisel.pl ${PGM} ${FUNC} $prefix");
} }
if ($tasks{'accel_sw'}){ if ($tasks{'accel_sw'}){
system("perl generate_wrapper.pl ${PGM} ${FUNC} $idx_addr $prefix"); system("$RDIR/tools/centrifuge/scripts/generate_wrapper.py --fname ${FUNC} " .
"--prefix $prefix " .
"--base $idx_addr " .
"--mode 'rocc' " .
"--source $bm_path");
} }
#system("make clean"); #system("make clean");
#system("make CUSTOM_INST=1"); #system("make CUSTOM_INST=1");
@ -87,7 +91,6 @@ sub generate_accel{
} }
if ($tasks{'accel_sw'}){ if ($tasks{'accel_sw'}){
# system("perl generate_wrapper_tl.pl ${PGM} ${FUNC} $idx_addr $prefix");
system("$RDIR/tools/centrifuge/scripts/generate_wrapper.py --fname ${FUNC} " . system("$RDIR/tools/centrifuge/scripts/generate_wrapper.py --fname ${FUNC} " .
"--base $idx_addr " . "--base $idx_addr " .
"--prefix $prefix " . "--prefix $prefix " .

View File

@ -1,337 +0,0 @@
#!/usr/bin/perl
use warnings;
use strict;
use Cwd;
use File::Copy;
use List::Util qw(first);
# Inputs: file_name, func_name, rocc_index, prefix(Optional)
my $dir = getcwd;
my $file_name = $ARGV[0];
my $func_name = $ARGV[1];
my $rocc_index= $ARGV[2];
my $prefix = undef;
my $num_args = $#ARGV + 1;
if ($num_args > 3) {
$prefix = $ARGV[3];
}
my $rdir = $ENV{'RDIR'};
#print $rdir;
if ((not defined($rdir)) or $rdir eq '') {
print("Please source sourceme-f1.sh!\n");
exit();
}
my $wrapper_func_name = $func_name;
my $wrapper_file= "accel_wrapper.c";
my $wrapper_header= "accel_wrapper.h";
if ($prefix) {
$func_name = $prefix.$func_name;
}
my $bm_inc_path = $rdir."/tools/centrifuge/scripts/sw_aux/sw_helper/";
#############################PARSE Verilog##############################
my $verilog_file = "$dir/../verilog/$func_name".".v";
my $line = undef;
my @verilog_input = ();
my @verilog_input_size = ();
my @verilog_output = ();
my @verilog_output_size = ();
print "Parsing ".$verilog_file."\n";
# parse the verilog file to get the info we need
if(!open VERILOG, "$verilog_file"){
print $!;
} else {
while(<VERILOG>){
$line = $_;
if($line =~ m/^\s*input\s+(.*)/){
my $input = $1;
#print "input:$input\n";
if($input =~ m/\s*\[(.*):(.*)\]\s*(.*)\s*;/){
my $end = $1;
my $start = $2;
my $input_name = $3;
#print "here!"."$input_name\n";
push (@verilog_input, $input_name);
my $size = $end - $start + 1;
push(@verilog_input_size, $size);
}elsif ($input =~ m/\s*(.*)\s*;/){
my $input_name = $1;
#print "here!"."$input_name\n";
push (@verilog_input, $input_name);
push(@verilog_input_size, 1);
}
}elsif($line =~ m/^\s*output\s+(.*)/){
my $output = $1;
#print "output:$output\n";
if($output =~ m/\s*\[(.*):(.*)\]\s*(.*)\s*;/){
my $end = $1;
my $start = $2;
my $output_name = $3;
#print "here!"."$output_name\n";
push(@verilog_output, $output_name);
my $size = $end - $start + 1;
push(@verilog_output_size, $size);
}elsif ($output =~ m/\s*(.*)\s*;/){
my $output_name = $1;
#print "here!"."$output_name\n";
push (@verilog_output, $output_name);
push(@verilog_output_size, 1);
}
}
}
print("Inputs:");
my $in_str = join ' ', @verilog_input;
print $in_str."\n";
print("Outputs:");
my $out_str = join ' ', @verilog_output;
print $out_str."\n";
}
#creat scala folder
my $scala_dir = "$dir/../scala";
mkdir $scala_dir unless (-d $scala_dir);
##############################################################################################################################
print "Generating BlackBox file ...\n";
# should be under scala folder
my $blackbox1 = "
package hls_test_c
import Chisel._
import freechips.rocketchip.config.{Parameters, Field}
import freechips.rocketchip.tile._
import freechips.rocketchip.util._
import vivadoHLS._
class test_c() extends BlackBox() {
";
$blackbox1 =~ s/test_c/$func_name/g;
my $i = undef;
my $bb_body = "";
# now if the input name does not start with ap, we assume it is an arg
my $ap_return = 0;
my $ap_clk = 0;
my $ap_rst = 0;
my @verilog_input_scalar = ();
my %verilog_input_pointer = ();
my @verilog_input_pointer_arg = (); # An ordered list of args
my $arg_count = 0;
my @sindices = ();
my @pindices = ();
for( $i = 0; $i < @verilog_input; $i = $i + 1 ){
my $input_name = $verilog_input[$i];
my $input_size = $verilog_input_size[$i];
if ($input_name =~ m/ap_clk(.*)/){
$ap_clk = 1;
}
elsif ($input_name =~ m/ap_rst(.*)/){
$ap_rst = 1;
}
# If the input is a ap_bus port, the signals should match the following format
# There should be 3 different input signals
elsif($input_name =~ m/(\S+)_req_full_n/ or $input_name =~ m/(\S+)_rsp_empty_n/ or $input_name =~ m/(\S+)_datain/){
my $arg_name = $1;
if ($input_name =~ m/(\S+)_datain/) {
push(@pindices, $arg_count);
$arg_count = $arg_count + 1;
push(@verilog_input_pointer_arg, $arg_name);
}
if (defined $verilog_input_pointer{$arg_name}) {
$verilog_input_pointer{$arg_name} += 1;
} else {
$verilog_input_pointer{$arg_name} = 1;
}
}
elsif(!($input_name =~ m/ap_(,*)/)){
push (@verilog_input_scalar, $input_name);
push(@sindices, $arg_count);
$arg_count = $arg_count + 1;
}
else{
print("Not func args: $input_name\n");
}
}
#foreach my $arg (keys %verilog_input_pointer) {
foreach my $arg (@verilog_input_pointer_arg) {
print("pointer_arg: $arg\n");
}
my $hash_count = keys %verilog_input_pointer;
print("hash_count: $hash_count\n");
if(@verilog_input_scalar + $hash_count> 2){
print "verilog_input_scalar: ";
my $in_str = join ' ', @verilog_input_scalar;
print $in_str."\n";
die "Only accept function with no more than 2 arguments!\n";
}
foreach my $arg (keys %verilog_input_pointer) {
if ($verilog_input_pointer{$arg} ne 3) {
die "The AP bus interfance did not generate expected number of inputs!\n";
}
}
for( $i = 0; $i < @verilog_output; $i = $i + 1 ){
my $output_name = $verilog_output[$i];
my $output_size = $verilog_output_size[$i];
if ($output_name =~ m/ap_return(.*)/){
$ap_return = 1;
}
$bb_body = $bb_body."\tio.".$output_name.".setName(\"".$output_name."\")\n";
}
if ($ap_clk eq 1){
$bb_body = $bb_body."addClock(Driver\.implicitClock)\n".'renameClock("clk", "ap_clk")'."\n";
}
if ($ap_rst eq 1){
$bb_body = $bb_body.'renameReset("ap_rst")'."\n";
}
my $bb_def = "class HLS$func_name"."Blackbox() extends Module {\n";
# Scalar IO Parameter
my @sdata_widths = ();
#my @sindices = ();
#my $sidx = 0;
foreach my $arg (@verilog_input_scalar) {
my $sdata_idx = first { $verilog_input[$_] eq $arg} 0..$#verilog_input;
my $sdata_width = $verilog_input_size[$sdata_idx];
push(@sdata_widths, $sdata_width);
#push(@sindices, $sidx);
#$sidx += 1;
}
my $sindices_str = join ',',@sindices;
my $sdata_widths_str = join ',',@sdata_widths;
print "scalar data_widths: $sdata_widths_str\n";
$bb_def .= "\tval scalar_io_dataWidths = List($sdata_widths_str)\n";
$bb_def .= "\tval scalar_io_argLoc = List($sindices_str) //Lists the argument number of the scalar_io\n";
# Pointer IO Parameter
my @addr_widths = ();
my @data_widths = ();
#my @indices = ();
my $idx = 0;
foreach my $arg (sort keys %verilog_input_pointer) {
my $addr_signal = $arg."_address";
my $data_signal = $arg."_dataout";
my $addr_idx = first { $verilog_output[$_] eq $addr_signal } 0..$#verilog_output;
my $data_idx = first { $verilog_output[$_] eq $data_signal } 0..$#verilog_output;
#my $addr_width = $verilog_output_size[$addr_idx];
my $addr_width = "64";
my $data_width = $verilog_output_size[$data_idx];
push(@addr_widths, $addr_width);
push(@data_widths, $data_width);
#push(@indices, $idx);
$idx += 1;
}
#my $indices_str = join ',',@indices;
my $pindices_str = join ',',@pindices;
my $addr_widths_str = join ',',@addr_widths;
print "addr_widths: $addr_widths_str\n";
my $data_widths_str = join ',',@data_widths;
print "data_widths: $data_widths_str\n";
foreach my $arg (@verilog_input_pointer_arg) {
print("pointer_arg: $arg\n");
}
my $wrapper = '#include "'.$bm_inc_path.'rocc.h"'."\n";
$wrapper .="#define ACCEL_WRAPPER\n";
$wrapper .='#include "accel.h"'."\n";
my $return_type = "void ";
if($ap_return){
$return_type = "uint64_t ";
}
my $total_args = @verilog_input_scalar + $hash_count;
my $func_prototype = "$return_type $wrapper_func_name(";
my @args = ();
foreach my $arg (@verilog_input_scalar) {
push(@args, $arg);
}
foreach my $arg (@verilog_input_pointer_arg) {
push(@args, $arg);
}
my $arg_str = join ', ', @args;
$i = 0;
foreach my $arg (@args) {
if ($i != 0){
$func_prototype.=", "
}
$func_prototype .="uint64_t $arg";
$i=1;
}
$func_prototype .= ")";
$wrapper .= $func_prototype;
if($ap_return){
$wrapper .= "
{
uint64_t ret_val;\n";
}
#$wrapper .= " ROCC_BARRIER();\n";
$wrapper .="
#define XCUSTOM_ACC ";
$wrapper .= $rocc_index."\n";
if ($ap_return){
if ($total_args == 0) {
$wrapper.=" ROCC_INSTRUCTION_D(XCUSTOM_ACC, ret_val, 0);\n";
} elsif ($total_args == 1) {
$wrapper.=" ROCC_INSTRUCTION_DS(XCUSTOM_ACC, ret_val, $arg_str, 0);\n";
} else {
$wrapper.=" ROCC_INSTRUCTION_DSS(XCUSTOM_ACC, ret_val, $arg_str, 0);\n";
}
} else{
if ($total_args == 0) {
$wrapper.=" ROCC_INSTRUCTION(XCUSTOM_ACC, 0);\n";
} elsif ($total_args == 1) {
$wrapper.=" ROCC_INSTRUCTION_S(XCUSTOM_ACC, $arg_str, 0);\n";
} else {
$wrapper.=" ROCC_INSTRUCTION_SS(XCUSTOM_ACC, $arg_str, 0);\n";
}
}
$wrapper .= " ROCC_BARRIER();\n";
if($ap_return){
$wrapper .= " return ret_val;\n";
}
$wrapper.="}";
open FILE, "> $wrapper_header";
print FILE "#ifndef ACCEL_WRAPPER_H
#define ACCEL_WRAPPER_H\n
";
print FILE "$func_prototype;\n";
print FILE "#endif";
close FILE;
open FILE, "> $wrapper_file";
print FILE $wrapper;
close FILE;

View File

@ -27,15 +27,77 @@ class MmioArg():
else: else:
raise RuntimeError("Unsupported variable size: " + str(self.size)) raise RuntimeError("Unsupported variable size: " + str(self.size))
def generateHeader(signature):
"""Given the signature of the accelerated function, return an appropriate
header file. """
header = ("#ifndef ACCEL_WRAPPER_H\n"
"#define ACCEL_WRAPPER_H\n")
header += '\n'
header += signature + ";\n"
header += "#endif"
return header
def ident(n):
return " "*n
def cleanRoccArg(body):
"""Cleans up a RoccArg. Returns True if the argument was cleaned and can be
used, returns False if the argument should be ignored."""
reIgnore = re.compile('ap_clk.*|ap_rst.*|\S+_req_full_n|\S+_rsp_empty_n')
reBaseName = re.compile('ap_(\S+)|(\S+)_datain')
if reIgnore.match(body):
return None
m = reBaseName.match(body)
if not m:
raise ValueError("Could not parse argument name: " + body)
return m.group(m.lastindex)
def parseVerilogRocc(vpath):
"""Parse a centrifuge-generated verilog file to extract the information
needed to generate a RoCC wrapper.
vpath: Path to main verilog function file
Returns: (inputs, retVal)
inputs - list of argument names
retVal - boolean indicating whether or not a return value is present
"""
# Input/Output statements in the verilog. We assume only one module in the file.
reInput = re.compile('^\s*input\s+\[.*:.*\]\s*(.*)')
reReturnVal = re.compile('^\s*output\s+\[(.*):(.*)\]\s*ap_return;')
print("Parsing: ",vpath)
inputs = []
retVal = False
with open(vpath, 'r') as vf:
for line in vf.readlines():
inMatch = reInput.match(line)
if inMatch:
argName = cleanRoccArg(inMatch.group(1))
if argName:
inputs.append(argName)
else:
if reReturnVal.match(line):
retVal = True
return inputs, retVal
def parseVerilogTL(vpath): def parseVerilogTL(vpath):
"""Parse a centrifuge-generated verilog file to extract the information """Parse a centrifuge-generated verilog file to extract the information
needed to generate tilelink wrappers. needed to generate tilelink wrappers.
vpath: Path to the verilog file to parse (path-like object) vpath: Path to the verilog file containing control signal info (path-like object)
returns: (returnSize, Args) returns: (returnSize, Args)
returnSize: The size of the return value in 32-bit words. Either 0, 1, or 2. retVal: MmioArg representing the return value (or None if no return).
Args: An ordered dictionary of mappings from argument name to base address Args: List of MmioArg representing the arguments to the accelerated function
""" """
with open(vpath, 'r') as vf: with open(vpath, 'r') as vf:
print("Parsing: ",vpath) print("Parsing: ",vpath)
@ -70,16 +132,74 @@ def parseVerilogTL(vpath):
return (retVal, list(args.values())) return (retVal, list(args.values()))
def generateHeaderTL(signature): def generateWrapperRocc(fname, roccIdx, inputs, retVal):
"""Given the signature of the accelerated function, return an appropriate """Returns a Rocc C wrapper given a function.
header file. """
header = ("#ifndef ACCEL_WRAPPER_H\n" fname - name of the function
"#define ACCEL_WRAPPER_H\n") inputs - list of argument names
retVal - boolean indicating whether or not a value is returned
"""
header += signature + ";\n" # current indentation level
header += "#endif" lvl = 0
return header
cWrapper = ('#include "rocc.h"\n'
'\n'
'#define ACCEL_WRAPPER\n'
'#include "accel.h"\n'
'\n')
cWrapper += ident(lvl) + "#define XCUSTOM_ACC " + roccIdx + "\n"
cWrapper += "\n"
signature = ""
if retVal:
retStr = "uint64_t"
else:
retStr = "void"
signature += retStr + " " + fname + "("
argStrs = []
for arg in inputs:
argStrs.append("uint64_t " + arg)
signature += ", ".join(argStrs)
signature += ")"
cWrapper += signature + "\n"
cWrapper += "{\n"
lvl = 1
if retVal:
cWrapper += ident(lvl) + "uint64_t ret_val;\n"
cWrapper += "\n"
if len(inputs) == 0:
cWrapper += ident(lvl) + "ROCC_INSTRUCTION_D(XCUSTOM_ACC, ret_val, 0);\n"
elif len(inputs) == 1:
cWrapper += ident(lvl) + "ROCC_INSTRUCTION_DS(XCUSTOM_ACC, ret_val, " + inputs[0] + ", 0);\n"
elif len(inputs) == 2:
cWrapper += ident(lvl) + "ROCC_INSTRUCTION_DSS(XCUSTOM_ACC, ret_val, " + inputs[0] + ", " + inputs[1] + ", 0);\n"
else:
raise ValueError("Too many inputs. Rocc only supports up to 2 arguments, was passed " + len(inputs))
else:
if len(inputs) == 0:
cWrapper += ident(lvl) + "ROCC_INSTRUCTION(XCUSTOM_ACC, 0);\n"
elif len(inputs) == 1:
cWrapper += ident(lvl) + "ROCC_INSTRUCTION_S(XCUSTOM_ACC, " + inputs[0] + ", 0);\n"
elif len(inputs) == 2:
cWrapper += ident(lvl) + "ROCC_INSTRUCTION_SS(XCUSTOM_ACC, " + inputs[0] + ", 0);\n"
else:
raise ValueError("Too many inputs. Rocc only supports up to 2 arguments, was passed " + len(inputs))
cWrapper += ident(lvl) + "ROCC_BARRIER();\n"
cWrapper += '\n'
if retVal:
cWrapper += ident(lvl) + "return ret_val;\n"
cWrapper += "}"
return cWrapper, generateHeader(signature)
def generateWrapperTL(fname, baseAddr, retVal, args): def generateWrapperTL(fname, baseAddr, retVal, args):
"""Given a set of mmio address/varialble pairs, produce the C wrapper """Given a set of mmio address/varialble pairs, produce the C wrapper
@ -92,9 +212,9 @@ def generateWrapperTL(fname, baseAddr, retVal, args):
""" """
cWrapper = ('#include "mmio.h"\n' cWrapper = ('#include "mmio.h"\n'
'#define ACCEL_WRAPPER\n'
'#include "accel.h"\n' '#include "accel.h"\n'
'\n' '\n'
'#define ACCEL_WRAPPER\n'
'#define AP_DONE_MASK 0b10\n') '#define AP_DONE_MASK 0b10\n')
# MMIO Constants # MMIO Constants
@ -125,7 +245,7 @@ def generateWrapperTL(fname, baseAddr, retVal, args):
# Pass Args to MMIO # Pass Args to MMIO
cWrapper += " //Disable Interrupts\n" cWrapper += " //Disable Interrupts\n"
cWrapper += " reg_write32(ACCEL_BASE + ACCEL_INT, 0x0)\n" cWrapper += " reg_write32(ACCEL_BASE + ACCEL_INT, 0x0);\n"
for arg in args: for arg in args:
cWrapper += " reg_write32(ACCEL_BASE + ACCEL_"+arg.name+"_0, (uint32_t) "+arg.name+");\n" cWrapper += " reg_write32(ACCEL_BASE + ACCEL_"+arg.name+"_0, (uint32_t) "+arg.name+");\n"
if arg.size == 2: if arg.size == 2:
@ -143,6 +263,7 @@ def generateWrapperTL(fname, baseAddr, retVal, args):
# Handle returns (if any) # Handle returns (if any)
if retVal is not None: if retVal is not None:
cWrapper += "\n"
cWrapper += " " + retVal.cType() + " ret_val = 0;\n" cWrapper += " " + retVal.cType() + " ret_val = 0;\n"
cWrapper += " ret_val = reg_read32(ACCEL_BASE + ACCEL_"+retVal.name+"_0);\n" cWrapper += " ret_val = reg_read32(ACCEL_BASE + ACCEL_"+retVal.name+"_0);\n"
if retVal.size == 2: if retVal.size == 2:
@ -150,14 +271,14 @@ def generateWrapperTL(fname, baseAddr, retVal, args):
cWrapper += "}" cWrapper += "}"
return cWrapper, generateHeaderTL(signature) return cWrapper, generateHeader(signature)
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Generate software wrappers for a given centrifuge-generated function.") description="Generate software wrappers for a given centrifuge-generated function.")
parser.add_argument('-n', '--fname', required=True, help="Name of function to accelerate") parser.add_argument('-n', '--fname', required=True, help="Name of function to accelerate")
parser.add_argument('-b', '--base', required=True, help="Base address of function (if tilelink)") parser.add_argument('-b', '--base', required=True, help="Base address of function (if tilelink), RoCC index (if rocc)")
parser.add_argument('-p', '--prefix', default="", help="Optional prefix for function") parser.add_argument('-p', '--prefix', default="", help="Optional prefix for function")
parser.add_argument('-m', '--mode', required=True, parser.add_argument('-m', '--mode', required=True,
help="Function integration mode (either 'tl' or 'rocc')") help="Function integration mode (either 'tl' or 'rocc')")
@ -171,11 +292,17 @@ if __name__ == '__main__':
args.source / 'src' / 'main' / 'verilog' / (args.prefix + args.fname + "_control_s_axi.v")) args.source / 'src' / 'main' / 'verilog' / (args.prefix + args.fname + "_control_s_axi.v"))
cWrapper, hWrapper = generateWrapperTL(args.fname, args.base, retVal, funcArgs) cWrapper, hWrapper = generateWrapperTL(args.fname, args.base, retVal, funcArgs)
with open(args.source / 'src' / 'main' / 'c' / 'accel_wrapper.c', 'w') as cF: elif args.mode == 'rocc':
cF.write(cWrapper) inputs, retVal = parseVerilogRocc(
args.source / 'src' / 'main' / 'verilog' / (args.prefix + args.fname + ".v"))
with open(args.source / 'src' / 'main' / 'c' / 'accel_wrapper.h', 'w') as hF: cWrapper, hWrapper = generateWrapperRocc(args.fname, args.base, inputs, retVal)
hF.write(hWrapper)
else: else:
raise NotImplementedError("Mode '" + args.mode + "' not supported.") raise NotImplementedError("Mode '" + args.mode + "' not supported.")
with open(args.source / 'src' / 'main' / 'c' / 'accel_wrapper.c', 'w') as cF:
cF.write(cWrapper)
with open(args.source / 'src' / 'main' / 'c' / 'accel_wrapper.h', 'w') as hF:
hF.write(hWrapper)

View File

@ -4,6 +4,10 @@ CFLAGS+=-mcmodel=medany -std=gnu99 -O2 -fno-common -fno-builtin-printf -Wall -DW
LDFLAGS=-static -nostdlib -nostartfiles -lgcc LDFLAGS=-static -nostdlib -nostartfiles -lgcc
BM_LIB_DIR=${RDIR}/tools/centrifuge/scripts/sw_aux/bm_linker_scripts/ BM_LIB_DIR=${RDIR}/tools/centrifuge/scripts/sw_aux/bm_linker_scripts/
BM_INC_DIR=${RDIR}/tools/centrifuge/scripts/sw_aux/sw_helper/
INCLUDES=-I${BM_LIB_DIR} -I${BM_INC_DIR}
BM_LIB_FLAG=-lriscvbm BM_LIB_FLAG=-lriscvbm
BM_LIB=$(BM_LIB_DIR)/libriscvbm.a BM_LIB=$(BM_LIB_DIR)/libriscvbm.a
@ -41,23 +45,23 @@ all: $(addsuffix .bm.rv,$(TARGET)) bm_accel
dumps: $(addsuffix .dump,$(TARGET)) dumps: $(addsuffix .dump,$(TARGET))
.s.o: $(SRC_S) %.s.o: %.S
$(CC) $(CFLAGS) -D__ASSEMBLY__=1 -c $< -o $@ $(CC) $(CFLAGS) $(INCLUDES) -D__ASSEMBLY__=1 -c $< -o $@
.o: $(SRC) %.o: %.c
$(CC) $(CFLAGS) -c $< -o $@ $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
#%.rv: %.o crt.o syscalls.o $(BM_LIB_DIR)/bm_linker_scripts/link.ld #%.rv: %.o crt.o syscalls.o $(BM_LIB_DIR)/bm_linker_scripts/link.ld
# Use $info to debug # Use $info to debug
#$(TARGET).rv: $(OBJ) $(BM_LIB) $(BM_LIB_DIR)/link.ld $(info $(OBJ)) #$(TARGET).rv: $(OBJ) $(BM_LIB) $(BM_LIB_DIR)/link.ld $(info $(OBJ))
$(TARGET).bm.rv: Makefile $(OBJ) $(BM_LIB) $(BM_LIB_DIR)/link.ld $(TARGET).bm.rv: Makefile $(OBJ) $(BM_LIB) $(BM_LIB_DIR)/link.ld
$(CC) -T $(BM_LIB_DIR)/link.ld $(LDFLAGS) -I$(BM_LIB_DIR) -L$(BM_LIB_DIR) $(BM_LIB_FLAG) $(OBJ_BASE) -o $@ $(CC) -T $(BM_LIB_DIR)/link.ld $(LDFLAGS) $(INCLUDES) -L$(BM_LIB_DIR) $(BM_LIB_FLAG) $(OBJ_BASE) -o $@
# Add new target # Add new target
bm_accel: $(addsuffix .bm_accel.rv,$(TARGET)) bm_accel: $(addsuffix .bm_accel.rv,$(TARGET))
$(TARGET).bm_accel.rv: $(OBJ) $(BM_LIB) $(BM_LIB_DIR)/link.ld $(TARGET).bm_accel.rv: $(OBJ) $(BM_LIB) $(BM_LIB_DIR)/link.ld
$(CC) -T $(BM_LIB_DIR)/link.ld $(LDFLAGS) -I$(BM_LIB_DIR) -L$(BM_LIB_DIR) $(BM_LIB_FLAG) $(OBJ_ACCEL) -o $@ $(CC) -T $(BM_LIB_DIR)/link.ld $(LDFLAGS) $(INCLUDES) -L$(BM_LIB_DIR) $(BM_LIB_FLAG) $(OBJ_ACCEL) -o $@
%.dump: %.rv %.dump: %.rv
$(OBJDUMP) -D $< > $@ $(OBJDUMP) -D $< > $@