Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions generators/firechip/LICENSE.Berkeley
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Copyright (c) 2012-2014, The Regents of the University of California
(Regents). 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 name of the Regents nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 changes: 23 additions & 0 deletions generators/firechip/bridgeinterfaces/src/main/scala/JTAG.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// See LICENSE for license details.

package firechip.bridgeinterfaces

import chisel3._

// TCK is a Bool (not a Clock) so that HostPort can channelize it as a regular
// data signal. The bridge stub casts it to Clock when connecting to the
// target's JTAGChipIO.
class JTAGBridgeTargetIO extends Bundle {
val jtag = new JTAGBridgePortIO
val clock = Input(Clock())
val reset = Input(Bool())
}

class JTAGBridgePortIO extends Bundle {
val TCK = Output(Bool())
val TMS = Output(Bool())
val TDI = Output(Bool())
val TDO = Input(Bool())
}

case class JTAGBridgeParams()
60 changes: 60 additions & 0 deletions generators/firechip/bridgestubs/src/main/cc/bridges/jtagbridge.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// See LICENSE for license details.

#include "bridges/jtagbridge.h"

#include <cstdlib>
#include <cstring>
#include <iostream>

char jtagbridge_t::KIND;

static const int DEFAULT_RBB_PORT = 25000;
static const char PORT_ARG_PREFIX[] = "+jtag_rbb_port=";

jtagbridge_t::jtagbridge_t(simif_t &simif,
const JTAGBRIDGEMODULE_struct &mmio_addrs,
int jtagno,
const std::vector<std::string> &args)
: bridge_driver_t(simif, &KIND),
mmio_addrs_(mmio_addrs),
rbb_(nullptr),
rbb_port_(DEFAULT_RBB_PORT + jtagno) {
for (const auto &arg : args) {
if (arg.find(PORT_ARG_PREFIX) == 0) {
rbb_port_ = std::atoi(arg.c_str() + strlen(PORT_ARG_PREFIX));
}
}
}

jtagbridge_t::~jtagbridge_t() { delete rbb_; }

void jtagbridge_t::init() {
rbb_ = new remote_bitbang_t((uint16_t)rbb_port_);
std::cout << "[JTAGBridge] remote_bitbang listening on port " << rbb_port_
<< std::endl;
}

// Semantics of one bridge tick:
// - Consumes exactly one remote_bitbang command byte from the client (a pin
// update '0'..'7', a 'R' TDO sample, or 'Q'); this advances the target by
// one token.
// - Reads the sampled TDO from the target (one MMIO read) and writes back the
// TCK/TMS/TDI pin state the client requested (three MMIO writes).
// A single tick is therefore one pin update or one TDO sample, NOT a complete
// JTAG bit: a full bit takes at least a TCK-low and a TCK-high command, plus a
// separate 'R' when the client wants to read TDO. The remote_bitbang client owns
// all TAP sequencing and samples TDO (via 'R') at the point it considers stable
// (conventionally while TCK is low, before driving the next rising edge).
void jtagbridge_t::tick() {
if (!rbb_)
return;

unsigned char tck = 0, tms = 0, tdi = 0, trstn = 0;
unsigned char tdo = (unsigned char)read(mmio_addrs_.tdo);

rbb_->tick(&tck, &tms, &tdi, &trstn, tdo);

write(mmio_addrs_.tck, tck);
write(mmio_addrs_.tms, tms);
write(mmio_addrs_.tdi, tdi);
}
41 changes: 41 additions & 0 deletions generators/firechip/bridgestubs/src/main/cc/bridges/jtagbridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// See LICENSE for license details.

#ifndef __JTAGBRIDGE_H
#define __JTAGBRIDGE_H

#include "bridges/remote_bitbang.h"
#include "core/bridge_driver.h"
#include "core/simif.h"

#include <string>
#include <vector>

struct JTAGBRIDGEMODULE_struct {
uint64_t tck;
uint64_t tms;
uint64_t tdi;
uint64_t tdo;
};

class jtagbridge_t final : public bridge_driver_t {
public:
static char KIND;

jtagbridge_t(simif_t &simif,
const JTAGBRIDGEMODULE_struct &mmio_addrs,
int jtagno,
const std::vector<std::string> &args);
~jtagbridge_t();

virtual void init() override;
virtual void tick() override;
virtual bool terminate() override { return rbb_ && rbb_->done(); }
virtual int exit_code() override { return rbb_ ? rbb_->exit_code() : 0; }

private:
const JTAGBRIDGEMODULE_struct mmio_addrs_;
remote_bitbang_t *rbb_;
int rbb_port_;
};

#endif // __JTAGBRIDGE_H
200 changes: 200 additions & 0 deletions generators/firechip/bridgestubs/src/main/cc/bridges/remote_bitbang.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// See LICENSE.Berkeley for license details.

