1
0

Compare commits

...

60 Commits

Author SHA1 Message Date
8710fe9561 Add WithClockFrequency class to update frequencies 2018-06-06 01:04:47 +02:00
81d631a6a1 Add small rocket config with fpu and mmu
This is required for booting linux. The caches are still as small as
in the small core config, so performance will not be great.
2018-05-19 18:56:56 +02:00
6df42fc360 ml507: readmemh does not support dynamic paths on ISE 2018-05-01 00:10:15 +02:00
4ba8acb4aa TLRAM: add support for ECC (#1304) 2018-03-22 14:27:43 -07:00
12583af4a8 buswrapper: remove buffer chains from api (#1303)
Just take a single BufferParams for all couplers.
Add TLBuffer.chain in the thunk if you need it.
Preserves default bufferings.
2018-03-21 23:44:05 -07:00
4cfae27efd Implement Hauser misa.C misalignment proposal (#1301)
See 0472bcdd16

- Reads of xEPC[1] are masked when RVC is disabled
- Writes to MISA are suppressed if they would cause a misaligned fetch
- Misaligned PCs no longer need to be checked in decode
2018-03-21 23:42:01 -07:00
7f96da2288 ECC: support poison during encode (#1166)
This makes it possible to update an ECC-protected word while
retaining the fact that the value has an ECC error.
2018-03-21 16:29:24 -07:00
7593baf2aa Merge pull request #1299 from freechipsproject/serializable-metadata
Store metadata in serializable case classes
2018-03-21 11:58:05 -07:00
f48c2767d7 subsytem: change front bus buffer defaults (#1300) 2018-03-21 11:56:22 -07:00
894960678c Update Debug Module registers (#1296)
* Debug: update versions of the files generated from the spec, mostly to get new SBA registers

* Debug: Clean up Halt Summary to use new terminology

* Debug: correct the address of HALTSUM1

* Debug: use simpler expression for numHaltedStatus

* Debug: remove now defunct haltStatus addr
2018-03-20 14:01:22 -07:00
70895b6ffa rocket: make RocketTileParams trivial to serialize
By storing ECC setting as Option[String] and converting it
to a scala Code class later.
2018-03-20 11:25:02 -07:00
12997a644d tilelink: TLToAXI4IdMapEntry 2018-03-20 11:24:46 -07:00
3cb9e57b5e diplomacy: AddressMapEntry and BindingScope.collect 2018-03-20 11:24:41 -07:00
2489a08328 Header required for -DVM_TRACE=1 (#1294)
With -DVM_TRACE=1 on gcc 7.2.0.

Very small change.  May only affect me.  Is it possible -DVM_TRACE=1 is not regressed?

~~~~
http://en.cppreference.com/w/cpp/memory/unique_ptr
[..]/emulator.cc: In function ‘int main(int, char**)’:
[..]/emulator.cc:254:19: error: ‘VerilatedVcdFILE’ was not declared in this scope
   std::unique_ptr<VerilatedVcdFILE> vcdfd(new VerilatedVcdFILE(vcdfile));
~~~~
More info : http://en.cppreference.com/w/cpp/memory/unique_ptr

~~~~
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.2.0-8ubuntu3.2' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.2.0 (Ubuntu 7.2.0-8ubuntu3.2) 
~~~~
2018-03-19 20:07:28 -05:00
9a56e44e32 Fix typo in RAMModel Get printf (#1293) 2018-03-19 11:30:41 -07:00
d6bc9c53f0 Save a little power during reset by not writing D$ tags (#1287) 2018-03-15 19:23:09 -05:00
78dad3e89b Merge pull request #1279 from freechipsproject/ipxact_descs
More IP-XACT-like RegFieldDesc
2018-03-14 06:46:00 -07:00
4e11491531 Merge remote-tracking branch 'origin/master' into ipxact_descs 2018-03-13 09:26:47 -07:00
1c1b6e8ffe Merge pull request #1282 from freechipsproject/revert_debug_flags
Revert "Debug: don't need to fully populate flags array"
2018-03-13 09:09:39 -07:00
d00a0bba32 Revert "Debug: don't need to fully populate flags array"
This reverts commit 197699b93a.
2018-03-12 21:29:55 -07:00
59d5e61366 regmapper: refactor how json is emitted 2018-03-12 08:24:36 -07:00
ea89259dd4 RegFieldDesc: reserved omits () 2018-03-12 08:24:36 -07:00
15e058e3da RegFieldDesc: change how reserved is indicated 2018-03-12 08:24:36 -07:00
d889a0ca16 RegFieldDesc: add volatile to cause reg in BUE 2018-03-12 08:24:36 -07:00
e0c3c63826 RegFieldDesc: Update the .bytes method to emit reserved register fields
instead of applying the same description to the registers that it doesn't
actually do anything with (the padding registers)
2018-03-12 08:24:36 -07:00
0fcacd37df RegFieldDesc: mark some more registers as volatile 2018-03-12 08:24:36 -07:00
7458378a4a RegFieldDesc: Update reg field descs to be more correct for devices. 2018-03-12 08:24:36 -07:00
3063fd1b46 RegFieldDesc: update DescribedReg to suppot new features 2018-03-12 08:24:36 -07:00
2f239f2a9a RegFieldDesc: Add more features to support more IP-XACT like descriptions & emit them in the JSON 2018-03-12 08:24:36 -07:00
e07b37c7ad Merge pull request #1186 from edcote/patch-1
Update TestDriver module to support FSDB
2018-03-11 11:40:25 -07:00
d3c16258fd Merge pull request #1280 from freechipsproject/reg-desc-anno
util: use chisel3.core.dontTouch
2018-03-10 19:50:54 -08:00
0e0963d360 util: use chisel3.core.dontTouch 2018-03-10 17:04:46 -08:00
99862942fe Merge pull request #1276 from freechipsproject/reg-desc-anno
sbt: bump json4s-jackson to 3.5.3
2018-03-08 19:04:23 -08:00
1b93b27da4 util: restore dontTouch annotation; Chisel's is broken on 0 element Aggregates 2018-03-08 16:12:15 -08:00
933f2ce958 Bump riscv-tools for riscv-fesvr submodule ptr fix (#1275)
The riscv-fesvr submodule was pointing at my local version, oops. This
corrects that in an updated version of riscv-tools.

Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
2018-03-08 14:27:51 -08:00
d6e2c1a73f more != wire deprecations 2018-03-08 12:36:51 -08:00
32592377c6 sbt: bump json4s-jackson to 3.5.3 2018-03-08 12:31:52 -08:00
8bb397a1b9 Fix VCS argument parsing (#1266)
* Add +permissive/+permissive-off for VCS args

This adds guards around Verilog/VCS options for VCS calls with HTIF's
new `+permissive`/`+permissive-off` options. This enables HTIF to
permissively parse all options inside one of these guards while not
erroring on unknonw commands. This is necessary for VCS, unlike with the
emulator, as HTIF is giving all commands as opposed to only host and
target arguments (like with Verilator/emulator.cc).

* Bump riscv-tools for fesvr VCS fix

* Bump riscv-rools/riscv-fesvr (VCS stderr fix)

Fixes #1266

Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
2018-03-07 22:59:04 -08:00
7d146f3401 Merge pull request #1273 from freechipsproject/no_jtag_vpi
Deprecate JTAGVPI
2018-03-07 14:50:26 -08:00
ef7a6115b7 vsim: don't need VPI without JTAGVPI 2018-03-07 10:58:09 -08:00
15dc7f6760 JTAGVPI: remove it from Chisel as it is unused 2018-03-07 10:55:45 -08:00
42e614550c JTAGVPI: remove it in favor of remote bitbang 2018-03-07 10:53:49 -08:00
64b707cbb6 Bump Chisel and FIRRTL for annotations refactor (#1261)
Also brings in an autoclonetype enhancement and some bug fixes
2018-03-07 10:22:38 -08:00
d0b46c5b8f Align RoCCIO with new cloneType (#1270)
- Aligns RoCC with #1232.
- Fixes #1268.

Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
2018-03-06 17:53:51 -08:00
f1bd9c99aa Merge pull request #1262 from freechipsproject/beu-regfield
Add BusErrorUnit RegFieldDesc
2018-03-06 12:31:00 -08:00
f00e9576e3 Merge pull request #1263 from freechipsproject/sim_jtag_reset
SimJTAG: make the reset/init connectivity more flexible.
2018-03-06 11:28:51 -08:00
b669fb3d6a Merge remote-tracking branch 'origin/master' into beu-regfield 2018-03-06 11:04:17 -08:00
2a0e67ab15 Merge pull request #1267 from freechipsproject/plic_source_0
PLIC: Update RegFieldDesc:  source 0 is different
2018-03-06 11:03:26 -08:00
a3d99e5ba2 DescribedReg: fix some imports 2018-03-06 11:02:10 -08:00
a20998e215 SimJTAG: fix verilog typo 2018-03-05 16:27:17 -08:00
8856953905 DescribedReg: move to regmapper 2018-03-05 16:12:14 -08:00
4256d99a9b PLIC: priority/threshold are really WARL (RWSPECIAL). Explain why. 2018-03-05 16:10:05 -08:00
41d1a62713 PLIC: Update RegFieldDesc to reflect the fact that source 0 isn't like all the others 2018-03-05 15:29:14 -08:00
bd3a72e585 Merge remote-tracking branch 'origin/master' into sim_jtag_reset 2018-03-05 12:41:39 -08:00
e3be5db3e6 BUE: more verbose register descriptions 2018-03-05 12:02:42 -08:00
878a357a0d RegFieldDesc: Add utilities for generating and describing registers at the same time. 2018-03-05 12:02:42 -08:00
5eae81038d SimJTAG: make the reset/init connectivity more flexible. This is because you may want to seperate the two 2018-03-02 17:29:17 -08:00
644ba6dafa Add BusErrorUnit RegFieldDesc 2018-03-02 17:25:13 -08:00
904f0f3d93 enhance error message when debug enabled
This commit enhances the error message when the user enables waveform dump at runtime but forgets to enable the compile time define.
2018-01-13 13:35:52 -08:00
42e5e92d43 Update TestDriver module to support FSDB
Add support for FSDB waveform dumping using existing API.  Feature is enabled using +define+FSDB.

Change has not been fully regressed (i.e., please don't pull blindly).  Impact on existing knobs is minimal, should not affect existing functionality.  Automated Travis builds should be sufficient to assess.

Alternatively could using +define+VCS.  Chose to introduce new define because multiple simulators support FSDB dumping.
2018-01-09 09:54:34 -08:00
55 changed files with 966 additions and 1272 deletions

View File

@ -15,7 +15,7 @@ lazy val commonSettings = Seq(
traceLevel := 15,
scalacOptions ++= Seq("-deprecation","-unchecked"),
libraryDependencies ++= Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value),
libraryDependencies ++= Seq("org.json4s" %% "json4s-jackson" % "3.5.0"),
libraryDependencies ++= Seq("org.json4s" %% "json4s-jackson" % "3.5.3"),
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
)

Submodule chisel3 updated: 97871178cb...531dd6cb7a

View File

@ -3,6 +3,7 @@
#include "verilated.h"
#if VM_TRACE
#include <memory>
#include "verilated_vcd_c.h"
#endif
#include <fesvr/dtm.h>

View File

@ -1,430 +0,0 @@
/*
* TCP/IP controlled VPI JTAG Interface.
* Based on Julius Baxter's work on jp_vpi.c
*
* Copyright (C) 2012 Franck Jullien, <franck.jullien@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of any
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <arpa/inet.h>
#include <vpi_user.h>
// Calling bind with port 0 will return a socket bound to an unused port.
#define RSP_SERVER_PORT 0
#define XFERT_MAX_SIZE 512
const char * cmd_to_string[] = {"CMD_RESET",
"CMD_TMS_SEQ",
"CMD_SCAN_CHAIN"};
struct vpi_cmd {
int cmd;
unsigned char buffer_out[XFERT_MAX_SIZE];
unsigned char buffer_in[XFERT_MAX_SIZE];
int length;
int nb_bits;
};
int listenfd = 0;
int connfd = 0;
int init_jtag_server(int port)
{
struct sockaddr_in serv_addr;
int flags;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(port);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 10);
socklen_t socklen = sizeof(serv_addr);
if (getsockname(listenfd, (struct sockaddr *)&serv_addr, &socklen) == -1) {
perror("init_jtag_server");
fflush(stderr);
exit(1);
} else {
printf("Listening on port %d\n", ntohs(serv_addr.sin_port));
fflush(stdout);
}
printf("Waiting for client connection...");
fflush(stdout);
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
printf("ok\n");
fflush(stdout);
flags = fcntl(listenfd, F_GETFL, 0);
fcntl(listenfd, F_SETFL, flags | O_NONBLOCK);
return 0;
}
// See if there's anything on the FIFO for us
void check_for_command(char *userdata)
{
vpiHandle systfref, args_iter, argh;
struct t_vpi_value argval;
struct vpi_cmd vpi;
int nb;
int loaded_words = 0;
(void)userdata;
// Get the command from TCP server
if(!connfd)
init_jtag_server(RSP_SERVER_PORT);
nb = read(connfd, &vpi, sizeof(struct vpi_cmd));
if (((nb < 0) && (errno == EAGAIN)) || (nb == 0)) {
// Nothing in the fifo this time, let's return
return;
} else {
if (nb < 0) {
// some sort of error
perror("check_for_command");
exit(1);
}
}
/************* vpi.cmd to VPI ******************************/
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
// get a handle on the variable passed to the function
argh = vpi_scan(args_iter);
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the command value
vpi_get_value(argh, &argval);
argval.value.integer = (uint32_t)vpi.cmd;
// And vpi_put_value() it back into the sim
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
/************* vpi.length to VPI ******************************/
// now get a handle on the next object (memory array)
argh = vpi_scan(args_iter);
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the command value
vpi_get_value(argh, &argval);
argval.value.integer = (uint32_t)vpi.length;
// And vpi_put_value() it back into the sim
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
/************* vpi.nb_bits to VPI ******************************/
// now get a handle on the next object (memory array)
argh = vpi_scan(args_iter);
// now store the command value back in the sim
argval.format = vpiIntVal;
// Now set the command value
vpi_get_value(argh, &argval);
argval.value.integer = (uint32_t)vpi.nb_bits;
// And vpi_put_value() it back into the sim
vpi_put_value(argh, &argval, NULL, vpiNoDelay);
/*****************vpi.buffer_out to VPI ********/
// now get a handle on the next object (memory array)
argh = vpi_scan(args_iter);
vpiHandle array_word;
// Loop to load the words
while (loaded_words < vpi.length) {
// now get a handle on the current word we want in the array that was passed to us
array_word = vpi_handle_by_index(argh, loaded_words);
if (array_word != NULL) {
argval.value.integer = (uint32_t)vpi.buffer_out[loaded_words];
// And vpi_put_value() it back into the sim
vpi_put_value(array_word, &argval, NULL, vpiNoDelay);
} else
return;
loaded_words++;
}
/*******************************************/
// Cleanup and return
vpi_free_object(args_iter);
}
void send_result_to_server(char *userdata)
{
vpiHandle systfref, args_iter, argh;
struct t_vpi_value argval;
ssize_t n;
struct vpi_cmd vpi;
int32_t length;
int sent_words;
vpiHandle array_word;
(void)userdata;
// Now setup the handles to verilog objects and check things
// Obtain a handle to the argument list
systfref = vpi_handle(vpiSysTfCall, NULL);
// Now call iterate with the vpiArgument parameter
args_iter = vpi_iterate(vpiArgument, systfref);
// get a handle on the length variable
argh = vpi_scan(args_iter);
argval.format = vpiIntVal;
// get the value for the length object
vpi_get_value(argh, &argval);
// now set length
length = argval.value.integer;
// now get a handle on the next object (memory array)
argh = vpi_scan(args_iter);
// check we got passed a memory (array of regs)
if (!((vpi_get(vpiType, argh) == vpiMemory)
#ifdef MODELSIM_VPI
|| (vpi_get(vpiType, argh) == vpiRegArray)
#endif
#ifdef VCS_VPI
|| (vpi_get(vpiType, argh) == vpiRegArray)
#endif
)) {
vpi_printf("jtag_vpi: ERROR: did not pass a memory to get_command_block_data\n");
vpi_printf("jtag_vpi: ERROR: was passed type %d\n", (int)vpi_get(vpiType, argh));
return;
}
// check the memory we're writing into is big enough
if (vpi_get(vpiSize, argh) < length ) {
vpi_printf("jtag_vpi: ERROR: buffer passed to get_command_block_data too small. size is %d words, needs to be %d\n",
vpi_get(vpiSize, argh), length);
return;
}
// Loop to load the words
sent_words = 0;
while (sent_words < length) {
// Get a handle on the current word we want in the array that was passed to us
array_word = vpi_handle_by_index(argh, sent_words);
if (array_word != NULL) {
vpi_get_value(array_word, &argval);
vpi.buffer_in[sent_words] = (uint32_t) argval.value.integer;
} else
return;
sent_words++;
}
n = write(connfd, &vpi, sizeof(struct vpi_cmd));
if (n < (ssize_t)sizeof(struct vpi_cmd))
vpi_printf("jtag_vpi: ERROR: error during write to server\n");
// Cleanup and return
vpi_free_object(args_iter);
}
void register_check_for_command(void)
{
s_vpi_systf_data data = {
vpiSysTask,
0,
"$check_for_command",
(void *)check_for_command,
0,
0,
0
};
vpi_register_systf(&data);
}
void register_send_result_to_server(void)
{
s_vpi_systf_data data = {
vpiSysTask,
0,
"$send_result_to_server",
(void *)send_result_to_server,
0,
0,
0
};
vpi_register_systf(&data);
}
void sim_reset_callback(void)
{
// nothing to do!
}
void setup_reset_callbacks(void)
{
// here we setup and install callbacks for
// the setup and management of connections to
// the simulator upon simulation start and
// reset
static s_vpi_time time_s = {vpiScaledRealTime, 0, 0, 0};
static s_vpi_value value_s = {.format = vpiBinStrVal};
static s_cb_data cb_data_s = {
cbEndOfReset, // or start of simulation - initing socket fds etc
(void *)sim_reset_callback,
NULL,
&time_s,
&value_s,
0,
NULL
};
cb_data_s.obj = NULL; /* trigger object */
cb_data_s.user_data = NULL;
// actual call to register the callback
vpi_register_cb(&cb_data_s);
}
void sim_endofcompile_callback(void)
{
}
void setup_endofcompile_callbacks(void)
{
// here we setup and install callbacks for
// simulation finish
static s_vpi_time time_s = {vpiScaledRealTime, 0, 0, 0};
static s_vpi_value value_s = {.format = vpiBinStrVal};
static s_cb_data cb_data_s = {
cbEndOfCompile, // end of compile
(void *)sim_endofcompile_callback,
NULL,
&time_s,
&value_s,
0,
NULL
};
cb_data_s.obj = NULL; /* trigger object */
cb_data_s.user_data = NULL;
// actual call to register the callback
vpi_register_cb(&cb_data_s);
}
void sim_finish_callback(void)
{
if(connfd)
printf("Closing RSP server\n");
close(connfd);
close(listenfd);
}
void setup_finish_callbacks(void)
{
// here we setup and install callbacks for
// simulation finish
static s_vpi_time time_s = {vpiScaledRealTime, 0, 0, 0};
static s_vpi_value value_s = {.format = vpiBinStrVal};
static s_cb_data cb_data_s = {
cbEndOfSimulation, // end of simulation
(void *)sim_finish_callback,
NULL,
&time_s,
&value_s,
0,
NULL
};
cb_data_s.obj = NULL; /* trigger object */
cb_data_s.user_data = NULL;
// actual call to register the callback
vpi_register_cb(&cb_data_s);
}
#ifndef VCS_VPI
// Register the new system task here
void (*vlog_startup_routines[])(void) = {
#ifdef CDS_VPI
// this installs a callback on simulator reset - something which
// icarus does not do, so we only do it for cadence currently
setup_reset_callbacks,
#endif
setup_endofcompile_callbacks,
setup_finish_callbacks,
register_check_for_command,
register_send_result_to_server,
0 // last entry must be 0
};
// Entry point for testing development of the vpi functions
int main(int argc, char *argv[])
{
(void)argc;
(void)argv;
return 0;
}
#endif

View File

@ -14,7 +14,7 @@ $(generated_dir)/%.fir $(generated_dir)/%.d: $(FIRRTL_JAR) $(chisel_srcs) $(boot
%.v %.conf: %.fir $(FIRRTL_JAR)
mkdir -p $(dir $@)
$(FIRRTL) $(patsubst %,-i %,$(filter %.fir,$^)) -o $*.v -X verilog --infer-rw $(MODEL) --repl-seq-mem -c:$(MODEL):-o:$*.conf -faf $*.anno
$(FIRRTL) $(patsubst %,-i %,$(filter %.fir,$^)) -o $*.v -X verilog --infer-rw $(MODEL) --repl-seq-mem -c:$(MODEL):-o:$*.conf -faf $*.anno.json
$(generated_dir)/$(long_name).behav_srams.v : $(generated_dir)/$(long_name).conf $(VLSI_MEM_GEN)
cd $(generated_dir) && \

2
firrtl

Submodule firrtl updated: b90fc784a1...6ebd1585e8

View File

@ -23,9 +23,6 @@ module {name}(
reg [{output_width_minus_1}:0] rom [0:{depth_minus_1}];
// 1024 is the maximum length of $readmemh filename supported by Cadence Incisive
reg [1024 * 8 - 1:0] path;
integer i;
initial begin
`ifdef RANDOMIZE
@ -35,10 +32,7 @@ module {name}(
end
`endif
`endif
if (!$value$plusargs("maskromhex=%s", path)) begin
path = "{rom_hex_file}";
end
$readmemh(path, rom);
$readmemh("{rom_hex_file}", rom);
end

View File

@ -30,8 +30,6 @@ object DMIConsts{
// This is used outside this block
// to indicate 'busy'.
def dmi_RESP_RESERVED = "b11".U
def dmi_haltStatusAddr = 0x40
}
object DsbBusConsts {
@ -254,7 +252,8 @@ object WNotifyWire {
set := valid
value := data
Bool(true)
}), Some(RegFieldDesc(name = name, desc = desc, access = RegFieldAccessType.WSPECIAL)))
}), Some(RegFieldDesc(name = name, desc = desc,
access = RegFieldAccessType.W)))
}
}
@ -328,7 +327,7 @@ class TLDebugModuleOuter(device: Device)(implicit p: Parameters) extends LazyMod
} .otherwise {
when (DMCONTROLWrEn) {
DMCONTROLNxt.ndmreset := DMCONTROLWrData.ndmreset
DMCONTROLNxt.hartsel := DMCONTROLWrData.hartsel
DMCONTROLNxt.hartsello := DMCONTROLWrData.hartsello
DMCONTROLNxt.haltreq := DMCONTROLWrData.haltreq
DMCONTROLNxt.resumereq := DMCONTROLWrData.resumereq
DMCONTROLNxt.ackhavereset := DMCONTROLWrData.ackhavereset
@ -375,14 +374,14 @@ class TLDebugModuleOuter(device: Device)(implicit p: Parameters) extends LazyMod
when (~dmactive) {
debugIntNxt(component) := false.B
}. otherwise {
when (DMCONTROLWrEn && DMCONTROLWrData.hartsel === component.U) {
when (DMCONTROLWrEn && DMCONTROLWrData.hartsello === component.U) {
debugIntNxt(component) := DMCONTROLWrData.haltreq
}
}
}
io.innerCtrl.valid := DMCONTROLWrEn
io.innerCtrl.bits.hartsel := DMCONTROLWrData.hartsel
io.innerCtrl.bits.hartsel := DMCONTROLWrData.hartsello
io.innerCtrl.bits.resumereq := DMCONTROLWrData.resumereq
io.innerCtrl.bits.ackhavereset := DMCONTROLWrData.ackhavereset
@ -559,7 +558,7 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I
HARTINFORdData.dataaddr := DsbRegAddrs.DATA.U
HARTINFORdData.nscratch := cfg.nScratch.U
//----HALTSUM (and halted registers)
//----HALTSUM*
val numHaltedStatus = ((nComponents - 1) / 32) + 1
val haltedStatus = Wire(Vec(numHaltedStatus, Bits(width = 32)))
@ -568,7 +567,12 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I
}
val haltedSummary = Cat(haltedStatus.map(_.orR).reverse)
val HALTSUMRdData = (new HALTSUMFields()).fromBits(haltedSummary)
val HALTSUM1RdData = (new HALTSUM1Fields()).fromBits(haltedSummary)
val selectedHaltedStatus = Mux((selectedHartReg >> 5) > numHaltedStatus.U, 0.U, haltedStatus(selectedHartReg >> 5))
val HALTSUM0RdData = (new HALTSUM0Fields()).fromBits(selectedHaltedStatus)
// Since we only support 1024 harts, we don't implement HALTSUM2 or HALTSUM3
//----ABSTRACTCS
@ -728,7 +732,8 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I
(DMI_DMSTATUS << 2) -> Seq(RegField.r(32, DMSTATUSRdData.asUInt(), RegFieldDesc("dmi_dmstatus", ""))),
//TODO (DMI_CFGSTRADDR0 << 2) -> cfgStrAddrFields,
(DMI_HARTINFO << 2) -> Seq(RegField.r(32, HARTINFORdData.asUInt(), RegFieldDesc("dmi_hartinfo", "" /*, reset=Some(HARTINFORdData.litValue)*/))),
(DMI_HALTSUM << 2) -> Seq(RegField.r(32, HALTSUMRdData.asUInt(), RegFieldDesc("dmi_haltsum", ""))),
(DMI_HALTSUM0 << 2) -> Seq(RegField.r(32, HALTSUM0RdData.asUInt(), RegFieldDesc("dmi_haltsum0", ""))),
(DMI_HALTSUM1 << 2) -> Seq(RegField.r(32, HALTSUM1RdData.asUInt(), RegFieldDesc("dmi_haltsum1", ""))),
(DMI_ABSTRACTCS << 2) -> Seq(RWNotify(32, ABSTRACTCSRdData.asUInt(), ABSTRACTCSWrDataVal, ABSTRACTCSRdEn, ABSTRACTCSWrEnMaybe,
Some(RegFieldDesc("dmi_abstractcs", "" /*, reset=Some(ABSTRACTCSReset.litValue)*/)))),
(DMI_ABSTRACTAUTO<< 2) -> Seq(RWNotify(32, ABSTRACTAUTORdData.asUInt(), ABSTRACTAUTOWrDataVal, ABSTRACTAUTORdEn, ABSTRACTAUTOWrEnMaybe,
@ -742,8 +747,7 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I
(DMI_PROGBUF0 << 2) -> RegFieldGroup("dmi_progbuf", None, programBufferMem.zipWithIndex.map{case (x, i) => RWNotify(8, x, programBufferNxt(i),
dmiProgramBufferRdEn(i),
dmiProgramBufferWrEnMaybe(i),
Some(RegFieldDesc(s"dmi_progbuf_$i", "", reset = Some(0))))}),
(DMIConsts.dmi_haltStatusAddr << 2) -> RegFieldGroup("dmi_halt_status", None, haltedStatus.zipWithIndex.map{case (x, i) => RegField.r(32, x, RegFieldDesc(s"halt_status_$i", ""))})
Some(RegFieldDesc(s"dmi_progbuf_$i", "", reset = Some(0))))})
)
abstractDataMem.zipWithIndex.foreach { case (x, i) =>
@ -784,7 +788,7 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I
val go = Bool()
}
val flags = Wire(init = Vec.fill(nComponents){new flagBundle().fromBits(0.U)})
val flags = Wire(init = Vec.fill(1024){new flagBundle().fromBits(0.U)})
assert ((cfg.hartSelToHartId(selectedHartReg) < 1024.U),
"HartSel to HartId Mapping is illegal for this Debug Implementation, because HartID must be < 1024 for it to work.");
flags(cfg.hartSelToHartId(selectedHartReg)).go := goReg
@ -898,15 +902,15 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I
programBufferMem.zipWithIndex.map {case (x, i) => RegField(8, x, RegFieldDesc(s"debug_progbuf_$i", ""))}),
// These sections are read-only.
IMPEBREAK(cfg)-> {if (cfg.hasImplicitEbreak) Seq(RegField.r(32, Instructions.EBREAK.value.U, RegFieldDesc("debug_impebreak", "Debug Implicit EBREAK"))) else Nil},
WHERETO -> Seq(RegField.r(32, jalAbstract.asUInt, RegFieldDesc("debug_whereto", "Instruction filled in by Debug Module to control hart in Debug Mode"))),
IMPEBREAK(cfg)-> {if (cfg.hasImplicitEbreak) Seq(RegField.r(32, Instructions.EBREAK.value.U,
RegFieldDesc("debug_impebreak", "Debug Implicit EBREAK", reset=Some(Instructions.EBREAK.value)))) else Nil},
WHERETO -> Seq(RegField.r(32, jalAbstract.asUInt, RegFieldDesc("debug_whereto", "Instruction filled in by Debug Module to control hart in Debug Mode", volatile = true))),
ABSTRACT(cfg) -> RegFieldGroup("debug_abstract", Some("Instructions generated by Debug Module"),
abstractGeneratedMem.zipWithIndex.map{ case (x,i) => RegField.r(32, x, RegFieldDesc(s"debug_abstract_$i", ""))}),
abstractGeneratedMem.zipWithIndex.map{ case (x,i) => RegField.r(32, x, RegFieldDesc(s"debug_abstract_$i", "", volatile=true))}),
FLAGS -> RegFieldGroup("debug_flags", Some("Memory region used to control hart going/resuming in Debug Mode"),
flags.zipWithIndex.map{case(x, i) => RegField.r(8, x.asUInt(), RegFieldDesc(s"debug_flags_${i}", ""))}),
flags.zipWithIndex.map{case(x, i) => RegField.r(8, x.asUInt(), RegFieldDesc(s"debug_flags_$i", "", volatile=true))}),
ROMBASE -> RegFieldGroup("debug_rom", Some("Debug ROM"),
DebugRomContents().zipWithIndex.map{case (x, i) => RegField.r(8, (x & 0xFF).U(8.W),
RegFieldDesc(s"debug_rom_$i", "", reset=Some(x)))})
DebugRomContents().zipWithIndex.map{case (x, i) => RegField.r(8, (x & 0xFF).U(8.W), RegFieldDesc(s"debug_rom_$i", "", reset=Some(x)))})
)
// Override System Bus accesses with dmactive reset.
@ -938,7 +942,7 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I
//------------------------
// DMI Register Control and Status
abstractCommandBusy := (ctrlStateReg != CtrlState(Waiting))
abstractCommandBusy := (ctrlStateReg =/= CtrlState(Waiting))
ABSTRACTCSWrEnLegal := (ctrlStateReg === CtrlState(Waiting))
COMMANDWrEnLegal := (ctrlStateReg === CtrlState(Waiting))

View File

@ -172,7 +172,7 @@ class DebugTransportModuleJTAG(debugAddrBits: Int, c: JtagDTMConfig)
// But there is actually no case in the current design where you SHOULD get an error,
// as we haven't implemented Bus Masters or Serial Ports, which are the only cases errors
// can occur.
nonzeroResp := stickyNonzeroRespReg | (io.dmi.resp.valid & (io.dmi.resp.bits.resp != UInt(0)))
nonzeroResp := stickyNonzeroRespReg | (io.dmi.resp.valid & (io.dmi.resp.bits.resp =/= UInt(0)))
assert(!nonzeroResp, "There is no reason to get a non zero response in the current system.");
assert(!stickyNonzeroRespReg, "There is no reason to have a sticky non zero response in the current system.");

View File

@ -46,8 +46,8 @@ trait HasPeripheryDebugBundle {
val dtm = Module(new SimDTM).connect(c, r, d, out)
}
debug.systemjtag.foreach { sj =>
//val jtag = Module(new JTAGVPI(tckHalfPeriod = tckHalfPeriod, cmdDelay = cmdDelay)).connect(sj.jtag, sj.reset, r, out)
val jtag = Module(new SimJTAG(tickDelay=3)).connect(sj.jtag, sj.reset, c, r, out)
val jtag = Module(new SimJTAG(tickDelay=3)).connect(sj.jtag, c, r, ~r, out)
sj.reset := r
sj.mfr_id := p(JtagDTMKey).idcodeManufId.U(11.W)
}
debug.psd.foreach { _ <> psd }
@ -120,15 +120,14 @@ class SimJTAG(tickDelay: Int = 50) extends BlackBox(Map("TICK_DELAY" -> IntParam
val exit = UInt(OUTPUT, 32)
}
def connect(dutio: JTAGIO, jtag_reset: Bool, tbclock: Clock, tbreset: Bool, tbsuccess: Bool) = {
def connect(dutio: JTAGIO, tbclock: Clock, tbreset: Bool, init_done: Bool, tbsuccess: Bool) = {
dutio <> io.jtag
jtag_reset := tbreset
io.clock := tbclock
io.reset := tbreset
io.enable := PlusArg("jtag_rbb_enable", 0, "Enable SimJTAG for JTAG Connections. Simulation will pause until connection is made.")
io.init_done := ~tbreset
io.init_done := init_done
// Success is determined by the gdbserver
// which is controlling this simulation.
@ -140,26 +139,3 @@ class SimJTAG(tickDelay: Int = 50) extends BlackBox(Map("TICK_DELAY" -> IntParam
}
}
class JTAGVPI(tckHalfPeriod: Int = 2, cmdDelay: Int = 2)(implicit val p: Parameters)
extends BlackBox ( Map ("TCK_HALF_PERIOD" -> IntParam(tckHalfPeriod),
"CMD_DELAY" -> IntParam(cmdDelay))) {
val io = new Bundle {
val jtag = new JTAGIO(hasTRSTn = false)
val enable = Bool(INPUT)
val init_done = Bool(INPUT)
}
def connect(dutio: JTAGIO, jtag_reset: Bool, tbreset: Bool, tbsuccess: Bool) = {
dutio <> io.jtag
dutio.TRSTn.foreach{ _:= false.B}
jtag_reset := tbreset
io.enable := ~tbreset
io.init_done := ~tbreset
// Success is determined by the gdbserver
// which is controlling this simulation.
tbsuccess := Bool(false)
}
}

View File

@ -25,6 +25,9 @@ class ACCESS_REGISTERFields extends Bundle {
If \Fsize specifies a size larger than the register's actual size,
then the access must fail. If a register is accessible, then reads of \Fsize
less than or equal to the register's actual size must be supported.
This field controls the Argument Width as referenced in
Table~\ref{tab:datareg}.
*/
val size = UInt(3.W)

View File

@ -14,16 +14,33 @@ object DMI_RegAddrs {
Harts are nonexistent if they will never be part of this system, no
matter how long a user waits. Eg. in a simple single-hart system only
one hart exists, and all others are nonexistent.
one hart exists, and all others are nonexistent. Debuggers may assume
that a system has no harts with indexes higher than the first
nonexistent one.
Harts are unavailable if they might exist/become available at a later
time. Eg. in a multi-hart system some might temporarily be powered
down, or a system might support hot-swapping harts.
time, or if there are other harts with higher indexes than this one. Eg.
in a multi-hart system some might temporarily be powered down, or a
system might support hot-swapping harts. Systems with very large number
of harts may permanently disable some during manufacturing, leaving
holes in the otherwise continuous hart index space. In order to let the
debugger discover all harts, they must show up as unavailable even if
there is no chance of them ever becoming available.
*/
def DMI_DMSTATUS = 0x11
/* This register controls the overall debug module
as well as the currently selected harts, as defined in \Fhasel.
\label{hartsel}
\index{hartsel}
Throughout this document we refer to \Fhartsel, which is \Fhartselhi
combined with \Fhartsello. While the spec allows for 20 \Fhartsel bits,
an implementation may choose to implement fewer than that. The actual
width of \Fhartsel is called {\tt HARTSELLEN}. It must be at least 0
and at most 20. A debugger should discover {\tt HARTSELLEN} by writing
all ones to \Fhartsel (assuming the maximum size) and reading back the
value to see which bits were actually set.
*/
def DMI_DMCONTROL = 0x10
@ -40,15 +57,6 @@ object DMI_RegAddrs {
*/
def DMI_HARTINFO = 0x12
/* This register contains a summary of which harts are halted.
Each bit contains the logical OR of 32 halt bits. When there are a
large number of harts in the system, the debugger can first read this
register, and then read from the halt region (0x40--0x5f) to determine
which hart is the one that is halted.
*/
def DMI_HALTSUM = 0x13
/* This register selects which of the 32-bit portion of the hart array mask register
is accessible in \Rhawindow.
@ -116,11 +124,20 @@ object DMI_RegAddrs {
def DMI_DEVTREEADDR3 = 0x1c
/* Basic read/write registers that may be read or changed by abstract
commands.
/* If there is more than one DM accessible on this DMI, this register
contains the base address of the next one in the chain, or 0 if this is
the last one in the chain.
*/
def DMI_NEXTDM = 0x1d
Accessing them while an abstract command is executing causes \Fcmderr
to be set.
/* \Rdatazero through \Rdataeleven are basic read/write registers that may
be read or changed by abstract commands. \Fdatacount indicates how many
of them are implemented, starting at \Rsbdatazero, counting up.
Table~\ref{tab:datareg} shows how abstract commands use these
registers.
Accessing these registers while an abstract command is executing causes
\Fcmderr to be set.
Attempts to write them while \Fbusy is set does not change their value.
@ -133,11 +150,12 @@ object DMI_RegAddrs {
def DMI_DATA11 = 0x0f
/* The {\tt progbuf} registers provide read/write access to the optional
program buffer.
/* \Rprogbufzero through \Rprogbuffifteen provide read/write access to the
optional program buffer. \Fprogbufsize indicates how many of them are
implemented starting at \Rprogbufzero, counting up.
Accessing them while an abstract command is executing causes \Fcmderr
to be set.
Accessing these registers while an abstract command is executing causes
\Fcmderr to be set.
Attempts to write them while \Fbusy is set does not change their value.
*/
@ -154,50 +172,114 @@ object DMI_RegAddrs {
*/
def DMI_AUTHDATA = 0x30
/* Each bit in this read-only register indicates whether one specific hart
is halted or not.
The LSB reflects the halt status of hart \{hartsel[19:5],5'h0\}, and the
MSB reflects halt status of hart \{hartsel[19:5],5'h1f\}.
*/
def DMI_HALTSUM0 = 0x40
/* Each bit in this read-only register indicates whether any of a group of
harts is halted or not.
This register may not be present in systems with fewer than
33 harts.
The LSB reflects the halt status of harts \{hartsel[19:10],10'h0\}
through \{hartsel[19:10],10'h1f\}.
The MSB reflects the halt status of harts \{hartsel[19:10],10'h3e0\}
through \{hartsel[19:10],10'h3ff\}.
*/
def DMI_HALTSUM1 = 0x13
/* Each bit in this read-only register indicates whether any of a group of
harts is halted or not.
This register may not be present in systems with fewer than
1025 harts.
The LSB reflects the halt status of harts \{hartsel[19:15],15'h0\}
through \{hartsel[19:15],15'h3ff\}.
The MSB reflects the halt status of harts \{hartsel[19:15],15'h7c00\}
through \{hartsel[19:15],15'h7fff\}.
*/
def DMI_HALTSUM2 = 0x34
/* Each bit in this read-only register indicates whether any of a group of
harts is halted or not.
This register may not be present in systems with fewer than
32769 harts.
The LSB reflects the halt status of harts 20'h0 through 20'h7fff.
The MSB reflects the halt status of harts 20'hf8000 through 20'hfffff.
*/
def DMI_HALTSUM3 = 0x35
/* If \Fsbasize is less than 97, then this register is not present.
When the system bus master is busy, writes to this register will set
\Fsbbusyerror and don't do anything else.
*/
def DMI_SBADDRESS3 = 0x37
def DMI_SBCS = 0x38
/* If \Fsbasize is 0, then this register is not present.
When the system bus master is busy,
writes to this register will set \Fsberror.
When the system bus master is busy, writes to this register will set
\Fsbbusyerror and don't do anything else.
If \Fsberror is 0 and \Fsbautoread is set then the system bus
master will start
to read after updating the address from \Faddress. The access size is
controlled by \Fsbaccess in \Rsbcs.
If \Fsbsingleread is set, the bit is cleared.
\begin{steps}{If \Fsberror is 0, \Fsbbusyerror is 0, and \Fsbreadonaddr
is set then writes to this register start the following:}
\item Set \Fsbbusy.
\item Perform a bus read from the new value of {\tt sbaddress}.
\item If the read succeeded and \Fsbautoincrement is set, increment
{\tt sbaddress}.
\item Clear \Fsbbusy.
\end{steps}
*/
def DMI_SBADDRESS0 = 0x39
/* If \Fsbasize is less than 33, then this register is not present.
When the system bus master is busy, writes to this register will set
\Fsbbusyerror and don't do anything else.
*/
def DMI_SBADDRESS1 = 0x3a
/* If \Fsbasize is less than 65, then this register is not present.
When the system bus master is busy, writes to this register will set
\Fsbbusyerror and don't do anything else.
*/
def DMI_SBADDRESS2 = 0x3b
/* If all of the {\tt sbaccess} bits in \Rsbcs are 0, then this register
is not present.
Any successful system bus read updates the data in this register, and
marks it no longer stale.
Any successful system bus read updates the data in this register.
If \Fsberror isn't 0 then accesses do nothing.
If \Fsberror or \Fsbbusyerror both aren't 0 then accesses do nothing.
\begin{steps}{Writes to this register:}
\item If the bus master is busy then accesses set \Fsberror, and
don't do anything else.
\item Start a bus write of {\tt sbdata} to {\tt sbaddress}.
\item If \Fsbautoincrement is set, increment {\tt sbaddress}.
If the bus master is busy then accesses set \Fsbbusyerror, and don't do
anything else.
\begin{steps}{Writes to this register start the following:}
\item Set \Fsbbusy.
\item Perform a bus write of the new value of {\tt sbdata} to {\tt sbaddress}.
\item If the write succeeded and \Fsbautoincrement is set,
increment {\tt sbaddress}.
\item Clear \Fsbbusy.
\end{steps}
\begin{steps}{Reads from this register:}
\item If the register is marked stale, then set \Fsberror and don't
do anything else.
\begin{steps}{Reads from this register start the following:}
\item ``Return'' the data.
\item Mark the register stale.
\item Set \Fsbbusy.
\item If \Fsbautoincrement is set, increment {\tt sbaddress}.
\item If \Fsbautoread is set, start another system bus read.
\item If \Fsbreadondata is set, perform another system bus read.
\item Clear \Fsbbusy.
\end{steps}
Only \Rsbdatazero has this behavior. The other {\tt sbdata} registers
@ -209,14 +291,23 @@ object DMI_RegAddrs {
/* If \Fsbaccesssixtyfour and \Fsbaccessonetwentyeight are 0, then this
register is not present.
If the bus master is busy then accesses set \Fsbbusyerror, and don't do
anything else.
*/
def DMI_SBDATA1 = 0x3d
/* This register only exists if \Fsbaccessonetwentyeight is 1.
If the bus master is busy then accesses set \Fsbbusyerror, and don't do
anything else.
*/
def DMI_SBDATA2 = 0x3e
/* This register only exists if \Fsbaccessonetwentyeight is 1.
If the bus master is busy then accesses set \Fsbbusyerror, and don't do
anything else.
*/
def DMI_SBDATA3 = 0x3f
@ -224,20 +315,7 @@ object DMI_RegAddrs {
class DMSTATUSFields extends Bundle {
val reserved0 = UInt(5.W)
/* Gets set if the Debug Module was accessed incorrectly.
0 (none): No error.
1 (badaddr): There was an access to an unimplemented Debug Module
address.
7 (other): An access failed for another reason.
*/
val dmerr = UInt(3.W)
val reserved1 = UInt(1.W)
val reserved0 = UInt(9.W)
/* If 1, then there is an implicit {\tt ebreak} instruction at the
non-existent word immediately after the Program Buffer. This saves
@ -248,7 +326,7 @@ class DMSTATUSFields extends Bundle {
*/
val impebreak = Bool()
val reserved2 = UInt(2.W)
val reserved1 = UInt(2.W)
/* This field is 1 when all currently selected harts have been reset but the reset has not been acknowledged.
*/
@ -317,7 +395,7 @@ class DMSTATUSFields extends Bundle {
*/
val authbusy = Bool()
val reserved3 = UInt(1.W)
val reserved2 = UInt(1.W)
/* 0: \Rdevtreeaddrzero--\Rdevtreeaddrthree hold information which
is not relevant to the Device Tree.
@ -401,12 +479,17 @@ class DMCONTROLFields extends Bundle {
*/
val hasel = Bool()
/* The DM-specific index of the hart to select. This hart is always part of the
currently selected harts.
/* The low 10 bits of \Fhartsel: the DM-specific index of the hart to
select. This hart is always part of the currently selected harts.
*/
val hartsel = UInt(10.W)
val hartsello = UInt(10.W)
val reserved1 = UInt(14.W)
/* The high 10 bits of \Fhartsel: the DM-specific index of the hart to
select. This hart is always part of the currently selected harts.
*/
val hartselhi = UInt(10.W)
val reserved1 = UInt(4.W)
/* This bit controls the reset signal from the DM to the rest of the
system. The signal should reset every part of the system, including
@ -468,6 +551,9 @@ class HARTINFOFields extends Bundle {
If \Fdataaccess is 1: Number of 32-bit words in the memory map
dedicated to shadowing the {\tt data} registers.
Since there are at most 12 {\tt data} registers, the value in this
register must be 12 or smaller.
*/
val datasize = UInt(4.W)
@ -481,79 +567,11 @@ class HARTINFOFields extends Bundle {
}
class HALTSUMFields extends Bundle {
val halt1023_992 = Bool()
val halt991_960 = Bool()
val halt959_928 = Bool()
val halt927_896 = Bool()
val halt895_864 = Bool()
val halt863_832 = Bool()
val halt831_800 = Bool()
val halt799_768 = Bool()
val halt767_736 = Bool()
val halt735_704 = Bool()
val halt703_672 = Bool()
val halt671_640 = Bool()
val halt639_608 = Bool()
val halt607_576 = Bool()
val halt575_544 = Bool()
val halt543_512 = Bool()
val halt511_480 = Bool()
val halt479_448 = Bool()
val halt447_416 = Bool()
val halt415_384 = Bool()
val halt383_352 = Bool()
val halt351_320 = Bool()
val halt319_288 = Bool()
val halt287_256 = Bool()
val halt255_224 = Bool()
val halt223_192 = Bool()
val halt191_160 = Bool()
val halt159_128 = Bool()
val halt127_96 = Bool()
val halt95_64 = Bool()
val halt63_32 = Bool()
val halt31_0 = Bool()
}
class HAWINDOWSELFields extends Bundle {
val reserved0 = UInt(27.W)
val reserved0 = UInt(17.W)
val hawindowsel = UInt(5.W)
val hawindowsel = UInt(15.W)
}
@ -606,12 +624,12 @@ class ABSTRACTCSFields extends Bundle {
*/
val cmderr = UInt(3.W)
val reserved3 = UInt(3.W)
val reserved3 = UInt(4.W)
/* Number of {\tt data} registers that are implemented as part of the
abstract command interface. Valid sizes are 0 - 12.
*/
val datacount = UInt(5.W)
val datacount = UInt(4.W)
}
@ -631,14 +649,14 @@ class COMMANDFields extends Bundle {
class ABSTRACTAUTOFields extends Bundle {
/* When a bit in this field is 1, read or write accesses the corresponding {\tt progbuf} word
/* When a bit in this field is 1, read or write accesses to the corresponding {\tt progbuf} word
cause the command in \Rcommand to be executed again.
*/
val autoexecprogbuf = UInt(16.W)
val reserved0 = UInt(4.W)
/* When a bit in this field is 1, read or write accesses the corresponding {\tt data} word
/* When a bit in this field is 1, read or write accesses to the corresponding {\tt data} word
cause the command in \Rcommand to be executed again.
*/
val autoexecdata = UInt(12.W)
@ -651,6 +669,12 @@ class DEVTREEADDR0Fields extends Bundle {
}
class NEXTDMFields extends Bundle {
val addr = UInt(32.W)
}
class DATA0Fields extends Bundle {
val data = UInt(32.W)
@ -669,17 +693,78 @@ class AUTHDATAFields extends Bundle {
}
class HALTSUM0Fields extends Bundle {
val haltsum0 = UInt(32.W)
}
class HALTSUM1Fields extends Bundle {
val haltsum1 = UInt(32.W)
}
class HALTSUM2Fields extends Bundle {
val haltsum2 = UInt(32.W)
}
class HALTSUM3Fields extends Bundle {
val haltsum3 = UInt(32.W)
}
class SBADDRESS3Fields extends Bundle {
/* Accesses bits 127:96 of the physical address in {\tt sbaddress} (if
the system address bus is that wide).
*/
val address = UInt(32.W)
}
class SBCSFields extends Bundle {
val reserved0 = UInt(11.W)
/* 0: The System Bus interface conforms to mainline drafts of this
spec older than 1 January, 2018.
/* When a 1 is written here, triggers a read at the address in {\tt
sbaddress} using the access size set by \Fsbaccess.
1: The System Bus interface conforms to this version of the spec.
Other values are reserved for future versions.
*/
val sbsingleread = Bool()
val sbversion = UInt(3.W)
/* Select the access size to use for system bus accesses triggered by
writes to the {\tt sbaddress} registers or \Rsbdatazero.
val reserved0 = UInt(6.W)
/* Set when the debugger attempts to read data while a read is in
progress, or when the debugger initiates a new access while one is
already in progress (while \Fsbbusy is set). It remains set until
it's explicitly cleared by the debugger.
While this field is non-zero, no more system bus accesses can be
initiated by the debug module.
*/
val sbbusyerror = Bool()
/* When 1, indicates the system bus master is busy. (Whether the
system bus itself is busy is related, but not the same thing.) This
bit goes high immediately when a read or write is requested for any
reason, and does not go low until the access is fully completed.
To avoid race conditions, debuggers must not try to clear \Fsberror
until they read \Fsbbusy as 0.
*/
val sbbusy = Bool()
/* When 1, every write to \Rsbaddresszero automatically triggers a
system bus read at the new address.
*/
val sbreadonaddr = Bool()
/* Select the access size to use for system bus accesses.
0: 8-bit
@ -691,8 +776,8 @@ class SBCSFields extends Bundle {
4: 128-bit
If an unsupported system bus access size is written here, the DM
does not perform the access and sberror is set to 3.
If \Fsbaccess has an unsupported value when the DM starts a bus
access, the access is not performed and \Fsberror is set to 3.
*/
val sbaccess = UInt(3.W)
@ -704,7 +789,7 @@ class SBCSFields extends Bundle {
/* When 1, every read from \Rsbdatazero automatically triggers a
system bus read at the (possibly auto-incremented) address.
*/
val sbautoread = Bool()
val sbreadondata = Bool()
/* When the debug module's system bus
master causes a bus error, this field gets set. The bits in this
@ -719,10 +804,6 @@ class SBCSFields extends Bundle {
2: A bad address was accessed.
3: There was some other error (eg. alignment).
4: The system bus master was busy when one of the
{\tt sbaddress} or {\tt sbdata} registers was written,
or \Rsbdatazero was read when it had stale data.
*/
val sberror = UInt(3.W)

View File

@ -103,7 +103,7 @@ class TLBusBypassBar(implicit p: Parameters) extends LazyModule
flight := next_flight
when (next_flight === UInt(0)) { bypass := io.bypass }
val stall = (bypass != io.bypass) && a_first
val stall = (bypass =/= io.bypass) && a_first
out0.a.valid := !stall && in.a.valid && bypass
out1.a.valid := !stall && in.a.valid && !bypass

View File

@ -82,10 +82,12 @@ class CLINT(params: CLINTParams, beatBytes: Int)(implicit p: Parameters) extends
*/
node.regmap(
0 -> RegFieldGroup ("msip", Some("MSIP Bits"), ipi.zipWithIndex.map{ case (r, i) => RegField(ipiWidth, r, RegFieldDesc(s"msip_$i", s"MSIP bit for Hart $i", reset=Some(0)))}),
timecmpOffset(0) -> timecmp.zipWithIndex.flatMap{ case (t, i) =>
RegFieldGroup(s"mtimecmp_$i", Some(s"MTIMECMP for hart $i"), RegField.bytes(t, Some(RegFieldDesc(s"mtimecmp_$i", "", reset=None))))},
timeOffset -> RegFieldGroup("mtime", Some("Timer Register"), RegField.bytes(time, Some(RegFieldDesc("mtime", "", reset=Some(0)))))
0 -> RegFieldGroup ("msip", Some("MSIP Bits"), ipi.zipWithIndex.map{ case (r, i) =>
RegField(ipiWidth, r, RegFieldDesc(s"msip_$i", s"MSIP bit for Hart $i", reset=Some(0)))}),
timecmpOffset(0) -> timecmp.zipWithIndex.flatMap{ case (t, i) => RegFieldGroup(s"mtimecmp_$i", Some(s"MTIMECMP for hart $i"),
RegField.bytes(t, Some(RegFieldDesc(s"mtimecmp_$i", "", reset=None))))},
timeOffset -> RegFieldGroup("mtime", Some("Timer Register"),
RegField.bytes(time, Some(RegFieldDesc("mtime", "", reset=Some(0), volatile=true))))
)
}
}

View File

@ -168,10 +168,23 @@ class TLPLIC(params: PLICParams, beatBytes: Int)(implicit p: Parameters) extends
harts(hart) := ShiftRegister(Reg(next = maxPri) > Cat(UInt(1), threshold(hart)), params.intStages)
}
def priorityRegDesc(i: Int) = RegFieldDesc(s"priority_$i", s"Acting priority of interrupt source $i", reset=if (nPriorities > 0) None else Some(1))
def pendingRegDesc(i: Int) = RegFieldDesc(s"pending_$i", s"Set to 1 if interrupt source $i is pending, regardless of its enable or priority setting.")
def priorityRegDesc(i: Int) = if (i > 0) {
RegFieldDesc(s"priority_$i", s"Acting priority of interrupt source $i",
reset=if (nPriorities > 0) None else Some(1),
wrType=Some(RegFieldWrType.MODIFY))
} else {
RegFieldDesc.reserved
}
def pendingRegDesc(i: Int) = if (i > 0) {
RegFieldDesc(s"pending_$i", s"Set to 1 if interrupt source $i is pending, regardless of its enable or priority setting.",
volatile = true)
} else {
RegFieldDesc.reserved
}
def priorityRegField(x: UInt, i: Int) = if (nPriorities > 0) RegField(32, x, priorityRegDesc(i)) else RegField.r(32, x, priorityRegDesc(i))
val priorityRegFields = Seq(PLICConsts.priorityBase -> RegFieldGroup("priority", Some("Acting priorities of each interrupt source. 32 bits for each interrupt source."),
val priorityRegFields = Seq(PLICConsts.priorityBase -> RegFieldGroup("priority",
Some(s"Acting priorities of each interrupt source. Maximum legal value is ${nPriorities}. 32 bits for each interrupt source."),
priority.zipWithIndex.map{case (p, i) => priorityRegField(p, i)}))
val pendingRegFields = Seq(PLICConsts.pendingBase -> RegFieldGroup("pending", Some("Pending Bit Array. 1 Bit for each interrupt source."),
pending.zipWithIndex.map{case (b, i) => RegField.r(1, b, pendingRegDesc(i))}))
@ -179,7 +192,11 @@ class TLPLIC(params: PLICParams, beatBytes: Int)(implicit p: Parameters) extends
val enableRegFields = enables.zipWithIndex.map { case (e, i) =>
PLICConsts.enableBase(i) -> RegFieldGroup(s"enables_${i}", Some(s"Enable bits for each interrupt source for target $i. 1 bit for each interrupt source."),
e.zipWithIndex.map{case (b, j) => RegField(1, b, RegFieldDesc(s"enable_${i}_${j}", s"Enable interrupt for source $j for target $i.", reset=None))})
e.zipWithIndex.map{case (b, j) => if (j > 0) {
RegField(1, b, RegFieldDesc(s"enable_${i}_${j}", s"Enable interrupt for source $j for target $i.", reset=None))
} else {
RegField(1, b, RegFieldDesc.reserved)
}})
}
// When a hart reads a claim/complete register, then the
@ -213,7 +230,9 @@ class TLPLIC(params: PLICParams, beatBytes: Int)(implicit p: Parameters) extends
g.complete := c
}
def thresholdRegDesc(i: Int) = RegFieldDesc(s"threshold_$i", s"Interrupt & claim threshold for target $i", reset=if (nPriorities > 0) None else Some(1))
def thresholdRegDesc(i: Int) = RegFieldDesc(s"threshold_$i", s"Interrupt & claim threshold for target $i. Maximum value is ${nPriorities}.",
reset=if (nPriorities > 0) None else Some(1),
wrType=Some(RegFieldWrType.MODIFY))
def thresholdRegField(x: UInt, i: Int) = if (nPriorities > 0) RegField(32, x, thresholdRegDesc(i)) else RegField.r(32, x, thresholdRegDesc(i))
val hartRegFields = Seq.tabulate(nHarts) { i =>
@ -235,7 +254,9 @@ class TLPLIC(params: PLICParams, beatBytes: Int)(implicit p: Parameters) extends
s"Claim/Complete register for Target $i. Reading this register returns the claimed interrupt number and makes it no longer pending." +
s"Writing the interrupt number back completes the interrupt.",
reset = None,
access = RegFieldAccessType.RWSPECIAL))
wrType = Some(RegFieldWrType.MODIFY),
rdAction = Some(RegFieldRdAction.MODIFY),
volatile = true))
)
)
}

View File

@ -0,0 +1,75 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.diplomacy
import Chisel._
// Use AddressSet instead -- this is just for pretty printing
case class AddressRange(base: BigInt, size: BigInt) extends Ordered[AddressRange]
{
val end = base + size
require (base >= 0, s"AddressRange base must be positive, got: $base")
require (size > 0, s"AddressRange size must be > 0, got: $size")
def compare(x: AddressRange) = {
val primary = (this.base - x.base).signum
val secondary = (x.size - this.size).signum
if (primary != 0) primary else secondary
}
def contains(x: AddressRange) = base <= x.base && x.end <= end
def union(x: AddressRange): Option[AddressRange] = {
if (base > x.end || x.base > end) {
None
} else {
val obase = if (base < x.base) base else x.base
val oend = if (end > x.end) end else x.end
Some(AddressRange(obase, oend-obase))
}
}
private def helper(base: BigInt, end: BigInt) =
if (base < end) Seq(AddressRange(base, end-base)) else Nil
def subtract(x: AddressRange) =
helper(base, end min x.base) ++ helper(base max x.end, end)
// We always want to see things in hex
override def toString() = "AddressRange(0x%x, 0x%x)".format(base, size)
}
object AddressRange
{
def fromSets(seq: Seq[AddressSet]): Seq[AddressRange] = unify(seq.flatMap(_.toRanges))
def unify(seq: Seq[AddressRange]): Seq[AddressRange] = {
if (seq.isEmpty) return Nil
val ranges = seq.sorted
ranges.tail.foldLeft(Seq(ranges.head)) { case (head :: tail, x) =>
head.union(x) match {
case Some(z) => z :: tail
case None => x :: head :: tail
}
}.reverse
}
// Set subtraction... O(n*n) b/c I am lazy
def subtract(from: Seq[AddressRange], take: Seq[AddressRange]): Seq[AddressRange] =
take.foldLeft(from) { case (left, r) => left.flatMap { _.subtract(r) } }
}
case class AddressMapEntry(range: AddressRange, permissions: ResourcePermissions, names: Seq[String]) {
val ResourcePermissions(r, w, x, c, a) = permissions
def toString(aw: Int) = s"\t%${aw}x - %${aw}x %c%c%c%c%c %s".format(
range.base,
range.base+range.size,
if (a) 'A' else ' ',
if (r) 'R' else ' ',
if (w) 'W' else ' ',
if (x) 'X' else ' ',
if (c) 'C' else ' ',
names.mkString(", "))
def serialize = s"""{"base":[${range.base}],"size":[${range.size}],""" +
s""""r":[$r],"w":[$w],"x":[$x],"c":[$c],"a":[$a],""" +
s""""names":[${names.map('"'+_+'"').mkString(",")}]}"""
}

View File

@ -104,40 +104,6 @@ object TransferSizes {
implicit def asBool(x: TransferSizes) = !x.none
}
// Use AddressSet instead -- this is just for pretty printing
case class AddressRange(base: BigInt, size: BigInt) extends Ordered[AddressRange]
{
val end = base + size
require (base >= 0, s"AddressRange base must be positive, got: $base")
require (size > 0, s"AddressRange size must be > 0, got: $size")
def compare(x: AddressRange) = {
val primary = (this.base - x.base).signum
val secondary = (x.size - this.size).signum
if (primary != 0) primary else secondary
}
def contains(x: AddressRange) = base <= x.base && x.end <= end
def union(x: AddressRange): Option[AddressRange] = {
if (base > x.end || x.base > end) {
None
} else {
val obase = if (base < x.base) base else x.base
val oend = if (end > x.end) end else x.end
Some(AddressRange(obase, oend-obase))
}
}
private def helper(base: BigInt, end: BigInt) =
if (base < end) Seq(AddressRange(base, end-base)) else Nil
def subtract(x: AddressRange) =
helper(base, end min x.base) ++ helper(base max x.end, end)
// We always want to see things in hex
override def toString() = "AddressRange(0x%x, 0x%x)".format(base, size)
}
// AddressSets specify the address space managed by the manager
// Base is the base address, and mask are the bits consumed by the manager
// e.g: base=0x200, mask=0xff describes a device managing 0x200-0x2ff
@ -210,24 +176,6 @@ case class AddressSet(base: BigInt, mask: BigInt) extends Ordered[AddressSet]
}
}
object AddressRange
{
def fromSets(seq: Seq[AddressSet]): Seq[AddressRange] = unify(seq.flatMap(_.toRanges))
def unify(seq: Seq[AddressRange]): Seq[AddressRange] = {
if (seq.isEmpty) return Nil
val ranges = seq.sorted
ranges.tail.foldLeft(Seq(ranges.head)) { case (head :: tail, x) =>
head.union(x) match {
case Some(z) => z :: tail
case None => x :: head :: tail
}
}.reverse
}
// Set subtraction... O(n*n) b/c I am lazy
def subtract(from: Seq[AddressRange], take: Seq[AddressRange]): Seq[AddressRange] =
take.foldLeft(from) { case (left, r) => left.flatMap { _.subtract(r) } }
}
object AddressSet
{
val everything = AddressSet(0, -1)

View File

@ -251,6 +251,15 @@ trait BindingScope
}
}
private def collect(path: List[String], value: ResourceValue): List[(String, ResourceAddress)] = {
value match {
case r: ResourceAddress => List((path(1), r))
case b: ResourceMapping => List((path(1), ResourceAddress(b.address, b.permissions)))
case ResourceMap(value, _) => value.toList.flatMap { case (key, seq) => seq.flatMap(r => collect(key :: path, r)) }
case _ => Nil
}
}
/** Generate the device tree. */
def bindingTree: ResourceMap = {
eval
@ -263,6 +272,9 @@ trait BindingScope
expand(tokens, Seq(ResourceMap(mapping, Seq(d.label)))) })
ResourceMap(SortedMap("/" -> tree))
}
/** Collect resource addresses from tree. */
def collectResourceAddresses = collect(Nil, bindingTree)
}
object BindingScope

View File

@ -22,10 +22,9 @@ abstract class DiplomaticSRAM(
def mask: List[Boolean] = bigBits(address.mask >> log2Ceil(beatBytes))
// Use single-ported memory with byte-write enable
def makeSinglePortedByteWriteSeqMem(size: Int) = {
def makeSinglePortedByteWriteSeqMem(size: Int, lanes: Int = beatBytes, bits: Int = 8) = {
// We require the address range to include an entire beat (for the write mask)
require ((address.mask & (beatBytes-1)) == beatBytes-1)
val mem = SeqMem(size, Vec(beatBytes, Bits(width = 8)))
val mem = SeqMem(size, Vec(lanes, Bits(width = bits)))
devName.foreach(n => mem.suggestName(n.split("-").last))
mem
}

View File

@ -27,7 +27,7 @@ class GroundTestSubsystem(implicit p: Parameters) extends BaseSubsystem
)}
tiles.flatMap(_.dcacheOpt).foreach { dc =>
sbus.fromTile(None, buffers = 1){ dc.node }
sbus.fromTile(None, buffer = BufferParams.default){ dc.node }
}
// No PLIC in ground test; so just sink the interrupts to nowhere

View File

@ -0,0 +1,23 @@
// See LICENSE.SiFive for license details.
package freechips.rocketchip.regmapper
import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods.{pretty, render}
object RegMappingAnnotation {
def serialize(base: BigInt, name: String, mapping: RegField.Map*): String = {
val regDescs = mapping.flatMap { case (byte, seq) =>
seq.map(_.width).scanLeft(0)(_ + _).zip(seq).map { case (bit, f) =>
val anonName = s"unnamedRegField${byte.toHexString}_${bit}"
(f.desc.map{ _.name}.getOrElse(anonName)) -> f.toJson(byte, bit)
}
}
pretty(render(
("peripheral" -> (
("displayName" -> name) ~
("baseAddress" -> s"0x${base.toInt.toHexString}") ~
("regfields" -> regDescs)))))
}
}

View File

@ -0,0 +1,47 @@
// See LICENSE for license details.
package freechips.rocketchip.regmapper
import Chisel._
import chisel3.experimental._
import chisel3.{Input, Output}
import freechips.rocketchip.util.{AsyncResetRegVec, SimpleRegIO}
object DescribedReg {
import freechips.rocketchip.regmapper.RegFieldAccessType._
import freechips.rocketchip.regmapper.RegFieldWrType._
import freechips.rocketchip.regmapper.RegFieldRdAction._
def apply[T <: Data](
gen: => T,
name: String,
desc: String,
reset: Option[T],
access: RegFieldAccessType = RW,
wrType: Option[RegFieldWrType] = None,
rdAction: Option[RegFieldRdAction] = None,
volatile: Boolean = false,
enumerations: Map[BigInt, (String, String)] = Map()): (T, RegFieldDesc) = {
val rdesc = RegFieldDesc(name, desc, None, None,
access, wrType, rdAction, volatile, reset.map{_.litValue}, enumerations)
val reg = reset.map{i => RegInit(i)}.getOrElse(Reg(gen))
reg.suggestName(name + "_reg")
(reg, rdesc)
}
def async(
width: Int,
name: String,
desc: String,
reset: Int,
access: RegFieldAccessType = RW,
wrType: Option[RegFieldWrType] = None,
rdAction: Option[RegFieldRdAction] = None,
volatile: Boolean = false,
enumerations: Map[BigInt, (String, String)] = Map()): (SimpleRegIO, RegFieldDesc) = {
val rdesc = RegFieldDesc(name, desc, None, None,
access, wrType, rdAction, volatile, Some(reset), enumerations)
val reg = Module(new AsyncResetRegVec(w = width, init = reset))
reg.suggestName(name + "_reg")
(reg.io, rdesc)
}
}

View File

@ -5,8 +5,11 @@ package freechips.rocketchip.regmapper
import Chisel._
import chisel3.util.{ReadyValidIO}
import freechips.rocketchip.util.{SimpleRegIO}
import org.json4s.JsonDSL._
import org.json4s.JsonAST.JValue
import org.json4s.jackson.JsonMethods.{pretty, render}
import freechips.rocketchip.util.{SimpleRegIO}
// This information is not used internally by the regmap(...) function.
// However, the author of a RegField may be the best person to provide this
@ -15,26 +18,47 @@ import freechips.rocketchip.util.{SimpleRegIO}
object RegFieldAccessType extends scala.Enumeration {
type RegFieldAccessType = Value
val R, W, RW, RSPECIAL, WSPECIAL, RWSPECIAL, OTHER = Value
val R, W, RW = Value
}
import RegFieldAccessType._
object RegFieldWrType extends scala.Enumeration {
type RegFieldWrType = Value
val ONE_TO_CLEAR, ONE_TO_SET, ONE_TO_TOGGLE, ZERO_TO_CLEAR,
ZERO_TO_SET, ZERO_TO_TOGGLE, CLEAR, SET, MODIFY = Value
}
import RegFieldWrType._
object RegFieldRdAction extends scala.Enumeration {
type RegFieldRdAction = Value
val CLEAR, SET, MODIFY = Value
}
import RegFieldRdAction._
case class RegFieldDesc (
name: String,
desc: String,
group: Option[String] = None,
groupDesc: Option[String] = None,
access: RegFieldAccessType = RegFieldAccessType.RW,
wrType: Option[RegFieldWrType] = None,
rdAction: Option[RegFieldRdAction] = None,
volatile: Boolean = false,
// TODO: testable?
reset: Option[BigInt] = None,
enumerations: Map[BigInt, (String, String)] = Map()
){
}
// Our descriptions are in terms of RegFields only, which is somewhat unusual for
// developers who are used to things being defined as bitfields within registers.
// The "Group" allows a string & (optional) description to be added which describes the conceptual "Group"
// the RegField belongs to. This can be used by downstream flows as they see fit to
// present the information.
object RegFieldDesc {
def reserved: RegFieldDesc = RegFieldDesc("reserved", "", access=RegFieldAccessType.R, reset=Some(0))
}
// Our descriptions are in terms of RegFields only, which is somewhat
// unusual for developers who are used to things being defined as bitfields
// within registers. The "Group" allows a string & (optional) description
// to be added which describes the conceptual "Group" the RegField belongs to.
// This can be used by downstream flows as they see fit to present the information.
object RegFieldGroup {
def apply (name: String, desc: Option[String], regs: Seq[RegField], descFirstOnly: Boolean = true): Seq[RegField] = {
@ -116,8 +140,29 @@ object RegWriteFn
case class RegField(width: Int, read: RegReadFn, write: RegWriteFn, desc: Option[RegFieldDesc])
{
require (width > 0, s"RegField width must be > 0, not $width")
def pipelined = !read.combinational || !write.combinational
def readOnly = this.copy(write = (), desc = this.desc.map(_.copy(access = RegFieldAccessType.R)))
def toJson(byteOffset: Int, bitOffset: Int): JValue = {
( ("byteOffset" -> s"0x${byteOffset.toHexString}") ~
("bitOffset" -> bitOffset) ~
("bitWidth" -> width) ~
("name" -> desc.map(_.name)) ~
("description" -> desc.map{ d=> if (d.desc == "") None else Some(d.desc)}) ~
("resetValue" -> desc.map{_.reset}) ~
("group" -> desc.map{_.group}) ~
("groupDesc" -> desc.map{_.groupDesc}) ~
("accessType" -> desc.map {d => d.access.toString}) ~
("writeType" -> desc.map {d => d.wrType.map(_.toString)}) ~
("readAction" -> desc.map {d => d.rdAction.map(_.toString)}) ~
("volatile" -> desc.map {d => if (d.volatile) Some(true) else None}) ~
("enumerations" -> desc.map {d =>
Option(d.enumerations.map { case (key, (name, edesc)) =>
(("value" -> key) ~ ("name" -> name) ~ ("description" -> edesc))
}).filter(_.nonEmpty)}) )
}
}
object RegField
@ -125,8 +170,7 @@ object RegField
// Byte address => sequence of bitfields, lowest index => lowest address
type Map = (Int, Seq[RegField])
def apply(n: Int) : RegField = apply(n, (), (),
Some(RegFieldDesc("reserved", "", access = RegFieldAccessType.R, reset = Some(0))))
def apply(n: Int) : RegField = apply(n, (), (), Some(RegFieldDesc.reserved))
def apply(n: Int, r: RegReadFn, w: RegWriteFn) : RegField = apply(n, r, w, None)
def apply(n: Int, r: RegReadFn, w: RegWriteFn, desc: RegFieldDesc) : RegField = apply(n, r, w, Some(desc))
@ -142,7 +186,7 @@ object RegField
// Setting takes priority over clearing.
def w1ToClear(n: Int, reg: UInt, set: UInt, desc: Option[RegFieldDesc] = None): RegField =
RegField(n, reg, RegWriteFn((valid, data) => { reg := ~(~reg | Mux(valid, data, UInt(0))) | set; Bool(true) }),
desc.map{_.copy(access = RegFieldAccessType.RWSPECIAL)})
desc.map{_.copy(access = RegFieldAccessType.RW, wrType=Some(RegFieldWrType.ONE_TO_CLEAR), volatile = true)})
// This RegField wraps an explicit register
// (e.g. Black-Boxed Register) to create a R/W register.
@ -151,26 +195,41 @@ object RegField
bb.en := valid
bb.d := data
Bool(true)
}), desc.map{_.copy(access = RegFieldAccessType.RW)})
}), desc)
// Create byte-sized read-write RegFields out of a large UInt register.
// It is updated when any of the bytes are written. Because the RegFields
// are all byte-sized, this is also suitable when a register is larger
// It is updated when any of the (implemented) bytes are written, the non-written
// bytes are just copied over from their current value.
// Because the RegField are all byte-sized, this is also suitable when a register is larger
// than the intended bus width of the device (atomic updates are impossible).
def bytes(reg: UInt, numBytes: Int, desc: Option[RegFieldDesc]): Seq[RegField] = {
require(reg.getWidth * 8 >= numBytes, "Can't break a ${reg.getWidth}-bit-wide register into only ${numBytes} bytes.")
val numFullBytes = reg.getWidth/8
val numPartialBytes = if ((reg.getWidth % 8) > 0) 1 else 0
val numPadBytes = numBytes - numFullBytes - numPartialBytes
val pad = reg | UInt(0, width = 8*numBytes)
val oldBytes = Vec.tabulate(numBytes) { i => pad(8*(i+1)-1, 8*i) }
val newBytes = Wire(init = oldBytes)
val valids = Wire(init = Vec.fill(numBytes) { Bool(false) })
when (valids.reduce(_ || _)) { reg := newBytes.asUInt }
Seq.tabulate(numBytes) { i =>
val newDesc = desc.map {d => d.copy(name = d.name + s"_$i")}
RegField(8, oldBytes(i),
RegWriteFn((valid, data) => {
def wrFn(i: Int): RegWriteFn = RegWriteFn((valid, data) => {
valids(i) := valid
when (valid) {newBytes(i) := data}
Bool(true)
}), newDesc)}}
})
val fullBytes = Seq.tabulate(numFullBytes) { i =>
val newDesc = desc.map {d => d.copy(name = d.name + s"_$i")}
RegField(8, oldBytes(i), wrFn(i), newDesc)}
val partialBytes = if (numPartialBytes > 0) {
val newDesc = desc.map {d => d.copy(name = d.name + s"_$numFullBytes")}
Seq(RegField(reg.getWidth % 8, oldBytes(numFullBytes), wrFn(numFullBytes), newDesc),
RegField(8 - (reg.getWidth % 8)))
} else Nil
val padBytes = Seq.fill(numPadBytes){RegField(8)}
fullBytes ++ partialBytes ++ padBytes
}
def bytes(reg: UInt, desc: Option[RegFieldDesc]): Seq[RegField] = {
val width = reg.getWidth

View File

@ -15,16 +15,20 @@ import freechips.rocketchip.interrupts._
import freechips.rocketchip.util.property._
trait BusErrors extends Bundle {
def toErrorList: List[Option[Valid[UInt]]]
def toErrorList: List[Option[(Valid[UInt], String, String)]]
}
class L1BusErrors(implicit p: Parameters) extends CoreBundle()(p) with BusErrors {
val icache = new ICacheErrors
val dcache = new DCacheErrors
def toErrorList =
List(None, None, icache.correctable, icache.uncorrectable,
None, Some(dcache.bus), dcache.correctable, dcache.uncorrectable)
def toErrorList = List(None, None,
icache.correctable.map((_, "I_CORRECTABLE", "Instruction cache or ITIM correctable ECC error ")),
icache.uncorrectable.map((_, "I_UNCORRECTABLE", "ITIM uncorrectable ECC error")),
None,
Some((dcache.bus, "DBUS", "Load or store TileLink bus error")),
dcache.correctable.map((_, "D_CORRECTABLE", "Data cache correctable ECC error")),
dcache.uncorrectable.map((_, "D_UNCORRECTABLE", "Data cache uncorrectable ECC error")))
}
case class BusErrorUnitParams(addr: BigInt, size: Int = 4096)
@ -44,14 +48,41 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit
val interrupt = Bool().asOutput
})
val sources = io.errors.toErrorList
val cause = Reg(init = UInt(0, log2Ceil(sources.lastIndexWhere(_.nonEmpty) + 1)))
val value = Reg(UInt(width = sources.flatten.map(_.bits.getWidth).max))
val sources_and_desc = io.errors.toErrorList
val sources = sources_and_desc.map(_.map(_._1))
val sources_enums = sources_and_desc.zipWithIndex.flatMap{case (s, i) => s.map {e => (BigInt(i) -> (e._2, e._3))}}
val causeWidth = log2Ceil(sources.lastIndexWhere(_.nonEmpty) + 1)
val (cause, cause_desc) = DescribedReg(UInt(causeWidth.W),
"cause", "Cause of error event", reset=Some(0.U(causeWidth.W)), volatile=true, enumerations=sources_enums.toMap)
val (value, value_desc) = DescribedReg(UInt(width = sources.flatten.map(_.bits.getWidth).max),
"value", "Physical address of error event", reset=None, volatile=true)
require(value.getWidth <= regWidth)
val enable = Reg(init = Vec(sources.map(_.nonEmpty.B)))
val enable_desc = sources.zipWithIndex.map { case (s, i) =>
if (s.nonEmpty) RegFieldDesc(s"enable_$i", "", reset=Some(1))
else RegFieldDesc.reserved
}
val global_interrupt = Reg(init = Vec.fill(sources.size)(false.B))
val global_interrupt_desc = sources.zipWithIndex.map { case (s, i) =>
if (s.nonEmpty) RegFieldDesc(s"plic_interrupt_$i", "", reset=Some(0))
else RegFieldDesc.reserved
}
val accrued = Reg(init = Vec.fill(sources.size)(false.B))
val accrued_desc = sources.zipWithIndex.map { case (s, i) =>
if (s.nonEmpty) RegFieldDesc(s"accrued_$i", "", reset=Some(0), volatile = true)
else RegFieldDesc.reserved
}
val local_interrupt = Reg(init = Vec.fill(sources.size)(false.B))
val local_interrupt_desc = sources.zipWithIndex.map { case (s, i) =>
if (s.nonEmpty) RegFieldDesc(s"local_interrupt_$i", "", reset=Some(0))
else RegFieldDesc.reserved
}
for ((((s, en), acc), i) <- (sources zip enable zip accrued).zipWithIndex; if s.nonEmpty) {
when (s.get.valid) {
@ -68,17 +99,18 @@ class BusErrorUnit[T <: BusErrors](t: => T, params: BusErrorUnitParams)(implicit
io.interrupt := (accrued.asUInt & local_interrupt.asUInt).orR
int_out(0) := (accrued.asUInt & global_interrupt.asUInt).orR
def reg(r: UInt) = RegField.bytes(r, (r.getWidth + 7)/8)
def reg(v: Vec[Bool]) = v.map(r => RegField(1, r))
def reg(r: UInt, gn: String, d: RegFieldDesc) = RegFieldGroup(gn, None, RegField.bytes(r, (r.getWidth + 7)/8, Some(d)))
def reg(v: Vec[Bool], gn: String, gd: String, d: Seq[RegFieldDesc]) =
RegFieldGroup(gn, Some(gd), (v zip d).map {case (r, rd) => RegField(1, r, rd)})
def numberRegs(x: Seq[Seq[RegField]]) = x.zipWithIndex.map {case (f, i) => (i * regWidth / 8) -> f }
node.regmap(numberRegs(Seq(
reg(cause),
reg(value),
reg(enable),
reg(global_interrupt),
reg(accrued),
reg(local_interrupt))):_*)
reg(cause, "cause", cause_desc),
reg(value, "value", value_desc),
reg(enable, "enable", "Event enable mask", enable_desc),
reg(global_interrupt, "plic_interrupt", "Platform-level interrupt enable mask", global_interrupt_desc),
reg(accrued, "accrued", "Accrued event mask" ,accrued_desc),
reg(local_interrupt, "local_interrupt", "Hart-local interrupt-enable mask", local_interrupt_desc))):_*)
// hardwire mask bits for unsupported sources to 0
for ((s, i) <- sources.zipWithIndex; if s.isEmpty) {

View File

@ -357,14 +357,14 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
CSRs.mip -> read_mip,
CSRs.mie -> reg_mie,
CSRs.mscratch -> reg_mscratch,
CSRs.mepc -> reg_mepc.sextTo(xLen),
CSRs.mepc -> readEPC(reg_mepc).sextTo(xLen),
CSRs.mbadaddr -> reg_mbadaddr.sextTo(xLen),
CSRs.mcause -> reg_mcause,
CSRs.mhartid -> io.hartid)
val debug_csrs = LinkedHashMap[Int,Bits](
CSRs.dcsr -> reg_dcsr.asUInt,
CSRs.dpc -> reg_dpc.sextTo(xLen),
CSRs.dpc -> readEPC(reg_dpc).sextTo(xLen),
CSRs.dscratch -> reg_dscratch.asUInt)
val fp_csrs = LinkedHashMap[Int,Bits](
@ -431,7 +431,7 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
read_mapping += CSRs.scause -> reg_scause
read_mapping += CSRs.sbadaddr -> reg_sbadaddr.sextTo(xLen)
read_mapping += CSRs.sptbr -> reg_sptbr.asUInt
read_mapping += CSRs.sepc -> reg_sepc.sextTo(xLen)
read_mapping += CSRs.sepc -> readEPC(reg_sepc).sextTo(xLen)
read_mapping += CSRs.stvec -> reg_stvec.sextTo(xLen)
read_mapping += CSRs.scounteren -> reg_scounteren
read_mapping += CSRs.mideleg -> reg_mideleg
@ -584,17 +584,17 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
reg_mstatus.spie := true
reg_mstatus.spp := PRV.U
new_prv := reg_mstatus.spp
io.evec := reg_sepc
io.evec := readEPC(reg_sepc)
}.elsewhen (Bool(usingDebug) && io.rw.addr(10)) {
new_prv := reg_dcsr.prv
reg_debug := false
io.evec := reg_dpc
io.evec := readEPC(reg_dpc)
}.otherwise {
reg_mstatus.mie := reg_mstatus.mpie
reg_mstatus.mpie := true
reg_mstatus.mpp := legalizePrivilege(PRV.U)
new_prv := reg_mstatus.mpp
io.evec := reg_mepc
io.evec := readEPC(reg_mepc)
}
}
@ -640,9 +640,12 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
when (decoded_addr(CSRs.misa)) {
val mask = UInt(isaStringToMask(isaMaskString), xLen)
val f = wdata('f' - 'a')
// suppress write if it would cause the next fetch to be misaligned
when (!usingCompressed || !io.pc(1) || wdata('c' - 'a')) {
if (coreParams.misaWritable)
reg_misa := ~(~wdata | (!f << ('d' - 'a'))) & mask | reg_misa & ~mask
}
}
when (decoded_addr(CSRs.mip)) {
// MIP should be modified based on the value in reg_mip, not the value
// in read_mip, since read_mip.seip is the OR of reg_mip.seip and
@ -838,5 +841,6 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param
}
}
def formEPC(x: UInt) = ~(~x | (if (usingCompressed) 1.U else 3.U))
def readEPC(x: UInt) = ~(~x | Mux(reg_misa('c' - 'a'), 1.U, 3.U))
def isaStringToMask(s: String) = s.map(x => 1 << (x - 'A')).foldLeft(0)(_|_)
}

View File

@ -15,16 +15,15 @@ import TLMessages._
class DCacheErrors(implicit p: Parameters) extends L1HellaCacheBundle()(p)
with CanHaveErrors {
val correctable = (cacheParams.tagECC.canCorrect || cacheParams.dataECC.canCorrect).option(Valid(UInt(width = paddrBits)))
val uncorrectable = (cacheParams.tagECC.canDetect || cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits)))
val correctable = (cacheParams.tagCode.canCorrect || cacheParams.dataCode.canCorrect).option(Valid(UInt(width = paddrBits)))
val uncorrectable = (cacheParams.tagCode.canDetect || cacheParams.dataCode.canDetect).option(Valid(UInt(width = paddrBits)))
val bus = Valid(UInt(width = paddrBits))
}
class DCacheDataReq(implicit p: Parameters) extends L1HellaCacheBundle()(p) {
val eccBytes = cacheParams.dataECCBytes
val addr = Bits(width = untagBits)
val write = Bool()
val wdata = UInt(width = cacheParams.dataECC.width(eccBytes*8) * rowBytes/eccBytes)
val wdata = UInt(width = encBits * rowBytes / eccBytes)
val wordMask = UInt(width = rowBytes / wordBytes)
val eccMask = UInt(width = wordBytes / eccBytes)
val way_en = Bits(width = nWays)
@ -37,9 +36,6 @@ class DCacheDataArray(implicit p: Parameters) extends L1HellaCacheModule()(p) {
}
require(rowBytes % wordBytes == 0)
val eccBits = cacheParams.dataECCBytes * 8
val encBits = cacheParams.dataECC.width(eccBits)
val encWordBits = encBits * (wordBits / eccBits)
val eccMask = if (eccBits == wordBits) Seq(true.B) else io.req.bits.eccMask.toBools
val wMask = if (nWays == 1) eccMask else (0 until nWays).flatMap(i => eccMask.map(_ && io.req.bits.way_en(i)))
val wWords = io.req.bits.wdata.grouped(encBits * (wordBits / eccBits))
@ -69,11 +65,8 @@ class DCache(hartid: Int, val scratch: () => Option[AddressSet] = () => None, va
}
class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
// no tag ECC support
val tECC = cacheParams.tagECC
val dECC = cacheParams.dataECC
val eccBytes = cacheParams.dataECCBytes
val eccBits = eccBytes * 8
val tECC = cacheParams.tagCode
val dECC = cacheParams.dataCode
require(isPow2(eccBytes) && eccBytes <= wordBytes)
require(eccBytes == 1 || !dECC.isInstanceOf[IdentityCode])
val usingRMW = eccBytes > 1 || usingAtomicsInCache
@ -700,7 +693,9 @@ class DCacheModule(outer: DCache) extends HellaCacheModule(outer) {
when (s2_correct) { pstore1_storegen_data := s2_data_word_corrected }
// flushes
val resetting = Reg(init=Bool(!usingDataScratchpad))
val resetting = RegInit(false.B)
if (!usingDataScratchpad)
when (RegNext(reset)) { resetting := true }
val flushed = Reg(init=Bool(true))
val flushing = Reg(init=Bool(false))
val flushCounter = Reg(init=UInt(nSets * (nWays-1), log2Ceil(nSets * nWays)))

View File

@ -19,8 +19,8 @@ case class DCacheParams(
nWays: Int = 4,
rowBits: Int = 64,
nTLBEntries: Int = 32,
tagECC: Code = new IdentityCode,
dataECC: Code = new IdentityCode,
tagECC: Option[String] = None,
dataECC: Option[String] = None,
dataECCBytes: Int = 1,
nMSHRs: Int = 1,
nSDQ: Int = 17,
@ -31,6 +31,9 @@ case class DCacheParams(
pipelineWayMux: Boolean = false,
scratch: Option[BigInt] = None) extends L1CacheParams {
def tagCode: Code = Code.fromString(tagECC)
def dataCode: Code = Code.fromString(dataECC)
def dataScratchpadBytes: Int = scratch.map(_ => nSets*blockBytes).getOrElse(0)
def replacement = new RandomReplacement(nWays)
@ -58,7 +61,11 @@ trait HasL1HellaCacheParameters extends HasL1CacheParameters with HasCoreParamet
def offsetlsb = wordOffBits
def rowWords = rowBits/wordBits
def doNarrowRead = coreDataBits * nWays % rowBits == 0
def encDataBits = cacheParams.dataECC.width(coreDataBits)
def eccBytes = cacheParams.dataECCBytes
val eccBits = cacheParams.dataECCBytes * 8
val encBits = cacheParams.dataCode.width(eccBits)
val encWordBits = encBits * (wordBits / eccBits)
def encDataBits = cacheParams.dataCode.width(coreDataBits) // NBDCache only
def encRowBits = encDataBits*rowWords
def lrscCycles = 32 // ISA requires 16-insn LRSC sequences to succeed
def lrscBackoff = 3 // disallow LRSC reacquisition briefly

View File

@ -20,13 +20,15 @@ case class ICacheParams(
rowBits: Int = 128,
nTLBEntries: Int = 32,
cacheIdBits: Int = 0,
tagECC: Code = new IdentityCode,
dataECC: Code = new IdentityCode,
tagECC: Option[String] = None,
dataECC: Option[String] = None,
itimAddr: Option[BigInt] = None,
prefetch: Boolean = false,
blockBytes: Int = 64,
latency: Int = 2,
fetchBytes: Int = 4) extends L1CacheParams {
def tagCode: Code = Code.fromString(tagECC)
def dataCode: Code = Code.fromString(dataECC)
def replacement = new RandomReplacement(nWays)
}
@ -41,8 +43,8 @@ class ICacheReq(implicit p: Parameters) extends CoreBundle()(p) with HasL1ICache
class ICacheErrors(implicit p: Parameters) extends CoreBundle()(p)
with HasL1ICacheParameters
with CanHaveErrors {
val correctable = (cacheParams.tagECC.canDetect || cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits)))
val uncorrectable = (cacheParams.itimAddr.nonEmpty && cacheParams.dataECC.canDetect).option(Valid(UInt(width = paddrBits)))
val correctable = (cacheParams.tagCode.canDetect || cacheParams.dataCode.canDetect).option(Valid(UInt(width = paddrBits)))
val uncorrectable = (cacheParams.itimAddr.nonEmpty && cacheParams.dataCode.canDetect).option(Valid(UInt(width = paddrBits)))
}
class ICache(val icacheParams: ICacheParams, val hartId: Int)(implicit p: Parameters) extends LazyModule {
@ -113,8 +115,8 @@ class ICacheModule(outer: ICache) extends LazyModuleImp(outer)
// Option.unzip does not exist :-(
val (tl_in, edge_in) = outer.slaveNode.in.headOption.unzip
val tECC = cacheParams.tagECC
val dECC = cacheParams.dataECC
val tECC = cacheParams.tagCode
val dECC = cacheParams.dataCode
require(isPow2(nSets) && isPow2(nWays))
require(!usingVM || pgIdxBits >= untagBits)

View File

@ -668,8 +668,8 @@ class NonBlockingDCacheModule(outer: NonBlockingDCache) extends HellaCacheModule
require(dataScratchpadSize == 0)
// ECC is only supported on the data array
require(cacheParams.tagECC.isInstanceOf[IdentityCode])
val dECC = cacheParams.dataECC
require(cacheParams.tagCode.isInstanceOf[IdentityCode])
val dECC = cacheParams.dataCode
val wb = Module(new WritebackUnit)
val prober = Module(new ProbeUnit)

View File

@ -228,14 +228,12 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p)
bpu.io.pc := ibuf.io.pc
bpu.io.ea := mem_reg_wdata
val id_pc_misaligned = !csr.io.status.isa('c'-'a') && ibuf.io.pc(1)
val id_xcpt0 = ibuf.io.inst(0).bits.xcpt0
val id_xcpt1 = ibuf.io.inst(0).bits.xcpt1
val (id_xcpt, id_cause) = checkExceptions(List(
(csr.io.interrupt, csr.io.interrupt_cause),
(bpu.io.debug_if, UInt(CSR.debugTriggerCause)),
(bpu.io.xcpt_if, UInt(Causes.breakpoint)),
(id_pc_misaligned, UInt(Causes.misaligned_fetch)),
(id_xcpt0.pf.inst, UInt(Causes.fetch_page_fault)),
(id_xcpt0.ae.inst, UInt(Causes.fetch_access)),
(id_xcpt1.pf.inst, UInt(Causes.fetch_page_fault)),
@ -572,7 +570,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p)
sboard.clear(ll_wen, ll_waddr)
def id_sboard_clear_bypass(r: UInt) = {
// ll_waddr arrives late when D$ has ECC, so reshuffle the hazard check
if (tileParams.dcache.get.dataECC.isInstanceOf[IdentityCode]) ll_wen && ll_waddr === r
if (!tileParams.dcache.get.dataECC.isDefined) ll_wen && ll_waddr === r
else div.io.resp.fire() && div.io.resp.bits.tag === r || dmem_resp_replay && dmem_resp_xpu && dmem_resp_waddr === r
}
val id_sboard_hazard = checkHazards(hazard_targets, rd => sboard.read(rd) && !id_sboard_clear_bypass(rd))

View File

@ -97,39 +97,22 @@ abstract class BaseSubsystem(implicit p: Parameters) extends BareSubsystem {
}
}
abstract class BaseSubsystemModuleImp[+L <: BaseSubsystem](_outer: L) extends BareSubsystemModuleImp(_outer) {
println("Generated Address Map")
private val aw = (outer.sbus.busView.bundle.addressBits-1)/4 + 1
private val fmt = s"\t%${aw}x - %${aw}x %c%c%c%c%c %s"
private def collect(path: List[String], value: ResourceValue): List[(String, ResourceAddress)] = {
value match {
case r: ResourceAddress => List((path(1), r))
case b: ResourceMapping => List((path(1), ResourceAddress(b.address, b.permissions)))
case ResourceMap(value, _) => value.toList.flatMap { case (key, seq) => seq.flatMap(r => collect(key :: path, r)) }
case _ => Nil
}
}
private val ranges = collect(Nil, outer.bindingTree).groupBy(_._2).toList.flatMap { case (key, seq) =>
AddressRange.fromSets(key.address).map { r => (r, key.permissions, seq.map(_._1)) }
}.sortBy(_._1)
private val json = ranges.map { case (range, ResourcePermissions(r, w, x, c, a), names) =>
println(fmt.format(
range.base,
range.base+range.size,
if (a) 'A' else ' ',
if (r) 'R' else ' ',
if (w) 'W' else ' ',
if (x) 'X' else ' ',
if (c) 'C' else ' ',
names.mkString(", ")))
s"""{"base":[${range.base}],"size":[${range.size}],"r":[$r],"w":[$w],"x":[$x],"c":[$c],"a":[$a],"names":[${names.map('"'+_+'"').mkString(",")}]}"""
abstract class BaseSubsystemModuleImp[+L <: BaseSubsystem](_outer: L) extends BareSubsystemModuleImp(_outer) {
private val mapping: Seq[AddressMapEntry] = {
outer.collectResourceAddresses.groupBy(_._2).toList.flatMap { case (key, seq) =>
AddressRange.fromSets(key.address).map { r => AddressMapEntry(r, key.permissions, seq.map(_._1)) }
}.sortBy(_.range)
}
println("Generated Address Map")
mapping.map(entry => println(entry.toString((outer.sbus.busView.bundle.addressBits-1)/4 + 1)))
println("")
ElaborationArtefacts.add("memmap.json", s"""{"mapping":[${json.mkString(",")}]}""")
ElaborationArtefacts.add("memmap.json", s"""{"mapping":[${mapping.map(_.serialize).mkString(",")}]}""")
// Confirm that all of memory was described by DTS
private val dtsRanges = AddressRange.unify(ranges.map(_._1))
private val dtsRanges = AddressRange.unify(mapping.map(_.range))
private val allRanges = AddressRange.unify(outer.topManagers.get.flatMap { m => AddressRange.fromSets(m.address) })
if (dtsRanges != allRanges) {

View File

@ -50,6 +50,28 @@ class WithNBigCores(n: Int) extends Config((site, here, up) => {
}
})
class WithNSmallLinuxCores(n: Int) extends Config((site, here, up) => {
case RocketTilesKey => {
val small = RocketTileParams(
core = RocketCoreParams(),
btb = None,
dcache = Some(DCacheParams(
rowBits = site(SystemBusKey).beatBits,
nSets = 64,
nWays = 1,
nTLBEntries = 4,
nMSHRs = 0,
blockBytes = site(CacheBlockBytes))),
icache = Some(ICacheParams(
rowBits = site(SystemBusKey).beatBits,
nSets = 64,
nWays = 1,
nTLBEntries = 4,
blockBytes = site(CacheBlockBytes))))
List.tabulate(n)(i => small.copy(hartId = i))
}
})
class WithNSmallCores(n: Int) extends Config((site, here, up) => {
case RocketTilesKey => {
val small = RocketTileParams(
@ -208,6 +230,14 @@ class WithRoccExample extends Config((site, here, up) => {
}
})
class WithClockFrequency(frequency: BigInt) extends Config((site, here, up) => {
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
r.copy(core = r.core.copy(bootFreqHz = frequency))
}
case PeripheryBusKey => up(PeripheryBusKey, site)
.copy(frequency = frequency)
})
class WithDefaultBtb extends Config((site, here, up) => {
case RocketTilesKey => up(RocketTilesKey, site) map { r =>
r.copy(btb = Some(BTBParams()))

View File

@ -12,7 +12,7 @@ case class FrontBusParams(
beatBytes: Int,
blockBytes: Int,
sbusCrossing: SubsystemClockCrossing = SynchronousCrossing(),
sbusBuffer: BufferParams = BufferParams.default) extends HasTLBusParams
sbusBuffer: BufferParams = BufferParams.none) extends HasTLBusParams
case object FrontBusKey extends Field[FrontBusParams]
@ -23,21 +23,23 @@ class FrontBus(params: FrontBusParams)
val crossing = params.sbusCrossing
def fromPort[D,U,E,B <: Data]
(name: Option[String] = None, buffers: Int = 1)
(name: Option[String] = None, buffer: BufferParams = BufferParams.none)
(gen: => NodeHandle[D,U,E,B,TLClientPortParameters,TLManagerPortParameters,TLEdgeOut,TLBundle] =
TLIdentity.gen): InwardNodeHandle[D,U,E,B] = {
from("port" named name) { fixFrom(TLFIFOFixer.all, buffers) :=* gen }
from("port" named name) { fixFrom(TLFIFOFixer.all, buffer) :=* gen }
}
def fromMasterNode(name: Option[String] = None, buffers: Int = 1)(gen: TLOutwardNode) {
from("master" named name) { fixFrom(TLFIFOFixer.all, buffers) :=* gen }
def fromMasterNode
(name: Option[String] = None, buffer: BufferParams = BufferParams.none)
(gen: TLOutwardNode) {
from("master" named name) { fixFrom(TLFIFOFixer.all, buffer) :=* gen }
}
def fromMaster[D,U,E,B <: Data]
(name: Option[String] = None, buffers: Int = 1)
(name: Option[String] = None, buffer: BufferParams = BufferParams.none)
(gen: => NodeHandle[D,U,E,B,TLClientPortParameters,TLManagerPortParameters,TLEdgeOut,TLBundle] =
TLIdentity.gen): InwardNodeHandle[D,U,E,B] = {
from("master" named name) { fixFrom(TLFIFOFixer.all, buffers) :=* gen }
from("master" named name) { fixFrom(TLFIFOFixer.all, buffer) :=* gen }
}
def fromCoherentChip(gen: => TLNode): TLInwardNode = {

View File

@ -44,9 +44,8 @@ case object MemoryBusKey extends Field[MemoryBusParams]
class MemoryBus(params: MemoryBusParams)(implicit p: Parameters) extends TLBusWrapper(params, "memory_bus")(p)
with HasTLXbarPhy {
def fromCoherenceManager(
name: Option[String] = None,
buffer: BufferParams = BufferParams.none)
def fromCoherenceManager
(name: Option[String] = None, buffer: BufferParams = BufferParams.none)
(gen: => TLNode): TLInwardNode = {
from("coherence_manager" named name) {
inwardNode := TLBuffer(buffer) := gen

View File

@ -108,10 +108,10 @@ class PeripheryBus(params: PeripheryBusParams)
def toTile
(name: Option[String] = None, buffers: Int = 0)
(name: Option[String] = None, buffer: BufferParams = BufferParams.none)
(gen: => TLNode): TLOutwardNode = {
to("tile" named name) { FlipRendering { implicit p =>
gen :*= bufferTo(buffers)
gen :*= bufferTo(buffer)
}}
}
}

View File

@ -130,7 +130,7 @@ trait HasSlaveAXI4Port { this: BaseSubsystem =>
id = IdRange(0, 1 << params.idBits))))))
private val fifoBits = 1
sbus.fromPort(Some(portName)) {
fbus.fromPort(Some(portName), buffer = BufferParams.default) {
(TLWidthWidget(params.beatBytes)
:= AXI4ToTL()
:= AXI4UserYanker(Some(1 << (params.sourceBits - fifoBits - 1)))

View File

@ -21,8 +21,8 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr
private val master_splitter = LazyModule(new TLSplitter)
inwardNode :=* master_splitter.node
protected def fixFromThenSplit(policy: TLFIFOFixer.Policy, buffers: Int): TLInwardNode =
master_splitter.node :=* TLBuffer.chain(buffers).foldLeft(TLFIFOFixer(policy))(_ :=* _)
protected def fixFromThenSplit(policy: TLFIFOFixer.Policy, buffer: BufferParams): TLInwardNode =
master_splitter.node :=* TLBuffer(buffer) :=* TLFIFOFixer(policy)
def busView = master_splitter.node.edges.in.head
@ -72,10 +72,10 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr
}
def fromTile
(name: Option[String], buffers: Int = 0, cork: Option[Boolean] = None)
(name: Option[String], buffer: BufferParams = BufferParams.none, cork: Option[Boolean] = None)
(gen: => TLNode): TLInwardNode = {
from("tile" named name) {
fixFromThenSplit(TLFIFOFixer.allUncacheable, buffers) :=* gen
fixFromThenSplit(TLFIFOFixer.allUncacheable, buffer) :=* gen
}
}
@ -87,23 +87,23 @@ class SystemBus(params: SystemBusParams)(implicit p: Parameters) extends TLBusWr
}
def fromPort[D,U,E,B <: Data]
(name: Option[String] = None, buffers: Int = 0)
(name: Option[String] = None, buffer: BufferParams = BufferParams.none)
(gen: => NodeHandle[D,U,E,B,TLClientPortParameters,TLManagerPortParameters,TLEdgeOut,TLBundle] =
TLIdentity.gen): InwardNodeHandle[D,U,E,B] = {
from("port" named name) { fixFromThenSplit(TLFIFOFixer.all, buffers) :=* gen }
from("port" named name) { fixFromThenSplit(TLFIFOFixer.all, buffer) :=* gen }
}
def fromCoherentMaster[D,U,E,B <: Data]
(name: Option[String] = None, buffers: Int = 0)
(name: Option[String] = None, buffer: BufferParams = BufferParams.none)
(gen: => NodeHandle[D,U,E,B,TLClientPortParameters,TLManagerPortParameters,TLEdgeOut,TLBundle] =
TLIdentity.gen): InwardNodeHandle[D,U,E,B] = {
from("coherent_master" named name) { fixFrom(TLFIFOFixer.all, buffers) :=* gen }
from("coherent_master" named name) { fixFrom(TLFIFOFixer.all, buffer) :=* gen }
}
def fromMaster[D,U,E,B <: Data]
(name: Option[String] = None, buffers: Int = 0)
(name: Option[String] = None, buffer: BufferParams = BufferParams.none)
(gen: => NodeHandle[D,U,E,B,TLClientPortParameters,TLManagerPortParameters,TLEdgeOut,TLBundle] =
TLIdentity.gen): InwardNodeHandle[D,U,E,B] = {
from("master" named name) { fixFromThenSplit(TLFIFOFixer.all, buffers) :=* gen }
from("master" named name) { fixFromThenSplit(TLFIFOFixer.all, buffer) :=* gen }
}
}

View File

@ -52,8 +52,6 @@ class RoCCCoreIO(implicit p: Parameters) extends CoreBundle()(p) {
val busy = Bool(OUTPUT)
val interrupt = Bool(OUTPUT)
val exception = Bool(INPUT)
override def cloneType = new RoCCCoreIO()(p).asInstanceOf[this.type]
}
/** Base classes for Diplomatic TL2 RoCC units **/
@ -64,7 +62,7 @@ abstract class LazyRoCC(implicit p: Parameters) extends LazyModule {
val tlNode: TLNode = TLIdentityNode()
}
class RoCCIO(outer: LazyRoCC)(implicit p: Parameters) extends RoCCCoreIO()(p) {
class RoCCIO(val outer: LazyRoCC)(implicit p: Parameters) extends RoCCCoreIO()(p) {
// Should be handled differently, eventually
val ptw = Vec(p(RoccNPTWPorts), new TLBPTWIO)
val fpu_req = Decoupled(new FPInput)

View File

@ -32,18 +32,12 @@ abstract class TLBusWrapper(params: HasTLBusParams, val busName: String)(implici
protected def bufferFrom(buffer: BufferParams): TLInwardNode =
inwardNode :=* TLBuffer(buffer)
protected def bufferFrom(buffers: Int): TLInwardNode =
TLBuffer.chain(buffers).foldLeft(inwardNode)(_ :=* _)
protected def fixFrom(policy: TLFIFOFixer.Policy, buffers: Int): TLInwardNode =
inwardNode :=* TLBuffer.chain(buffers).foldLeft(TLFIFOFixer(policy))(_ :=* _)
protected def fixFrom(policy: TLFIFOFixer.Policy, buffer: BufferParams): TLInwardNode =
inwardNode :=* TLBuffer(buffer) :=* TLFIFOFixer(policy)
protected def bufferTo(buffer: BufferParams): TLOutwardNode =
TLBuffer(buffer) :*= delayNode :*= outwardNode
protected def bufferTo(buffers: Int): TLOutwardNode =
TLBuffer.chain(buffers).foldRight(delayNode)(_ :*= _) :*= outwardNode
protected def fixedWidthTo(buffer: BufferParams): TLOutwardNode =
TLWidthWidget(beatBytes) :*= bufferTo(buffer)

View File

@ -35,7 +35,7 @@ trait ExampleModule extends HasRegMap
Some(RegFieldDesc("pending", "Pending: Example of a special (W1ToC) Register. " +
"Writing a bit here causes it to be reset to 0. " +
"The bits are set when the corresponding bit in 'state' is high.",
reset=Some(0xF)))))
reset=Some(0xF), volatile=true))))
)
}

View File

@ -147,7 +147,7 @@ class TLRAMModel(log: String = "", ignoreErrorData: Boolean = false)(implicit p:
}
when (a.opcode === TLMessages.Get) {
printf(log + " G 0x%x - 0%x\n", a_base, a_base | UIntToOH1(a_size, addressBits))
printf(log + " G 0x%x - 0x%x\n", a_base, a_base | UIntToOH1(a_size, addressBits))
}
}

View File

@ -10,9 +10,6 @@ import freechips.rocketchip.interrupts._
import freechips.rocketchip.util.{HeterogeneousBag, ElaborationArtefacts}
import scala.math.{min,max}
import org.json4s.JsonDSL._
import org.json4s.jackson.JsonMethods.{pretty, render}
case class TLRegisterNode(
address: Seq[AddressSet],
device: Device,
@ -85,44 +82,15 @@ case class TLRegisterNode(
bundleIn.e.ready := Bool(true)
// Dump out the register map for documentation purposes.
val regDescs = mapping.flatMap { case (offset, seq) =>
var currentBitOffset = 0
seq.zipWithIndex.map { case (f, i) => {
val tmp = (f.desc.map{ _.name}.getOrElse(s"unnamedRegField${offset.toHexString}_${currentBitOffset}") -> (
("byteOffset" -> s"0x${offset.toHexString}") ~
("bitOffset" -> currentBitOffset) ~
("bitWidth" -> f.width) ~
("name" -> f.desc.map(_.name)) ~
("description" -> f.desc.map{d => if (d.desc == "") None else Some(d.desc)}) ~
("resetValue" -> f.desc.map{_.reset}) ~
("group" -> f.desc.map{_.group}) ~
("groupDesc" -> f.desc.map{_.groupDesc}) ~
("accessType" -> f.desc.map {d => d.access.toString}) ~
("enumerations" -> f.desc.map {d =>
Option(d.enumerations.map { case (key, (name, desc)) =>
(("value" -> key) ~
("name" -> name) ~
("description" -> desc))
}).filter(_.nonEmpty)})
))
currentBitOffset = currentBitOffset + f.width
tmp
}}
}
//TODO: It would be better to name this other than "Device at ...."
val base = s"0x${address.head.base.toInt.toHexString}"
val json = ("peripheral" -> (
("displayName" -> s"deviceAt${base}") ~
("baseAddress" -> base) ~
("regfields" -> regDescs)
))
val base = address.head.base
val baseHex = s"0x${base.toInt.toHexString}"
val name = s"deviceAt${baseHex}" //TODO: It would be better to name this other than "Device at ...."
val json = RegMappingAnnotation.serialize(base, name, mapping:_*)
var suffix = 0
while( ElaborationArtefacts.contains(s"${base}.${suffix}.regmap.json")){
while( ElaborationArtefacts.contains(s"${baseHex}.${suffix}.regmap.json")){
suffix = suffix + 1
}
ElaborationArtefacts.add(s"${base}.${suffix}.regmap.json", pretty(render(json)))
ElaborationArtefacts.add(s"${baseHex}.${suffix}.regmap.json", json)
}
}

View File

@ -13,10 +13,16 @@ class TLRAM(
cacheable: Boolean = true,
executable: Boolean = true,
beatBytes: Int = 4,
eccBytes: Int = 1,
devName: Option[String] = None,
errors: Seq[AddressSet] = Nil)
errors: Seq[AddressSet] = Nil,
code: Code = new IdentityCode)
(implicit p: Parameters) extends DiplomaticSRAM(address, beatBytes, devName)
{
require (eccBytes >= 1 && isPow2(eccBytes))
require (beatBytes >= 1 && isPow2(beatBytes))
require (eccBytes <= beatBytes, s"TLRAM eccBytes (${eccBytes}) > beatBytes (${beatBytes}). Use a WidthWidget=>Fragmenter=>SRAM if you need high density and narrow ECC; it will do bursts efficiently")
val node = TLManagerNode(Seq(TLManagerPortParameters(
Seq(TLManagerParameters(
address = List(address) ++ errors,
@ -33,46 +39,127 @@ class TLRAM(
lazy val module = new LazyModuleImp(this) {
val (in, edge) = node.in(0)
val width = code.width(eccBytes*8)
val lanes = beatBytes/eccBytes
val addrBits = (mask zip edge.addr_hi(in.a.bits).toBools).filter(_._1).map(_._2)
val a_legal = address.contains(in.a.bits.address)
val memAddress = Cat(addrBits.reverse)
val mem = makeSinglePortedByteWriteSeqMem(1 << addrBits.size)
val mem = makeSinglePortedByteWriteSeqMem(1 << addrBits.size, lanes, width)
/* This block uses a two-stage pipeline; A=>D
* Both stages vie for access to the single SRAM port.
* Stage D has absolute priority over stage A.
* - read-modify-writeback for sub-lane access happens here
* - writeback of correctable data happens here
* - both actions may occur concurrently
* Stage A has lower priority and will stall if blocked
* - read operations happen here
* - full-lane write operations happen here
*/
// D stage registers from A
val d_full = RegInit(Bool(false))
val d_read = Reg(Bool())
val d_ram_valid = RegInit(Bool(false)) // true if we just read-out from SRAM
val d_size = Reg(UInt())
val d_source = Reg(UInt())
val d_data = Wire(UInt())
val d_legal = Reg(Bool())
val d_read = Reg(Bool())
val d_address = Reg(UInt(width = addrBits.size))
val d_rmw_mask = Reg(UInt(width = beatBytes))
val d_rmw_data = Reg(UInt(width = 8*beatBytes))
// Flow control
when (in.d.fire()) { d_full := Bool(false) }
when (in.a.fire()) { d_full := Bool(true) }
in.d.valid := d_full
in.a.ready := in.d.ready || !d_full
// Decode raw unregistered SRAM output
val d_raw_data = Wire(Vec(lanes, Bits(width = width)))
val d_decoded = d_raw_data.map(lane => code.decode(lane))
val d_corrected = Cat(d_decoded.map(_.corrected).reverse)
val d_uncorrected = Cat(d_decoded.map(_.uncorrected).reverse)
val d_correctable = d_decoded.map(_.correctable)
val d_uncorrectable = d_decoded.map(_.uncorrectable)
val d_need_fix = d_correctable.reduce(_ || _)
val d_error = d_uncorrectable.reduce(_ || _)
// What does D-stage want to write-back?
val d_wb_data = Vec(Seq.tabulate(beatBytes) { i =>
val upd = d_rmw_mask(i)
val rmw = d_rmw_data (8*(i+1)-1, 8*i)
val fix = d_corrected(8*(i+1)-1, 8*i) // safe to use, because D-stage write-back always wins arbitration
Mux(upd, rmw, fix)
}.grouped(eccBytes).map(lane => Cat(lane.reverse)).toList)
val (d_wb_lanes, d_wb_poison) = Seq.tabulate(lanes) { i =>
val upd = d_rmw_mask(eccBytes*(i+1)-1, eccBytes*i)
(upd.orR || d_correctable(i),
!upd.andR && d_uncorrectable(i)) // sub-lane writes should not correct uncorrectable
}.unzip
val d_wb = d_rmw_mask.orR || (d_ram_valid && d_need_fix)
// Extend the validity of SRAM read-out
val d_held_data = RegEnable(d_corrected, d_ram_valid)
val d_held_error = RegEnable(d_error, d_ram_valid)
in.d.bits := edge.AccessAck(d_source, d_size, !d_legal)
// avoid data-bus Mux
in.d.bits.data := d_data
in.d.bits.opcode := Mux(d_read, TLMessages.AccessAckData, TLMessages.AccessAck)
in.d.bits.param := UInt(0)
in.d.bits.size := d_size
in.d.bits.source := d_source
in.d.bits.sink := UInt(0)
// It is safe to use uncorrected data here because of d_pause
in.d.bits.data := Mux(d_ram_valid, d_uncorrected, d_held_data)
in.d.bits.error := !d_legal || Mux(d_ram_valid, d_error, d_held_error)
val read = in.a.bits.opcode === TLMessages.Get
val rdata = Wire(Vec(beatBytes, Bits(width = 8)))
val wdata = Vec.tabulate(beatBytes) { i => in.a.bits.data(8*(i+1)-1, 8*i) }
d_data := Cat(rdata.reverse)
// Formulate a response only when SRAM output is unused or correct
val d_pause = d_read && d_ram_valid && d_need_fix
in.d.valid := d_full && !d_pause
in.a.ready := !d_full || (in.d.ready && !d_pause && !d_wb)
val a_legal = Bool(errors.isEmpty) || address.contains(in.a.bits.address)
val a_address = Cat(addrBits.reverse)
val a_read = in.a.bits.opcode === TLMessages.Get
val a_data = Vec(Seq.tabulate(lanes) { i => in.a.bits.data(eccBytes*8*(i+1)-1, eccBytes*8*i) })
/*
val a_sublane = Seq.tabulate(lanes) { i =>
val upd = in.a.bits.mask(eccBytes*(i+1)-1, eccBytes*i)
upd.orR && !upd.andR
}.reduce(_ || _)
*/
val a_sublane = if (eccBytes == 1) Bool(false) else
in.a.bits.opcode === TLMessages.PutPartialData ||
in.a.bits.size < UInt(log2Ceil(eccBytes))
val a_ren = a_read || a_sublane
val a_lanes = Seq.tabulate(lanes) { i => in.a.bits.mask(eccBytes*(i+1)-1, eccBytes*i).orR }
when (in.d.fire()) { d_full := Bool(false) }
d_ram_valid := Bool(false)
d_rmw_mask := UInt(0)
when (in.a.fire()) {
d_read := read
d_full := Bool(true)
d_ram_valid := a_ren && a_legal
d_size := in.a.bits.size
d_source := in.a.bits.source
d_legal := a_legal
d_read := a_read
d_address := a_address
d_rmw_mask := UInt(0)
when (!a_read && a_sublane) {
d_rmw_mask := in.a.bits.mask
d_rmw_data := in.a.bits.data
}
d_held_error:= Bool(false)
}
// exactly this pattern is required to get a RWM memory
when (in.a.fire() && !read && a_legal) {
mem.write(memAddress, wdata, in.a.bits.mask.toBools)
}
val ren = in.a.fire() && read
rdata := mem.readAndHold(memAddress, ren)
// SRAM arbitration
val a_fire = in.a.fire() && a_legal
val wen = d_wb || (a_fire && !a_ren)
// val ren = !d_wb && (a_fire && a_ren)
val ren = !wen && a_fire // help Chisel infer a RW-port
val addr = Mux(d_wb, d_address, a_address)
val sel = Mux(d_wb, Vec(d_wb_lanes), Vec(a_lanes))
val dat = Mux(d_wb, d_wb_data, a_data)
val poison = Mux(d_wb, Vec(d_wb_poison), Vec.fill(lanes) { Bool(false) })
val coded = Vec((dat zip poison) map { case (d, p) =>
if (code.canDetect) code.encode(d, p) else code.encode(d)
})
d_raw_data := mem.read(addr, ren)
when (wen) { mem.write(addr, coded, sel) }
// Tie off unused channels
in.b.valid := Bool(false)
@ -88,10 +175,12 @@ object TLRAM
cacheable: Boolean = true,
executable: Boolean = true,
beatBytes: Int = 4,
eccBytes: Int = 1,
devName: Option[String] = None,
errors: Seq[AddressSet] = Nil)(implicit p: Parameters): TLInwardNode =
errors: Seq[AddressSet] = Nil,
code: Code = new IdentityCode)(implicit p: Parameters): TLInwardNode =
{
val ram = LazyModule(new TLRAM(address, cacheable, executable, beatBytes, devName, errors))
val ram = LazyModule(new TLRAM(address, cacheable, executable, beatBytes, eccBytes, devName, errors, code))
ram.node
}
}
@ -115,3 +204,20 @@ class TLRAMSimpleTest(ramBeatBytes: Int, txns: Int = 5000, timeout: Int = 500000
val dut = Module(LazyModule(new TLRAMSimple(ramBeatBytes, txns)).module)
io.finished := dut.io.finished
}
class TLRAMECC(ramBeatBytes: Int, eccBytes: Int, txns: Int)(implicit p: Parameters) extends LazyModule {
val fuzz = LazyModule(new TLFuzzer(txns))
val model = LazyModule(new TLRAMModel("SRAMSimple"))
val ram = LazyModule(new TLRAM(AddressSet(0x0, 0x3ff), beatBytes = ramBeatBytes, eccBytes = eccBytes, code = new SECDEDCode))
ram.node := TLDelayer(0.25) := model.node := fuzz.node
lazy val module = new LazyModuleImp(this) with UnitTestModule {
io.finished := fuzz.module.io.finished
}
}
class TLRAMECCTest(ramBeatBytes: Int, eccBytes: Int, txns: Int = 5000, timeout: Int = 500000)(implicit p: Parameters) extends UnitTest(timeout) {
val dut = Module(LazyModule(new TLRAMECC(ramBeatBytes, eccBytes, txns)).module)
io.finished := dut.io.finished
}

View File

@ -9,6 +9,30 @@ import freechips.rocketchip.util._
import freechips.rocketchip.amba.axi4._
import scala.math.{min, max}
class TLtoAXI4IdMap(tl: TLClientPortParameters, axi4: AXI4MasterPortParameters) {
private val axiDigits = String.valueOf(axi4.endId-1).length()
private val tlDigits = String.valueOf(tl.endSourceId-1).length()
private val fmt = s"\t[%${axiDigits}d, %${axiDigits}d) <= [%${tlDigits}d, %${tlDigits}d) %s%s%s"
private val sorted = tl.clients.sortWith(TLToAXI4.sortByType)
val mapping: Seq[TLToAXI4IdMapEntry] = (sorted zip axi4.masters) map { case (c, m) =>
TLToAXI4IdMapEntry(m.id, c.sourceId, c.name, c.supportsProbe, c.requestFifo)
}
def pretty: String = mapping.map(_.pretty(fmt)).mkString(",\n")
}
case class TLToAXI4IdMapEntry(axi4Id: IdRange, tlId: IdRange, name: String, isCache: Boolean, requestFifo: Boolean) {
def pretty(fmt: String) = fmt.format(
axi4Id.start,
axi4Id.end,
tlId.start,
tlId.end,
s""""$name"""",
if (isCache) " [CACHE]" else "",
if (requestFifo) " [FIFO]" else "")
}
case class TLToAXI4Node(stripBits: Int = 0)(implicit valName: ValName) extends MixedAdapterNode(TLImp, AXI4Imp)(
dFn = { p =>
p.clients.foreach { c =>
@ -59,32 +83,25 @@ class TLToAXI4(val combinational: Boolean = true, val adapterName: Option[String
require (slaves(0).interleavedId.isDefined)
slaves.foreach { s => require (s.interleavedId == slaves(0).interleavedId) }
val axiDigits = String.valueOf(edgeOut.master.endId-1).length()
val tlDigits = String.valueOf(edgeIn.client.endSourceId-1).length()
// Construct the source=>ID mapping table
adapterName.foreach { n => println(s"$n AXI4-ID <= TL-Source mapping:") }
val map = new TLtoAXI4IdMap(edgeIn.client, edgeOut.master)
val sourceStall = Wire(Vec(edgeIn.client.endSourceId, Bool()))
val sourceTable = Wire(Vec(edgeIn.client.endSourceId, out.aw.bits.id))
val idStall = Wire(init = Vec.fill(edgeOut.master.endId) { Bool(false) })
var idCount = Array.fill(edgeOut.master.endId) { None:Option[Int] }
val maps = (edgeIn.client.clients.sortWith(TLToAXI4.sortByType) zip edgeOut.master.masters) flatMap { case (c, m) =>
for (i <- 0 until c.sourceId.size) {
val id = m.id.start + (if (c.requestFifo) 0 else (i >> stripBits))
sourceStall(c.sourceId.start + i) := idStall(id)
sourceTable(c.sourceId.start + i) := UInt(id)
}
if (c.requestFifo) { idCount(m.id.start) = Some(c.sourceId.size) }
adapterName.map { n =>
val fmt = s"\t[%${axiDigits}d, %${axiDigits}d) <= [%${tlDigits}d, %${tlDigits}d) %s%s"
println(fmt.format(m.id.start, m.id.end, c.sourceId.start, c.sourceId.end, c.name, if (c.supportsProbe) " CACHE" else ""))
s"""{"axi4-id":[${m.id.start},${m.id.end}],"tilelink-id":[${c.sourceId.start},${c.sourceId.end}],"master":["${c.name}"],"cache":[${!(!c.supportsProbe)}]}"""
map.mapping.foreach { case TLToAXI4IdMapEntry(axi4Id, tlId, _, _, fifo) =>
for (i <- 0 until tlId.size) {
val id = axi4Id.start + (if (fifo) 0 else (i >> stripBits))
sourceStall(tlId.start + i) := idStall(id)
sourceTable(tlId.start + i) := UInt(id)
}
if (fifo) { idCount(axi4Id.start) = Some(tlId.size) }
}
adapterName.foreach { n =>
println("")
ElaborationArtefacts.add(s"${n}.axi4.json", s"""{"mapping":[${maps.mkString(",")}]}""")
println(s"$n AXI4-ID <= TL-Source mapping:\n${map.pretty}\n")
ElaborationArtefacts.add(s"$n.axi4.json", s"""{"mapping":[${map.mapping.mkString(",")}]}""")
}
// We need to keep the following state from A => D: (size, source)

View File

@ -50,7 +50,10 @@ class WithTLSimpleUnitTests extends Config((site, here, up) => {
Module(new TLRR1Test( txns= 3*txns, timeout=timeout)),
Module(new TLRAMRationalCrossingTest(txns= 3*txns, timeout=timeout)),
Module(new TLRAMAsyncCrossingTest( txns= 5*txns, timeout=timeout)),
Module(new TLRAMAtomicAutomataTest( txns=10*txns, timeout=timeout)) ) }
Module(new TLRAMAtomicAutomataTest( txns=10*txns, timeout=timeout)),
Module(new TLRAMECCTest(8, 4, txns=15*txns, timeout=timeout)),
Module(new TLRAMECCTest(4, 1, txns=15*txns, timeout=timeout)),
Module(new TLRAMECCTest(1, 1, txns=15*txns, timeout=timeout)) ) }
})
class WithTLWidthUnitTests extends Config((site, here, up) => {

View File

@ -19,7 +19,12 @@ abstract class Code
def canCorrect: Boolean
def width(w0: Int): Int
def encode(x: UInt): UInt
/** Encode x to a codeword suitable for decode.
* If poison is true, the decoded value will report uncorrectable
* error despite decoding to the supplied value 'x'.
*/
def encode(x: UInt, poison: Bool = Bool(false)): UInt
def decode(x: UInt): Decoding
/** Copy the bits in x to the right bit positions in an encoded word,
@ -36,7 +41,10 @@ class IdentityCode extends Code
def canCorrect = false
def width(w0: Int) = w0
def encode(x: UInt) = x
def encode(x: UInt, poison: Bool = Bool(false)) = {
require (poison.isLit && poison.litValue == 0, "IdentityCode can not be poisoned")
x
}
def swizzle(x: UInt) = x
def decode(y: UInt) = new Decoding {
def uncorrected = y
@ -52,7 +60,7 @@ class ParityCode extends Code
def canCorrect = false
def width(w0: Int) = w0+1
def encode(x: UInt) = Cat(x.xorR, x)
def encode(x: UInt, poison: Bool = Bool(false)) = Cat(x.xorR ^ poison, x)
def swizzle(x: UInt) = Cat(false.B, x)
def decode(y: UInt) = new Decoding {
val uncorrected = y(y.getWidth-2,0)
@ -67,20 +75,26 @@ class SECCode extends Code
def canDetect = true
def canCorrect = true
// SEC codes may or may not be poisonous depending on the length
// If the code is perfect, every non-codeword is correctable
def poisonous(n: Int) = !isPow2(n+1)
def width(k: Int) = {
val m = log2Floor(k) + 1
k + m + (if((1 << m) < m+k+1) 1 else 0)
}
def encode(x: UInt) = {
def encode(x: UInt, poison: Bool = Bool(false)) = {
val k = x.getWidth
require(k > 0)
val n = width(k)
require ((poison.isLit && poison.litValue == 0) || poisonous(n), s"SEC code of length ${n} cannot be poisoned")
val y = for (i <- 1 to n) yield {
if (isPow2(i)) {
val r = for (j <- 1 to n; if j != i && (j & i) != 0)
yield x(mapping(j))
r reduce (_^_)
r.reduce(_^_) ^ poison
} else
x(mapping(i))
}
@ -106,7 +120,7 @@ class SECCode extends Code
val uncorrected = swizzle(y)
val corrected = swizzle(((y << 1) ^ UIntToOH(syndrome)) >> 1)
val correctable = syndrome.orR
val uncorrectable = syndrome > UInt(n)
val uncorrectable = if (poisonous(n)) { syndrome > UInt(n) } else { Bool(false) }
}
private def mapping(i: Int) = i-1-log2Up(i)
}
@ -120,7 +134,12 @@ class SECDEDCode extends Code
private val par = new ParityCode
def width(k: Int) = sec.width(k)+1
def encode(x: UInt) = par.encode(sec.encode(x))
def encode(x: UInt, poison: Bool = Bool(false)) = {
// toggling two bits ensures the error is uncorrectable
val toggle_lo = poison.asUInt // a non-data bit in SEC
val toggle_hi = toggle_lo << sec.width(x.getWidth) // the parity bit
par.encode(sec.encode(x)) ^ toggle_lo ^ toggle_hi
}
def swizzle(x: UInt) = par.swizzle(sec.swizzle(x))
def decode(x: UInt) = new Decoding {
val secdec = sec.decode(x(x.getWidth-2,0))
@ -178,3 +197,15 @@ trait CanHaveErrors extends Bundle {
val correctable: Option[ValidIO[UInt]]
val uncorrectable: Option[ValidIO[UInt]]
}
object Code {
def fromString(s: Option[String]): Code = fromString(s.getOrElse("none"))
def fromString(s: String): Code = s.toLowerCase match {
case "none" => new IdentityCode
case "identity" => new IdentityCode
case "parity" => new ParityCode
case "sec" => new SECCode
case "secded" => new SECDEDCode
case _ => throw new IllegalArgumentException("Unknown ECC type")
}
}

View File

@ -10,8 +10,7 @@ import freechips.rocketchip.system.{TestGeneration, DefaultTestSuites}
import freechips.rocketchip.config._
import freechips.rocketchip.diplomacy.LazyModule
import java.io.{File, FileWriter}
import net.jcazevedo.moultingyaml._
import firrtl.annotations.AnnotationYamlProtocol._
import firrtl.annotations.JsonProtocol
/** Representation of the information this Generator needs to collect from external sources. */
case class ParsedInputNames(
@ -99,9 +98,9 @@ trait GeneratorApp extends App with HasGeneratorUtilities {
}
def generateAnno {
val annotationFile = new File(td, s"$longName.anno")
val annotationFile = new File(td, s"$longName.anno.json")
val af = new FileWriter(annotationFile)
af.write(circuit.annotations.toArray.toYaml.prettyPrint)
af.write(JsonProtocol.serialize(circuit.annotations.map(_.toFirrtl)))
af.close()
}

View File

@ -4,21 +4,18 @@
package freechips.rocketchip.util
import Chisel._
import chisel3.experimental.{ChiselAnnotation, RawModule}
import chisel3.experimental.RawModule
import freechips.rocketchip.config.Parameters
import scala.math._
class ParameterizedBundle(implicit p: Parameters) extends Bundle
// TODO: replace this with an implicit class when @chisel unprotects dontTouchPorts
trait DontTouch {
self: RawModule =>
trait DontTouch { self: RawModule =>
def dontTouch(data: Data): Unit = data match {
case agg: Aggregate =>
agg.getElements.foreach(dontTouch)
case elt: Element =>
annotate(ChiselAnnotation(elt, classOf[firrtl.Transform], "DONTtouch!"))
case agg: Aggregate => agg.getElements.foreach(dontTouch)
case elt: Element => chisel3.core.dontTouch(elt)
}
/** Marks every port as don't touch

View File

@ -57,10 +57,6 @@ VCS_OPTS = -notice -line +lint=all,noVCDE,noONGS,noUI -error=PCWM-L -timescale=1
+define+RANDOMIZE_INVALID_ASSIGN \
+libext+.v \
VCS_OPTS += +vpi
VCS_OPTS += -CC "-DVCS_VPI"
#--------------------------------------------------------------------
# Build the simulator
#--------------------------------------------------------------------
@ -84,5 +80,5 @@ $(simv_debug) : $(sim_vsrcs) $(sim_csrcs)
#--------------------------------------------------------------------
seed = $(shell date +%s)
exec_simv = $(simv) -q +ntb_random_seed_automatic
exec_simv_debug = $(simv_debug) -q +ntb_random_seed_automatic
exec_simv = $(simv) +permissive -q +ntb_random_seed_automatic +permissive-off
exec_simv_debug = $(simv_debug) +permissive -q +ntb_random_seed_automatic +permissive-off

View File

@ -14,7 +14,7 @@ $(generated_dir)/%.fir $(generated_dir)/%.d: $(FIRRTL_JAR) $(chisel_srcs) $(boot
$(generated_dir)/%.v $(generated_dir)/%.conf: $(generated_dir)/%.fir $(FIRRTL_JAR)
mkdir -p $(dir $@)
$(FIRRTL) -i $< -o $(generated_dir)/$*.v -X verilog --infer-rw $(MODEL) --repl-seq-mem -c:$(MODEL):-o:$(generated_dir)/$*.conf -faf $(generated_dir)/$*.anno
$(FIRRTL) -i $< -o $(generated_dir)/$*.v -X verilog --infer-rw $(MODEL) --repl-seq-mem -c:$(MODEL):-o:$(generated_dir)/$*.conf -faf $(generated_dir)/$*.anno.json
$(generated_dir)/$(long_name).behav_srams.v : $(generated_dir)/$(long_name).conf $(mem_gen)
cd $(generated_dir) && \
@ -28,19 +28,19 @@ $(generated_dir)/$(long_name).behav_srams.v : $(generated_dir)/$(long_name).conf
.PRECIOUS: $(output_dir)/%.vpd
$(output_dir)/%.run: $(output_dir)/% $(simv)
cd $(sim_dir) && $(exec_simv) +max-cycles=$(timeout_cycles) $< 2> /dev/null 2> $@ && [ $$PIPESTATUS -eq 0 ]
cd $(sim_dir) && $(exec_simv) +permissive +max-cycles=$(timeout_cycles) +permissive-off $< 2> /dev/null 2> $@ && [ $$PIPESTATUS -eq 0 ]
$(output_dir)/%.out: $(output_dir)/% $(simv)
cd $(sim_dir) && $(exec_simv) +verbose +max-cycles=$(timeout_cycles) $< $(disasm) $@ && [ $$PIPESTATUS -eq 0 ]
cd $(sim_dir) && $(exec_simv) +permissive +verbose +max-cycles=$(timeout_cycles) +permissive-off $< $(disasm) $@ && [ $$PIPESTATUS -eq 0 ]
$(output_dir)/%.vcd: $(output_dir)/% $(simv_debug)
cd $(sim_dir) && $(exec_simv_debug) +verbose +vcdfile=$@ +max-cycles=$(timeout_cycles) $< $(disasm) $(patsubst %.vcd,%.out,$@) && [ $$PIPESTATUS -eq 0 ]
cd $(sim_dir) && $(exec_simv_debug) +permissive +verbose +vcdfile=$@ +max-cycles=$(timeout_cycles) +permissive-off $< $(disasm) $(patsubst %.vcd,%.out,$@) && [ $$PIPESTATUS -eq 0 ]
$(output_dir)/%.vpd: $(output_dir)/% $(simv_debug)
cd $(sim_dir) && $(exec_simv_debug) +verbose +vcdplusfile=$@ +max-cycles=$(timeout_cycles) $< $(disasm) $(patsubst %.vpd,%.out,$@) && [ $$PIPESTATUS -eq 0 ]
cd $(sim_dir) && $(exec_simv_debug) +permissive +verbose +vcdplusfile=$@ +max-cycles=$(timeout_cycles) +permissive-off $< $(disasm) $(patsubst %.vpd,%.out,$@) && [ $$PIPESTATUS -eq 0 ]
$(output_dir)/%.saif: $(output_dir)/% $(simv_debug)
cd $(sim_dir) && rm -f $(output_dir)/pipe-$*.vcd && vcd2saif -input $(output_dir)/pipe-$*.vcd -pipe "$(exec_simv_debug) +verbose +vcdfile=$(output_dir)/pipe-$*.vcd +max-cycles=$(bmark_timeout_cycles) $<" -output $@ > $(patsubst %.saif,%.out,$@) 2>&1
cd $(sim_dir) && rm -f $(output_dir)/pipe-$*.vcd && vcd2saif -input $(output_dir)/pipe-$*.vcd -pipe "$(exec_simv_debug) +permissive +verbose +vcdfile=$(output_dir)/pipe-$*.vcd +max-cycles=$(bmark_timeout_cycles) +permissive-off $<" -output $@ > $(patsubst %.saif,%.out,$@) 2>&1
run: run-asm-tests run-bmark-tests
run-debug: run-asm-tests-debug run-bmark-tests-debug

View File

@ -49,6 +49,8 @@ module SimJTAG #(
bit __jtag_TRSTn;
int __exit;
reg init_done_sticky;
assign #0.1 jtag_TCK = __jtag_TCK;
assign #0.1 jtag_TMS = __jtag_TMS;
assign #0.1 jtag_TDI = __jtag_TDI;
@ -61,8 +63,10 @@ module SimJTAG #(
if (reset || r_reset) begin
__exit = 0;
tickCounterReg <= TICK_DELAY;
init_done_sticky <= 1'b0;
end else begin
if (enable && init_done) begin
init_done_sticky <= init_done | init_done_sticky;
if (enable && init_done_sticky) begin
tickCounterReg <= tickCounterNxt;
if (tickCounterReg == 0) begin
__exit = jtag_tick(
@ -72,7 +76,7 @@ module SimJTAG #(
__jtag_TRSTn,
__jtag_TDO);
end
end // if (enable && init_done)
end // if (enable && init_done_sticky)
end // else: !if(reset || r_reset)
end // always @ (posedge clock)

View File

@ -18,6 +18,7 @@ module TestDriver;
reg [63:0] max_cycles = 0;
reg [63:0] dump_start = 0;
reg [63:0] trace_count = 0;
reg [1023:0] fsdbfile = 0;
reg [1023:0] vcdplusfile = 0;
reg [1023:0] vcdfile = 0;
int unsigned rand_value;
@ -50,7 +51,19 @@ module TestDriver;
`ifdef VCS
$vcdplusfile(vcdplusfile);
`else
$fdisplay(stderr, "Error: +vcdplusfile is VCS-only; use +vcdfile instead");
$fdisplay(stderr, "Error: +vcdplusfile is VCS-only; use +vcdfile instead or recompile with VCS=1");
$fatal;
`endif
end
if ($value$plusargs("fsdbfile=%s", fsdbfile))
begin
`ifdef FSDB
$fsdbDumpfile(fsdbfile);
$fsdbDumpvars("+all");
//$fsdbDumpSVA;
`else
$fdisplay(stderr, "Error: +fsdbfile is FSDB-only; use +vcdfile/+vcdplus instead or recompile with FSDB=1");
$fatal;
`endif
end
@ -60,7 +73,11 @@ module TestDriver;
$dumpfile(vcdfile);
$dumpvars(0, testHarness);
end
`ifdef VCS
`ifdef FSDB
`define VCDPLUSON $fsdbDumpon;
`define VCDPLUSCLOSE $fsdbDumpoff;
`elsif VCS
`define VCDPLUSON $vcdpluson(0); $vcdplusmemon(0);
`define VCDPLUSCLOSE $vcdplusclose; $dumpoff;
`else
@ -72,9 +89,9 @@ module TestDriver;
`define VCDPLUSON
`define VCDPLUSCLOSE
if ($test$plusargs("vcdplusfile=") || $test$plusargs("vcdfile="))
if ($test$plusargs("vcdplusfile=") || $test$plusargs("vcdfile=") || $test$plusargs("fsdbfile="))
begin
$fdisplay(stderr, "Error: +vcdfile or +vcdplusfile requested but compile did not have +define+DEBUG enabled");
$fdisplay(stderr, "Error: +vcdfile, +vcdplusfile, or +fsdbfile requested but compile did not have +define+DEBUG enabled");
$fatal;
end

View File

@ -1,2 +0,0 @@
$send_result_to_server call=send_result_to_server acc=rw:*
$check_for_command call=check_for_command acc=rw:*

View File

@ -1,301 +0,0 @@
// See LICENSE.SiFive for license details.
/*
* TCP/IP controlled VPI JTAG Interface.
* Based on Julius Baxter's work on jp_vpi.c
*
* Copyright (C) 2012 Franck Jullien, <franck.jullien@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of any
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
//VCS coverage exclude_file
`define CMD_RESET 0
`define CMD_TMS_SEQ 1
`define CMD_SCAN_CHAIN 2
`define CMD_SCAN_CHAIN_FLIP_TMS 3
`define CMD_STOP_SIMU 4
module JTAGVPI
#( parameter DEBUG_INFO = 0,
parameter TP = 1,
parameter TCK_HALF_PERIOD = 2,// 50, // Clock half period (Clock period = 100 ns => 10 MHz)
parameter CMD_DELAY = 2, // 1000
parameter INIT_DELAY = 200
)
(
output jtag_TMS,
output jtag_TCK,
output jtag_TDI,
input jtag_TDO_data,
input jtag_TDO_driven,
input enable,
input init_done);
reg tms;
reg tck;
reg tdi;
wire tdo;
assign jtag_TMS = tms;
assign jtag_TCK = tck;
assign jtag_TDI = tdi;
assign tdo = jtag_TDO_driven ? jtag_TDO_data : 1'bz;
integer cmd;
integer length;
integer nb_bits;
reg [31:0] buffer_out [0:4095]; // Data storage from the jtag server
reg [31:0] buffer_in [0:4095]; // Data storage to the jtag server
integer flip_tms;
reg [31:0] data_out;
reg [31:0] data_in;
integer debug;
initial
begin
tck <= #TP 1'b0;
tdi <= #TP 1'bz;
tms <= #TP 1'b0;
data_out <= 32'h0;
data_in <= 32'h0;
// Small delay to get past reset instability
// before checking for init_done
#INIT_DELAY
wait(init_done)
if($test$plusargs("jtag_vpi_enable")) main;
end
task main;
begin
$display("JTAG debug module with VPI interface enabled\n");
reset_tap;
goto_run_test_idle_from_reset;
while (1) begin
// Check for incoming command
// wait until a command is sent
// poll with a delay here
cmd = -1;
while (cmd == -1)
begin
#CMD_DELAY $check_for_command(cmd, length, nb_bits, buffer_out);
end
// now switch on the command
case (cmd)
`CMD_RESET :
begin
if (DEBUG_INFO)
$display("%t ----> CMD_RESET %h\n", $time, length);
reset_tap;
goto_run_test_idle_from_reset;
end
`CMD_TMS_SEQ :
begin
if (DEBUG_INFO)
$display("%t ----> CMD_TMS_SEQ\n", $time);
do_tms_seq;
end
`CMD_SCAN_CHAIN :
begin
if (DEBUG_INFO)
$display("%t ----> CMD_SCAN_CHAIN\n", $time);
flip_tms = 0;
do_scan_chain;
$send_result_to_server(length, buffer_in);
end
`CMD_SCAN_CHAIN_FLIP_TMS :
begin
if(DEBUG_INFO)
$display("%t ----> CMD_SCAN_CHAIN\n", $time);
flip_tms = 1;
do_scan_chain;
$send_result_to_server(length, buffer_in);
end
`CMD_STOP_SIMU :
begin
if(DEBUG_INFO)
$display("%t ----> End of simulation\n", $time);
$finish();
end
default:
begin
$display("Somehow got to the default case in the command case statement.");
$display("Command was: %x", cmd);
$display("Exiting...");
$finish();
end
endcase // case (cmd)
end // while (1)
end
endtask // main
// Generation of the TCK signal
task gen_clk;
input [31:0] number;
integer i;
begin
for (i = 0; i < number; i = i + 1)
begin
#TCK_HALF_PERIOD tck <= 1;
#TCK_HALF_PERIOD tck <= 0;
end
end
endtask
// TAP reset
task reset_tap;
begin
if (DEBUG_INFO)
$display("(%0t) Task reset_tap", $time);
tms <= #1 1'b1;
gen_clk(5);
end
endtask
// Goes to RunTestIdle state
task goto_run_test_idle_from_reset;
begin
if (DEBUG_INFO)
$display("(%0t) Task goto_run_test_idle_from_reset", $time);
tms <= #1 1'b0;
gen_clk(1);
end
endtask
//
task do_tms_seq;
integer i,j;
reg [31:0] data;
integer nb_bits_rem;
integer nb_bits_in_this_byte;
begin
if (DEBUG_INFO)
$display("(%0t) Task do_tms_seq of %d bits (length = %d)", $time, nb_bits, length);
// Number of bits to send in the last byte
nb_bits_rem = nb_bits % 8;
for (i = 0; i < length; i = i + 1)
begin
// If we are in the last byte, we have to send only
// nb_bits_rem bits. If not, we send the whole byte.
nb_bits_in_this_byte = (i == (length - 1)) ? nb_bits_rem : 8;
data = buffer_out[i];
for (j = 0; j < nb_bits_in_this_byte; j = j + 1)
begin
tms <= #1 1'b0;
if (data[j] == 1) begin
tms <= #1 1'b1;
end
gen_clk(1);
end
end
tms <= #1 1'b0;
end
endtask
//
task do_scan_chain;
integer _bit;
integer nb_bits_rem;
integer nb_bits_in_this_byte;
integer index;
begin
if(DEBUG_INFO)
$display("(%0t) Task do_scan_chain of %d bits (length = %d)", $time, nb_bits, length);
// Number of bits to send in the last byte
nb_bits_rem = nb_bits % 8;
for (index = 0; index < length; index = index + 1)
begin
// If we are in the last byte, we have to send only
// nb_bits_rem bits if it's not zero.
// If not, we send the whole byte.
nb_bits_in_this_byte = (index == (length - 1)) ? ((nb_bits_rem == 0) ? 8 : nb_bits_rem) : 8;
data_out = buffer_out[index];
for (_bit = 0; _bit < nb_bits_in_this_byte; _bit = _bit + 1)
begin
tdi <= 1'b0;
if (data_out[_bit] == 1'b1) begin
tdi <= 1'b1;
end
// On the last bit, set TMS to '1'
if (((_bit == (nb_bits_in_this_byte - 1)) && (index == (length - 1))) && (flip_tms == 1)) begin
tms <= 1'b1;
end
#TCK_HALF_PERIOD tck <= 1;
data_in[_bit] <= tdo;
#TCK_HALF_PERIOD tck <= 0;
end
buffer_in[index] = data_in;
end
tdi <= 1'b0;
tms <= 1'b0;
end
endtask
endmodule