Merge branch 'master' of iis-git.ee.ethz.ch:pulp-project/riscv

This commit is contained in:
Francesco Conti 2016-02-11 16:14:50 +01:00
commit 9ecd6d9868
16 changed files with 1249 additions and 116 deletions

22
README.md Normal file
View file

@ -0,0 +1,22 @@
# RI5CY: RISC-V Core
RI5CY is a small 4-stage RISC-V core. It starte its life as a
fork of the OR10N cpu core that is based on the OpenRISC ISA.
RI5CY fully implements the RV32I instruction set, the multiply instruction from
RV32M and many custom instruction set extensions that improve its performance
for signal processing applications.
The core was developed as part of the [PULP platform](http://pulp.ethz.ch/) for
energy-efficient computing and is currently used as the processing core for
PULP and PULPino.
## Documentation
A datasheet that explains the most important features of the core can be found
in `docs/datasheet/`.
It is written using LaTeX and can be generated as follows
make all

View file

@ -71,7 +71,8 @@ module riscv_controller
input logic trap_hit_i, // a trap was hit, so we have to flush EX and WB
output logic save_pc_id_o,
output logic exc_save_id_o,
output logic exc_restore_id_o,
// Debug Unit Signals
input logic dbg_stall_i, // Pipeline stall is requested
@ -158,23 +159,24 @@ module riscv_controller
always_comb
begin
// Default values
instr_req_o = 1'b1;
instr_req_o = 1'b1;
exc_ack_o = 1'b0;
save_pc_id_o = 1'b0;
exc_ack_o = 1'b0;
exc_save_id_o = 1'b0;
exc_restore_id_o = 1'b0;
pc_mux_o = `PC_BOOT;
pc_set_o = 1'b0;
jump_done = jump_done_q;
pc_mux_o = `PC_BOOT;
pc_set_o = 1'b0;
jump_done = jump_done_q;
ctrl_fsm_ns = ctrl_fsm_cs;
ctrl_fsm_ns = ctrl_fsm_cs;
core_busy_o = 1'b1;
is_decoding_o = 1'b0;
core_busy_o = 1'b1;
is_decoding_o = 1'b0;
halt_if_o = 1'b0;
halt_id_o = 1'b0;
dbg_trap_o = 1'b0;
halt_if_o = 1'b0;
halt_id_o = 1'b0;
dbg_trap_o = 1'b0;
unique case (ctrl_fsm_cs)
// We were just reset, wait for fetch_enable
@ -227,7 +229,7 @@ module riscv_controller
// TODO: This assumes that the pipeline is always flushed before
// going to sleep.
save_pc_id_o = 1'b1;
exc_save_id_o = 1'b1;
end
end
@ -266,7 +268,7 @@ module riscv_controller
exc_ack_o = 1'b1;
halt_id_o = 1'b1; // we don't want to propagate this instruction to EX
save_pc_id_o = 1'b1;
exc_save_id_o = 1'b1;
// we don't have to change our current state here as the prefetch
// buffer is automatically invalidated, thus the next instruction
@ -276,8 +278,9 @@ module riscv_controller
end
if (eret_insn_i) begin
pc_mux_o = `PC_ERET;
pc_set_o = 1'b1;
pc_mux_o = `PC_ERET;
pc_set_o = 1'b1;
exc_restore_id_o = 1'b1;
end
// handle WFI instruction, flush pipeline and (potentially) go to

View file

@ -55,10 +55,11 @@ module riscv_cs_registers
// Interrupts
output logic irq_enable_o,
output logic [31:0] epcr_o,
output logic [31:0] mepc_o,
input logic [31:0] curr_pc_id_i,
input logic save_pc_id_i,
input logic exc_save_i,
input logic exc_restore_i,
input logic [5:0] exc_cause_i,
input logic save_exc_cause_i,
@ -115,17 +116,16 @@ module riscv_cs_registers
logic is_pcer;
logic is_pcmr;
// Generic CSRs
logic [31:0] mepc_q, mepc_n;
// CSR update logic
logic [31:0] csr_wdata_int;
logic [31:0] csr_rdata_int;
logic csr_we_int;
// Interrupt control signals
logic irq_enable, irq_enable_n;
logic [5:0] exc_cause, exc_cause_n;
logic [31:0] mepc_q, mepc_n;
logic [ 0:0] mestatus_q, mestatus_n;
logic [ 0:0] mstatus_q, mstatus_n;
logic [ 5:0] exc_cause, exc_cause_n;
////////////////////////////////////////////
@ -144,7 +144,7 @@ module riscv_cs_registers
case (csr_addr_i)
// mstatus: always M-mode, contains IE bit
12'h300: csr_rdata_int = {29'b0, 2'b11, irq_enable};
12'h300: csr_rdata_int = {29'b0, 2'b11, mstatus_q};
// mepc: exception program counter
12'h341: csr_rdata_int = mepc_q;
@ -165,6 +165,8 @@ module riscv_cs_registers
12'h7B4: csr_rdata_int = hwlp_start_i[1];
12'h7B5: csr_rdata_int = hwlp_end_i[1];
12'h7B6: csr_rdata_int = hwlp_cnt_i[1];
12'h7C0: csr_rdata_int = {29'b0, 2'b11, mestatus_q};
endcase
end
@ -173,14 +175,15 @@ module riscv_cs_registers
always_comb
begin
mepc_n = mepc_q;
irq_enable_n = irq_enable;
mestatus_n = mestatus_q;
mstatus_n = mstatus_q;
exc_cause_n = exc_cause;
hwlp_we_o = '0;
hwlp_regid_o = '0;
case (csr_addr_i)
// mstatus: IE bit
12'h300: if (csr_we_int) irq_enable_n = csr_wdata_int[0];
12'h300: if (csr_we_int) mstatus_n = csr_wdata_int[0];
// mepc: exception program counter
12'h341: if (csr_we_int) mepc_n = csr_wdata_int;
@ -194,7 +197,24 @@ module riscv_cs_registers
12'h7B4: if (csr_we_int) begin hwlp_we_o = 3'b001; hwlp_regid_o = 1'b1; end
12'h7B5: if (csr_we_int) begin hwlp_we_o = 3'b010; hwlp_regid_o = 1'b1; end
12'h7B6: if (csr_we_int) begin hwlp_we_o = 3'b100; hwlp_regid_o = 1'b1; end
// mestatus: machine exception status
12'h7C0: if (csr_we_int) mestatus_n = csr_wdata_int[0];
endcase
// exception controller gets priority over other writes
if (exc_save_i) begin
mepc_n = curr_pc_id_i;
mestatus_n = mstatus_q;
mstatus_n = 1'b0;
end
if (save_exc_cause_i)
exc_cause_n = exc_cause_i;
if (exc_restore_i) begin
mstatus_n = mestatus_q;
end
end
assign hwlp_data_o = csr_wdata_int;
@ -231,8 +251,8 @@ module riscv_cs_registers
// directly output some registers
assign irq_enable_o = irq_enable;
assign epcr_o = mepc_q;
assign irq_enable_o = mstatus_q[0];
assign mepc_o = mepc_q;
// actual registers
@ -240,25 +260,20 @@ module riscv_cs_registers
begin
if (rst_n == 1'b0)
begin
irq_enable <= 1'b0;
mstatus_q <= '0;
mepc_q <= '0;
mestatus_q <= '0;
exc_cause <= '0;
end
else
begin
// update CSRs
irq_enable <= irq_enable_n;
mstatus_q <= mstatus_n;
// exception controller gets priority over other writes
if (save_pc_id_i == 1'b1)
mepc_q <= curr_pc_id_i;
else
mepc_q <= mepc_n;
mepc_q <= mepc_n;
mestatus_q <= mestatus_n;
if (save_exc_cause_i)
exc_cause <= exc_cause_i;
else
exc_cause <= exc_cause_n;
exc_cause <= exc_cause_n;
end
end

View file

@ -18,9 +18,10 @@ as possible and avoid any overhead that we do not explicitely need.
00 & 11 & 01 & 000001 & 0x341 & MEPC & R/W & Machine exception program counter \\ \hline
00 & 11 & 01 & 000010 & 0x342 & MCAUSE & R/W & Machine trap cause \\ \hline
01 & 11 & 00 & 0XXXXX & 0x780 - 0x79F & PCCRs & R/W & Performance Counter Counter Registers \\ \hline
01 & 11 & 10 & 200000 & 0x7A0 & PCER & R/W & Performance Counter Enable Register \\ \hline
01 & 11 & 10 & 100000 & 0x7A0 & PCER & R/W & Performance Counter Enable Register \\ \hline
01 & 11 & 10 & 100001 & 0x7A1 & PCMR & R/W & Performance Counter Mode Register \\ \hline
01 & 11 & 10 & 110XXX & 0x7B0 - 0x7B6 & HWLP & R/W & Hardware Loop Registers \\ \hline
01 & 11 & 10 & 111000 & 0x7C0 & MESTATUS & R/W & Machine exception Status Register \\ \hline
11 & 11 & 00 & 000000 & 0xF00 & MCPUID & R & CPU description \\ \hline
11 & 11 & 00 & 000001 & 0xF01 & MIMPID & R & Vendor ID and version number \\ \hline
11 & 11 & 00 & 010000 & 0xF10 & MHARTID & R & Hardware Thread ID \\ \bottomrule
@ -41,6 +42,28 @@ as possible and avoid any overhead that we do not explicitely need.
}
Note that \signal{PRV[1:0]} is statically \signal{2'b11} and cannot be altered (read-only).
When en exception is encountered, \signal{Interrupt Enable} will be set to
\signal{1'b0}. When the \signal{eret} instruction is executed, the original
value of \signal{Interrupt Enable} will be restored, as \signal{MESTATUS} will
replace \signal{MSTATUS}.
If you want to enable interrupt handling in your exception hanlder, set the
\signal{Interrupt Enable} to \signal{1'b1} inside your handler code.
\subsection{MESTATUS}
\csrDesc{0x7C0}{0x0000\_0006}{MESTATUS}{
\begin{bytefield}[endianness=big,bitheight=60pt]{32}
\bitheader{31,2,1,0} \\
\bitbox{29}{ Unused }
\bitbox{2}{\rotatebox{90}{\tiny PRV[1:0] }}
\bitbox{1}{\rotatebox{90}{\tiny Interrupt Enable }}
\end{bytefield}
}
Note that \signal{PRV[1:0]} is statically \signal{2'b11} and cannot be altered (read-only).
When an exception is encountered, the current value of \signal{MSTATUS} is saved
in \signal{MESTATUS}. When an \instr{eret} instruction is executed, the value
from \signal{MESTATUS} replaces the \signal{MSTATUS} register.
\subsection{MEPC}
@ -52,9 +75,9 @@ Note that \signal{PRV[1:0]} is statically \signal{2'b11} and cannot be altered (
}
When an exception is encountered, the current program counter is saved in
\signal{mepc} and the core jumps to the exception address.
When an \instr{eret} instruction is executed, the value from \signal{mepc}
replaces the current program counter.
\signal{MEPC}, and the core jumps to the exception address. When an \instr{eret}
instruction is executed, the value from \signal{MEPC} replaces the current
program counter.
\subsection{MCAUSE}
\csrDesc{0x341}{0x0000\_0000}{MCAUSE}{

View file

@ -29,7 +29,15 @@ exception/interrupt.
interrupt lines. Interrupts can only be enabled/disabled on a global basis and
not individually. It is assumed that there is an event/interrupt controller
outside of the core that performs masking and buffering of the interrupt lines.
The global interrupt enable is done via the CSR register \signal{mstatus}.
The global interrupt enable is done via the CSR register \signal{MSTATUS}.
If multiple interrupts arrive in the same cycle, the interrupt with the lowest
number will be executed first. As soon as IRQs are re-enabled, either after an
\signal{eret} or an explicit enable, the interrupt with lowest number will be
executed.
This means that it is important to clear the interrupt line before re-enabling
interrupts, as otherwise the same interrupt handler could be called over and
over again.
\section{Exceptions}
@ -38,16 +46,21 @@ exceptions and ecall instruction exceptions can not be disabled and are always
active.
The illegal instruction exception and the load and store invalid memory access
exceptions are precise exceptions, i.e. the value of \signal{mepc} will be the
exceptions are precise exceptions, i.e. the value of \signal{MEPC} will be the
instruction address that caused it.
\section{Handling}
\rvcore does not support nested interrupt/exception handling. Exceptions inside
interrupt/exception handlers are ignored and thus a user must ensure that such
a situation does not happen, as otherwise the behaviour is undefined.
\rvcore does support nested interrupt/exception handling. Exceptions inside
interrupt/exception handlers cause another exception, thus exceptions during the
critical part of your exception handlers, i.e. before having saved the
\signal{MEPC} and \signal{MESTATUS} registers, will cause those register to be
overwritten.
Interrupts during interrupt/exception handlers are disabled by default, but can
be explicitely enabled if desired.
Upon executing an \instr{eret} instruction, the core jumps to the program
counter saved in the CSR register \signal{mepc}. When entering an
interrupt/exception handler, the core sets \signal{mepc} to the current program
counter.
counter saved in the CSR register \signal{MEPC} and restores the value of
register \signal{MESTATUS} to \signal{MSTATUS}. When entering an
interrupt/exception handler, the core sets \signal{MEPC} to the current program
counter and saves the current value of \signal{MSTATUS} in \signal{MESTATUS}.

View file

@ -13,6 +13,9 @@ the loop body is executed. RI5CY contains two hardware loop register sets, each
of them can store these three values.
If the end address of the two hardware loops is identical, loop 0 has higher
priority and only the loop counter for hardware loop 0 is decremented.
As soon as the counter of loop 0 reaches 1 at an end address, meaning it is
decremented to 0 now, loop 1 gets active too. In this case, both counters will
be decremented and the core jumps to the start of loop 1.
The instructions described below are used to setup the hardware loop registers.
Note that the minimum loop size is two instructions.

View file

@ -0,0 +1,44 @@
\chapter{Pipeline}
\label{chap:pipeline}
\rvcore has a fully independent pipeline, meaning that whenever possible data
will propagate through the pipeline and therefor does not suffer from any
unneeded stalls.
The pipeline design is easily extendable to incorporate out-of-order
completion. E.g. it would be possible to complete an instruction that only
needs the EX stage before the WB stage, that is currently blocked waiting for
an rvalid, is ready.
Currently this is not done in \rvcore, but might be added in the future.
Figure~\ref{fig:pipeline} shows the control signals relevant for the pipeline
operation. Running from right to left are the main control signals, the
\signal{ready} signals of each pipeline stage.
Each pipeline stage has two control inputs: an enable and a clear. The enable
activates the pipeline stage and the core moves forward by one instruction. The
clear removes the instruction from the pipeline stage as it is completed.
At every pipeline stage, when the \signal{ready} coming from the stage to the
right is high, but the valid signal of the stage is low, the stage is cleared.
If the valid signal is high, it is enabled.
Going from right to left every stage is independent, no stage depends on the
stage on its left. Going from left to right every stage depends on its right
neighbor and can only continue when it is ready.
This means that in addition that a single stage has to be ready, also the stage
on its right has to be ready to move on.
\begin{figure}[H]
\centering
\includegraphics[width=0.9\textwidth]{./figures/pipeline}
\caption{\rvcore Pipeline.}
\label{fig:pipeline}
\end{figure}
\begin{boxnote}
In contrast to \orion there is no global stall controller any more, instead
every stage manages its own dependencies. The main controller of \rvcore is now
only responsible for control flow operations, i.e. flushing the pipe, branches,
jumps and exceptions.
\end{boxnote}

View file

@ -37,6 +37,7 @@
\input{./content/mac.tex}
\input{./content/aluext.tex}
\input{./content/hwloop.tex}
\input{./content/pipeline.tex}
\input{./content/rf.tex}
\input{./content/csr.tex}
\input{./content/perfcounters.tex}

View file

@ -0,0 +1,641 @@
%TGIF 4.2.5-QPL
state(0,37,100.000,0,0,0,32,1,16,2,2,1,0,0,0,1,1,'Helvetica-Bold',1,97920,0,0,0,10,0,0,1,1,0,16,0,0,1,1,1,1,1088,1408,1,0,5760,0).
%
% @(#)$Header$
% %W%
%
unit("1 pixel/pixel").
color_info(66,65535,0,[
"black", 0, 0, 0, 0, 0, 0, 1,
"white", 65535, 65535, 65535, 65535, 65535, 65535, 1,
"#F0F0F0", 61680, 61680, 61680, 61440, 61440, 61440, 1,
"#C8C8C8", 51400, 51400, 51400, 51200, 51200, 51200, 1,
"#505050", 20560, 20560, 20560, 20480, 20480, 20480, 1,
"#282828", 10280, 10280, 10280, 10240, 10240, 10240, 1,
"#FF0000", 65535, 0, 0, 65280, 0, 0, 1,
"#0000FF", 0, 0, 65535, 0, 0, 65280, 1,
"#00FF00", 0, 65535, 0, 0, 65280, 0, 1,
"#009000", 0, 37008, 0, 0, 36864, 0, 1,
"#1F407A", 7967, 16448, 31354, 7936, 16384, 31232, 1,
"#3C5A0F", 15420, 23130, 3855, 15360, 23040, 3840, 1,
"#0069B4", 0, 26985, 46260, 0, 26880, 46080, 1,
"#71791C", 29041, 31097, 7196, 28928, 30976, 7168, 1,
"#91056A", 37265, 1285, 27242, 37120, 1280, 27136, 1,
"#6F6F6E", 28527, 28527, 28270, 28416, 28416, 28160, 1,
"#A8322D", 43176, 12850, 11565, 43008, 12800, 11520, 1,
"#007A92", 0, 31354, 37522, 0, 31232, 37376, 1,
"#956013", 38293, 24672, 4883, 38144, 24576, 4864, 1,
"#82BE1E", 33410, 48830, 7710, 33280, 48640, 7680, 1,
"#758fbd", 30069, 36751, 48573, 29952, 36608, 48384, 1,
"#8eab63", 36494, 43947, 25443, 36352, 43776, 25344, 1,
"#6cacd9", 27756, 44204, 55769, 27648, 44032, 55552, 1,
"#b4ba72", 46260, 47802, 29298, 46080, 47616, 29184, 1,
"#c967ae", 51657, 26471, 44718, 51456, 26368, 44544, 1,
"#b8b8b6", 47288, 47288, 46774, 47104, 47104, 46592, 1,
"#d48985", 54484, 35209, 34181, 54272, 35072, 34048, 1,
"#65b9c9", 25957, 47545, 51657, 25856, 47360, 51456, 1,
"#c9a571", 51657, 42405, 29041, 51456, 42240, 28928, 1,
"#bbde81", 48059, 57054, 33153, 47872, 56832, 33024, 1,
"#a5b7d6", 42405, 47031, 54998, 42240, 46848, 54784, 1,
"#b8cc99", 47288, 52428, 39321, 47104, 52224, 39168, 1,
"#a2cbe8", 41634, 52171, 59624, 41472, 51968, 59392, 1,
"#d2d6a5", 53970, 54998, 42405, 53760, 54784, 42240, 1,
"#de9ecc", 57054, 40606, 52428, 56832, 40448, 52224, 1,
"#d4d4d2", 54484, 54484, 53970, 54272, 54272, 53760, 1,
"#e6b5b3", 59110, 46517, 46003, 58880, 46336, 45824, 1,
"#9bd3de", 39835, 54227, 57054, 39680, 54016, 56832, 1,
"#dec6a4", 57054, 50886, 42148, 56832, 50688, 41984, 1,
"#d5ebb0", 54741, 60395, 45232, 54528, 60160, 45056, 1,
"#b3cde3", 46003, 52685, 58339, 45824, 52480, 58112, 1,
"#bae4bc", 47802, 58596, 48316, 47616, 58368, 48128, 1,
"#edf8fb", 60909, 63736, 64507, 60672, 63488, 64256, 1,
"#ffffcc", 65535, 65535, 52428, 65280, 65280, 52224, 1,
"magenta", 65535, 0, 65535, 65535, 0, 65535, 1,
"#f0f9e8", 61680, 63993, 59624, 61440, 63744, 59392, 1,
"#feebe2", 65278, 60395, 58082, 65024, 60160, 57856, 1,
"cyan", 0, 65535, 65535, 0, 65535, 65535, 1,
"#fecc5c", 65278, 52428, 23644, 65024, 52224, 23552, 1,
"yellow", 65535, 65535, 0, 65535, 65535, 0, 1,
"red", 65535, 0, 0, 65535, 0, 0, 1,
"green", 0, 65535, 0, 0, 65535, 0, 1,
"blue", 0, 0, 65535, 0, 0, 65535, 1,
"pink", 65535, 49344, 52171, 65535, 49344, 52171, 1,
"CadetBlue", 24415, 40606, 41120, 24415, 40606, 41120, 1,
"DarkSlateGray", 12079, 20303, 20303, 12079, 20303, 20303, 1,
"#FF4D08", 65535, 19789, 2056, 65280, 19712, 2048, 1,
"#FF6437", 65535, 25700, 14135, 65280, 25600, 14080, 1,
"#7F321B", 32639, 12850, 6939, 32512, 12800, 6912, 1,
"#FF8080", 65535, 32896, 32896, 65280, 32768, 32768, 1,
"#FF8A7E", 65535, 35466, 32382, 65280, 35328, 32256, 1,
"#FFC37C", 65535, 50115, 31868, 65280, 49920, 31744, 1,
"#7F4A0D", 32639, 19018, 3341, 32512, 18944, 3328, 1,
"#DE82FF", 57054, 33410, 65535, 56832, 33280, 65280, 1,
"#EFB8FF", 61423, 47288, 65535, 61184, 47104, 65280, 1,
"#6F367F", 28527, 13878, 32639, 28416, 13824, 32512, 1
]).
script_frac("0.6").
fg_bg_colors('#A8322D','white').
dont_reencode("FFDingbests:ZapfDingbats").
objshadow_info('#c0c0c0',2,2).
rotate_pivot(0,0,0,0).
spline_tightness(1).
page(1,"",1,'').
box('#EFB8FF','',288,256,320,560,1,2,0,288070,0,0,0,0,0,'2',0,[
]).
box('#EFB8FF','',592,256,624,560,1,2,0,288062,0,0,0,0,0,'2',0,[
]).
box('#EFB8FF','',888,400,920,560,1,2,0,288031,0,0,0,0,0,'2',0,[
]).
rcbox('#f0f9e8','',332,256,580,616,1,1,0,0,16,287695,0,0,0,0,'1',0,[
]).
rcbox('#f0f9e8','',636,256,876,616,1,1,0,0,16,287722,0,0,0,0,'1',0,[
]).
rcbox('#f0f9e8','',932,256,1052,616,1,1,0,0,16,287742,0,0,0,0,'1',0,[
]).
rcbox('#f0f9e8','',24,256,276,616,1,1,0,0,16,287635,0,0,0,0,'1',0,[
]).
rcbox('#d4d4d2','',24,256,276,616,0,1,1,0,16,287685,0,0,0,0,'1',0,[
]).
poly('black','',2,[
820,280,820,192],1,1,1,286345,0,0,0,0,0,0,0,'1',0,0,
"0","",[
0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[
]).
text('black',816,170,1,1,1,40,17,286346,14,3,0,0,0,0,2,40,17,0,0,"",0,0,0,0,184,'',[
minilines(40,17,0,0,1,0,0,[
mini_line(40,14,3,0,0,0,[
str_block(0,40,14,3,0,-1,0,0,0,[
str_seg('#0069B4','Courier-Bold',1,97920,40,14,3,0,-1,0,0,0,0,0,
"addr")])
])
])]).
text('black',960,170,1,1,1,60,17,286404,14,3,0,0,0,0,2,60,17,0,0,"",0,0,0,0,184,'',[
minilines(60,17,0,0,1,0,0,[
mini_line(60,14,3,0,0,0,[
str_block(0,60,14,3,0,-1,0,0,0,[
str_seg('#0069B4','Courier-Bold',1,97920,60,14,3,0,-1,0,0,0,0,0,
"rvalid")])
])
])]).
text('black',872,170,1,1,1,50,17,286468,14,3,0,0,0,0,2,50,17,0,0,"",0,0,0,0,184,'',[
minilines(50,17,0,0,1,0,0,[
mini_line(50,14,3,0,0,0,[
str_block(0,50,14,3,0,-1,0,0,0,[
str_seg('#0069B4','Courier-Bold',1,97920,50,14,3,0,-1,0,0,0,0,0,
"grant")])
])
])]).
rcbox('#0069B4','',784,136,1024,192,0,1,1,0,16,286710,0,0,0,0,'1',0,[
]).
text('black',888,142,1,1,1,127,23,286718,18,5,0,0,0,0,2,127,23,0,0,"",0,0,0,0,160,'',[
minilines(127,23,0,0,1,0,0,[
mini_line(127,18,5,0,0,0,[
str_block(0,127,18,5,0,-1,0,0,0,[
str_seg('#0069B4','Helvetica-Bold',1,115200,127,18,5,0,-1,0,0,0,0,0,
"Data Interface")])
])
])]).
box('black','',12,224,1064,664,0,1,1,286736,0,0,0,0,0,'1',0,[
]).
text('black',184,170,1,1,1,40,17,286355,14,3,0,0,0,0,2,40,17,0,0,"",0,0,0,0,184,'',[
minilines(40,17,0,0,1,0,0,[
mini_line(40,14,3,0,0,0,[
str_block(0,40,14,3,0,-1,0,0,0,[
str_seg('#0069B4','Courier-Bold',1,97920,40,14,3,0,-1,0,0,0,0,0,
"addr")])
])
])]).
text('black',120,170,1,1,1,60,17,286569,14,3,0,0,0,0,2,60,17,0,0,"",0,0,0,0,184,'',[
minilines(60,17,0,0,1,0,0,[
mini_line(60,14,3,0,0,0,[
str_block(0,60,14,3,0,-1,0,0,0,[
str_seg('#0069B4','Courier-Bold',1,97920,60,14,3,0,-1,0,0,0,0,0,
"rvalid")])
])
])]).
rcbox('#0069B4','',56,136,264,192,0,1,1,0,16,286711,0,0,0,0,'1',0,[
]).
text('black',160,142,1,1,1,181,23,286715,18,5,0,0,0,0,2,181,23,0,0,"",0,0,0,0,160,'',[
minilines(181,23,0,0,1,0,0,[
mini_line(181,18,5,0,0,0,[
str_block(0,181,18,5,0,-1,0,0,0,[
str_seg('#0069B4','Helvetica-Bold',1,115200,181,18,5,0,-1,0,0,0,0,0,
"Instruction Interface")])
])
])]).
box('#6F367F','',288,256,320,560,0,2,1,283037,0,0,0,0,0,'2',0,[
]).
text('black',294,415,2,0,1,20,35,283038,14,3,0,0,0,0,2,20,34,0,0,"",0,1,0,0,429,'',[
294,415,294,415,314,449,1000,0,0,1022.73,0,4,293,414,315,450],[
minilines(20,34,0,0,0,0,0,[
mini_line(20,14,3,0,0,0,[
str_block(0,20,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,20,14,3,0,-1,0,0,0,0,0,
"IF")])
]),
mini_line(20,14,3,0,0,0,[
str_block(0,20,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,20,14,3,0,-1,0,0,0,0,0,
"ID")])
])
])]).
box('#6F367F','',592,256,624,560,0,2,1,283031,0,0,0,0,0,'2',0,[
]).
text('black',598,415,2,0,1,20,34,283032,14,3,0,0,0,0,2,20,34,0,0,"",0,0,0,0,429,'',[
minilines(20,34,0,0,0,0,0,[
mini_line(20,14,3,0,0,0,[
str_block(0,20,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,20,14,3,0,-1,0,0,0,0,0,
"ID")])
]),
mini_line(20,14,3,0,0,0,[
str_block(0,20,14,3,0,0,0,0,0,[
str_seg('black','Courier-Bold',1,97920,20,14,3,0,0,0,0,0,0,0,
"EX")])
])
])]).
box('#6F367F','',888,400,920,560,0,2,1,283042,0,0,0,0,0,'2',0,[
]).
text('black',894,415,2,0,1,20,34,283043,14,3,0,0,0,0,2,20,34,0,0,"",0,0,0,0,429,'',[
minilines(20,34,0,0,0,0,0,[
mini_line(20,14,3,0,0,0,[
str_block(0,20,14,3,0,0,0,0,0,[
str_seg('black','Courier-Bold',1,97920,20,14,3,0,0,0,0,0,0,0,
"EX")])
]),
mini_line(20,14,3,0,0,0,[
str_block(0,20,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,20,14,3,0,-1,0,0,0,0,0,
"WB")])
])
])]).
poly('black','',2,[
172,280,172,192],1,1,1,287533,0,0,0,0,0,0,0,'1',0,0,
"0","",[
0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[
]).
poly('black','',2,[
116,192,116,280],1,1,1,287631,0,0,0,0,0,0,0,'1',0,0,
"0","",[
0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[
]).
rcbox('#d4d4d2','',332,256,580,616,0,1,1,0,16,287693,0,0,0,0,'1',0,[
]).
rcbox('#d4d4d2','',636,256,876,616,0,1,1,0,16,287738,0,0,0,0,'1',0,[
]).
rcbox('#d4d4d2','',932,256,1052,616,0,1,1,0,16,287749,0,0,0,0,'1',0,[
]).
poly('#6F367F','',3,[
296,560,304,548,312,560],0,2,1,288021,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#6F367F','',3,[
600,560,608,548,616,560],0,2,1,288025,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#6F367F','',3,[
896,560,904,548,912,560],0,2,1,288028,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
text('#6F367F',376,554,1,1,1,80,17,288303,14,3,0,0,0,0,-65534,80,17,0,0,"",0,0,0,0,568,'',[
minilines(80,17,0,0,1,0,0,[
mini_line(80,14,3,0,0,0,[
str_block(0,80,14,3,0,0,0,0,0,[
str_seg('black','Courier-Bold',1,97920,80,14,3,0,0,0,0,0,0,0,
"id_ready")])
])
])]).
text('#6F367F',680,554,1,1,1,80,17,288352,14,3,0,0,0,0,-65534,80,17,0,0,"",0,0,0,0,568,'',[
minilines(80,17,0,0,1,0,0,[
mini_line(80,14,3,0,0,0,[
str_block(0,80,14,3,0,0,0,0,0,[
str_seg('black','Courier-Bold',1,97920,80,14,3,0,0,0,0,0,0,0,
"ex_ready")])
])
])]).
text('#6F367F',980,554,1,1,1,80,17,288361,14,3,0,0,0,0,-65534,80,17,0,0,"",0,0,0,0,568,'',[
minilines(80,17,0,0,1,0,0,[
mini_line(80,14,3,0,0,0,[
str_block(0,80,14,3,0,0,0,0,0,[
str_seg('black','Courier-Bold',1,97920,80,14,3,0,0,0,0,0,0,0,
"wb_ready")])
])
])]).
poly('black','',3,[
496,384,496,560,472,560],1,2,1,288369,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('black','',2,[
728,576,472,576],1,2,1,288370,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
text('#6F367F',456,410,1,1,1,60,17,288372,14,3,0,0,0,0,-65534,60,17,0,0,"",0,0,0,0,424,'',[
minilines(60,17,0,0,1,0,0,[
mini_line(60,14,3,0,0,0,[
str_block(0,60,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,60,14,3,0,-1,0,0,0,0,0,
"!stall")])
])
])]).
text('#6F367F',744,402,1,1,1,70,17,288380,14,3,0,0,0,0,-65534,70,17,0,0,"",0,0,0,0,416,'',[
minilines(70,17,0,0,1,0,0,[
mini_line(70,14,3,0,0,0,[
str_block(0,70,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,70,14,3,0,-1,0,0,0,0,0,
"granted")])
])
])]).
text('#6F367F',988,402,1,1,1,60,17,288385,14,3,0,0,0,0,-65534,60,17,0,0,"",0,0,0,0,416,'',[
minilines(60,17,0,0,1,0,0,[
mini_line(60,14,3,0,0,0,[
str_block(0,60,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,60,14,3,0,-1,0,0,0,0,0,
"rvalid")])
])
])]).
poly('black','',2,[
1028,576,776,576],1,2,1,288388,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#3C5A0F','',3,[
424,576,424,608,464,608],0,2,1,288395,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#3C5A0F','',4,[
448,608,568,608,568,520,592,520],1,2,1,288396,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
text('#6F367F',520,586,1,1,1,80,17,288398,14,3,0,0,0,0,-65534,80,17,0,0,"",0,0,0,0,600,'',[
minilines(80,17,0,0,1,0,0,[
mini_line(80,14,3,0,0,0,[
str_block(0,80,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,80,14,3,0,-1,0,0,0,0,0,
"id_valid")])
])
])]).
poly('#3C5A0F','',3,[
728,576,728,608,752,608],0,2,1,288403,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#3C5A0F','',4,[
736,608,864,608,864,520,888,520],1,2,1,288404,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
text('#6F367F',816,586,1,1,1,80,17,288405,14,3,0,0,0,0,-65534,80,17,0,0,"",0,0,0,0,600,'',[
minilines(80,17,0,0,1,0,0,[
mini_line(80,14,3,0,0,0,[
str_block(0,80,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,80,14,3,0,-1,0,0,0,0,0,
"ex_valid")])
])
])]).
poly('#3C5A0F','',3,[
40,568,40,608,168,608],0,2,1,288407,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#3C5A0F','',4,[
160,608,256,608,256,520,288,520],1,2,1,288408,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
text('#6F367F',208,586,1,1,1,80,17,288409,14,3,0,0,0,0,-65534,80,17,0,0,"",0,0,0,0,600,'',[
minilines(80,17,0,0,1,0,0,[
mini_line(80,14,3,0,0,0,[
str_block(0,80,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,80,14,3,0,-1,0,0,0,0,0,
"if_valid")])
])
])]).
text('#6F367F',80,546,1,1,1,80,17,288418,14,3,0,0,0,0,-65534,80,17,0,0,"",0,0,0,0,560,'',[
minilines(80,17,0,0,1,0,0,[
mini_line(80,14,3,0,0,0,[
str_block(0,80,14,3,0,0,0,0,0,[
str_seg('black','Courier-Bold',1,97920,80,14,3,0,0,0,0,0,0,0,
"if_ready")])
])
])]).
rcbox('#bbde81','',80,280,208,432,1,2,0,0,10,288422,0,0,0,0,'2',0,[
]).
poly('#009000','',3,[
136,432,144,420,152,432],0,2,1,288423,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
text('black',144,296,2,1,1,101,58,288424,24,5,0,0,0,0,2,101,58,0,0,"",0,0,0,0,320,'',[
minilines(101,58,0,0,1,0,0,[
mini_line(101,24,5,0,0,0,[
str_block(0,101,24,5,0,-2,0,0,0,[
str_seg('black','Helvetica-Bold',1,138240,101,24,5,0,-2,0,0,0,0,0,
"Prefetch")])
]),
mini_line(75,24,5,0,0,0,[
str_block(0,75,24,5,0,-1,0,0,0,[
str_seg('black','Helvetica-Bold',1,138240,75,24,5,0,-1,0,0,0,0,0,
"Buffer")])
])
])]).
rcbox('#009000','',80,280,208,432,0,2,1,0,10,288425,0,0,0,0,'2',0,[
]).
text('#6F367F',152,458,1,1,1,50,17,288428,14,3,0,0,0,0,-65534,50,17,0,0,"",0,0,0,0,472,'',[
minilines(50,17,0,0,1,0,0,[
mini_line(50,14,3,0,0,0,[
str_block(0,50,14,3,0,-1,0,0,0,[
str_seg('black','Courier-Bold',1,97920,50,14,3,0,-1,0,0,0,0,0,
"valid")])
])
])]).
rcbox('#b8cc99','',432,328,560,384,1,2,1,0,10,288430,0,0,0,0,'2',0,[
]).
rcbox('#3C5A0F','',432,328,560,384,0,2,1,0,10,288431,0,0,0,0,'2',0,[
]).
text('black',496,337,2,1,1,104,46,288432,18,5,0,0,0,0,2,104,46,0,0,"",0,0,0,0,355,'',[
minilines(104,46,0,0,1,0,0,[
mini_line(104,18,5,0,0,0,[
str_block(0,104,18,5,0,-1,0,0,0,[
str_seg('black','Helvetica-Bold',1,115200,104,18,5,0,-1,0,0,0,0,0,
"Forwarding")])
]),
mini_line(67,18,5,0,0,0,[
str_block(0,67,18,5,0,-1,0,0,0,[
str_seg('black','Helvetica-Bold',1,115200,67,18,5,0,-1,0,0,0,0,0,
"Control")])
])
])]).
poly('black','',2,[
964,192,964,280],1,1,1,288438,0,0,0,0,0,0,0,'1',0,0,
"0","",[
0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[
]).
rcbox('#a5b7d6','',768,280,1040,384,1,2,0,0,10,287905,0,0,0,0,'2',0,[
]).
rcbox('#1F407A','',768,280,1040,384,0,2,1,0,10,286743,0,0,0,0,'2',0,[
]).
text('black',824,288,1,1,1,51,29,286745,24,5,0,0,0,0,2,51,29,0,0,"",0,0,0,0,312,'',[
minilines(51,29,0,0,1,0,0,[
mini_line(51,24,5,0,0,0,[
str_block(0,51,24,5,0,-2,0,0,0,[
str_seg('black','Helvetica-Bold',1,138240,51,24,5,0,-2,0,0,0,0,0,
"LSU")])
])
])]).
poly('black','',2,[
904,280,904,384],0,2,1,288448,0,0,5,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('black','',2,[
868,192,868,280],1,1,1,288459,0,0,0,0,0,0,0,'1',0,0,
"0","",[
0,8,3,0,'8','3','0'],[0,8,3,0,'8','3','0'],[
]).
text('black',896,508,1,1,1,10,20,288462,16,4,0,0,0,0,-65534,10,20,0,0,"",0,0,0,0,524,'',[
minilines(10,20,0,0,1,0,0,[
mini_line(10,16,4,0,0,0,[
str_block(0,10,16,4,0,-1,0,0,0,[
str_seg('black','Helvetica-Bold',1,97920,10,16,4,0,-1,0,0,0,0,0,
"E")])
])
])]).
text('black',600,508,1,1,1,10,20,288494,16,4,0,0,0,0,-65534,10,20,0,0,"",0,0,0,0,524,'',[
minilines(10,20,0,0,1,0,0,[
mini_line(10,16,4,0,0,0,[
str_block(0,10,16,4,0,-1,0,0,0,[
str_seg('black','Helvetica-Bold',1,97920,10,16,4,0,-1,0,0,0,0,0,
"E")])
])
])]).
text('black',296,508,1,1,1,10,20,288498,16,4,0,0,0,0,-65534,10,20,0,0,"",0,0,0,0,524,'',[
minilines(10,20,0,0,1,0,0,[
mini_line(10,16,4,0,0,0,[
str_block(0,10,16,4,0,-1,0,0,0,[
str_seg('black','Helvetica-Bold',1,97920,10,16,4,0,-1,0,0,0,0,0,
"E")])
])
])]).
group([
arc('black','',0,2,1,0,744,552,760,568,760,552,760,584,0,32,32,5760,11520,288353,0,0,10,4,0,0,0,'2','10','4',0,[
]),
poly('black','',4,[
760,552,776,552,776,584,760,584],0,2,1,288354,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
])
],
288516,0,0,[
]).
poly('black','',3,[
744,568,728,568,728,576],0,2,1,288522,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('black','',3,[
792,384,792,560,776,560],1,2,1,288531,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('black','',4,[
1028,384,1028,520,1028,520,1028,576],0,2,1,288539,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
group([
arc('black','',0,2,1,0,440,552,456,568,456,552,456,584,0,32,32,5760,11520,288315,0,0,10,4,0,0,0,'2','10','4',0,[
]),
poly('black','',4,[
456,552,472,552,472,584,456,584],0,2,1,288314,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
])
],
288544,0,0,[
]).
poly('black','',2,[
424,576,160,576],1,2,1,288560,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('black','',3,[
440,568,424,568,424,576],0,2,1,288561,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
group([
arc('black','',0,2,1,0,128,552,144,568,144,552,144,584,0,32,32,5760,11520,288574,0,0,10,4,0,0,0,'2','10','4',0,[
]),
poly('black','',4,[
144,552,160,552,160,584,144,584],0,2,1,288573,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
])
],
288572,0,0,[
]).
poly('black','',3,[
184,432,184,560,160,560],1,2,1,288581,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('black','',2,[
128,568,40,568],0,2,1,288588,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
text('black',600,476,1,1,1,12,20,288598,16,4,0,0,0,0,-65534,12,20,0,0,"",0,0,0,0,492,'',[
minilines(12,20,0,0,1,0,0,[
mini_line(12,16,4,0,0,0,[
str_block(0,12,16,4,0,-1,0,0,0,[
str_seg('black','Helvetica-Bold',1,97920,12,16,4,0,-1,0,0,0,0,0,
"C")])
])
])]).
oval('#A8322D','',536,492,544,500,0,2,1,288611,0,0,0,0,0,'2',0,[
]).
group([
arc('#A8322D','',0,2,1,0,544,472,560,488,560,472,560,504,1,32,32,5760,-11520,288605,0,0,10,4,0,0,0,'2','10','4',0,[
]),
poly('#A8322D','',4,[
560,472,544,472,544,504,560,504],0,2,1,288604,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
])
],
288603,0,0,[
]).
poly('#A8322D','',3,[
512,576,512,480,544,480],0,2,1,288629,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#3C5A0F','',4,[
568,520,528,520,528,496,536,496],0,2,1,288632,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#A8322D','',2,[
576,488,592,488],0,2,1,288639,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
oval('#A8322D','',832,492,840,500,0,2,1,288653,0,0,0,0,0,'2',0,[
]).
group([
arc('#A8322D','',0,2,1,0,840,472,856,488,856,472,856,504,1,32,32,5760,-11520,288656,0,0,10,4,0,0,0,'2','10','4',0,[
]),
poly('#A8322D','',4,[
856,472,840,472,840,504,856,504],0,2,1,288655,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
])
],
288654,0,0,[
]).
poly('#A8322D','',3,[
808,576,808,480,840,480],0,2,1,288657,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#A8322D','',2,[
872,488,888,488],0,2,1,288658,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#3C5A0F','',4,[
864,520,824,520,824,496,832,496],0,2,1,288668,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
oval('#A8322D','',232,492,240,500,0,2,1,288675,0,0,0,0,0,'2',0,[
]).
group([
arc('#A8322D','',0,2,1,0,240,472,256,488,256,472,256,504,1,32,32,5760,-11520,288678,0,0,10,4,0,0,0,'2','10','4',0,[
]),
poly('#A8322D','',4,[
256,472,240,472,240,504,256,504],0,2,1,288677,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
])
],
288676,0,0,[
]).
poly('#A8322D','',3,[
208,576,208,480,240,480],0,2,1,288679,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#A8322D','',2,[
272,488,288,488],0,2,1,288680,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
poly('#3C5A0F','',4,[
256,520,224,520,224,496,232,496],0,2,1,288682,0,0,0,0,0,0,0,'2',0,0,
"0","",[
0,10,4,0,'10','4','0'],[0,10,4,0,'10','4','0'],[
]).
text('black',296,476,1,1,1,12,20,288685,16,4,0,0,0,0,-65534,12,20,0,0,"",0,0,0,0,492,'',[
minilines(12,20,0,0,1,0,0,[
mini_line(12,16,4,0,0,0,[
str_block(0,12,16,4,0,-1,0,0,0,[
str_seg('black','Helvetica-Bold',1,97920,12,16,4,0,-1,0,0,0,0,0,
"C")])
])
])]).
text('black',896,476,1,1,1,12,20,288687,16,4,0,0,0,0,-65534,12,20,0,0,"",0,0,0,0,492,'',[
minilines(12,20,0,0,1,0,0,[
mini_line(12,16,4,0,0,0,[
str_block(0,12,16,4,0,-1,0,0,0,[
str_seg('black','Helvetica-Bold',1,97920,12,16,4,0,-1,0,0,0,0,0,
"C")])
])
])]).

View file

@ -55,6 +55,8 @@
\usepackage{enumitem}
\usepackage{tcolorbox}
\usepackage{pdflscape}
@ -115,3 +117,10 @@
\textbf{Operation:} \texttt{#2}%
}
\newenvironment{boxnote}%
{%
\begin{tcolorbox}[colback=red!5!white,colframe=red!75!black,title=Note]%
}%
{%
\end{tcolorbox}%
}%

View file

@ -64,7 +64,7 @@ module riscv_exc_controller
);
enum logic [1:0] { IDLE, WAIT_CONTROLLER, IN_ISR } exc_ctrl_cs, exc_ctrl_ns;
enum logic [0:0] { IDLE, WAIT_CONTROLLER } exc_ctrl_cs, exc_ctrl_ns;
logic req_int;
logic [1:0] pc_mux_int, pc_mux_int_q;
@ -173,7 +173,7 @@ module riscv_exc_controller
if (ack_i) begin
save_cause_o = 1'b1;
exc_ctrl_ns = IN_ISR;
exc_ctrl_ns = IDLE;
end
end
end
@ -184,16 +184,10 @@ module riscv_exc_controller
if (ack_i) begin
save_cause_o = 1'b1;
exc_ctrl_ns = IN_ISR;
exc_ctrl_ns = IDLE;
end
end
IN_ISR:
begin
if (eret_insn_i)
exc_ctrl_ns = IDLE;
end
default:
begin
exc_ctrl_ns = IDLE;

View file

@ -140,7 +140,8 @@ module riscv_id_stage
output logic [5:0] exc_cause_o,
output logic save_exc_cause_o,
output logic save_pc_id_o,
output logic exc_save_id_o,
output logic exc_restore_id_o,
input logic lsu_load_err_i,
input logic lsu_store_err_i,
@ -714,7 +715,8 @@ module riscv_id_stage
.exc_ack_o ( exc_ack ),
.trap_hit_i ( trap_hit ),
.save_pc_id_o ( save_pc_id_o ),
.exc_save_id_o ( exc_save_id_o ),
.exc_restore_id_o ( exc_restore_id_o ),
// Debug Unit Signals
.dbg_stall_i ( dbg_stall_i ),

View file

@ -29,6 +29,7 @@
// no traces for synthesis, they are not synthesizable
`ifndef SYNTHESIS
`define TRACE_EXECUTION
//`define SIMCHECKER
`endif

View file

@ -190,11 +190,12 @@ module riscv_core
// Interrupts
logic irq_enable;
logic [31:0] epcr;
logic [31:0] mepc;
logic [5:0] exc_cause;
logic save_exc_cause;
logic save_pc_id;
logic exc_save_id;
logic exc_restore_id;
// Hardware loop controller signals
@ -280,7 +281,7 @@ module riscv_core
// control signals
.clear_instr_valid_i ( clear_instr_valid ),
.pc_set_i ( pc_set ),
.exception_pc_reg_i ( epcr ), // exception return address
.exception_pc_reg_i ( mepc ), // exception return address
.pc_mux_i ( pc_mux_id ), // sel for pc multiplexer
.exc_pc_mux_i ( exc_pc_mux_id ),
.exc_vec_pc_mux_i ( exc_vec_pc_mux_id ),
@ -425,7 +426,8 @@ module riscv_core
.irq_enable_i ( irq_enable ), // global interrupt enable
.exc_cause_o ( exc_cause ),
.save_exc_cause_o ( save_exc_cause ),
.save_pc_id_o ( save_pc_id ), // control signal to save pc
.exc_save_id_o ( exc_save_id ), // control signal to save pc
.exc_restore_id_o ( exc_restore_id ), // control signal to restore pc
.lsu_load_err_i ( lsu_load_err ),
.lsu_store_err_i ( lsu_store_err ),
@ -611,10 +613,11 @@ module riscv_core
// Interrupt related control signals
.irq_enable_o ( irq_enable ),
.epcr_o ( epcr ),
.mepc_o ( mepc ),
.curr_pc_id_i ( current_pc_id ), // from IF stage
.save_pc_id_i ( save_pc_id ),
.exc_save_i ( exc_save_id ),
.exc_restore_i ( exc_restore_id ),
.exc_cause_i ( exc_cause ),
.save_exc_cause_i ( save_exc_cause ),
@ -715,47 +718,98 @@ module riscv_core
`ifdef TRACE_EXECUTION
riscv_tracer riscv_tracer_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.clk ( clk ),
.rst_n ( rst_n ),
.core_id ( core_id_i ),
.cluster_id ( cluster_id_i ),
.fetch_enable ( fetch_enable_i ),
.core_id ( core_id_i ),
.cluster_id ( cluster_id_i ),
.pc ( id_stage_i.current_pc_id_i ),
.instr ( id_stage_i.instr ),
.compressed ( id_stage_i.is_compressed_i ),
.id_valid ( id_stage_i.id_valid_o ),
.is_decoding ( id_stage_i.is_decoding_o ),
.pipe_flush ( id_stage_i.controller_i.pipe_flush_i ),
.pc ( id_stage_i.current_pc_id_i ),
.instr ( id_stage_i.instr ),
.compressed ( id_stage_i.is_compressed_i ),
.id_valid ( id_stage_i.id_valid_o ),
.is_decoding ( id_stage_i.is_decoding_o ),
.pipe_flush ( id_stage_i.controller_i.pipe_flush_i ),
.rs1_value ( id_stage_i.operand_a_fw_id ),
.rs2_value ( id_stage_i.operand_b_fw_id ),
.rs3_value ( id_stage_i.alu_operand_c ),
.rs1_value ( id_stage_i.operand_a_fw_id ),
.rs2_value ( id_stage_i.operand_b_fw_id ),
.rs3_value ( id_stage_i.alu_operand_c ),
.ex_valid ( ex_valid ),
.ex_reg_addr ( regfile_alu_waddr_fw ),
.ex_reg_we ( regfile_alu_we_fw ),
.ex_reg_wdata ( regfile_alu_wdata_fw ),
.ex_valid ( ex_valid ),
.ex_reg_addr ( regfile_alu_waddr_fw ),
.ex_reg_we ( regfile_alu_we_fw ),
.ex_reg_wdata ( regfile_alu_wdata_fw ),
.ex_data_addr ( data_addr_o ),
.ex_data_req ( data_req_o ),
.ex_data_gnt ( data_gnt_i ),
.ex_data_we ( data_we_o ),
.ex_data_wdata ( data_wdata_o ),
.ex_data_addr ( data_addr_o ),
.ex_data_req ( data_req_o ),
.ex_data_gnt ( data_gnt_i ),
.ex_data_we ( data_we_o ),
.ex_data_wdata ( data_wdata_o ),
.wb_valid ( wb_valid ),
.wb_reg_addr ( regfile_waddr_fw_wb_o ),
.wb_reg_we ( regfile_we_wb ),
.wb_reg_wdata ( regfile_wdata ),
.wb_valid ( wb_valid ),
.wb_reg_addr ( regfile_waddr_fw_wb_o ),
.wb_reg_we ( regfile_we_wb ),
.wb_reg_wdata ( regfile_wdata ),
.imm_u_type ( id_stage_i.imm_u_type ),
.imm_uj_type ( id_stage_i.imm_uj_type ),
.imm_i_type ( id_stage_i.imm_i_type ),
.imm_iz_type ( id_stage_i.imm_iz_type[11:0] ),
.imm_z_type ( id_stage_i.imm_z_type ),
.imm_s_type ( id_stage_i.imm_s_type ),
.imm_sb_type ( id_stage_i.imm_sb_type )
.imm_u_type ( id_stage_i.imm_u_type ),
.imm_uj_type ( id_stage_i.imm_uj_type ),
.imm_i_type ( id_stage_i.imm_i_type ),
.imm_iz_type ( id_stage_i.imm_iz_type[11:0] ),
.imm_z_type ( id_stage_i.imm_z_type ),
.imm_s_type ( id_stage_i.imm_s_type ),
.imm_sb_type ( id_stage_i.imm_sb_type )
);
`endif
`ifdef SIMCHECKER
logic is_interrupt;
assign is_interrupt = (pc_mux_id == `PC_EXCEPTION) && (exc_pc_mux_id == `EXC_PC_IRQ);
riscv_simchecker riscv_simchecker_i
(
.clk ( clk ),
.rst_n ( rst_n ),
.fetch_enable ( fetch_enable_i ),
.boot_addr ( boot_addr_i ),
.core_id ( core_id_i ),
.cluster_id ( cluster_id_i ),
.instr_compressed ( if_stage_i.fetch_rdata[15:0] ),
.pc_set ( pc_set ),
.if_valid ( if_valid ),
.pc ( id_stage_i.current_pc_id_i ),
.instr ( id_stage_i.instr ),
.is_compressed ( is_compressed_id ),
.id_valid ( id_stage_i.id_valid_o ),
.is_decoding ( id_stage_i.is_decoding_o ),
.is_illegal ( id_stage_i.illegal_insn_dec ),
.is_interrupt ( is_interrupt ),
.irq_no ( exc_vec_pc_mux_id ),
.pipe_flush ( id_stage_i.controller_i.pipe_flush_i ),
.ex_valid ( ex_valid ),
.ex_reg_addr ( id_stage_i.registers_i.waddr_b_i ),
.ex_reg_we ( id_stage_i.registers_i.we_b_i ),
.ex_reg_wdata ( id_stage_i.registers_i.wdata_b_i ),
.ex_data_addr ( data_addr_o ),
.ex_data_req ( data_req_o ),
.ex_data_gnt ( data_gnt_i ),
.ex_data_we ( data_we_o ),
.ex_data_wdata ( data_wdata_o ),
.lsu_misaligned ( data_misaligned ),
.wb_valid ( wb_valid ),
.wb_reg_addr ( id_stage_i.registers_i.waddr_a_i ),
.wb_reg_we ( id_stage_i.registers_i.we_a_i ),
.wb_reg_wdata ( id_stage_i.registers_i.wdata_a_i ),
.wb_data_rvalid ( data_rvalid_i ),
.wb_data_rdata ( data_rdata_i )
);
`endif

309
riscv_simchecker.sv Normal file
View file

@ -0,0 +1,309 @@
// Copyright 2015 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
////////////////////////////////////////////////////////////////////////////////
// Engineer: Andreas Traber - atraber@iis.ee.ethz.ch //
// //
// Additional contributions by: //
// //
// Design Name: RISC-V Tracer //
// Project Name: RI5CY //
// Language: SystemVerilog //
// //
// Description: Compares the executed instructions with a golden model //
// //
////////////////////////////////////////////////////////////////////////////////
import "DPI-C" function chandle riscv_checker_init(input int boot_addr, input int core_id, input int cluster_id);
import "DPI-C" function int riscv_checker_step(input chandle cpu, input longint simtime, input int cycle, input logic [31:0] pc, input logic [31:0] instr);
import "DPI-C" function void riscv_checker_irq(input chandle cpu, input int irq, input int irq_no);
import "DPI-C" function void riscv_checker_mem_access(input chandle cpu, input int we, input logic [31:0] addr, input logic [31:0] data);
import "DPI-C" function void riscv_checker_reg_access(input chandle cpu, input logic [31:0] addr, input logic [31:0] data);
module riscv_simchecker
(
// Clock and Reset
input logic clk,
input logic rst_n,
input logic fetch_enable,
input logic [31:0] boot_addr,
input logic [4:0] core_id,
input logic [4:0] cluster_id,
input logic [15:0] instr_compressed,
input logic if_valid,
input logic pc_set,
input logic [31:0] pc,
input logic [31:0] instr,
input logic is_compressed,
input logic id_valid,
input logic is_decoding,
input logic is_illegal,
input logic is_interrupt,
input logic [4:0] irq_no,
input logic pipe_flush,
input logic ex_valid,
input logic [ 4:0] ex_reg_addr,
input logic ex_reg_we,
input logic [31:0] ex_reg_wdata,
input logic ex_data_req,
input logic ex_data_gnt,
input logic ex_data_we,
input logic [31:0] ex_data_addr,
input logic [31:0] ex_data_wdata,
input logic lsu_misaligned,
input logic wb_valid,
input logic [ 4:0] wb_reg_addr,
input logic wb_reg_we,
input logic [31:0] wb_reg_wdata,
input logic wb_data_rvalid,
input logic [31:0] wb_data_rdata
);
// DPI stuff
chandle dpi_simdata;
// SV-only stuff
typedef struct {
logic [ 4:0] addr;
logic [31:0] value;
} reg_t;
typedef struct {
logic [31:0] addr;
logic we;
logic [ 3:0] be;
logic [31:0] wdata;
logic [31:0] rdata;
} mem_acc_t;
class instr_trace_t;
time simtime;
int cycles;
logic [31:0] pc;
logic [31:0] instr;
logic irq;
logic [ 4:0] irq_no;
reg_t regs_write[$];
mem_acc_t mem_access[$];
function new ();
irq = 1'b0;
regs_write = {};
mem_access = {};
endfunction
endclass
mailbox rdata_stack = new (4);
integer rdata_writes = 0;
integer cycles;
logic [15:0] instr_compressed_id;
logic is_irq_if, is_irq_id;
logic [ 4:0] irq_no_id, irq_no_if;
mailbox instr_ex = new (2);
mailbox instr_wb = new (2);
// simchecker initialization
initial
begin
wait(rst_n == 1'b1);
wait(fetch_enable == 1'b1);
dpi_simdata = riscv_checker_init(boot_addr, core_id, cluster_id);
end
// virtual ID/EX pipeline
initial
begin
instr_trace_t trace;
mem_acc_t mem_acc;
reg_t reg_write;
while(1) begin
instr_ex.get(trace);
// wait until we are going to the next stage
do begin
@(negedge clk);
reg_write.addr = ex_reg_addr;
reg_write.value = ex_reg_wdata;
if (ex_reg_we)
trace.regs_write.push_back(reg_write);
// look for data accesses and log them
if (ex_data_req && ex_data_gnt) begin
mem_acc.addr = ex_data_addr;
mem_acc.we = ex_data_we;
if (mem_acc.we)
mem_acc.wdata = ex_data_wdata;
else
mem_acc.wdata = 'x;
trace.mem_access.push_back(mem_acc);
end
end while (!ex_valid || lsu_misaligned);
instr_wb.put(trace);
end
end
// virtual EX/WB pipeline
initial
begin
instr_trace_t trace;
reg_t reg_write;
logic [31:0] tmp_discard;
while(1) begin
instr_wb.get(trace);
// wait until we are going to the next stage
do begin
@(negedge clk);
#1;
// pop rdata from stack when there were pending writes
while(rdata_stack.num() > 0 && rdata_writes > 0) begin
rdata_writes--;
rdata_stack.get(tmp_discard);
end
end while (!wb_valid);
reg_write.addr = wb_reg_addr;
reg_write.value = wb_reg_wdata;
if (wb_reg_we)
trace.regs_write.push_back(reg_write);
// keep care of rdata
foreach(trace.mem_access[i]) begin
if (trace.mem_access[i].we) begin
// for writes we don't need to wait for the rdata, so if it has
// not appeared yet, we count it and remove it later from out
// stack
rdata_writes++;
end else begin
if (rdata_stack.num() == 0)
$warning("rdata stack is empty, but we are waiting for a read");
rdata_stack.get(trace.mem_access[i].rdata);
end
end
// instruction is ready now, all data is inserted
foreach(trace.mem_access[i]) begin
if (trace.mem_access[i].we)
riscv_checker_mem_access(dpi_simdata, trace.mem_access[i].we, trace.mem_access[i].addr, trace.mem_access[i].wdata);
else
riscv_checker_mem_access(dpi_simdata, trace.mem_access[i].we, trace.mem_access[i].addr, trace.mem_access[i].rdata);
end
foreach(trace.regs_write[i]) begin
riscv_checker_reg_access(dpi_simdata, trace.regs_write[i].addr, trace.regs_write[i].value);
end
riscv_checker_irq(dpi_simdata, trace.irq, trace.irq_no);
if (riscv_checker_step(dpi_simdata, trace.simtime, trace.cycles, trace.pc, trace.instr))
$display("%t: Cluster %d, Core %d: Mismatch between simulator and RTL detected", trace.simtime, cluster_id, core_id);
end
end
// cycle counter
always_ff @(posedge clk, negedge rst_n)
begin
if (rst_n == 1'b0)
cycles = 0;
else
cycles = cycles + 1;
end
// create rdata stack
initial
begin
while(1) begin
@(negedge clk);
if (wb_data_rvalid) begin
rdata_stack.put(wb_data_rdata);
end
end
end
always_ff @(posedge clk)
begin
if (pc_set) begin
is_irq_if <= is_interrupt;
irq_no_if <= irq_no;
end else if (if_valid) begin
is_irq_if <= 1'b0;
end
end
always_ff @(posedge clk)
begin
if (if_valid) begin
instr_compressed_id <= instr_compressed;
is_irq_id <= is_irq_if;
irq_no_id <= irq_no_if;
end
end
// log execution
initial
begin
instr_trace_t trace;
while(1) begin
@(negedge clk);
// - special case for WFI because we don't wait for unstalling there
// - special case for illegal instructions, since they will not go through
// the pipe
if ((id_valid && is_decoding) || pipe_flush || (is_decoding && is_illegal))
begin
trace = new ();
trace.simtime = $time;
trace.cycles = cycles;
trace.pc = pc;
if (is_compressed)
trace.instr = {instr_compressed_id, instr_compressed_id};
else
trace.instr = instr;
if (is_irq_id) begin
trace.irq = 1'b1;
trace.irq_no = irq_no_id;
end
instr_ex.put(trace);
end
end
end
endmodule

View file

@ -30,6 +30,7 @@ module riscv_tracer
input logic clk,
input logic rst_n,
input logic fetch_enable,
input logic [4:0] core_id,
input logic [4:0] cluster_id,
@ -67,7 +68,6 @@ module riscv_tracer
input logic [31:0] imm_z_type,
input logic [31:0] imm_s_type,
input logic [31:0] imm_sb_type
);
integer f;
@ -187,7 +187,7 @@ module riscv_tracer
function void printUInstr(input string mnemonic);
begin
regs_write.push_back({rd, 'x});
str = $sformatf("%-16s x%0d, 0x%0h000", mnemonic, rd, imm_u_type[31:12]);
str = $sformatf("%-16s x%0d, 0x%0h", mnemonic, rd, {imm_u_type[31:12], 12'h000});
end
endfunction // printUInstr
@ -375,11 +375,13 @@ module riscv_tracer
// open/close output file for writing
initial
begin
#1 // delay needed for valid core_id and cluster_id
wait(rst_n == 1'b1);
wait(fetch_enable == 1'b1);
$sformat(fn, "trace_core_%h_%h.log", cluster_id, core_id);
$display("[TRACER] Output filename is: %s", fn);
f = $fopen(fn, "w");
$fwrite(f, "%20s\t%6s\t%10s\t%10s\t \t%s\n", "Time", "Cycles", "PC", "Instr", "Mnemonic");
$fwrite(f, " Time Cycles PC Instr Mnemonic\n");
end
final
@ -403,7 +405,7 @@ module riscv_tracer
// wait until we are going to the next stage
do begin
@(posedge clk);
@(negedge clk);
// replace register written back
foreach(trace.regs_write[i])
@ -438,7 +440,7 @@ module riscv_tracer
// wait until we are going to the next stage
do begin
@(posedge clk);
@(negedge clk);
// replace register written back
foreach(trace.regs_write[i])
@ -451,7 +453,7 @@ module riscv_tracer
end
// log execution
always @(posedge clk)
always @(negedge clk)
begin
instr_trace_t trace;
@ -502,10 +504,10 @@ module riscv_tracer
`INSTR_SRA: trace.printRInstr("sra");
`INSTR_OR: trace.printRInstr("or");
`INSTR_AND: trace.printRInstr("and");
`INSTR_EXTHS: trace.printRInstr("exths");
`INSTR_EXTHZ: trace.printRInstr("exthz");
`INSTR_EXTBS: trace.printRInstr("extbs");
`INSTR_EXTBZ: trace.printRInstr("extbz");
`INSTR_EXTHS: trace.printRInstr("p.exths");
`INSTR_EXTHZ: trace.printRInstr("p.exthz");
`INSTR_EXTBS: trace.printRInstr("p.extbs");
`INSTR_EXTBZ: trace.printRInstr("p.extbz");
`INSTR_PAVG: trace.printRInstr("p.avg");
`INSTR_PAVGU: trace.printRInstr("p.avgu");
`INSTR_PSLET: trace.printRInstr("p.slet");
@ -545,7 +547,4 @@ module riscv_tracer
end
end // always @ (posedge clk)
endmodule