Lecture 15: RTL (Register Transfer Language)
Register Transfer Language and
Verilog • Designing processors at the gate level is difficult
• Use a higher-level language
COS / ELE 375 RTL: a language for describing the behavior of computers
in terms of step-wise register contents
Computer Architecture and Organization
Princeton University
Fall 2015
Bochao Wang
(Based on slides by David Penry and Neil Vachharajani)
(Prof. David August)
1 2
RTL Tools Hardware Description Languages
RTL, just like (most) programming languages: • Used to describe hardware for simulation and synthesis
• Precise and unambiguous • Why? Designs are too big to just draw schematics
• Programmer must debug
• Major languages:
• Code can be checked automatically for certain • Verilog
properties • Cadence, Inc.
• Type checking • Emphasis on practical use (I/O well-defined, ability to record)
• Possibly most widely used
• Check RTL model against more abstract state machine
• VHDL
• Tools can process the code • Department of Defence
• RTL simulator • Emphasis on abstraction (derived from Ada)
• Popular in academic circles, Europe; required of defence contractors
• RTL processor
• SystemC
• Synopsys, Inc.
• RTL • Emphasis is “higher-level” simulation – really just a C++ template library
• Up-and-coming
3 4
Simulation vs. Synthesis Verilog Design Flow
• HDLs are used for both simulation and synthesis
• Simulation: does the design work?
• Can also be used for “does the design meet timing?”
• Synthesis: generate a circuit that is equivalent
• Recognize state and combinational logic
• Optimize the circuit
Not all valid HDL programs are synthesizable
5 6
Example Modified Example
Modules have initial, continuous, and always blocks
• Use assign statement for combinational circuit
• Note the bit-wise operators (implies wire width…)
7 8
Basic syntax
• ; is the statement terminator (terminator, not
separator)
• /* */ for multi-line comments
Elements of Verilog • // can be used for single-line comments
• Constants can have bit-width and radix:
<bit-width>’<radix><val>
32’h1234ab34 = 1234ab3416
8’b0100_0110 = 010001102 ; note that underlines are legal
9 10
Datatypes Module Overall Structure
• 4-valued logic: 0, 1, x, z module the_design ( input, output );
• 0, 1 – normal binary 0 and 1 Declarations: ports, constants, variables(wire, reg)
• z – high-impedance value: this is what tri-state buffers drive Instantiations of other modules
when they are off Continuous assignment: assign y = ...
• x – simulator doesn’t know; sometimes used as “don’t care” Behavioral statements (initial, always) {
procedural blocking assignment
• Integers – don’t use these outside of test benches procedural nonblocking assignment
}
• At simulation start, all signals have x’s in every bit endmodule
• Unconnected inputs to a module have value ‘z’.
11 12
Signals Wires
• Signal: a “variable” that can have values assigned “ahead of time” • Wires need not be declared unless it is multiple wires
• Can be thought of as a wire or a group of wires
• Syntax:
module example(b, c);
<kind> [<width specifier>] name, name, …;
input b;
• Examples: output c;
reg [15:0] IR;
wire a; // not necessary
wire [3:0] a; a[3] is MSB
wire [1:8] b; b[1] is MSB //not recommend wire [3:0] d; // necessary
wire doit; …
assign c = b | a;
• Registers vs. wires:
• Reg: inside “always” block, lhs, e.g. IR = …
endmodule
• Wire: outside “always” block, lhs, e.g. assign a = …
13 14
Register Transfer Language? Module Overall Structure
• Variables correspond to the hardware registers
• “always” blocks module the_design ( input, output );
Declarations: ports, constants, variables(wire, reg)
Instantiations of other modules
Module D_FlipFlop(Q, D, CLK);
Continuous assignment: assign y = ...
output Q; Processes(initial, always) {
reg Q; procedural blocking assignment
input D, CLK; procedural nonblocking assignment
always @(negedge CLK) // Sensitivity List }
begin // Not needed for 1 statement endmodule
Q <= D; // Note: No assign
end
endmodule
15 16
Modules Module Overall Structure
• Allow you to organize the design hierarchically module the_design ( input, output );
• Allow structural reuse of the design Declarations: ports, constants, variables(wire, reg)
Instantiations of other modules
• Defining a module: Continuous assignment: assign y = ...
• Example: Processes(initial, always) {
module flop (clk, D, Q); // name, list of ports
procedural blocking assignment
input clk; // define directions of ports
input D; procedural nonblocking assignment
output Q; }
…. // code to do things
endmodule
endmodule
• Instantiating a module:
flop U1 (.clk(someclk), .D(someD), .Q(someQ));
17 18
Kinds of assignments Assignment
• Continuous (assign = )
• Only to “wire”
• Always sensitive to things on the right-hand side a = b Do Sequentially (blocking, sequentially)
A <= b Do RHS first (nonblocking, grab at t=0)
• Blocking ( = )
• Made inside a process
• Only to “reg”
• Value of lhs changes immediately Which 3 are Shift Registers?
• Non-blocking ( <= ) Z<=Y; Y<=X;
• Made inside a process Y<=X; Z<=Y;
• Only to “reg”
• Value of lhs changes only after all rhs have been evaluated
Z=Y; Y=X;
• A time-spec after the statement says to wait before changing the value Y=X; Z=Y;
• Continue executing process even if there is a time-spec
19 20
Processes Process examples
• A group of sequential statements; three kinds: reg rst_l, Q;
• Initial - runs only at simulation start wire cachehit;
• Always – runs over and over
• Continuous – special syntax for a common kind of always block initial begin
rst_l = 0;
#300;
• Can be suspended, waiting for something to happen
rst_l = 1;
• For a signal in a group of signals to change
end
• For an amount of time to pass
• For a signal to become true (I’ve never needed this)
always @(posedge clk)
Q <= #1 D;
assign cachehit = comparator_matches & valid;
21 22
Assignment examples Blocking a process
reg rst_l, Q; • Wait for signals to change:
wire cachehit; always @(signal1 or signal2)
initial begin • Wait for a signal edge:
rst_l = 0; // blocking always @(posedge clk or negedge rst_l)
#300;
rst_l = 1; // blocking • Wait for time:
# 300;
end
# 300 a = b; // can also put before a statement
always @(posedge clk)
• Wait for logical value:
Q <= #1 D; // non-blocking wait(b); // I’ve never used this
assign cachehit = comparator_matches &
valid; // continuous
23 24
Operators Statements
• Most of the operators look like C: • Control structures
• Bitwise operators: &, |, ~, ^ • C-like: if, while, for
• Logical operators: &&, ||, ! • forever – do following statement forever
• Comparisons: ==, !=, <, <=, >, >= • repeat (<#>) – do following statement a number of times
• If either operand is x or z, they return FALSE.
• case (see next slide)
• Arithmetic: +, -, *, /, %, <<, >>
• Choice: ?:
• Parallel control structures
• Order of operations may differ from C; use parenthesis • fork/join – do statements in between in parallel
• Special operators: • Signal overrides
• Comparison with x or z values: ===, !== • force – override the value of a signal
• Bitwise operators can be used as reduction operators: • release – stop overriding the value of a signal
(|x) = or all the bits of x together.
25 26
Case statements Example: 4 to 1 Mux
• Rather different from C switch statements: module mux4_to_1 (out, i0, i1, i2, i3, s1, s0);
case (myvar) output out;
input i0, i1, i2, i3;
1 : dothis = 1;
input s1, s0;
2 : dothat = 3;
reg out;
3 : dosomemore = 4; always @(s1 or s0 or i0 or i1 or i2 or i3)
default: noneoftheabove = 1; begin
endcase case ({s1, s0})
2'b00: out = i0;
2'b01: out = i1;
• Note that there are no fall-throughs 2'b10: out = i2;
• Multiple statements inside one case require begin/end 2'b11: out = i3;
around them default: out = 1'bx; // x is don’t care
endcase
end
endmodule
27 28
Parameters Using the mux module
• Increases ability to reuse modules • It’s a 4-input mux for busses with a ‘width’ parameter for the size
of the bus
• Defining a parameter (with a default value): wire [7:0] A,B,C,D, result;
parameter me = 3; wire [1:0] sel;
• Overriding the default value mux4 mymux (.out(result), .in0(A), .in1(B),
defparam myunit.me = 4; .in2(C), .in3(D), .sel(sel));
defparam mymux.width = 8;
• Can also use a #(value) syntax when instantiating for modules
with small numbers of parameters: OR
e.g. module my_module #( parameter BIT_WIDTH = 32, …)
(input clk, input [BIT_WIDTH-1:0] addr, output a…) mux4 #(8) mymux (.out(result), .in0(A), .in1(B),
.in2(C), .in3(D), .sel(sel));
29 30
Preprocessor directives A Sample Finite State Machine
reg [1:0] state;
`define IDLE 2’b00
• Always begin with a back-tick `define READ 2’b01
`define WRITE 2’b10
• `define name value `define DONE 2’b11
• defined values are referenced as `name always @(posedge clk or negedge rst_l)
if (~rst_l) state <= `IDLE;
else
case (state)
`IDLE:
if (req)
if (wr) state <= `WRITE;
else state <= `READ;
else state <= `IDLE; // not strictly necessary
`READ:
state <= `DONE;
`WRITE:
state <= `DONE;
`DONE:
state <= `IDLE;
default:
state <= `IDLE;
endcase
31 32
Dealing with Synthesis My Rules
• Things you can’t synthesize reliably: • Make all flops (edge-sensitive always blocks) use a non-blocking
• Some for loops (hard to guess) assigment with #1 delay
• @() in the middle of a process • Easier to see what’s going on in waverforms
• Time specifiers
• force/release
• Make all other always blocks use blocking assignment and use
complete sensitivity lists
• Watch out for hidden latches! • always @(*) for next state logic combinational
always @(a)
• always @(posedge clk) for sequential
c = a | b;
• Actually creates a latch
• All things on the rhs must go on the sensitivity list unless you are • Do combinational logic in continuous assignments except for next
trying to create a state element state logic
• Using don’t cares:
• If you really don’t care about a value, assign x to it, and the synthesis
tool will choose a value which simplifies the logic
33 34
Another Sample Finite State Machine
Thank you
35 36
Using the regfile2 module Functions and tasks
• You should use this module for your register file. • Functions are like C functions, but cannot have side effects
• It synthesizes properly • Tasks do not have return values, but can have side effects
• It has a nice task for displaying the register file contents
• Examples:
• Interesting characteristics: function [31:0] add1;
input [31:0] x;
• One read ports, one read/write port
begin
• Port A writes if the enable bits are set (bytes are controlled add1 = x + 1;
individually); it will always read as well
end
• Port B can only read endfunction
• Clocked on the positive edge of the clock (you can’t do the write in first
half, read in second half trick from P & H) task addtask;
input [31:0] x;
• If you name your datapath DATA (the instance name, not the output [31:0] y;
module name), and make IR_Enable a signal indicating when the begin
IR is to be loaded with a new instruction, you can uncomment code y = x + 1;
in monitors.v to get automatic register dumps before each mycrazysignal = 3;
instruction. end
endtask
37 38
I/O Simulation control
• Displaying data: • $finish; – end simulation and exit the simulator
$display(<format string>, ….);
• Like printf, but • $stop; – stop simulating; go to the command-line interface
• %b gives binary; %h gives hex
• %t formats a time value
• automatically puts on a newline
• Recording signals:
• $dumpfile(<file name>); – set the dumpfile name
• $dumpvars(<# levels>, <hierarchy>);
• Adds signals below a particular point in the hierarchy to the list of signals to
dump; only decends the hierarchy for the number of levels specified; 0
means no limit
• $dumpon; - turns on dumping
• $dumpoff; - turns off dumping
39 40