// Generic OpenOCD-compatible remote_bitbang JTAG server. Derived from
// rocket-chip's src/main/resources/csrc/remote_bitbang.cc (originally from the
// Berkeley/Spike riscv-isa-sim project). The only functional change from that
// source is that accept()/execute_command() are non-blocking (they service at
// most one client action per call and return), which is required by the FireSim
// bridge tick model; no target- or bridge-specific logic has been added. The
// referenced LICENSE.Berkeley file is provided at the root of the firechip
// generator (generators/firechip/LICENSE.Berkeley).

#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>

#include "remote_bitbang.h"

/////////// remote_bitbang_t

remote_bitbang_t::remote_bitbang_t(uint16_t port) :
err(0),
socket_fd(0),
client_fd(0),
recv_start(0),
recv_end(0)
{
socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd == -1) {
fprintf(stderr, "remote_bitbang failed to make socket: %s (%d)\n",
strerror(errno), errno);
abort();
}

fcntl(socket_fd, F_SETFL, O_NONBLOCK);
int reuseaddr = 1;
if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
sizeof(int)) == -1) {
fprintf(stderr, "remote_bitbang failed setsockopt: %s (%d)\n",
strerror(errno), errno);
abort();
}

struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);

if (::bind(socket_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
fprintf(stderr, "remote_bitbang failed to bind socket: %s (%d)\n",
strerror(errno), errno);
abort();
}

if (listen(socket_fd, 1) == -1) {
fprintf(stderr, "remote_bitbang failed to listen on socket: %s (%d)\n",
strerror(errno), errno);
abort();
}

socklen_t addrlen = sizeof(addr);
if (getsockname(socket_fd, (struct sockaddr *) &addr, &addrlen) == -1) {
fprintf(stderr, "remote_bitbang getsockname failed: %s (%d)\n",
strerror(errno), errno);
abort();
}

tck = 1;
tms = 1;
tdi = 1;
trstn = 1;
quit = 0;

fprintf(stderr, "This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.\n");
fprintf(stderr, "Listening on port %d\n",
ntohs(addr.sin_port));
}

void remote_bitbang_t::accept()
{
client_fd = ::accept(socket_fd, NULL, NULL);
if (client_fd == -1) {
if (errno == EAGAIN) {
// No client waiting; return and let the simulation proceed.
} else {
fprintf(stderr, "failed to accept on socket: %s (%d)\n", strerror(errno),
errno);
abort();
}
} else {
fcntl(client_fd, F_SETFL, O_NONBLOCK);
fprintf(stderr, "Accepted successfully.\n");
}
}

void remote_bitbang_t::tick(
unsigned char * jtag_tck,
unsigned char * jtag_tms,
unsigned char * jtag_tdi,
unsigned char * jtag_trstn,
unsigned char jtag_tdo
)
{
if (client_fd > 0) {
tdo = jtag_tdo;
execute_command();
} else {
// client_fd <= 0 means no client connected; try non-blocking accept
this->accept();
}

* jtag_tck = tck;
* jtag_tms = tms;
* jtag_tdi = tdi;
* jtag_trstn = trstn;

}

void remote_bitbang_t::reset(){
//trstn = 0;
}

void remote_bitbang_t::set_pins(char _tck, char _tms, char _tdi){
tck = _tck;
tms = _tms;
tdi = _tdi;
}

void remote_bitbang_t::execute_command()
{
char command;
ssize_t num_read = read(client_fd, &command, sizeof(command));
if (num_read == -1) {
if (errno == EAGAIN) {
// No data available right now; will try on next tick.
return;
} else {
fprintf(stderr, "remote_bitbang failed to read on socket: %s (%d)\n",
strerror(errno), errno);
abort();
}
} else if (num_read == 0) {
// Client disconnected; go back to accepting new clients.
fprintf(stderr, "Remote end disconnected.\n");
close(client_fd);
client_fd = -1;
return;
}

int dosend = 0;

char tosend = '?';

switch (command) {
case 'B': /* fprintf(stderr, "*BLINK*\n"); */ break;
case 'b': /* fprintf(stderr, "_______\n"); */ break;
case 'r': reset(); break; // This is wrong. 'r' has other bits that indicated TRST and SRST.
case '0': set_pins(0, 0, 0); break;
case '1': set_pins(0, 0, 1); break;
case '2': set_pins(0, 1, 0); break;
case '3': set_pins(0, 1, 1); break;
case '4': set_pins(1, 0, 0); break;
case '5': set_pins(1, 0, 1); break;
case '6': set_pins(1, 1, 0); break;
case '7': set_pins(1, 1, 1); break;
case 'R': dosend = 1; tosend = tdo ? '1' : '0'; break;
case 'Q': quit = 1; break;
default:
fprintf(stderr, "remote_bitbang got unsupported command '%c'\n",
command);
}

if (dosend){
while (1) {
ssize_t bytes = write(client_fd, &tosend, sizeof(tosend));
if (bytes == -1) {
fprintf(stderr, "failed to write to socket: %s (%d)\n", strerror(errno), errno);
abort();
}
if (bytes > 0) {
break;
}
}
}

if (quit) {
// The remote disconnected.
fprintf(stderr, "Remote end disconnected\n");
close(client_fd);
client_fd = 0;
}
}
Loading