570 likes | 661 Views
Selective Term-Level Abstraction with Type-Inference. Bryan Brady Advisor: Sanjit Seshia In collaboration with: Randy Bryant, Daniel Kroening, Joel Ouaknine, Ofer Strichman. Processor Verification. How to verify? Two options: Simulation Formal Verification.
E N D
Selective Term-Level Abstraction with Type-Inference Bryan Brady Advisor: Sanjit Seshia In collaboration with: Randy Bryant, Daniel Kroening, Joel Ouaknine, Ofer Strichman
Processor Verification How to verify? Two options: Simulation Formal Verification OpenSPARC T1 Microarchitecture Specification, Sun Microsystems, Inc., 2006
Processor Verification Simulation • Advantages • Can test actual design • No verification model needed • Disadvantages • Misses corner cases • Takes too long to fully test design
Example: Pentium FDIV • Certain input data results in inaccuracies • Fraction of input space prone to failure • 1.14 * 10-10 • Cause: Missing entries in the lookup table used in the hardware divide algorithm Statistical Analysis of Floating Point Flaw, Intel White Paper, CS-013007, 1994
Processor Verification Formal Verification • Advantages • Can mathematically prove correctness • Implicitly tests all input combinations • Disadvantages • Requires a separate verification model • Computationally hard.
Bridge the Gap Two extremes: • Manually • Tedious, error prone process • Time consuming • Automatically • Abstract away everything • Model precisely, abstract nothing • Somewhere in between HDL Verification Model
Bridge the Gap Automatically generate verification model • Abstract everything • Spurious counter-examples will result • Need some level of precision • Model precisely • Models become very large • Not scalable • Need to find the sweet spot • Precise enough, but still scalable
Our Goals • Remove the burden of creating a verification model • Develop a scalable approach to large scale processor verification
Semi-Automatic, Selective Abstraction via Type-Inference • Designer partially annotates Verilog with abstraction information • Our algorithm • Determine the level of abstraction for non-annotated variables using type-inference • Generate abstracted verification model Annotation input [3:0] a; //bit-vector input [3:0] b; output [3:0] c; assign c = a + b;
OpenSPARC • Industrial scale: 300K+ lines of Verilog • ~100K lines of Verilog in SPARC core • Open source, industrial scale designs are hard to come by without an NDA • Want reproducible results
Currently • We have been using a toy example • Y86 [Bryant, O’Hallaron, 2002] • Simplified version of x86 • 5 stage, single-threaded, in-order pipeline • 7 versions of varying complexity • Will revisit this later... • OpenSPARC is much larger
Outline • OpenSPARC • Modeling Techniques • UCLID • Experimental Results • Selective Abstraction using Type-Inference • Summary
Outline • OpenSPARC • Modeling Techniques • UCLID • Experimental Results • Selective Abstraction using Type-Inference • Summary
Our focus: SPARC core • For now... OpenSPARC • OpenSPARC T1 processor • 8 SPARC V9 CPU cores • 4 threads per core • Crossbar interconnect between CPUs (x8), L2 cache (x4), FPU (x1), I/O Bus (x1) • 64-bit data path OpenSPARC T1 Microarchitecture Specification, Sun Microsystems, Inc., 2006
OpenSPARC: SPARC core • 4 threads, hardware supported • Windowed register file, 8 per thread • Shared Instr/Data Caches • Single-issue, 6 stage pipeline • Stream based crypto coprocessor OpenSPARC T1 Microarchitecture Specification, Sun Microsystems, Inc., 2006
Outline • OpenSPARC • Modeling Techniques • UCLID • Experimental Results • Selective Abstraction using Type-Inference • Summary
Bit-vector Modeling • View each register or memory bit as a state variable • Each variable is defined by a Boolean function • Conceptually simple, allow high degree of automation • State space can be very large
Modeling with Abstraction • Abstract details of data encodings and operations • Keep control logic precise • Assume functional units are correct, verify overall correctness
x Data Abstraction • View data as symbolic words • Arbitrary integers, no assumptions on size or encoding x0 x1 x2 xn-1
Data Path Data Path Com. Log. 1 Com. Log. 1 ? Com.Log. 2 Com. Log. 1 ? What do we do about logic functions? Data Abstraction Control Logic
ALU Function Abstraction • Replace blocks that transform or evaluate data with generic, unspecified function • Assume only functional consistency a = x b = y f (a, b) = f (x, y) f
F1 F2 Function Abstraction • Conservative approximation • Ignores detailed functionality Control Logic Data Path Com. Log. 1 Com. Log. 1
p 1 0 x 1 0 ITE(p, x, y) x x 1 0 1 0 y x y y y Data Selection • If-then-else operator • Its a multiplexor • Allows control-dependent data flow
Data-Dependent Control • Model with Uninterpreted Predicate • Yields arbitrary Boolean value for each control + data combination • Functional consistency holds Branch? Cond Adata p Branch Logic Bdata
M a M m0 a Memories as Mutable Functions • Memory M modeled as a function • M(a): Value in memory location a • Initially • Arbitrary state • Modeled by uninterpreted function m0
M wa = wd 1 0 a M Memories as Mutable Functions • Writing Transforms Memory • M’ = Write(M, wa, wd) • Reading from updated memory • Address wa gets wd • Otherwise, return what was there • Express with Lambda notation • M’ = a.ITE(a=wa, wd, M(a))
Outline • OpenSPARC • Modeling Techniques • UCLID • Experimental Results • Selective Abstraction using Type-Inference • Summary
UCLID • Tool for verifying infinite-state systems • Originally developed at CMU by Seshia & Lahiri • Multiple uses • Bounded Model Checking (BMC) • Inductive invariant checking • Correspondence checking • Tailored for pipelined processor verification
Correspondence Checking SImpl Sspec Verify that the spec can simulate (mimic) the pipelined implementation Compare shared state before and after the spec and implementation execute PC, RF, MEM Flush, Project Old Impl State Old Spec State Execute 1 cycle Execute 1 cycle New Impl State New Spec State Flush, Project S’Impl S’spec Automatic Verification of Pipelined Microprocessor Control, Burch and Dill, CAV 1994
UCLID Front End Symbolic Simulator Back End VALID or COUNTER- EXAMPLE UCLID Specification Decision Procedure “Unrolls” model in BMC, Inductive Invariant Checking, and Correspondence Checking Deals with function applications, encodes terms/bit-vectors to CNF SAT Checker UCLID
UCLID • Bit-vector modeling • Finite precision bit-vector operators • Arithmetic, logical, relational • Extraction, concatenation • Boolean operators • Term-level modeling • Term-level operators • successor, predecessor, relational • Boolean operators
UCLID • Both terms and bit-vectors • Uninterpreted functions • Uninterpreted predicates • Lambda expressions • Just a way to specify functions, like memory
alu_out := alu_fun(alu_cntl,aluA,aluB); alu_out := alu_fun(alu_cntl,aluA,aluB); Term-level (TERM) Bit-vector (BV-BASE) alu_fun := case (alu_cntl = ((0 <S 2) # [1:0])) : (aluA +_32 aluB); (alu_cntl = ((1 <S 2) # [1:0])) : (aluA -_32 aluB); (alu_cntl = ((2 <S 2) # [1:0])) : (aluA && aluB); default : xor_fun(aluA, aluB); esac; Bit-vector, partially interpreted (BV-ALU-XOR-UF) alu_fun := case (alu_cntl = ((0 <S 2) # [1:0])) : (aluA +_32 aluB); (alu_cntl = ((1 <S 2) # [1:0])) : (aluA -_32 aluB); (alu_cntl = ((2 <S 2) # [1:0])) : (aluA && aluB); default : aluA ^^ aluB; esac; Bit-vector, fully interpreted (BV-ALU) UCLID Example: ALU
UCLID Example: Bit Ops f_rA := getHi(iMem(succ(f_pc))); f_rB := getLo(iMem(succ(f_pc))); ... f_valC := quadmerge(iMem(succ(f_pc)), iMem(succ^2(f_pc)), iMem(succ^3(f_pc)), iMem(succ^4(f_pc))); Term-level (TERM) f_rA := (iMem(( 1 +_32 f_pc ))) # [7:4]; f_rB := (iMem(( 1 +_32 f_pc ))) # [3:0]; ... f_valC := (iMem(( 1 +_32 f_pc )) @ iMem(( 2 +_32 f_pc )) @ iMem(( 3 +_32 f_pc )) @ iMem(( 4 +_32 f_pc ))); Bit-vector, interpreted (BV-BIT)
Outline • OpenSPARC • Modeling Techniques • UCLID • Experimental Results • Selective Term-Level Abstraction using Type-Inference • Summary
Experiment: Y86 • Y86 • 5 stage pipeline • single-threaded • in-order execution • simplified x86 R. E. Bryan and D. R. O’Hallaron. Computer Systems: A Programmer’s Perspective. Prentice-Hall 2002
Experiment: Y86 • Compare runtimes between various encodings of Y86 • Term-level • Bit-vector, uninterpreted • Bit-vector, partially interpreted • Bit-vector, “fully” interpreted • We still represent memory and the register file as a mutable function
Experiment: Y86 • 7 versions of Y86 of varying complexity • Some use forwarding, some do not • Varying methods of branch prediction • Backward taken, forward not taken • None • One version has a single write port for the register
Experiment: Y86 • Term-level version is faster in every case • Interpreting the ALU (BV-ALU) greatly increases runtime in most cases • Mostly due to interpreting XOR • SAT has a hard time with XOR • Interpreting bit extracts and concats doesn’t degrade performance (sometimes its faster!) • Using abstraction in the “right” places can greatly reduce verification time
Outline • OpenSPARC • Modeling Techniques • UCLID • Experimental Results • Selective Term-Level Abstraction using Type-Inference • Summary
Proposed Approach • Starting with a Verilog design, annotate with type-qualifiers, generate a hybrid term/bit-vector UCLID model • Requirements: • Type-qualifiers: syntax, usage • Type-inference rules • Type-inference algorithm
Proposed Approach: Benefits • No need to manually create verification model • Eliminates human-introduced errors • Designer has an intuition about what can and can’t be abstracted • They know where the data-dependent control is • Can operate directly on Verilog • Only need to partially annotate, type-inference algorithm takes care of the rest
Type-Qualifiers • Type-qualifiers are used to give extra properties to variables • Example (C/C++) • const int x; • const gives variable x the property that it can’t be changed • We will use them to denote what level of abstraction to use
Type-Qualifiers • Two kinds of type-qualifiers • Variables: term, bit-vector • inputs, outputs, wires • Operations: interpreted, uninterpreted • assignments, modules
Type-Qualifiers • Initially: • All variables are terms (except Booleans) • All operations are uninterpreted • Except purely Boolean operations (control) • Want to use as much abstraction as possible, model precisely only when we need to
input [7:0] a; //bit-vector input [7:0] b; wire [7:0] c; wire d; assign c = d ? a : b; //interpret a : BITVEC[8]; b : TERM; c := some_func(a,b,d); Type-Qualifiers input [7:0] a; //bit-vector input [7:0] b; wire [7:0] c; wire d; assign c = d ? a : b; a : BITVEC[8]; b : TERM; c := some_func(a,b,d); How do we represent “some_func”?
d d f a(bit-vector) a(bit-vector) 1 0 1 0 c(bit-vector) ? ? b(term) b(term) What if “b” is a different size than bit-vector “c” ? Type-Inference input [7:0] a; //bit-vector input [7:0] b; wire [7:0] c; wire d; assign c = d ? a : b; input [7:0] a; //bit-vector input [7:0] b; wire [7:0] c; wire d; assign c = d ? a : b; //interpret c(bit-vector)
Type-Inference • Type reconciliation • “Type-cast” terms to bit-vectors • Propagate through circuit • Only need to do this when function is interpreted • Use a term2bv function • If term is smaller, pad with zeros • If term is bigger, extract low-order bits? • UCLID’s decision procedure figures out the smallest size for terms • Generate run-time warning
d a(bit-vector) 1 0 c(bit-vector) ? b(term) term2bv d a(bit-vector) 1 0 c(bit-vector) ? b(bit-vector) Type-Inference input [7:0] a; //bit-vector input [7:0] b; wire [7:0] c; wire d; assign c = d ? a : b; //interpret