diff --git a/Makefrag b/Makefrag index a04a1e4..4b6e4a6 100644 --- a/Makefrag +++ b/Makefrag @@ -55,6 +55,9 @@ $(build_dir)/$(long_name).fir $(build_dir)/$(long_name).prm $(build_dir)/$(long_ mkdir -p $(build_dir) cd $(base_dir) && $(SBT) "run-main $(PROJECT).Generator $(CHISEL_ARGS) $(build_dir) $(PROJECT) $(MODEL) $(CFG_PROJECT) $(CONFIG)" +$(base_dir)/vsrc/JtagTestHarness.v: $(build_dir)/$(long_name).fir + cd $(base_dir) && $(SBT) "run-main craft.JtagTestHarnessApp" + $(build_dir)/$(long_name).v $(build_dir)/$(long_name).harness.v $(build_dir)/$(long_name).conf: $(build_dir)/$(long_name).fir $(FIRRTL_JAR) cd $(base_dir) && $(SBT) "run-main barstools.tapeout.transforms.GenerateTopAndHarness -i $< --top-o $(build_dir)/$(long_name).v --harness-o $(build_dir)/$(long_name).harness.v --syn-top $(VLSICORE) --harness-top $(MODEL) --seq-mem-flags \"-o:$(build_dir)/$(long_name).conf\" --list-clocks \"-o:$(build_dir)/$(long_name).domains\" --anno-file $(build_dir)/$(long_name).anno" diff --git a/src/main/resources/JtagTestHarness.v b/src/main/resources/JtagTestHarness.v new file mode 100644 index 0000000..4199da0 --- /dev/null +++ b/src/main/resources/JtagTestHarness.v @@ -0,0 +1,58 @@ +`timescale {{timeUnitPs}}ps / {{timePrecisionFs}}fs +`define CLK_PERIOD {{clkMul}} +`define HALF_CLK_PERIOD {{clkHalfMul}} +`define RESET_TIME {{resetTime}} +`define INIT_TIME {{initTime}} + +`define expect(nodeName, nodeVal, expVal, cycle, message) \ + if (nodeVal !== expVal) begin \ + $display("\t ASSERTION ON %s FAILED @ CYCLE = %d, 0x%h != EXPECTED 0x%h\n", nodeName,cycle,nodeVal,expVal); \ + $display(message); \ + $stop; \ +end + +module {{moduleName}}( + // Inputs of DUT, outputs to this testbench + {{#each inputs}}output {{signed}}[{{width}}-1:0] {{name}}, + {{/each}} + // Outputs of DUT, inputs to this testbench + {{#each outputs}}input {{signed}}[{{width}}-1:0] {{name}}, + {{/each}} + output finish +); + + integer cycle = 0; + reg clock = 1; + reg reset = 1; + + {{#each inputs}}reg {{signed}}[{{width}}-1:0] reg_{{name}} = 0; + {{/each}} + + {{#each inputs}}assign {{name}} = reg_{{name}}; + {{/each}} + + always #`HALF_CLK_PERIOD clock = ~clock; + + initial begin + #`RESET_TIME + forever #`CLK_PERIOD cycle = cycle + 1; + end + + initial begin + #`INIT_TIME reset = 0; + {{#each statements}} + {{#if step}}// step {{step_n}} + #({{step_n}}*`CLK_PERIOD){{/if}}{{#if reset}}// reset {{reset_n}} + reset = 1; + #({{reset_n}}*`CLK_PERIOD) + reset = 0;{{/if}}{{#if poke}}// poke {{poke_name}} {{poke_value}} + reg_{{poke_name}} = {{poke_value}};{{/if}}{{#if expect}}// expect {{expect_name}} {{expect_value}} {{expect_message}} + `expect("{{expect_name}}", {{expect_name}}, {{expect_value}}, cycle, "{{expect_message}}"){{/if}}{{/each}} + + // finish = 1; + {{#if end_on_finish}} + #`CLK_PERIOD $display("\t **Ran through all test vectors**"); $finish; + {{/if}} + end +endmodule + diff --git a/src/main/scala/craft/JTAG.scala b/src/main/scala/craft/JTAG.scala index 4702d71..4a2718e 100644 --- a/src/main/scala/craft/JTAG.scala +++ b/src/main/scala/craft/JTAG.scala @@ -20,5 +20,6 @@ trait JTAGTestLevelIO { val tdi = Input(Bool()) val tdo = Output(Bool()) val tclk = Input(Bool()) + val tdo_driven = Output(Bool()) } diff --git a/src/main/scala/craft/JtagTestHarness.scala b/src/main/scala/craft/JtagTestHarness.scala new file mode 100644 index 0000000..c0b44df --- /dev/null +++ b/src/main/scala/craft/JtagTestHarness.scala @@ -0,0 +1,139 @@ +package craft + + +import cde._ +import chisel3.iotesters._ +import chisel3.iotesters.experimental._ +import diplomacy._ +import dspblocks._ +import jtag._ +import jtag.test._ +import uncore.tilelink._ +import _root_.junctions._ + +import org.scalatest._ +object ReportVerilog { + def getResource(name: String):String = { + import scala.io.Source + val stream = getClass.getResourceAsStream(name) + Source.fromInputStream( stream ).getLines.mkString("\n") + } + + def writeFile(name: String, contents:String): Unit = { + import java.io.{File, PrintWriter} + val writer = new PrintWriter(new File(name)) + writer.write(contents) + writer.close() + } + + def apply(stmts: Seq[Statement]): Unit = { + // inputs of the testbench, outputs of the DUT + val inputStrs = Set(stmts.map(_ match { + case PokeStatement(s, _) => Some(s) + case _ => None + }).flatten: _*) + // outputs of the testbench, inputs of the DUT + val outputStrs = Set(stmts.map(_ match { + case ExpectStatement(s, _, _) => Some(s) + case _ => None + }).flatten: _*) -- inputStrs + object JtagTest { + val moduleName = "JtagTestHarness" + val timeUnitPs = 1 + val timePrecisionFs = 100 + val clkMul = 16666 + val clkHalfMul = clkMul/2 + val resetTime = 0 + val initTime = 0 + val end_on_finish = true + val inputs = inputStrs.map(i => Map( + "width" -> 1, + "signed" -> "", + "name" -> i)) + val outputs = outputStrs.map(o => Map( + "width" -> 1, + "signed" -> "", + "name" -> o)) + val statements = stmts.map(s => { + val stepMap = s match { + case StepStatement(n) => Map( + "step" -> true, + "step_n" -> n) + case _ => Map( + "step" -> false, + "step_n" -> 0) + } + val resetMap = s match { + case ResetStatement(n) => Map( + "reset" -> true, + "reset_n" -> n) + case _ => Map( + "reset" -> false, + "reset_n" -> 0) + } + val pokeMap = s match { + case PokeStatement(n, v) => Map( + "poke" -> true, + "poke_name" -> n, + "poke_value" -> v) + case _ => Map( + "poke" -> false, + "poke_name" -> "", + "poke_value" -> 0) + } + val expectMap = s match { + case ExpectStatement(n, v, m) => Map( + "expect" -> true, + "expect_name" -> n, + "expect_value" -> v, + "expect_message" -> m) + case _ => Map( + "expect" -> false, + "expect_name" -> "", + "expect_value" -> 0, + "expect_message" -> "") + } + stepMap ++ resetMap ++ pokeMap ++ expectMap + }) + } + val testbench: String = { + import com.gilt.handlebars.scala.binding.dynamic._ + import com.gilt.handlebars.scala.Handlebars + + val template = getResource("/JtagTestHarness.v") + val t= Handlebars(template) + t(JtagTest) + } + + writeFile("vsrc/JtagTestHarness.v", testbench) + println(testbench) + } +} + +object JtagTestHarnessApp extends App with JtagAxiUtilities { + val p = Parameters.root((new Craft2SimpleConfig).toInstance).alterPartial { + case TLId => "craft-radar" + } + def dut(p: Parameters) = LazyModule(new DspChainWithADC()(p)).module + test(dut(p), testerBackend=chisel3.iotesters.experimental.IntermediateBackend, options = new TesterOptionsManager { + testerOptions = testerOptions.copy(intermediateReportFunc = ReportVerilog.apply _) + interpreterOptions = interpreterOptions.copy(setVerbose = false, writeVCD = true) + }) { implicit t => c => + implicit val n: HasNastiParameters = c.io.data_axi.ar.bits + + c.io.jtag map { j => + // let the chain come up + step(20) + + axiRead(j, BigInt(0x7000L), BigInt(0x0)) + step(10) + + axiWrite(j, BigInt(0x7000L), BigInt(0x7), id = 1) + step(10) + + axiRead(j, BigInt(0x7000L), BigInt(0x7)) + step(10) + } + } + +} diff --git a/tests/Makefile b/tests/Makefile index da9d757..fb1d7a8 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -2,7 +2,7 @@ GCC=riscv64-unknown-elf-gcc CFLAGS=-mcmodel=medany -std=gnu99 -O2 -fno-common -fno-builtin-printf LDFLAGS=-static -nostdlib -nostartfiles -lgcc -default: memcpy-dma.riscv pwm.riscv noop.riscv fft.riscv adc.riscv pg_prog.riscv +default: memcpy-dma.riscv pwm.riscv noop.riscv fft.riscv adc.riscv pg_prog.riscv spin.riscv %.o: %.S $(GCC) $(CFLAGS) -D__ASSEMBLY__=1 -c $< -o $@ diff --git a/tests/noop.c b/tests/noop.c index 7646a78..3300d31 100644 --- a/tests/noop.c +++ b/tests/noop.c @@ -2,6 +2,8 @@ #define PWM_DUTY 0x2008 #define PWM_ENABLE 0x2010 +#include + static inline void write_reg(unsigned long addr, unsigned long data) { volatile unsigned long *ptr = (volatile unsigned long *) addr; @@ -18,4 +20,5 @@ int main(void) { int i = 0; i++; + printf("Oh hai mark"); } diff --git a/tests/spin.c b/tests/spin.c new file mode 100644 index 0000000..7ccc917 --- /dev/null +++ b/tests/spin.c @@ -0,0 +1,5 @@ +int main(void) +{ + while(1); + return 0; +} diff --git a/vsrc/TestDriver.v b/vsrc/TestDriver.v index f96fba3..4124031 100644 --- a/vsrc/TestDriver.v +++ b/vsrc/TestDriver.v @@ -156,6 +156,27 @@ module TestDriver; end end + reg trst = 1'b0; + reg tclk; + reg tms; + reg tdi; + reg tdo; + reg tdo_driven; + + `ifdef JTAG_HARNESS + JtagTestHarness jtagHarness( + .io_jtag_TMS(tms), + .io_jtag_TCK(tclk), + .io_jtag_TDI(tdi), + .io_jtag_TDO_driven(tdo_driven), + .io_jtag_TDO_data(tdo) + ); + `else + tms = 1'b0; + tdi = 1'b0; + tclk = 1'b0; + `endif + wire [1:0] dummy; TestHarness testHarness( // TSI clock and reset @@ -180,11 +201,12 @@ module TestDriver; .io_ADCCLKP(dsp_clock), .io_ADCCLKM(~dsp_clock), // JTAG - .io_trst(reset), - .io_tclk(1'b0), - .io_tms(1'b0), - .io_tdi(1'b0), - .io_tdo(), + .io_trst(trst), + .io_tclk(tclk), + .io_tms(tms), + .io_tdi(tdi), + .io_tdo(tdo), + .io_tdo_driven(tdo_driven), // test IO .io_success(success) );