Tutorial: Incisive Enterprise Specman Elite Testbench
Tutorial: Incisive Enterprise Specman Elite Testbench
Tutorial
©1998-2013 Cadence Design Systems, Inc. All rights reserved worldwide.
Printed in the United States of America.
Cadence Design Systems, Inc. (Cadence), 2655 Seely Ave., San Jose, CA 95134, USA.
This product contains third party software. Please refer to <install_dir>/doc/thirdpartyinfo/SPMNthirdpartyinfo.txt to review
copyright & licensing terms.
Trademarks: Trademarks and service marks of Cadence Design Systems, Inc. contained in this document are attributed to
Cadence with the appropriate symbol. For queries regarding Cadence’s trademarks, contact the corporate legal department at
the address shown above or call 800.862.4522. All other trademarks are the property of their respective holders.
Open SystemC, Open SystemC Initiative, OSCI, SystemC, and SystemC Initiative are trademarks or registered trademarks of
Open SystemC Initiative, Inc. in the United States and other countries and are used with permission.
Restricted Permission: This publication is protected by copyright law and international treaties and contains trade secrets
and proprietary information owned by Cadence. Unauthorized reproduction or distribution of this publication, or any portion
of it, may result in civil and criminal penalties. Except as specified in this permission statement, this publication may not be
copied, reproduced, modified, published, uploaded, posted, transmitted, or distributed in any way, without prior written
permission from Cadence. Unless otherwise agreed to by Cadence in writing, this statement grants Cadence customers
permission to print one (1) hard copy of this publication subject to the following conditions:
1. The publication may be used only in accordance with a written agreement between Cadence and its customer;
2. The publication may not be modified in any way;
3. Any authorized copy of the publication or portion thereof must include all original copyright, trademark, and other
proprietary notices and this permission statement;
4. The information contained in this document cannot be used in the development of like products or software, whether
for internal or external use, and shall not be used for the benefit of any other party, whether or not for consideration
Disclaimer: Information in this publication is subject to change without notice and does not represent a commitment on the
part of Cadence. Except as may be explicitly set forth in such agreement, Cadence does not make, and expressly disclaims, any
representations or warranties as to the completeness, accuracy or usefulness of the information contained in this document.
Cadence does not warrant that use of such information will not infringe any third party rights, nor does Cadence assume any
liability for damages or costs of any kind that may result from use of such information.
Restricted Rights: Use, duplication, or disclosure by the Government is subject to restrictions as set forth in FAR52.227-
14 and DFAR252.227-7013 et seq. or its successor.
Contents
1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1-1
Tutorial Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-1
Tutorial Goals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-3
Accessing the Specman Software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4
Setting up the Tutorial Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4
Document Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-5
iv Specman Tutorial
Specman Tutorial v
vi Specman Tutorial
Tutorial Overview
Incisive® Enterprise Specman Elite® Testbench provides benefits that result in:
• Easily capture your design specifications to set up an accurate and appropriate verification
environment
• Quickly and effectively create as many tests as you need
• Create self-checking modules that include protocols checking
• Accurately identify when your verification cycle is complete
The Specman system provides three main enabling technologies that enhance your productivity:
Figure 1-1 shows the main component technologies of the Specman system and its interface with an
HDL simulator.
HDL simulator
Tutorial Goals
The goal of this tutorial is to give you first-hand experience in how the Specman system effectively
addresses functional verification challenges.
As you work through the tutorial, you follow the process described in Figure 1-2. The tutorial uses the
Specman system to create a verification environment for a simple CPU design.
Generate constraint-
driven tests
Create corner-case
tests
When the “e” directory is extracted, it should match the following listing.
gold:
cpu_bypass.e cpu_dut.e cpu_top.e
cpu_checker.e cpu_instr.e cpu_tst1.e
cpu_cover.e cpu_misc.e cpu_tst2.e
cpu_cover_extend.e cpu_refmodel.e cpu_tst3.e
cpu_drive.e cpu_smp.e
src:
cpu_bypass.e cpu_dut.e cpu_top.e
cpu_checker.e cpu_instr.e cpu_tst1.e
cpu_cover.e cpu_misc.e cpu_tst2.e
cpu_cover_extend.e cpu_refmodel.e cpu_tst3.e
cpu_drive.e cpu_smp.e
Note As you work through this tutorial, you will be modifying the files in the src directory. If you have
trouble making the modifications correctly, you can view or use the files in the gold directory. The files
in the gold directory are complete and correct.
Now that the files are installed, you are ready to proceed with the design verification task flow shown in
Figure 1-2 on page 1-3. To start the first step in that flow, turn to Chapter 2 “Understanding the
Environment”. In this chapter, you review the DUT specifications and functional test plan for the CPU
design and define the overall verification environment.
Document Conventions
This tutorial uses the document conventions described in Table 1-1.
courier bold Text that you need to type exactly as it appears to complete a
procedure or modify a file.
• Design specifications
• Interface specifications
• Functional test plan
• Overall verification environment
For more detailed information on the CPU instructions, the CPU interface, and the CPU’s internal
registers, see Appendix A “Design Specifications for the CPU”.
Available Instructions
CPU
clock ALU Arithmetic:
ADD, ADDI, SUB, SUBI
rst Fetch & Execute Logic:
8 State Machine AND, ANDI, XOR, XORI
data r0
Control Flow:
r1 JMP, JMPC, CALL, RET
r2 pc No-Operation:
NOP
r3 pcs
The state machine diagram for the CPU is shown in Figure 2-2. The second fetch cycle is only for
immediate instructions and for instructions that control execution flow.
Fetch1 Fetch2
Execute
There is a 1-bit signal associated with each state, exec, fetch2, fetch1, strt. If no reset occurs, the fetch1
signal must be asserted exactly one cycle after entering the execute state.
• Register instructions—The second operand specifies another one of the four internal registers.
byte 1
bit 7 6 5 4 3 2 1 0
• Immediate instructions—The second operand is an 8-bit value. When the opcode is of type JMP,
JMPC, or CALL, this operand must be a 4-bit memory location.
byte 1 2
bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
Test 1
Test Objective
A simple go/no-go confirming that the verification environment is working properly.
Test Specifications
• Generate five instructions.
• Use either the ADD or ADDI opcode.
Test 2
Test Objective
Multiple random variations on a test gains high percentage coverage on commonly executed
instructions.
Test Specifications
• Use constraints to direct random testing towards the more common arithmetic and logic operations
rather than the control flow operations.
• Run the test many times, each time with a different random seed.
Test 3
Test Objective
Generation of a corner case test scenario that exercises JMPC opcode when the carry bit is asserted.
Note that it is difficult to efficiently cover this scenario by purely random or purely directed tests.
Test Specifications
• Generate many arithmetic opcodes to increase the chances of carry bit assertion.
• Monitor the DUT and use on-the-fly generation to generate many JMPC opcodes when the carry
signal is high.
Reference Model
Constraints
struct cpu_refmodel_s {
regs[4]: list of byte;
pc : byte;
Test Generator stack : list of byte;
fetch(r:cpu_reg_t): byte is {
return(regs[r.as_a(int)];
Temporal
};
Rules
update(r:cpu_reg_t, val:byte) is {
...
Instructions Checker
CPU
Pass / Fail
Coverage
Because the focus of this tutorial is the Specman system, we do not include an HDL simulator. Rather
than instantiating an HDL DUT, we model the DUT in e and simulate it in Specman. The process you
use to drive and sample the DUT in e is exactly the same as a DUT in HDL.
Now you are ready to create the first piece of the verification environment, the CPU instruction stream.
As you work through this chapter, you gain experience with one of the Specman system’s enabling
features—easy specification capture. Using a few constructs from the e language, you define the legal
CPU instructions exactly as they are described in the interface specifications.
extend Adds the data structure containing the CPU instructions to the
Specman system of data structures.
For a complete description of the legal CPU instructions, refer to Appendix A “Design Specifications for
the CPU”.
Procedure
To capture the design specifications in e:
1. Make a new working directory and copy the src/cpu_instr.e file to the working directory.
The first part of the file has a summary of the design specifications for the CPU instructions.
Register Instruction:
bit | 7 6 5 4 | 3 2 | 1 0 |
| opcode | op1 | op2 |
(reg)
:
Immediate Instruction:
byte | 1 | 2 |
bit | 7 6 5 4 | 3 2 | 1 0 | 7 6 5 4 3 2 1 0 |
| opcode | op1 | don’t | op2 |
| care |
3. Find the portion of the file that starts with the <' e code delineator and review the constructs:
<'
type cpu_opcode_t: [ // Opcodes
defines the legal
ADD, ADDI, SUB, SUBI,
opcodes as an
AND, ANDI, XOR, XORI,
enumerated type
JMP, JMPC, CALL, RET,
NOP
] (bits: 4);
when complete, };
this construct
adds the CPU extend sys {
instruction set to // creates the stream of instructions
the Specman
system };
4. Define two fields in the cpu_instr_s structure, one to hold the opcode and one to hold the first
operand.
Use the enumerated types, cpu_opcode_t and cpu_reg_t, to define the types of these fields. To
indicate that the Specman system must drive the values generated for these fields into the DUT,
place a % character in front of the field name. You will see how this % character facilitates packing
automation in Chapter 5 “Driving and Sampling the DUT”.
struct cpu_instr_s {
//defines opcode, operand 1 and instruction kind
add these two
%opcode :cpu_opcode_t;
lines into the file
%op1 :cpu_reg_t;
The second operand is either a 2-bit register or an 8-bit memory location, depending on the kind of
instruction, so you need to define a single field (kind) that specifies the two kinds of instructions.
Because the generated values for kind are not driven into the design, do not put a % in front of the
field name.
struct cpu_instr_s {
//defines opcode, operand 1 and instruction kind
%opcode :cpu_opcode_t;
add this line to %op1 :cpu_reg_t;
define the field kind :[imm, reg];
‘kind’ and define
an enumerated // defines 2nd op of reg instruction
type at the .
same time .
.
};
6. Define the conditions under which the second operand is a register and those under which it is a byte
of data.
struct cpu_instr_s {
//defines opcode, operand 1 and instruction kind
%opcode :cpu_opcode_t;
%op1 :cpu_reg_t;
kind :[imm, reg];
7. Constrain the opcodes for immediate instructions and register instructions to the proper values.
Whenever the opcode is one of the register opcodes, then the kind field must be reg. Whenever the
opcode is one of the immediate opcodes, then the kind field must be imm. You can use the keep
construct with the implication operator => to easily create these complex constraints.
struct cpu_instr_s {
.
.
.
// defines legal opcodes for reg instr
keep opcode in [ADD, SUB, AND, XOR, RET, NOP]
=> kind == reg;
};
8. Constrain the second operand to a valid memory location (less than 16) when the instruction is
immediate.
You can use the when construct together with keep and => to create this constraint.
struct cpu_instr_s {
.
.
.
// ensures 4-bit addressing scheme
when imm cpu_instr_s {
keep read_only(opcode in [JMP, JMPC, CALL]) => op2 < 16;
};
};
Procedure
To create the list of instructions:
1. Within the same cpu_instr.e file, find the lines of code that extend the Specman system:
extend sys {
// creates a stream of instructions
};
When defining a field that is an array or a list, you must precede the field type with the keyword list
of.
extend sys {
// creates a stream of instructions
!instrs: list of cpu_instr_s;
};
The exclamation point preceding the field name instrs tells the Specman system to create an empty
data structure to hold the instructions. Then, each test tells the system when to generate values for
the list, either before simulation (pre-run generation) or during simulation (on-the-fly generation).
In this tutorial you use both types of generation.
Now you have created the core definition of the CPU instructions. You are ready to extend this
definition to create the first test.
You will also get a look at the Data Browser and the Generation Debugger GUIs, which are features that
provide visibility into the data structure and the generation order of the e objects.
As you work through this chapter to create the first test, you gain experience with the following enabling
features of the Specman system:
• Extensibility—This enables adding definitions, constraints, and methods to a struct in order to change
or extend its original behavior without altering the original definition.
• Constraint solver—This is the core technology that intelligently resolves all specification constraints
and test constraints and then generates the desired test.
This chapter shows new uses of the e constructs introduced in Chapter 3 “Creating the CPU Instruction
Structure”. It also introduces the Specman console menu commands shown in Table 4-1.
Table 4-1 New Constructs and SimVision Menu Commands Used in this Chapter
keep Limits the possible values of the instruction fields and the number
of instructions generated for this test.
File ›› Load e File Loads uncompiled e modules into the Specman system.
Verification ›› e Modules Lists the e modules you have loaded into the Specman system.
Verification ›› Data Browser Opens the Data Browser GUI, in which you view the hierarchy of
generated objects and their values.
Tip In most cases, the menu commands presented in this tutorial can be issued by clicking a button.
For example, clicking the Load e source file button is the same as clicking File ›› Load e File.
Similarly, you can click the Show loaded modules button instead of clicking Verification ›› e
Modules. To see what a given button does, hover your mouse over the icon.
The steps required to generate the first test for the CPU model are:
Test Objective
The objective is to confirm that the verification environment is working properly.
Test Specifications
To meet the test objective, the test should:
Procedure
To capture the test constraints in e:
1. Copy the src/cpu_tst1.e to the working directory and open the cpu_tst1.e file in an editor.
<'
import cpu_top;
extend cpu_instr_s {
// test constraints
};
extend sys {
// generate 5 instructions
};
.
.
.
3. Add lines below the comments as follows to constrain the opcode, operands, and number of
instructions:
<'
extend cpu_instr_s {
//test constraints
constrains the keep opcode in [ADD, ADDI];
opcode and keep op1 == REG0;
operands when reg cpu_instr_s { keep op2 == REG1; };
when imm cpu_instr_s { keep op2 == 0x5; };
};
constrains the
number of extend sys {
instructions //generate 5 instructions
keep instrs.size() == 5;
};
• cpu_tst1.e—imports (includes) cpu_top.e and contains the test constraints for the first test.
• cpu_top.e—imports cpu_instr.e and cpu_misc.e.
• cpu_instr.e—contains the definitions and specification constraints for CPU instructions.
• cpu_misc.e—configures settings for print and coverage display.
These files are called modules in the Specman system. Before the system can generate the test, you must
load all the modules.
Procedure
To load all modules:
The working directory should now contain four files: cpu_instr.e, cpu_misc.e, cpu_top.e, and
cpu_tst1.e
3. From the working directory, type the following command at the system prompt to invoke Specman’s
graphical user interface, SimVision™:
% specman -gui
Note If your screen looks different from is shown in this tutorial, it is probably because you are
using a different version of Specman than that shown in this tutorial.
5. In the “Select A File” dialog box, double-click cpu_tst1.e in the list of files.
Specman automatically loads all four files contained in your working directory. In SimVision, you
should see a message that looks as follows:
Loading cpu_instr.e (imported by cpu_top.e) ...
Loading cpu_misc.e (imported by cpu_top.e) ...
Loading cpu_top.e (imported by cpu_tst1.e) ...
Loading cpu_tst1.e ...
Tip If the cpu_tst1.e file name does not appear in the dialog box, you probably did not invoke Specman
from the working directory. Use the list of directories in the dialog box to navigate to the working
directory.
Tip If the cpu_tst1.e file does not load completely because of a syntax error, use a diff utility to
compare your version of cpu_tst1.e to cpu/gold/cpu_tst1.e. Fix the error and click the Reload
button. Alternatively, you can click the blue hypertext link in the SimVision, and the error location
will be displayed in the Debugger window.
7. In the “Modules” window, click File ›› Close to close the window after you verify that all four
modules are loaded.
We perform this step in order to be able to view the generation order in the next procedure,
“Analyzing Generation”. Using Collect Gen is necessary when you want to use the Generation
Debugger, but is not required for most Specman test runs.
Tip Remember that if your screen shows slightly different information than that shown in the figure,
it is probably because you are using a Specman version that is different from the one used in the
tutorial.
4. Click the 5 items link on the instrs line in the left pane.
The list of five generated instructions appears in the top right pane.
5. Click on the “+” that appears in front of the 5 items link on the instrs line in the left pane.
The generated values for the fields of the first reg instruction object appear in the right pane.
Tip If the results you see are significantly different from the results shown here, use a diff utility to
compare your version of the e files to the files in the gold directory.
7. Click each of the other instrs[n] lines in the left panel and review their contents in the right panel to
confirm that the instructions follow both the general constraints for CPU instructions and the
constraints for this particular test.
8. Click File ›› Close or the “Close Window” button to close the Data Browser window.
Based on the definitions, specification constraints, and test constraints that you have provided, the
Specman generator quickly generated the desired instruction stream.
Analyzing Generation
To open the Generation Debugger and view the generation order:
The Gen Debugger GUI shows information organized around the generation process—that is, the
solving of connected field sets (CFSs). A CFS is a set of variables in a generation action that are
connected by a set of constraints.
2. In the top left-hand “Generation Process Tree,” click the + symbol by one of the CFS lines to view
the “solving steps”—that is, the reduction and assignment steps—performed for that CFS.
The following figure shows the reduction and assignment steps for the CFS sys-@1.instrs[2].
3. Click on one of the solving steps to make it the focus of the Generation Debugger.
In the following figure, the solving step op1->[REG0] is selected. As you can see, the main section
of the Generation Debugger now displays information about this particular solving step, including a
text description of the step.
The information in the “Variables” table tells you that, during this reduction step, Specman’s
generator initially assigned the values REG0, REG1, REG2, and REG3 to op1. These initial values
consist of all the legal values for the internal registers (defined in the cpu_instr.e module). The
generator then considered the keep op1 == REG0 constraint that you created for the cpu_tst1.e
module. Because of this constraint, the generator reduced the range of values available for op1 to
REG0.
4. Now click on the keep op1 == REG0 constraint in the “Constraints” pane (the top far-right-hand
pane).
Notice that new information and tabs appears in the “General Info” pane. The panes in the
Generation Debugger are interlinked—when you click on an item, the “General Info” pane switches
to information about that item.
One of the tabs that is displayed for constraints is the “Source” tab. The following figure shows the
“Source” tab open, displaying the code for the keep op1 == REG0 constraint.
These simple examples illustrate some of the ways you can use the Generation Debugger to
investigate the steps taken during generation. When you start coding more complicated constraints,
you will find the Generation Debugger to be an invaluable tool for solving issues regarding your
generation code.
5. Click File ›› Close or the “Close Window” button to close Generation Debugger.
This procedure has introduced you to the Generation Debugger analysis tool and how you can use it to
investigate particular generation results.
Now you are ready to drive this instruction stream into the DUT and run simulation.
In a typical verification environment, where the DUT is modeled in an HDL, you need to link the
Specman system with an HDL simulator before running simulation. To streamline this tutorial, we have
modeled the DUT in e.
As you work through this chapter, you gain experience with these features of the Specman verification
system:
• Time consuming methods (TCMs)—You can write procedures in e that are synchronized to other
TCMs or to an HDL clock. You can use these procedures to drive and sample test data.
• DUT signal access—You can easily access signals and variables in the DUT, either for driving and
sampling test data or for synchronizing TCMs.
• Simulator interface automation—You can drive and sample a DUT without having to write PLI
(Verilog simulators) or FLI/CLI (VHDL simulators) code. The Specman system automatically creates
the necessary PLI/FLI calls for you.
pack () Converts data from higher level e structs and fields into the bit or
byte representation expected by the DUT.
The drive instructions protocol has one TCM for pre-run generation, where the complete list of
instructions is generated and then simulation starts. There is another TCM for on-the-fly generation,
where signals in the DUT are sampled before the instruction is generated. The test in this chapter uses
the simple methodology of pre-run generation, while subsequent tests in this tutorial use the more
powerful on-the-fly generation.
The TCMs required to drive the CPU are described briefly in Table 5-2. A complete description of one
of the TCMs follows the table. You can also view the cpu_drive.e file in the src directory, if you want to
see the complete description of the other TCMs in e.
Name Function
reset_cpu() Drives the rst signal in the DUT to low for one cycle, to high
for five cycles, and then to low.
Figure 5-1 shows the e code for the drive_one_instr () TCM. The CPU architecture requires that tests
drive and sample the DUT on the falling edge of the clock. Therefore, all TCMs are synchronized to
cpuclk, which is defined as follows:
extend sys {
event cpuclk is (fall(smp.clk_p$)@sys.any);
};
emit instr.start_drv_DUT;
The assignment statements in Figure 5-1 show how to drive and sample signals in an HDL model. Each
“port$” construct—for example, “smp.data_p$”—represents the value sampled by an e port that is
connected to an HDL signal.
The start_drv_DUT event emitted by drive_one_instr is not used by any of the TCMs that drive the
CPU. You will use it in a later chapter to trigger functional coverage analysis.
The last line shown in Figure 5-1 executes the reference model and is commented out at the moment.
You will use it in a later chapter to trigger data checking.
The pack() function is a Specman built-in function that facilitates the conversion from higher level data
structure to the bit stream required by the DUT. In Chapter 3 “Creating the CPU Instruction Structure”,
you used the % character to identify the fields that should be driven into the DUT. The pack() function
intelligently and automatically performs the conversion, as shown in Figure 5-2.
opcode == ADD 0 0 0 0
op1 == REG0 0 0
op2 == REG1 0 1
The instruction packed into a bit stream, using the packing.high ordering
0 0 0 0 0 0 0 1
list of bit [7] list of bit [0]
The difference is that this time you are including the DUT (contained in cpu_dut.e) and TCMs that drive
it (contained in cpu_drive.e).
Procedure
Tip If you have exited SimVision, you must reinvoke it and load cpu_tst1.e again. To do so, enter the
specman -gui command at the Linux prompt, click File ›› Load e Files, and select cpu_tst1.e.
4. Remove the comment characters in front of the import line so the lines look like this:
6. Because you will not be using the Generation Debugger in the remainder of this tutorial, enter the
following command in the Specman> command line in the SimVision window:
Because you activated the “import cpu_smp, cpu_dut, cpu_drive” line by removing the comment
markers from that line, those two modules will be loaded along with the modules that were loaded
in the previous procedure.
Tip If you see a message such as
*** Error: No match for 'cpu_dut.e'
you need to check whether the working directory contains the following files:
cpu_instr.e cpu_smp.e
cpu_misc.e cpu_top.e
cpu_dut.e cpu_tst1.e
cpu_drive.e
You should see the following messages (or something similar) in the Specman console.
Doing setup…
Generating the test with IntelliGen using seed 1…
You can see from the output that five instructions were executed and no errors were found. It looks like
the verification environment is working properly, so you are ready to generate a larger number of tests.
As you work through this chapter, you gain experience with two of the Specman verification system’s
enabling features:
• Directed-random test generation—This feature lets you apply constraints to focus random test
generation on areas of the design that need to be exercised the most.
• Random seed generation—Changing the seed used for random generation enables the Specman
system to quickly generate a whole new set of tests.
This chapter introduces the e constructs and SimVision menu commands shown in Table 6-1.
Table 6-1 New Constructs and SimVision Menu Commands Used in this Chapter
keep soft Specifies a soft constraint that is kept only if it does not
conflict with other hard keep constraints.
Verification ›› Specman Configuration Used to access the Generation tab of the Specman
Configuration Options window for creating a
user-defined seed for random test generation.
Verification ›› Save Specman State Saves the current test environment, including the random
seed, to an .esv file.
You can load this file with the Verification ›› Restore
Specman State command.
Verification ›› Test with Random Seed Generates a set of tests with a new random seed.
Procedure
To see how weighted constraints are created in e:
3. Find the portion of the file that looks as follows and review the keep soft constraint.
<'
import cpu_top;
extend cpu_instr_s {
puts equal weight
keep soft opcode == select {
on arithmetic and
10 : [JMP, JMPC, CALL, RET, NOP];
logical operations
30 : [ADD, ADDI, SUB, SUBI];
and less weight
30 : [AND, ANDI, XOR, XORI];
on control flow
};
operations
};
'>
Procedure
This procedure shows how to create a random seed:
1. In SimVision, click Verification ›› Restore Specman State ›› Restore to Last State to remove all
of the e modules from the current session.
The Specman system loads the cpu_tst2.e file along with its imported modules.
4. Click the Generation tab and then enter a number of your choice in the Seed text box.
The Specman system runs the test with the seed value you entered above, and reports the results.
8. Click the blue x items link following “instrs =” in the left pane (where x is the number of instruction
instances that were generated).
Procedure
To run a test using a Specman-generated random seed:
The Specman system runs the test with the random seed shown in the Specman console window and
reports the results.
You should again see an approximately equal distribution of arithmetic and logical operations, and
about one-third as many control flow operations as there are either arithmetic or logical operations.
The results should be different from the previous run.
4. Optionally you can repeat steps 1-3 several times to confirm that you see different results each time.
Tip If you see similar results in subsequent runs, it is likely that you forgot to reload the design before
running the test. If you do not reload the design, the test is run with the current seed.
You can see that using different random seeds lets you easily generate many tests. Quickly analyzing the
results of all these tests would be difficult without Specman’s coverage analysis technology. The next
two chapters show how to use coverage analysis to accurately measure the progress of your verification
effort.
As you work through this chapter, you gain experience with another one of the Specman verification
system’s enabling features—the Functional Coverage Analyzer. The Specman coverage analysis
feature lets you define exactly what functionality of the device you want to monitor and report. With
coverage analysis, you can see whether generated tests meet the goals set in the functional test plan and
whether these tests continue to be sufficient as the design develops, the design specifications change,
and bug fixes are implemented.
The three types of coverage data that you might want to collect are:
Procedure
To define coverage for the FSM:
1. Copy the src/cpu_cover.e file to the working directory and open cpu_cover.e in an editor.
2. Find the portion of the file that looks like the excerpt below and review the declaration that defines
the sampling event for the FSM:
extend cpu_env_s {
defines FSM
event cpu_fsm is @sys.cpuclk;
sampling event
// DUT Coverage: State Machine and State
// Machine transition coverage
3. Add the coverage group and coverage items for state machine coverage.
The coverage group name (cpu_fsm) must be the same as the event name defined in Step 2 above.
The item statement declares the name of the coverage item (fsm), its data type (FSM_type_t), and
the object in the DUT to be sampled. The transition statement says that the current and previous
values of fsm must be collected. This means that whenever the sys.cpuclk signal changes, the
Specman system collects the current and previous values of top.cpu.curr_FSM.
extend cpu_env_s {
event cpu_fsm is @sys.cpuclk;
• opcode
• op1
This coverage group uses a sampling event that is declared and triggered in the cpu_drive.e file.
drive_one_instr(instr: cpu_instr_s) @sys.cpuclk is {
.
.
.
emit instr.start_drv_DUT;
.
.
.
Thus data collection for the instruction stream occurs each time an instruction is driven into the DUT.
Procedure
To extend the cpu_instr_s struct to define coverage for the generated instructions:
1. Find the portion of the cpu_cover.e file that looks like the excerpt below and review the coverage
group declaration.
extend cpu_instr_s {
defines
cover start_drv_DUT is {
coverage group
};
};
extend cpu_instr_s {
cover start_drv_DUT is {
item opcode;
item op1;
};
};
Procedure
To define coverage data for the designated corner case:
extend cpu_instr_s {
cover start_drv_DUT is {
item opcode;
item op1;
item carry: bit = sys.smp.carry_p$;
};
};
Cross coverage lets you define the intersections of two or more coverage items, generating a more
informative report. The cross coverage item defined here shows every combination of carry value
and opcode that is generated in the test.
extend cpu_instr_s {
cover start_drv_DUT is {
item opcode;
item op1;
item carry: bit = sys.smp.carry_p$;
cross opcode, carry;
};
};
Now that you have defined the coverage groups, you are ready to simulate and view the coverage
reports.
• Determine whether the tests you have generated meet the specifications in the functional test plan
• Based on that information, decide whether additional tests must be created to complete design
verification.
You will examine coverage grades for different types of coverage items. A coverage grade indicates how
thoroughly the item was covered during a test or set of tests. The maximum grade is 1.00, which means
that every possible value for that item occurred, or was “hit”, during the tests. Incomplete coverage, or a
“hole”, is represented by a decimal fraction: A grade of 0.75, for example, means that three out of every
four possible values were hit.
As you work through this chapter, you gain experience with these Specman features:
• Help—This helps you find the information you need in the Specman Online Documentation.
• Coverage Extensibility—This allows you to change coverage group and coverage item definitions.
This chapter introduces the SimVision menu commands shown in Table 8-1.
Help ›› Specman Help Library Invokes the Specman Online Documentation browser.
The steps required to analyze test coverage for the CPU design are:
Procedure
To run tests with coverage groups defined:
// Add Coverage:
//import cpu_cover;
3. Remove the comment characters in front of the import line so the lines look like this:
// Add Coverage:
import cpu_cover;
5. In SimVision, click File ›› Reload e Files to reload the files for test 2.
Tip If you have exited SimVision, you must reinvoke it and load cpu_tst2.e again. To do so, enter the
specman -gui command at the Linux prompt, click File ›› Load e Files, and select cpu_tst2.e.
You should see something similar to the following in the Specman console. The last line indicates
that coverage data was written to a ucd file (a coverage data file).
test
Doing setup…
Generating the test with IntelliGen using seed 1
If you are using a different seed or a version of the Specman verification system other than the version
for this tutorial, you might see different results in your coverage reports.
Procedure
1. In the Specman console, click on Verification ›› Specman Configuration to display the
“Configuration Options” form.
2. In the “Configuration Options” form, select the Coverage tab and then click on Use specview
coverage window for the Coverage Analysis Window (on the center far-right of the form). Then
close the form.
This tutorial uses the Specview coverage window as the default coverage GUI.
Coverage Icon
4. In the left pane, click the + to the left of cpu_env_s.cpu_fsm and then click on fsm.
The figure below shows that, during this run, the fetch1_st state was entered 134 times in the
339 times sampled.
You can change the display to show only data for transitions that have occurred by clicking
View ›› Full in the Coverage GUI toolbar. (The View ›› Full option shows only data for transitions
that have occurred; the View ›› Holes Only option shows only data for transitions that have not
occurred.)
You can also define transitions as illegal so that they do not appear in the coverage report. Illegal
transition definition is described in the following steps.
6. For an explanation of how to define transitions as illegal so that they do not appear in the coverage
report, click Help ›› Help Browser.
b. Click the down-pointing red arrow to the right of the Search Term field and click Search Selected.
d. Click the Search Selected magnifying glass next to the Search Term field.
e. Look for and select the “transition” section in the Specman e Language Reference.
a. Scroll down the page to the illegal coverage item option description.
b. In the illegal option description, click on the “illegal” link to display an example showing the
use of the illegal option:
struct packet {
packet_len: uint (bits: 12);
event rcv_clk;
cover rcv_clk is {
item len: uint (bits: 12) = packet_len using
ranges = {
range( [16..255], "small");
range( [256..3k-1], "medium");
range( [3k..4k-1], "big");
},
illegal = (len < 16 or len > 4000);
};
};
Extending Coverage
In this section, the coverage group is extended by the addition of a new item, and by making an existing
item a per-instance item, which allows us to see coverage separately for different subtypes.
Procedure
To extend a coverage group:
1. Copy the src/cpu_cover_extend.e file to the working directory and open the cpu_cover_extend.e file
in an editor.
extend cpu_instr_s {
3. Add the coverage group extension struct member. Do not forget the closing bracket.
The syntax for a coverage group extension is the same as for the original coverage group definition,
except that it uses is also instead of is.
extend cpu_instr_s {
4. Add a new coverage item to cover the kind field of the cpu_instr_s struct.
extend cpu_instr_s {
5. Extend the op1 item with using also, to make it a per_instance item.
Since the op1 item can have one of the enumerated types REG0, REG1, REG2, or REG3, making
this item a per_instance item will provide separate coverage for each of those four subtypes.
extend cpu_instr_s {
// Extend Coverage:
//import cpu_cover_extend;
9. Remove the comment characters in front of the import line so the lines look like this:
// Extend Coverage:
import cpu_cover_extend;
11. In SimVision, click File ›› Reload e Files to reload the files for test 2.
Tip If you have exited SimVision, you must reinvoke it and load cpu_tst2.e again. To do so, enter the
specman -gui command at the Linux prompt, click File ›› Load e Files, and select cpu_tst2.e.
12. Click Modules from the Files menu to confirm that nine modules are loaded:
cpu_instr
cpu_misc
cpu_smp
cpu_dut
cpu_drive
cpu_cover
cpu_cover_extend
cpu_top
cpu_tst2
You should see something similar to the following in the Specman console. The last line indicates
that coverage data was written to a ucd file (a coverage data file).
Doing setup…
Generating the test with IntelliGen using seed 1
Starting the test…
Running the test…
DUT executing instr 0 : ADD REG0x3, REG0x0
DUT executing instr 1 : ANDI REG0x3, @0x20
DUT executing instr 2 : XOR REG0x3, REG0x2
DUT executing instr 3 : ADD REG0x3, REG0x1
DUT executing instr 4 : SUBI REG0x3, @0x9f
.
.
.
Last specman tick - stop_run() was called
Normal stop - stop_run() is completed
Checking the test ...
Checking is complete - 0 DUT errors, 0 DUT warnings.
Wrote 1 cover_struct to ./cov_work/scope/cpu_tst2_sn1/sn.ucd
14. In SimVision, click on the Coverage icon to display the Coverage GUI.
The coverage data now includes information about the number of samples of each subtype (REG0,
REG1, REG2, REG3) of the cpu_instr_s type. Each sample also includes information about the new
kind item.
Procedure
To view coverage by op1 subtype of the cpu_instr_s instances:
1. If you closed the Coverage window after the previous procedure, you must reopen it. In SimVision.
Click on the Coverage icon in SimVision.
In the left pane, we now see that the instr.start_drv_DUT data has four additional entries:
cpu_instr_s.start_drv_DUT(op1==REG0) through cpu_instr_s.start_drv_DUT(op1==REG3).
We see that the kind item now appears in the cpu_instr_s.start_drv_DUT group.
3. Click on kind.
The coverage data for the imm and reg values of kind appears in the right pane. These are the
coverage results for kind when the op1 value is REG0, since we selected the
cpu_instr_s.start_drv_DUT(op1==REG0) instance in the left pane.
4. In the left pane, click the + to the left of cpu_instr_s.start_drv_DUT and each of the instances
(op1==REG1), (op1==REG2), (op1==REG3) to expand the top instance and all of the subtypes.
We see that the cross__opcode__carry item has a different grade for each instance.
5. Click on each cross__opcode__carry item in turn to see which crosses of opcode and carry never
occurred at all, and which additional crosses never occurred under each particular subtype. The
crosses that never occurred are shown in red, and with 0 in the Hits column.
Procedure
To view corner case coverage of the JMPC opcode:
1. If you closed the Coverage window after the previous procedure, you must reopen it. In SimVision.
Click on the Coverage icon in SimVision.
2. In the left pane, click the + to the left of cpu_instr_s.start_drv_DUT and then click on
cross__opcode__carry.
The cross-coverage report for opcode and carry appears in the right-hand pane.
In the figure below, you can see that carry was 0 each time that opcode was JMPC. The
combination of opcode JMPC and carry 1 never occurred in this set of tests, which means that there
is a coverage hole for that item and it has a grade of 0. The other red items indicate other
combinations of carry and opcode that never were hit in this set of tests. Any grade less than 1.00 is
a hole. Grades less than 1.00 but more than 0 are shown in yellow in the coverage GUI.
The ability to cross test input with the DUT’s internal state yields the valuable information that the tests
created so far do not truly test the JMPC opcode. You could raise the weight on JMPC and hope to
achieve the goal. However, many simulation cycles would be wasted to cover this corner case. The
Specman system lets you attack this type of corner case scenario much more efficiently. In the next
chapter you learn how to do this.
In the next chapter, we see how to modify the test files to push the test into a corner that is not being
covered well by the current test.
port$ * weight : value Used as an expression containing a DUT signal within the select block
of a keep soft constraint that controls the distribution of generated
values.
Procedure
To increase the probability of arithmetic operations:
1. Copy the src/cpu_tst3.e file to the working directory and open the cpu_tst3.e file in an editor.
2. Find the portion of the file that contains the keep soft constraint.
extend cpu_instr_s {
keep soft opcode == select {
// high weights on arithmetic
};
};
3. Put a high weight on arithmetic operations and low weights on the others.
extend cpu_instr_s {
keep soft opcode == select {
// high weights on arithmetic
keeps high weight 40 : [ADD, ADDI, SUB, SUBI];
on arithmetic 20 : [AND, ANDI, XOR, XORI];
operations 10 : [JMP, CALL, RET, NOP];
This methodology lets you reach the corner case from multiple paths—in other words, from different
opcodes issued prior to the JMPC opcode. This test shows how the DUT behaves under various
sequences of opcodes.
Procedure
1. Find the portion of the cpu_tst3.e file that looks like this:
extend cpu_instr_s {
keep soft opcode == select {
// high weights on arithmetic
40 : [ADD, ADDI, SUB, SUBI];
20 : [AND, ANDI, XOR, XORI];
10 : [JMP, CALL, RET, NOP];
2. On a separate line within the select block, enter a weight for the JMPC opcode, as a function of the
carry signal (weight is 0 when carry = 0, or 90 when carry = 1).
extend cpu_instr_s {
keep soft opcode == select {
// high weights on arithmetic
40 : [ADD, ADDI, SUB, SUBI];
20 : [AND, ANDI, XOR, XORI];
10 : [JMP, CALL, RET, NOP];
You are now ready to run this test to create the corner case test scenario. Before running this test,
however, you want to address another important part of functional verification: self-checking module
creation. In the next chapter, you learn easy, self-checking module creation, another powerful feature
provided by the Specman system.
As you work through this chapter, you will gain experience with two of the Specman verification
system’s enabling features:
• Specman temporal constructs—These powerful constructs let you easily capture the DUT interface
specifications, verify the protocols of the interfaces, and efficiently debug them. The temporal
constructs minimize the size of complex self-checking modules and significantly reduce the time it
takes to implement self-checking.
• Specman data checking—Data checking methodology can be flexibly implemented in the Specman
system. For data-mover applications like switches or routers, you can use powerful built-in constructs
for rule-based checking. For processor-type applications like the application used in this tutorial,
reference model methodology is commonly implemented.
expect Checks that a temporal expression is true and, if not, reports an error.
check Checks that a Boolean expression is true and, if not, reports an error.
Procedure
To create the temporal check:
1. Copy the src/cpu_checker.e file to the working directory and open the cpu_checker.e file in an editor.
event fetch1_assert is (
defines rise of change(smp.fetch1_p$) and
fetch1 true(smp.fetch1_p$ == 1)) @sys.cpuclk;
3. Define a temporal check for the enter_exec_st event by creating an expect statement.
event fetch1_assert is (
change(smp.fetch1_p$) and
true(smp.fetch1_p$ == 1)) @sys.cpuclk;
Reference models are not required for data checking. You could use a rule-based methodology.
However, reference models are part of a typical strategy for verifying CPU designs. The Specman
system supports reference models written in Verilog, VHDL, C, or, as in this tutorial, e. All you need to
do is to create checks that compare the program counter in the DUT to their counterparts in the reference
model.
Procedure
Creating data checks has two parts:
1. Find the portion of the cpu_checker.e file where the exec_done event is defined.
Notice that there is an event, exec_done, and associated method, on_exec_done. The Specman
system automatically creates an associated method for every event you define. The method is empty
until you extend it. The method executes every time the event occurs.
// Data Checker
event exec_done is (fall(smp.exec_p$) and
event definition
true(smp.rst_p$ == 0))@sys.cpuclk;
method associated
with event on_exec_done() is {
// Compare PC - program counter
};
.
.
.
// Data Checker
event exec_done is (fall(smp.exec_p$) and
true(smp.rst_p$ == 0))@sys.cpuclk;
on_exec_done() is {
issues an error if // Compare PC - program counter
there is a check that sys.cpu_dut.pc == sys.cpu_refmodel.pc else
mismatch in the dut_error("DATA MISMATCH(pc)");
program
counters of the
DUT and the
reference model
2. At the top of the file, find the line that imports the CPU reference model and remove the comment
characters from the import line.
<'
import cpu_refmodel;
imports the
reference model
extend sys {
event cpuclk is fall(smp.clk_p$)@sys.any;
cpu_env : cpu_env_s;
cpu_dut : cpu_dut_s;
//cpu_refmodel : cpu_refmodel_s;
};
'>
3. Find the line that extends the Specman system by creating an instance of the CPU reference model
and remove the comment characters.
<'
import cpu_refmodel;
extend sys {
event cpuclk is fall(smp.clk_p$)@sys.any;
cpu_env : cpu_env_s;
cpu_dut : cpu_dut_s;
creates an cpu_refmodel : cpu_refmodel_s;
instance of the };
reference model '>
4. Find the line in the reset_cpu TCM that resets the reference model and remove the comment
characters.
reset_cpu() @sys.cpuclk is {
smp.rst_p$ = 0;
wait [1] * cycle;
smp.rst_p$ = 1;
wait [5] * cycle;
resets the sys.cpu_refmodel.reset(); // reset reference model
reference model smp.rst_p$ = 0;
};
5. Find the line in the drive_one_instr TCM that executes the reference model when the DUT is in the
execute state and remove the comment characters.
The only difference is that this time you will include the reference model and checks.
Procedure
To run the simulation:
// Add Checking:
//import cpu_checker;
3. Remove the comment characters in front of the import line so the lines look like this:
// Add Checking:
import cpu_checker;
7. Click Verification ›› Restore Specman State ›› Restore to Last State to remove any loaded
modules from the current session.
8. Click File ›› Load e File, select the cpu_tst3.e file, and click OK.
Remember, this is the test that you edited in Chapter 9 “Writing a Corner Case Test”.
It looks like we hit a bug here. The Specman system is reporting a protocol violation.
test
Doing setup ...
Generating the test with IntelliGen using seed 7...
PROTOCOL ERROR
------------------------------------------------------
Will stop execution immediately (check effect is ERROR)
10. Click the error hyperlink that is similar to “Checked at line 39 in @cpu_checker” to view the line in
the source that generated this message.
This message comes from the checker module that you just created.
Do not quit SimVision at this time. The first procedure in the next chapter starts from this point.
In the next chapter, you learn how to identify the conditions under which this bug occurs and how to
bypass the bug until it can be fixed.
• The Specman debugger—Provides powerful debugging capability with visibility into the HDL
design.
• The Specman bypass feature—Lets you temporarily prevent the Specman system from generating
test data that reveals a bug in the design. With this feature you can continue testing while the bug is
being fixed.
This chapter introduces the SimVision menu commands shown in Table 11-1 and the generation
debugger menu commands shown in Table 11-2.
Verification ›› Specman Debugger ›› Open Thread Browser Opens the Thread Browser,
which displays all of the TCMs
(threads) that are currently active.
Verification ›› Specman Debugger ›› Open Debug Window Opens the Debugger window,
which displays the source for the
current thread with the current
line highlighted.
Breakpoint ›› Set Breakpoint ›› Break Sets a breakpoint on the currently highlighted line of e
code.
Run ›› Step Any Advances simulation to the next line of e code executed
in any thread.
2. Setting breakpoints.
4. Bypassing bugs.
Procedure
To display DUT values:
The Thread Browser indicates the status of each TCM that is currently active in the Specman
system:
• Clock generation
• Drive and Sample CPU
• DUT
To debug the error, look first at the TCM that drives the DUT.
2. Click on line 2, the line for cpu_env_s-@12.drive_cpu, to display the corresponding source file for
this thread.
The Source File window at the bottom of the screen displays a section of the cpu_drive.e e code
module, with line 62 highlighted. The highlighted line shows that the drive_one_instr TCM is
waiting for the exec signal to rise.
The Debug window appears, displaying the cpu_drive.e file. Line 62 is highlighted.
For step 4
For steps 5
and 6
a. Use your mouse to highlight the phrase instr.kind (line 53 in the figure above).
5. Similarly, highlight the phrase instr.opcode in line 57, click the right-mouse button and select Show
Value.
In the Specman console window, you can see that the value of opcode is JMPC.
6. Optionally, use the same method to display the value of any HDL signal by highlighting the
corresponding port expression.
For example, to display the value of top.data, highlight smp.data_p$, click the right-mouse button
and select Show Value.
Setting Breakpoints
You have determined that the bug appears on an immediate instruction when the opcode is JMPC. It may
be possible to narrow down even further the conditions under which the bug occurs. You can set a
breakpoint on the statement that drives the immediate instruction data into the DUT to see what the
operands of the instruction are.
Procedure
You can set a breakpoint on any line by double clicking on the line number (the narrow column of
numbers on the left of the code in the Source Browser).
However, in this case we want to set a breakpoint as close as possible to the error. In the following
procedure, you set a conditional breakpoint that enables the breakpoint soon after the error occurs:
1. Look again at the error message in the Specman console (as shown in Step 9 in “Running the
Simulation” on page 10-7) to see when the error occurred.
The error message says the error occurred at simulation time 1966.
2. To set a conditional breakpoint that is enabled just before the error occurs:
a. Right click on the line number 57 (the start of the immediate instruction) and select Break at
Line if...
An Input window appears that prompts you to input the conditional expression.
b. Type in “sys.time > 1900” and click OK.
This enables the breakpoint after 1900 cycles (shortly before the error occurs at time1966).
A red dot appears to the left of the line indicating that a breakpoint is set on this line.
Procedure
To step through the simulation:
1. In SimVision, click File ›› Reload e Files to run the simulation in debug mode.
The simulation stops at the breakpoint, and the current line in the SimVision Source Browser is
shown at the breakpoint.
3. To step to the next source line in any subsequent thread, click the Step button in the Source Browser
window.
Step button
4. Continue clicking the Step button until you hit the Protocol error. (It takes over 100 steps to get to
the error.)
The Source Browser is on line 68 in the cpu_dut.e file. This line is the source of the bug.
For the purpose of simplifying this tutorial, we planted an obvious bug in the DUT. Whenever a
JMPC instruction jumps to a location greater than 10, execution requires two extra cycles to
complete—not one, as specified on this line.
Line 68 in the
cpu_dut.e file,
the source of
the bug.
The Specman system’s extensibility feature, however, lets you temporarily prevent generation of the
conditions that cause the bug to be revealed.
This particular bug seems to surface when the JMPC operation is performed using a memory location
greater than 10. To continue testing other scenarios, you simply extend the test constraints to prevent the
Specman system from generating this combination.
Procedure
To bypass the JMPC bug:
<'
extend imm cpu_instr_s {
};
'>
6. Click File ›› Load e File, select the cpu_bypass.e file, and click OK.
Tutorial Summary
Congratulations! You have successfully completed the major steps required to verify a device with the
Specman verification system.
In this tutorial:
• You captured the interface specifications for the CPU instructions in e and created the instruction
stream.
• You used specification constraints to ensure that only legal instructions were generated. You used
test constraints to create a simple go/no-go test.
• You created a Specman TCM (time consuming method) to define the driver protocol and then drove
the generated CPU instruction stream into the DUT. The results confirmed that you had generated
the first test and driven it correctly into the design.
• Using Specman’s powerful constraint-driven generator, you generated many sets of instructions.
Using weight to control the generation value distribution, you effectively focused these sets of
instructions on the commonly executed portion of the CPU DUT.
• Using Specman’s unique Functional Coverage Analyzer, you accurately measured the effectiveness
of the coverage of the regression tests. You identified a corner case “hole” by viewing the graphical
coverage reports.
• To address the corner case scenario, you used Specman’s powerful on-the-fly generation capability
to generate a test based on the internal state of the design during simulation. Compared to the
traditional deterministic test approach, this approach tests the corner case much more effectively
from multiple paths.
• You then used the unique temporal constructs provided by the Specman system to create a
self-checking monitor for verifying protocol conformance.
• When the self-checking monitor revealed a bug, the Specman debugger provided extensive features
to debug the design efficiently.
Note You have created this verification environment, including self-checking modules and functional
coverage analysis, in a short period of time. Once the environment is established, creating a large number
of effective tests is merely one click away. The ultimate advantage of using the Specman system is a
tremendous reduction in verification time and resources.
• CPU instructions
• CPU interface
• CPU register list
CPU Instructions
The instructions are from three main categories:
• Register instructions—The second operand is another one of the four internal registers.
• Immediate instructions—The second operand is an 8-bit value contained in the next instruction.
When the opcode is of type JMP, JMPC, or CALL, this operand must be a 4-bit memory location.
byte 1
bit 7 6 5 4 3 2 1 0
byte 1 2
bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
CPU Interface
The CPU has three inputs and no outputs, as shown in Table A-2.
When the CPU is reset by the rst signal, rst must return to its inactive value no sooner than
min_reset_duration and no later than max_reset_duration.
register 0 8 bits r0
register 1 8 bits r1
register 2 8 bits r2
register 3 8 bits r3