Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
9 changes: 9 additions & 0 deletions riscv/execute.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "config.h"
#include "processor.h"
#include "trace_ingress.h"
#include "trace_encoder_n.h"
#include "mmu.h"
#include "disasm.h"
#include "decode_macros.h"
Expand Down Expand Up @@ -173,6 +175,13 @@ static inline reg_t execute_insn_logged(processor_t* p, reg_t pc, insn_fetch_t f

try {
npc = fetch.func(p, fetch.insn, pc);

if (p->get_log_commits_enabled()) {
hart_to_encoder_ingress_t packet;
hart_to_encoder_ingress_init(p, &packet, &fetch.insn, npc);
p->get_trace_encoder()->trace_encoder_push_commit(&packet);
}

if (npc != PC_SERIALIZE_BEFORE) {
if (p->get_log_commits_enabled()) {
commit_log_print_insn(p, pc, fetch.insn);
Expand Down
1 change: 1 addition & 0 deletions riscv/processor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ processor_t::processor_t(const char* isa_str, const char* priv_str,

register_base_instructions();
mmu = new mmu_t(sim, cfg->endianness, this);
trace_encoder = new trace_encoder_n();

disassembler = new disassembler_t(&isa);
for (auto e : isa.get_extensions())
Expand Down
5 changes: 5 additions & 0 deletions riscv/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "triggers.h"
#include "../fesvr/memif.h"
#include "vector_unit.h"
#include "trace_encoder_n.h"

#define FIRST_HPMCOUNTER 3
#define N_HPMCOUNTERS 29
Expand All @@ -28,6 +29,7 @@ class simif_t;
class trap_t;
class extension_t;
class disassembler_t;
class trace_encoder_n;

reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc);

Expand Down Expand Up @@ -367,6 +369,8 @@ class processor_t : public abstract_device_t

void check_if_lpad_required();

trace_encoder_n* get_trace_encoder() { return trace_encoder; }

private:
const isa_parser_t isa;
const cfg_t * const cfg;
Expand All @@ -381,6 +385,7 @@ class processor_t : public abstract_device_t
bool histogram_enabled;
bool log_commits_enabled;
FILE *log_file;
trace_encoder_n *trace_encoder;
std::ostream sout_; // needed for socket command interface -s, also used for -d and -l, but not for --log
bool halt_on_reset;
bool in_wfi;
Expand Down
4 changes: 4 additions & 0 deletions riscv/riscv.mk.in
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ riscv_install_hdrs = \
rocc.h \
sim.h \
simif.h \
trace_encoder_n.h \
trace_ingress.h \
trap.h \
triggers.h \
vector_unit.h \
Expand All @@ -49,6 +51,8 @@ riscv_precompiled_hdrs = \
insn_template.h \

riscv_srcs = \
trace_encoder_n.cc \
trace_ingress.cc \
processor.cc \
execute.cc \
dts.cc \
Expand Down
201 changes: 201 additions & 0 deletions riscv/trace_encoder_n.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
#include "trace_encoder_n.h"

trace_encoder_n::trace_encoder_n() {
this->trace_sink= fopen("trace_n.bin", "wb");
this->active = true;
this->enabled = false;
this->src = 0;
this->state = TRACE_ENCODER_N_IDLE;
this->icnt = 0;
}

void trace_encoder_n::set_enable(bool enabled) {
bool was_enabled = this->enabled;
printf("[trace_encoder_n] setting enable to %d\n", enabled);
this->enabled = enabled;
if (!was_enabled && enabled) {
this->state = TRACE_ENCODER_N_IDLE;
}
}

void trace_encoder_n::trace_encoder_push_commit(hart_to_encoder_ingress_t* packet) {
printf("[trace_encoder_n] pushed commit packet at i_addr: %lx\n", packet->i_addr);
this->packet = packet;
if (this->enabled) {
if (this->state == TRACE_ENCODER_N_IDLE) {
trace_encoder_generate_packet(TCODE_PROG_TRACE_SYNC);
this->state = TRACE_ENCODER_N_DATA;
this->icnt += this->packet->ilastsize;
} else if (this->state == TRACE_ENCODER_N_DATA) {
this->icnt += this->packet->ilastsize;
if (this->packet->i_type == I_BRANCH_TAKEN) {
trace_encoder_generate_packet(TCODE_DBR);
this->icnt = 0;
} else if (this->packet->i_type == I_JUMP_INFERABLE || this->packet->i_type == I_JUMP_UNINFERABLE) {
trace_encoder_generate_packet(TCODE_IBR);
this->icnt = 0;
}
this->state = this->icnt >= MAX_ICNT ? TRACE_ENCODER_N_FULL : TRACE_ENCODER_N_DATA;
} else if (this->state == TRACE_ENCODER_N_FULL) {
trace_encoder_generate_packet(TCODE_FULL);
this->state = TRACE_ENCODER_N_DATA;
this->icnt = 0;
}
}
}

void print_packet(trace_encoder_n_packet_t* packet) {
printf("[trace_encoder_n] printing packet: tcode: %lx, src: %lx, icnt: %lx, f_addr: %lx, u_addr: %lx, b_type: %lx\n", packet->tcode, packet->src, packet->icnt, packet->f_addr, packet->u_addr, packet->b_type);
}

void print_encoded_packet(uint8_t* buffer, int num_bytes) {
printf("[trace_encoder_n] encoded packet: ");
for (int i = 0; i < num_bytes; i++) {
printf("%lx ", buffer[i]);
}
printf("\n");
}

void trace_encoder_n::trace_encoder_generate_packet(tcode_t tcode) {
trace_encoder_n_packet_t packet;
int num_bytes;
switch (tcode) {
case TCODE_PROG_TRACE_SYNC:
_set_program_trace_sync_packet(&packet);
print_packet(&packet);
num_bytes = packet_to_buffer(&packet);
fwrite(this->buffer, 1, num_bytes, this->trace_sink);
print_encoded_packet(this->buffer, num_bytes);
break;
case TCODE_DBR:
_set_direct_branch_packet(&packet);
print_packet(&packet);
num_bytes = packet_to_buffer(&packet);
fwrite(this->buffer, 1, num_bytes, this->trace_sink);
print_encoded_packet(this->buffer, num_bytes);
break;
case TCODE_IBR:
_set_indirect_branch_packet(&packet);
print_packet(&packet);
num_bytes = packet_to_buffer(&packet);
fwrite(this->buffer, 1, num_bytes, this->trace_sink);
print_encoded_packet(this->buffer, num_bytes);
break;
default:
break;
}
}

void trace_encoder_n::_set_program_trace_sync_packet(trace_encoder_n_packet_t* packet){
packet->tcode = TCODE_PROG_TRACE_SYNC;
packet->src = this->src;
packet->sync = SYNC_TRACE_EN;
packet->icnt = 0;
packet->f_addr = this->packet->i_addr >> 1;
}

void trace_encoder_n::_set_direct_branch_packet(trace_encoder_n_packet_t* packet){
packet->tcode = TCODE_DBR;
packet->src = this->src;
packet->icnt = this->icnt;
}

void trace_encoder_n::_set_indirect_branch_packet(trace_encoder_n_packet_t* packet){
packet->tcode = TCODE_IBR;
packet->src = this->src;
packet->b_type = B_INDIRECT;
packet->icnt = this->icnt;
uint64_t e_addr = this->packet->i_addr >> 1;
packet->u_addr = e_addr ^ this->prev_addr;
this->prev_addr = e_addr;
}

// returns the number of bytes written to the buffer
int trace_encoder_n::packet_to_buffer(trace_encoder_n_packet_t* packet){
switch (packet->tcode) {
case TCODE_PROG_TRACE_SYNC:
return _packet_to_buffer_program_trace_sync(packet);
case TCODE_DBR:
return _packet_to_buffer_direct_branch_packet(packet);
case TCODE_IBR:
return _packet_to_buffer_indirect_branch_packet(packet);
default:
break;
}
}

int trace_encoder_n::_packet_to_buffer_program_trace_sync(trace_encoder_n_packet_t* packet) {
int msb = find_msb(packet->f_addr);
this->buffer[0] = packet->tcode << MDO_OFFSET | MSEO_IDLE;
this->buffer[1] = packet->sync << MDO_OFFSET | MSEO_IDLE;
this->buffer[1] |= (packet->f_addr & 0b11) << 6;
int num_bytes = 0;
if (msb < 2) {
this->buffer[1] |= MSEO_LAST;
} else {
packet->f_addr >>= 2;
msb -= 2;
num_bytes = ceil_div(msb, 6);
for (int iter = 0; iter < num_bytes; iter++) {
this->buffer[2 + iter] = ((packet->f_addr & 0x3F) << MDO_OFFSET) | MSEO_IDLE;
packet->f_addr >>= 6;
}
this->buffer[2 + num_bytes - 1] |= MSEO_LAST;
}
return 2 + num_bytes;
}

int trace_encoder_n::_packet_to_buffer_direct_branch_packet(trace_encoder_n_packet_t* packet) {
this->buffer[0] = packet->tcode << MDO_OFFSET | MSEO_IDLE;
int msb = find_msb(packet->icnt);
int num_bytes = ceil_div(msb, 6);
for (int iter = 0; iter < num_bytes; iter++) {
this->buffer[1 + iter] = ((packet->icnt & 0x3F) << MDO_OFFSET) | MSEO_IDLE;
packet->icnt >>= 6;
}
this->buffer[1 + num_bytes - 1] |= MSEO_LAST;
return 1 + num_bytes;
}

int trace_encoder_n::_packet_to_buffer_indirect_branch_packet(trace_encoder_n_packet_t* packet) {
printf("[trace_encoder_n] _packet_to_buffer_indirect_branch_packet: packet->icnt: %lx\n", packet->icnt);
this->buffer[0] = packet->tcode << MDO_OFFSET | MSEO_IDLE;
this->buffer[1] = packet->b_type << MDO_OFFSET | MSEO_IDLE;
// icnt
int icnt_msb = find_msb(packet->icnt);
int icnt_num_bytes = ceil_div(icnt_msb, 6);
this->buffer[1] |= (packet->u_addr & 0xF) << 4;
if (icnt_msb < 4) {
this->buffer[1] |= MSEO_EOF;
} else {
packet->icnt >>= 4;
icnt_msb -= 4;
icnt_num_bytes = ceil_div(icnt_msb, 6);
for (int iter = 0; iter < icnt_num_bytes; iter++) {
this->buffer[2 + iter] = ((packet->icnt & 0x3F) << MDO_OFFSET) | MSEO_IDLE;
packet->icnt >>= 6;
}
this->buffer[2 + icnt_num_bytes - 1] |= MSEO_EOF;
}
// u_addr
int u_addr_start = 2 + icnt_num_bytes;
int u_addr_msb = find_msb(packet->u_addr);
int u_addr_num_bytes = ceil_div(u_addr_msb, 6);
for (int iter = 0; iter < u_addr_num_bytes; iter++) {
this->buffer[u_addr_start + iter] = ((packet->u_addr & 0x3F) << MDO_OFFSET) | MSEO_IDLE;
packet->u_addr >>= 6;
}
this->buffer[u_addr_start + u_addr_num_bytes - 1] |= MSEO_LAST;
return u_addr_start + u_addr_num_bytes;
}

// returns the 0-index of the most significant bit
int find_msb(uint64_t x) {
if (x == 0) return -1;
return 63 - __builtin_clzll(x);
}

// returns the ceiling of the division of a 0-indexed a by b
int ceil_div(int a, int b) {
return a / b + 1;
}
101 changes: 101 additions & 0 deletions riscv/trace_encoder_n.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#ifndef _RISCV_TRACE_ENCODER_N_H
#define _RISCV_TRACE_ENCODER_N_H

#include "trace_ingress.h"
#include <stdio.h>

class hart_to_encoder_ingress_t;

enum tcode_t {
TCODE_OWN = 2, // ownership
TCODE_DBR = 3, // direct branch
TCODE_IBR = 4, // indirect branch
TCODE_ERR = 8, // error
TCODE_PROG_TRACE_SYNC = 9, // program trace sync
TCODE_DBR_SYNC = 10, // direct branch sync
TCODE_IBR_SYNC = 11, // indirect branch sync
TCODE_FULL = 27, // resource full
TCODE_IBR_HIST = 28, // indirect branch history
TCODE_IBR_HIST_SYNC = 29, // indirect branch history sync
TCODE_RBR = 30, // repeated branches
TCODE_PROG_TRACE_CORR = 33 // program trace correlation
};

enum b_type_t {
B_INDIRECT = 0, // indirect branch
B_TRAP = 1, // trap
B_EXCEPTION = 2, // exception
B_INTERRUPT = 3 // interrupt
};

enum sync_t {
SYNC_TRACE_EN = 5,
};

struct trace_encoder_n_packet_t {
uint8_t size; // 8 bits
tcode_t tcode; // 6 bits
uint16_t src; // unused for now
uint8_t sync; // 4 bit
uint8_t b_type; // 2 bits
uint16_t icnt; // 16 bits
uint64_t f_addr; // 64 bits
uint64_t u_addr; // 64 bits
uint64_t tstamp; // unused for now
};

void print_packet(trace_encoder_n_packet_t* packet);
void print_encoded_packet(uint8_t* buffer, int num_bytes);

int find_msb(uint64_t x);
int ceil_div(int a, int b);

enum trace_encoder_n_state_t {
TRACE_ENCODER_N_IDLE,
TRACE_ENCODER_N_DATA,
TRACE_ENCODER_N_FULL
};

#define MAX_TRACE_BUFFER_SIZE 38

#define MDO_OFFSET 2

#define MSEO_IDLE 0b00
#define MSEO_EOF 0b01
#define MSEO_RES 0b10 // reserved
#define MSEO_LAST 0b11

#define MAX_ICNT_BITS 15
#define MAX_ICNT 1 << MAX_ICNT_BITS

class trace_encoder_n {
public:
trace_encoder_n();
void trace_encoder_push_commit(hart_to_encoder_ingress_t* packet);
void trace_encoder_generate_packet(tcode_t tcode);

void set_enable(bool enabled);
private:
FILE* trace_sink;

hart_to_encoder_ingress_t* packet;
bool active;
bool enabled;
uint16_t src;
trace_encoder_n_state_t state;
uint8_t buffer[MAX_TRACE_BUFFER_SIZE];
uint16_t icnt;
uint64_t prev_addr;

void _set_direct_branch_packet(trace_encoder_n_packet_t* packet);
void _set_indirect_branch_packet(trace_encoder_n_packet_t* packet);
void _set_program_trace_sync_packet(trace_encoder_n_packet_t* packet);

int packet_to_buffer(trace_encoder_n_packet_t* packet);
int _packet_to_buffer_program_trace_sync(trace_encoder_n_packet_t* packet);
int _packet_to_buffer_direct_branch_packet(trace_encoder_n_packet_t* packet);
int _packet_to_buffer_indirect_branch_packet(trace_encoder_n_packet_t* packet);
};


#endif
Loading