using formal methods to create instruction set architectures
TRANSCRIPT
Using Formal Methods to
Create Instruction Set
Architectures
Steve Wright
Bristol University
Department of
COMPUTER SCIENCE
Steve Wright
• Chartered Software Engineer.
• 8 years at Rolls-Royce.
• 2 years at STMicroelectronics.
• 7 years at Airbus.
• Now at University of Bristol.
ISA Applications
Objective
Formally construct all possible
outcomes for an instruction
set during program execution.
Normal Operation
“I'm completely operational,
and all
my circuits are
functioning perfectly.”
Actions easy to identify.
Failure Conditions
“Open the pod bay doors, HAL.”
“I'm sorry Dave, I'm afraid
I can't do that.”
Harder to identify.
Formal Methods
• Define “events”: “actions” predicated by“guards”.
• Use set theory to prove that one or moreevents is subset of a single more abstract
event.
• “Model Checking” needed to prove thatrefined events fully implement abstract.
ISA Common Properties
• Binary image in contiguous memory.
• Instructions selected by “ProgramCounter”.
• All operations as bit-manipulationsbetween registers.
• Register data stored across multiplecontiguous memory locations.
Top-level Abstraction
RUNNING/FAILED/HALTED state and instruction:
Iterate =
BEGIN
act1: inst :∈ INST
act2: status :∈ STATE
END
First Refinement
Loading
REFINES Iterate
WHEN
grd1: status = LOADING
THEN
act1: inst :∈ Inst
act2: status :∈ { LOADING, RUNNING}
END
Running
REFINES Iterate
WHEN
grd1: status = RUNNING
THEN
act1: inst :∈ Inst // Instruction is updated
act3: status :∈ { RUNNING, HALTED, FAILED}
END
Halted // Explicit deadlock achieved
REFINES Iterate
WHEN
grd1: status = HALTED
THEN
skip
END
Failed // Explicit deadlock achieved
REFINES Iterate
WHEN
grd1: status = FAILED
THEN
skip
END
Create state machine to switch states RUNNING/FAILED/HALTED:
=
32nd(!) Refinement
NopOk
REFINES NopOk
ANY
op
opVal
nextInstPtr
WHERE
grd6: op : DataByte
grd7: op = mem(instPtr)
grd5: opVal : 0..255
grd2: opVal = DataByte2Int(op)
grd1: opVal = 16
grd3: instPtr <= 99992
grd4: statusCode = 2
grd8: nextInstPtr : -2147483647.. 2147483647
grd9: nextInstPtr = instPtr + 1
THEN
act1: instPtr := nextInstPtr
END
For example, the humble NOP:
Proof Obligations
status = RUNNING
⇒
status ∈{LOADING,RUNNING,HALTED,FAILED}
Proof Obligations
∀x · x∈MemArrayDom
⇒
(memArrayDataLongmemIndex ↦DataBytes2DataLong(resByte(0)↦resByte(1) ↦resByte(2) ↦resByte(3))})(x) =
DataBytes2DataLong((memArrayDataBytememIndex↦resByte(0)}memIndex+1 ↦resByte(1)}memIndex+2↦resByte(2)}memIndex+3 ↦resByte(3)})(x)↦(memArrayDataBytememIndex ↦resByte(0)}memIndex+1↦resByte(1)}memIndex+2 ↦resByte(2)}memIndex+3↦resByte(3)})(x+1) ↦(memArrayDataBytememIndex↦resByte(0)}memIndex+1 ↦resByte(1)}memIndex+2↦resByte(2)}memIndex+3 ↦resByte(3)})(x+2)↦(memArrayDataBytememIndex ↦resByte(0)}memIndex+1↦resByte(1)}memIndex+2 ↦resByte(2)}memIndex+3↦resByte(3)})(x+3))
Tool Support
RODIN
• Integrated Development Environment for Event-B.
• Eclipse-based.
• Windows, Linux and Mac.
• Free, open-source.
• Extensible via Java plug-ins.
“MIDAS” Example Machines
• Stack and register machines.
• 35 instructions.
• “Modified Harvard” memoryarchitecture.
• Stack and Register Variants
MIDAS Events
35 instructions ⇒ 112 events
i.e. Many more failure cases than OKcases.
VM Auto-generation
NopOk
REFINES NopOk
ANY
op
opVal
nextInstPtr
WHERE
grd6: op : DataSmall
grd7: op = mem(instPtr)
grd5: opVal : DataSmallNat
grd2: opVal= DataSmall2Nat(op)
grd1: opVal = 16
grd3: instPtr <= 99994
grd4: statusCode = 2
grd8: nextInstPtr : DataLargeNat
grd9: nextInstPtr = instPtr + 1
THEN
act1: instPtr := nextInstPtr
END
/* Event5 [NopOk] */
BOOL NopOk(void){
/* Local variable declarations */
DataLargeNat nextInstPtr;
DataSmall op;
DataSmallNat opVal;
/* Guard 1 */
op = mem[instPtr];
DataSmall2Nat(op,&opVal);
if(opVal!=16) return BFALSE;
/* Guard 2 */
if(instPtr>99994) return BFALSE;
/* Guard 3 */
if(statusCode!=2) return BFALSE;
/* Local assignments in actions */
nextInstPtr = (instPtr+1);
/* Actions */
instPtr = nextInstPtr;
/* Report hit */
ReportEventbEvent("NopOk",5);
return BTRUE;}
> B2C >
Compiled Target Executable
int x;
for(x=0;x<10;x++) {
/* Do nothing */
}
.L3:
# Addsi [fp] [fp] 1
# imm push 1
psh.si.im 1
# indirect push [fp]
psh.si.in fp
ari.si.add
# indirect pop [fp]
pop.si.in fp
pop.si.di void
pop.si.di void
.L2:
# Cmp [fp] 9
# CondBra [fp] 9 le
# imm push 9
psh.si.im 9
# indirect push [fp]
psh.si.in fp
cmp.si.le
pop.si.di void
pop.si.di void
# bra.tr .L3
psh.ad.im .L3
jmp.ad.tr
pop.ad.di void
> GCC >
Program Execution
Future Work
• Expand Event-B to enhance the
process.
• Model checking (dead-
lock/determinism).
• Apply to existing ISAs.
Summary
• EventB can capture generic
properties and refine to example.
• RODIN allows refinement to
executable.
Questions
?