# Using ASLi with Arm's v8.6-A ISA specification
https://alastairreid.github.io/using-asli/
在這篇文章有提到說怎麼安裝和使用ASLi 也就是
```
ASLi is an interpreter for Arm’s Architecture Specification Language.
```
實際上ASLi 版本已經 0.2.0了
![](https://hackmd.io/_uploads/HJelwrjz6.png)
一些安裝的步驟會發生改變來更新一下
這個網站的人使用done來管理專案了
```bash
git clone https://github.com/alastairreid/mra_tools.git
git clone https://github.com/alastairreid/asl-interpreter.git
make -C asl-interpreter asli
```
原版的可以讀這裡
https://github.com/ARM-software/asl-interpreter
# install asl-interpreter
安裝大概分兩塊先處理asl-interpreter,
其中ocaml 直接升級到 5.1.0以上,z3也一樣,pprint版本我是控制在pprint.20200226
```bash
# environment setup
opam init
eval $(opam env)
# install given version of the compiler
opam switch create 5.1.0
eval $(opam env)
# check you got what you want
which ocaml
ocaml -version
opam install z3
opam install menhir
opam install ocamlfind
opam install ott
opam install linenoise
opam install pprint
opam install zarith
opam install alcotest
eval `opam config env`
```
在找尋可用的軟體版本可以用
```bash
opam list pprint
opam install pprint.20200226
opam switch pprint.20200226
```
查看opam lib 也可以查看
https://opam.ocaml.org/packages/z3/z3.4.12.2-1/找到相對應版本
在pprint.20200226這個版本是可以編譯完asl-interpreter.git
不然會遇到下列錯誤
```error
Error: This expression has type PPrintEngine.documentbut an expression was expected of type document
```
```bash=
make install
_____ _ _ ___________________________________
/\ / ____|| | (_) ASL interpreter
/ \ | (___ | | _ Copyright Arm Limited (c) 2017-2019
/ /\ \ \___ \ | | | |
/ ____ \ ____) || |____ | | ASL 0.2.0 alpha
/_/ \_\|_____/ |______||_| ___________________________________
Type :? for help
ASLi> 1+1
2
ASLi> 2+2
4
ASLi> 3+3
6
ASLi> bits(32) x = ZeroExtend('11', 32);
ASLi> x
32'00000000000000000000000000000011'
ASLi>
```
到這邊 asli 就安裝完畢了
# install mra_tools
再來是安裝mra_tools
```bash=
git clone https://github.com/alastairreid/mra_tools
cd mra_tools
mkdir -p v8.6
cd v8.6
wget https://developer.arm.com/-/media/developer/products/architecture/armv8-a-architecture/2019-12/SysReg_xml_v86A-2019-12.tar.gz
wget https://developer.arm.com/-/media/developer/products/architecture/armv8-a-architecture/2019-12/A64_ISA_xml_v86A-2019-12.tar.gz
wget https://developer.arm.com/-/media/developer/products/architecture/armv8-a-architecture/2019-12/AArch32_ISA_xml_v86A-2019-12.tar.gz
tar zxf A64_ISA_xml_v86A-2019-12.tar.gz
tar zxf AArch32_ISA_xml_v86A-2019-12.tar.gz
tar zxf SysReg_xml_v86A-2019-12.tar.gz
cd ..
make all
```
順利的話會看到這些output
```bash=
mkdir -p arch
bin/reg2asl.py v8.6/SysReg_xml_v86A-2019-12 -o arch/regs.asl
mkdir -p arch
bin/instrs2asl.py --altslicesyntax --demangle --verbose -oarch/arch v8.6/ISA_AArch32_xml_v86A-2019-12 v8.6/ISA_A64_xml_v86A-2019-12
Selecting entire architecture
Reading decoder v8.6/ISA_A64_xml_v86A-2019-12/encodingindex.xml
Reading decoder v8.6/ISA_AArch32_xml_v86A-2019-12/t32_encindex.xml
Reading decoder v8.6/ISA_AArch32_xml_v86A-2019-12/a32_encindex.xml
Keeping entire specification
Writing instruction encodings to arch/arch.tag
Writing instructions to arch/arch_instrs.asl
Writing instruction decoder to arch/arch_decode.asl
Writing ASL definitions to arch/arch.asl
patch -Np0 < arch.patch
patching file arch/arch.asl
patching file arch/arch_instrs.asl
Hunk #1 succeeded at 20178 with fuzz 2 (offset 19948 lines).
```
# run ASLi
```bash=
asli prelude.asl ../mra_tools/arch/regs.asl ../mra_tools/types.asl ../mra_tools/arch/arch.asl ../mra_tools/arch/arch_instrs.asl ../mra_tools/arch/arch_decode.asl ../mra_tools/support/aes.asl ../mra_tools/support/barriers.asl ../mra_tools/support/debug.asl ../mra_tools/support/feature.asl ../mra_tools/support/hints.asl ../mra_tools/support/interrupts.asl ../mra_tools/support/memory.asl ../mra_tools/support/stubs.asl ../mra_tools/support/fetchdecode.asl
_____ _ _ ___________________________________
/\ / ____|| | (_) ASL interpreter
/ \ | (___ | | _ Copyright Arm Limited (c) 2017-2019
/ /\ \ \___ \ | | | |
/ ____ \ ____) || |____ | | ASL 0.2.0 alpha
/_/ \_\|_____/ |______||_| ___________________________________
Type :? for help
ASLi> :project tests/test.prj
Loading ELF file tests/test_O2.elf.
Entry point = 0x400168
Test
Program exited by writing ^D to TUBE
Exception taken
ASLi>
Fatal error: exception Stdlib.Sys.Break
```
這邊可以看到他可以以:project tests/test.prj 形式去開啟專案
這個專案很像bash ,只不過從 linux 的指令 變成 一連串的 ASLi的指令.
# asl code
```
root@HOME-X213212:~/x21321219/arm/mra_tools/arch# ll
total 9472
drwxr-xr-x 2 root root 4096 Oct 29 03:33 ./
drwxr-xr-x 7 root root 4096 Oct 29 03:32 ../
-rw-r--r-- 1 root root 678438 Oct 29 03:33 arch.asl
-rw-r--r-- 1 root root 1698510 Oct 29 03:33 arch.tag
-rw-r--r-- 1 root root 721260 Oct 29 03:33 arch_decode.asl
-rw-r--r-- 1 root root 3229167 Oct 29 03:33 arch_instrs.asl
-rw-r--r-- 1 root root 3229271 Oct 29 03:33 arch_instrs.asl.orig
-rw-r--r-- 1 root root 119022 Oct 29 03:33 regs.asl
```
```asl=
__instruction aarch32_CSDB_A
__encoding aarch32_CSDB_A1_A
__instruction_set A32
__field cond 28 +: 4
__opcode 'xxxx0011 00100000 xxxxxxxx 00010100'
__guard cond != '1111'
__unpredictable_unless 15 == '1'
__unpredictable_unless 14 == '1'
__unpredictable_unless 13 == '1'
__unpredictable_unless 12 == '1'
__unpredictable_unless 11 == '0'
__unpredictable_unless 10 == '0'
__unpredictable_unless 9 == '0'
__unpredictable_unless 8 == '0'
__decode
if cond != '1110' then UNPREDICTABLE; // CSDB must be encoded with AL condition
__encoding aarch32_CSDB_T1_A
__instruction_set T32
__opcode '11110011 1010xxxx 10x0x000 00010100'
__guard TRUE
__unpredictable_unless 19 == '1'
__unpredictable_unless 18 == '1'
__unpredictable_unless 17 == '1'
__unpredictable_unless 16 == '1'
__unpredictable_unless 13 == '0'
__unpredictable_unless 11 == '0'
__decode
if InITBlock() then UNPREDICTABLE;
__execute __conditional
ConsumptionOfSpeculativeDataBarrier();
__instruction aarch32_VST3_m_A
__encoding aarch32_VST3_m_T1A1_A
__instruction_set A32
__field D 22 +: 1
__field Rn 16 +: 4
__field Vd 12 +: 4
__field itype 8 +: 4
__field size 6 +: 2
__field align 4 +: 2
__field Rm 0 +: 4
__opcode '11110100 0x00xxxx xxxx010x xxxxxxxx'
__guard TRUE
__decode
if size == '11' || align[1] == '1' then UNDEFINED;
case itype of
when '0100'
inc = 1;
when '0101'
inc = 2;
otherwise
SEE "Related encodings";
alignment = if align[0] == '0' then 1 else 8;
ebytes = 1 << UInt(size); elements = 8 DIV ebytes;
d = UInt(D:Vd); d2 = d + inc; d3 = d2 + inc; n = UInt(Rn); m = UInt(Rm);
wback = (m != 15); register_index = (m != 15 && m != 13);
if n == 15 || d3 > 31 then UNPREDICTABLE;
```
# asli.ml
```asl=
let banner = [
{| _____ _ _ ___________________________________|};
{| /\ / ____|| | (_) ASL interpreter |};
{| / \ | (___ | | _ Copyright Arm Limited (c) 2017-2019|};
{| / /\ \ \___ \ | | | | |};
{| / ____ \ ____) || |____ | | |} ^ version;
{|/_/ \_\|_____/ |______||_| ___________________________________|}
]
let usage_msg =
( version
^ "\nusage: asl <options> <file1> ... <fileN>\n"
)
let _ =
Arg.parse options
(fun s -> opt_filenames := (!opt_filenames) @ [s])
usage_msg
let main () =
if !opt_print_version then Printf.printf "%s\n" version
else begin
List.iter print_endline banner;
print_endline "\nType :? for help";
let t = LoadASL.read_file "prelude.asl" true !opt_verbose in
let ts = List.map (fun filename ->
if Utils.endswith filename ".spec" then begin
LoadASL.read_spec filename !opt_verbose
end else if Utils.endswith filename ".asl" then begin
LoadASL.read_file filename false !opt_verbose
end else begin
failwith ("Unrecognized file suffix on "^filename)
end
) !opt_filenames
in
if !opt_verbose then Printf.printf "Building evaluation environment\n";
let env = (try
Eval.build_evaluation_environment (List.concat (t::ts))
with
| Value.EvalError (loc, msg) ->
Printf.printf " %s: Evaluation error: %s\n" (pp_loc loc) msg;
exit 1
) in
if !opt_verbose then Printf.printf "Built evaluation environment\n";
LNoise.history_load ~filename:"asl_history" |> ignore;
LNoise.history_set ~max_length:100 |> ignore;
repl (TC.Env.mkEnv TC.env0) (Cpu.mkCPU env)
end
let _ =ignore(main ())
(****************************************************************
* End
****************************************************************)
```
```asl=
__decode A64
// A64
case (29 +: 3, 24 +: 5, 0 +: 24) of
when (_, '0000x', _) =>
// reserved
case (29 +: 3, 25 +: 4, 16 +: 9, 0 +: 16) of
when ('000', _, '000000000', _) => // perm_undef
__field imm16 0 +: 16
case () of
when () => __encoding aarch64_udf // UDF_only_perm_undef
when (_, _, !'000000000', _) => __UNPREDICTABLE
when (!'000', _, _, _) => __UNPREDICTABLE
when (_, '00011', _) => __UNPREDICTABLE
when (_, '0010x', _) =>
// sve
case (29 +: 3, 25 +: 4, 23 +: 2, 22 +: 1, 17 +: 5, 16 +: 1, 10 +: 6, 0 +: 10) of
when ('000', _, '0x', _, '0xxxx', _, 'x1xxxx', _) =>
// sve_int_muladd_pred
case (24 +: 8, 22 +: 2, 21 +: 1, 16 +: 5, 15 +: 1, 14 +: 1, 0 +: 14) of
when (_, _, _, _, '0', _, _) => // sve_int_mlas_vvv_pred
__field size 22 +: 2
__field Zm 16 +: 5
__field op 13 +: 1
__field Pg 10 +: 3
__field Zn 5 +: 5
__field Zda 0 +: 5
case (op) of
when ('0') => __encoding MLA_Z_P_ZZZ__ // mla_z_p_zzz_
when ('1') => __encoding MLS_Z_P_ZZZ__ // mls_z_p_zzz_
when (_, _, _, _, '1', _, _) => // sve_int_mladdsub_vvv_pred
__field size 22 +: 2
__field Zm 16 +: 5
__field op 13 +: 1
__field Pg 10 +: 3
__field Za 5 +: 5
__field Zdn 0 +: 5
case (op) of
when ('0') => __encoding MAD_Z_P_ZZZ__ // mad_z_p_zzz_
when ('1') => __encoding MSB_Z_P_ZZZ__ // msb_z_p_zzz_
```
在arm/asl-interpreter/bin/asli.ml
應該可以找到相對應的入口點
```
| [":run"] ->
(try
while true do
cpu.step ()
done
with
| Value.Throw (_, Primops.Exc_ExceptionTaken) ->
Printf.printf "Exception taken\n"
)
```
# cpu.ml
```
let mkCPU (env : Eval.Env.t): cpu =
let loc = AST.Unknown in
let reset (_ : unit): unit =
Eval.eval_proccall loc env (AST.FIdent ("__TakeColdReset", 0)) [] []
and step (_ : unit): unit =
Eval.eval_proccall loc env (AST.FIdent ("__InstructionExecute", 0)) [] []
and getPC (_ : unit): Primops.bigint =
let r = Eval.eval_funcall loc env (AST.FIdent ("__getPC", 0)) [] [] in
Value.to_integer loc r
and setPC (x : Primops.bigint): unit =
let a = Value.VInt x in
Eval.eval_proccall loc env (AST.FIdent ("__setPC", 0)) [] [a]
and elfwrite (addr: Int64.t) (b: char): unit =
let a = Value.VBits (Primops.mkBits 64 (Z.of_int64 addr)) in
let b = Value.VBits (Primops.mkBits 8 (Z.of_int (Char.code b))) in
Eval.eval_proccall loc env (AST.FIdent ("__ELFWriteMemory", 0)) [] [a; b]
and opcode (iset: string) (opcode: Primops.bigint): unit =
let op = Value.VBits (Primops.prim_cvt_int_bits (Z.of_int 32) opcode) in
let decoder = Eval.Env.getDecoder env (Ident iset) in
Eval.eval_decode_case AST.Unknown env decoder op
in
{
env = env;
reset = reset;
step = step;
getPC = getPC;
setPC = setPC;
elfwrite = elfwrite;
opcode = opcode
}
```
# 觀察專案進入點
前面大致了解架構來看一下內部
```
__TakeColdReset();
:elf tests/test_O2.elf
_PC = 0x400168[63:0];
SP[] = 0x100000[63:0];
:set -trace:instr
:set -trace:fun
:set -trace:prim
:set -trace:write
:run
```
wsl 目前不能安裝arm toolchain 暫且用 ida pro 觀看elf執行檔案的 call flow,
作者說用 write 寫 ascii
```
The example binary writes the word “Test” to a serial port and then writes the ASCII character EOT (end of transmission) to stop the interpreter. This produces output like this
```
![](https://hackmd.io/_uploads/r19NMmTz6.png)
Entry point = 0x400168
![](https://hackmd.io/_uploads/HykJm7pMT.png)
print_sting
![](https://hackmd.io/_uploads/SJ72QQTGp.png)
這邊可能發生 print_sting inline 到 main function
![](https://hackmd.io/_uploads/SylRXQTfT.png)
實際上可能直接使用x2的值
LDRB W0, [X2],#1 ; "est\n"
目前沒arm toolchain 環境 大概研究這邊
# asli.ml
找尋如何解析elf
```
| [":elf"; file] ->
Printf.printf "Loading ELF file %s.\n" file;
let entry = Elf.load_file file cpu.elfwrite in
Printf.printf "Entry point = 0x%Lx\n" entry
```
# cpu.ml
```
and elfwrite (addr: Int64.t) (b: char): unit =
let a = Value.VBits (Primops.mkBits 64 (Z.of_int64 addr)) in
let b = Value.VBits (Primops.mkBits 8 (Z.of_int (Char.code b))) in
Eval.eval_proccall loc env (AST.FIdent ("__ELFWriteMemory", 0)) [] [a; b]
```
# memory.asl
```
__ELFWriteMemory(bits(64) address, bits(8) val)
__WriteRAM(52, 1, __Memory, address[0 +: 52], val);
return;
```
設置 pc 和 stack 後 ,cpu 開始逐步往下執行
# cpu.ml
```
and step (_ : unit): unit =
Eval.eval_proccall loc env (AST.FIdent ("__InstructionExecute", 0)) [] []
```
# fetchdecode.asl
觀察怎麼fetchecode
```
__InstructionExecute()
try
__BranchTaken = FALSE;
bits(64) pc = ThisInstrAddr();
(enc, instr) = __FetchInstr(pc);
__SetThisInstrDetails(enc, instr, __DefaultCond(enc));
__DecodeExecute(enc, instr);
```
(enc, instr) = __FetchInstr(pc);
這邊是處理 64,32,__T16,__T32
```
(__InstrEnc, bits(32)) __FetchInstr(bits(64) pc)
__InstrEnc enc;
bits(32) instr;
CheckSoftwareStep();
if PSTATE.nRW == '0' then
AArch64.CheckPCAlignment();
enc = __A64;
instr = AArch64.MemSingle[pc, 4, AccType_IFETCH, TRUE];
AArch64.CheckIllegalState();
else
AArch32.CheckPCAlignment();
if PSTATE.T == '1' then
hw1 = AArch32.MemSingle[pc[31:0], 2, AccType_IFETCH, TRUE];
isT16 = UInt(hw1[15:11]) < UInt('11101');
if isT16 then
enc = __T16;
instr = Zeros(16) : hw1;
else
hw2 = AArch32.MemSingle[pc[31:0]+2, 2, AccType_IFETCH, TRUE];
enc = __T32;
instr = hw1 : hw2;
else
enc = __A32;
instr = AArch32.MemSingle[pc[31:0], 4, AccType_IFETCH, TRUE];
AArch32.CheckIllegalState();
return (enc, instr);
```
# arch.asl
檢查 AArch64 alignment
```
AArch64.CheckPCAlignment()
bits(64) pc = ThisInstrAddr();
if pc[1:0] != '00' then
AArch64.PCAlignmentFault();
```
檢查 AArch32 alignment
```
AArch32.CheckPCAlignment()
bits(32) pc = ThisInstrAddr();
if (CurrentInstrSet() == InstrSet_A32 && pc[1] == '1') || pc[0] == '1' then
if AArch32.GeneralExceptionsToAArch64() then AArch64.PCAlignmentFault();
// Generate an Alignment fault Prefetch Abort exception
vaddress = pc;
acctype = AccType_IFETCH;
iswrite = FALSE;
secondstage = FALSE;
AArch32.Abort(vaddress, AArch32.AlignmentFault(acctype, iswrite, secondstage));
```
# __DefaultCond
```
給指令一個預設的 cond,可能最後會在某一個狀態更新掉cond裡面的值
// Default condition for an instruction with encoding 'enc'.
// This may be overridden for instructions with explicit condition field.
bits(4) __DefaultCond(__InstrEnc enc)
if enc IN {__A64, __A32} || PSTATE.IT[3:0] == Zeros(4) then
cond = 0xE[3:0];
else
cond = PSTATE.IT[7:4];
return cond;
__SetThisInstrDetails(enc, instr, __DefaultCond(enc));
```
# decode
到這邊已經知道 指令是否合法和 屬於哪一種指令集架構
return (enc, instr);
```
__DecodeExecute(__InstrEnc enc, bits(32) instr)
case enc of
when __A64
ExecuteA64(instr);
when __A32
ExecuteA32(instr);
when __T16
ExecuteT16(instr[15:0]);
when __T32
ExecuteT32(instr[31:16], instr[15:0]);
return;
```
# Execute
```
ExecuteA64(bits(32) instr)
__decode A64 instr;
ExecuteA32(bits(32) instr)
__decode A32 instr;
ExecuteT32(bits(16) hw1, bits(16) hw2)
__decode T32 (hw1 : hw2);
ExecuteT16(bits(16) instr)
__decode T16 instr;
```
這邊應該是在ram/tool中將xml 轉成tree之類的東西,我們的inst丟進來進行查表,並更根據不同的指令操作ocaml 模擬出來的 register
# arch_decode.asl
```
__decode A64
// A64
case (29 +: 3, 24 +: 5, 0 +: 24) of
when (_, '0000x', _) =>
// reserved
case (29 +: 3, 25 +: 4, 16 +: 9, 0 +: 16) of
when ('000', _, '000000000', _) => // perm_undef
__field imm16 0 +: 16
case () of
when () => __encoding aarch64_udf // UDF_only_perm_undef
when (_, _, !'000000000', _) => __UNPREDICTABLE
when (!'000', _, _, _) => __UNPREDICTABLE
when (_, '00011', _) => __UNPREDICTABLE
when (_, '0010x', _) =>
....
when (_, _, _, _, '1', _, _) => // sve_int_mladdsub_vvv_pred
__field size 22 +: 2
__field Zm 16 +: 5
__field op 13 +: 1
__field Pg 10 +: 3
__field Za 5 +: 5
__field Zdn 0 +: 5
case (op) of
when ('0') => __encoding MAD_Z_P_ZZZ__ // mad_z_p_zzz_
when ('1') => __encoding MSB_Z_P_ZZZ__ // msb_z_p_zzz_
when ('000', _, '0x', _, '0xxxx', _, '000xxx', _) =>
```
# arch_instrs.asl
可以看到最終是呼叫 __encoding ,從inst根據指令的type將該指令某幾個bit切到相對應的ocaml variable
```
__instruction FMAD_Z_P_ZZZ__
__encoding FMAD_Z_P_ZZZ__
__instruction_set A64
__field size 22 +: 2
__field Za 16 +: 5
__field Pg 10 +: 3
__field Zm 5 +: 5
__field Zdn 0 +: 5
__opcode '01100101 xx1xxxxx 100xxxxx xxxxxxxx'
__guard TRUE
__decode
if !HaveSVE() then UNDEFINED;
if size == '00' then UNDEFINED;
integer esize = 8 << UInt(size);
integer g = UInt(Pg);
integer dn = UInt(Zdn);
integer m = UInt(Zm);
integer a = UInt(Za);
boolean op1_neg = FALSE;
boolean op3_neg = FALSE;
```
在paser 有可能會有一段decode完 執行會做哪些操作__execute , __execute __conditional ,再根據前面設定的 ocmal 的 variable進行操作,以此來模擬操作cpu的 register
```
__execute
CheckSVEEnabled();
integer elements = VL DIV esize;
bits(PL) mask = P[g];
bits(VL) operand1 = Z[dn];
bits(VL) operand2 = Z[m];
bits(VL) operand3 = Z[a];
bits(VL) result;
for e = 0 to elements-1
bits(esize) element1 = Elem[operand1, e, esize];
bits(esize) element2 = Elem[operand2, e, esize];
bits(esize) element3 = Elem[operand3, e, esize];
if ElemP[mask, e, esize] == '1' then
if op1_neg then element1 = FPNeg(element1);
if op3_neg then element3 = FPNeg(element3);
Elem[result, e, esize] = FPMulAdd(element3, element1, element2, FPCR);
else
Elem[result, e, esize] = element1;
Z[dn] = result;
```
到這邊大概了解怎麼執行一行指令
# 研究xml 與 ocaml 關聯
## instrs2asl.py
前面已經將大致流程致流程致流程走過一次,大概就是將 arm 將isa xml 進行 parsing 然後在模擬器decode完成時候查詢這些asl code 在來根據這些ocaml variable 來模擬操作register.
```
bin/instrs2asl.py --altslicesyntax --demangle --verbose -oarch/arch v8.6/ISA_AArch32_xml_v86A-2019-12 v8.6/ISA_A64_xml_v86A-2019-12
Selecting entire architecture
Reading decoder v8.6/ISA_A64_xml_v86A-2019-12/encodingindex.xml
Reading decoder v8.6/ISA_AArch32_xml_v86A-2019-12/t32_encindex.xml
Reading decoder v8.6/ISA_AArch32_xml_v86A-2019-12/a32_encindex.xml
Keeping entire specification
Writing instruction encodings to arch/arch.tag
Writing instructions to arch/arch_instrs.asl
Writing instruction decoder to arch/arch_decode.asl
Writing ASL definitions to arch/arch.asl
patch -Np0 < arch.patch
patching file arch/arch.asl
patching file arch/arch_instrs.asl
Hunk #1 succeeded at 20178 with fuzz 2 (offset 19948 lines).
```
改動一下print就可以看到instruction name
```
def emit_asl_syntax(self, ofile):
print("__instruction "+ deslash(self.name), file=ofile)
print( deslash(self.name))
```
```
aarch64_vector_arithmetic_binary_uniform_div_fp16
0x101110 010xxxxx 001111xx xxxxxxxx
0x101110 0x1xxxxx 111111xx xxxxxxxx
aarch64_vector_arithmetic_binary_element_mul_acc_long
0xx01111 xxxxxxxx 0x10x0xx xxxxxxxx
aarch64_float_arithmetic_max_min
00011110 xx1xxxxx 01xx10xx xxxxxxxx
Writing instruction decoder to arch/arch_decode.asl
Writing ASL definitions to arch/arch.asl
patch -Np0 < arch.patch
patching file arch/arch.asl
patching file arch/arch_instrs.asl
Hunk #1 succeeded at 20178 with fuzz 2 (offset 19948 lines).
```
再查看 instrs2asl.py
可以看到 instr2asl讀取三個xml 格式檔案
```
Reading decoder v8.6/ISA_A64_xml_v86A-2019-12/encodingindex.xml
Reading decoder v8.6/ISA_AArch32_xml_v86A-2019-12/t32_encindex.xml
Reading decoder v8.6/ISA_AArch32_xml_v86A-2019-12/a32_encindex.xml
```
可以觀察到之前有假設的這是一個查表的tree
```
when (_, '0010x', _) =>
// sve
case (29 +: 3, 25 +: 4, 23 +: 2, 22 +: 1, 17 +: 5, 16 +: 1, 10 +: 6, 0 +: 10) of
when ('000', _, '0x', _, '0xxxx', _, 'x1xxxx', _) =>
// sve_int_muladd_pred
case (24 +: 8, 22 +: 2, 21 +: 1, 16 +: 5, 15 +: 1, 14 +: 1, 0 +: 14) of
when (_, _, _, _, '0', _, _) => // sve_int_mlas_vvv_pred
__field size 22 +: 2
__field Zm 16 +: 5
__field op 13 +: 1
__field Pg 10 +: 3
__field Zn 5 +: 5
__field Zda 0 +: 5
case (op) of
when ('0') => __encoding MLA_Z_P_ZZZ__ // mla_z_p_zzz_
when ('1') => __encoding MLS_Z_P_ZZZ__ // mls_z_p_zzz_
when (_, _, _, _, '1', _, _) => // sve_int_mladdsub_vvv_pred
__field size 22 +: 2
__field Zm 16 +: 5
__field op 13 +: 1
__field Pg 10 +: 3
__field Za 5 +: 5
__field Zdn 0 +: 5
case (op) of
when ('0') => __encoding MAD_Z_P_ZZZ__ // mad_z_p_zzz_
when ('1') => __encoding MSB_Z_P_ZZZ__ // msb_z_p_zzz_
```
也就是以sve_int_mlas_vvv_pred 來說可以對印到
```xml=
<iclass_sect id="sve_int_mlas_vvv_pred" title="SVE integer multiply-accumulate writing addend (predicated)">
<regdiagram form="32" psname="">
<box hibit="31" width="8" settings="8">
<c>0</c>
<c>0</c>
<c>0</c>
<c>0</c>
<c>0</c>
<c>1</c>
<c>0</c>
<c>0</c>
</box>
<box hibit="23" width="2" name="size" usename="1">
<c colspan="2"></c>
</box>
<box hibit="21" settings="1">
<c>0</c>
</box>
<box hibit="20" width="5" name="Zm" usename="1">
<c colspan="5"></c>
</box>
<box hibit="15" width="2" settings="2">
<c>0</c>
<c>1</c>
</box>
<box hibit="13" name="op" usename="1">
<c></c>
</box>
<box hibit="12" width="3" name="Pg" usename="1">
<c colspan="3"></c>
</box>
<box hibit="9" width="5" name="Zn" usename="1">
<c colspan="5"></c>
</box>
<box hibit="4" width="5" name="Zda" usename="1">
<c colspan="5"></c>
</box>
</regdiagram>
<instructiontable iclass="sve_int_mlas_vvv_pred" cols="3">
<col colno="1" printwidth="15*" />
<col colno="2" printwidth="18*" />
<col colno="3" printwidth="10*" />
<thead class="instructiontable">
<tr id="heading1">
<th colno="1" class="bitfields-heading">Decode fields</th>
<th rowspan="2" class="iformname">Instruction page</th>
<th rowspan="2" class="enctags">Encoding</th>
</tr>
<tr id="heading2">
<th class="bitfields">op</th>
</tr>
</thead>
<tbody>
<tr class="instructiontable" encname="mla_z_p_zzz_" iformfile="mla_z_p_zzz.xml" first="t" last="t">
<td bitwidth="1" class="bitfield">0</td>
<td class="iformname" iformid="mla_z_p_zzz">MLA</td>
</tr>
<tr class="instructiontable" encname="mls_z_p_zzz_" iformfile="mls_z_p_zzz.xml" first="t" last="t">
<td bitwidth="1" class="bitfield">1</td>
<td class="iformname" iformid="mls_z_p_zzz">MLS</td>
</tr>
</tbody>
</instructiontable>
</iclass_sect>
<iclass_sect id="sve_int_mladdsub_vvv_pred" title="SVE integer multiply-add writing multiplicand (predicated)">
<regdiagram form="32" psname="">
<box hibit="31" width="8" settings="8">
<c>0</c>
<c>0</c>
<c>0</c>
<c>0</c>
<c>0</c>
<c>1</c>
<c>0</c>
<c>0</c>
</box>
<box hibit="23" width="2" name="size" usename="1">
<c colspan="2"></c>
</box>
<box hibit="21" settings="1">
<c>0</c>
</box>
<box hibit="20" width="5" name="Zm" usename="1">
<c colspan="5"></c>
</box>
<box hibit="15" width="2" settings="2">
<c>1</c>
<c>1</c>
</box>
<box hibit="13" name="op" usename="1">
<c></c>
</box>
<box hibit="12" width="3" name="Pg" usename="1">
<c colspan="3"></c>
</box>
<box hibit="9" width="5" name="Za" usename="1">
<c colspan="5"></c>
</box>
<box hibit="4" width="5" name="Zdn" usename="1">
<c colspan="5"></c>
</box>
</regdiagram>
<instructiontable iclass="sve_int_mladdsub_vvv_pred" cols="3">
<col colno="1" printwidth="15*" />
<col colno="2" printwidth="18*" />
<col colno="3" printwidth="10*" />
<thead class="instructiontable">
<tr id="heading1">
<th colno="1" class="bitfields-heading">Decode fields</th>
<th rowspan="2" class="iformname">Instruction page</th>
<th rowspan="2" class="enctags">Encoding</th>
</tr>
<tr id="heading2">
<th class="bitfields">op</th>
</tr>
</thead>
<tbody>
<tr class="instructiontable" encname="mad_z_p_zzz_" iformfile="mad_z_p_zzz.xml" first="t" last="t">
<td bitwidth="1" class="bitfield">0</td>
<td class="iformname" iformid="mad_z_p_zzz">MAD</td>
</tr>
<tr class="instructiontable" encname="msb_z_p_zzz_" iformfile="msb_z_p_zzz.xml" first="t" last="t">
<td bitwidth="1" class="bitfield">1</td>
<td class="iformname" iformid="msb_z_p_zzz">MSB</td>
</tr>
</tbody>
</instructiontable>
</iclass_sect>
```
也就是剛剛看到
```
when ('000', _, '0x', _, '0xxxx', _, 'x1xxxx', _)
<c>0</c>
<c>0</c>
<c>0</c>
<c>0</c>
<c>0</c>
<c>1</c>
<c>0</c>
<c>0</c>
有可能滿足條件會被分到這一個分類
00000x00
x應該是任意數
```
在進一步查看
```xml=
case (24 +: 8, 22 +: 2, 21 +: 1, 16 +: 5, 15 +: 1, 14 +: 1, 0 +: 14) of
when (_, _, _, _, '0', _, _) => // sve_int_mlas_vvv_pred
__field size 22 +: 2
__field Zm 16 +: 5
__field op 13 +: 1
__field Pg 10 +: 3
__field Zn 5 +: 5
__field Zda 0 +: 5
```
對印到instrs2asl.py 裡面的程式碼
```asl=
for (fnm, hi, wd) in fields:
print(" "*level + "__field "+ fnm +" "+str(hi-wd+1) +" +: "+str(wd), file=ofile)
print(" "*level +"case ("+ ", ".join(hdr) +") of", file=ofile)
```
也就是要求field = str(hi-wd+1) +" +: "+str(wd)
差不多就是有name 才進行處理
```
__field size 22 +: 2 <box hibit="23" width="2" name="size" usename="1">
__field Zm 16 +: 5 <box hibit="20" width="5" name="Zm" usename="1">
__field op 13 +: 1 <box hibit="13" name="op" usename="1">
__field Pg 10 +: 3 <box hibit="12" width="3" name="Pg" usename="1">
__field Zn 5 +: 5 <box hibit="9" width="5" name="Za" usename="1">
__field Zda 0 +: 5 <box hibit="4" width="5" name="Zdn" usename="1">
```
那麼在runtime可能這些值都會持續變動直到滿足走向到一個確切的分類為止
```
case (op) of
when ('0') => __encoding MLA_Z_P_ZZZ__ // mla_z_p_zzz_
when ('1') => __encoding MLS_Z_P_ZZZ__ // mls_z_p_zzz_
```
## reg2asl.py
應該也是根據不同的xml type來描述register之類的事
bin/reg2asl.py v8.6/SysReg_xml_v86A-2019-12 -o arch/regs.asl
首先先從main開始解析
```
# read all the registers
regs = {}
for d in args.dir:
for f in glob.glob(os.path.join(d, '*.xml')):
print(f)
```
output
```
v8.6/SysReg_xml_v86A-2019-12/ext-gicv_aprn.xml
v8.6/SysReg_xml_v86A-2019-12/ext-gicr_partidr.xml
v8.6/SysReg_xml_v86A-2019-12/ext-cntfrq.xml
v8.6/SysReg_xml_v86A-2019-12/AArch64-mpamvpm7_el2.xml
v8.6/SysReg_xml_v86A-2019-12/ext-gicc_abpr.xml
v8.6/SysReg_xml_v86A-2019-12/AArch64-dc-gva.xml
v8.6/SysReg_xml_v86A-2019-12/AArch32-id_isar6.xml
v8.6/SysReg_xml_v86A-2019-12/ext-gicv_eoir.xml
v8.6/SysReg_xml_v86A-2019-12/ext-gicd_statusr.xml
v8.6/SysReg_xml_v86A-2019-12/AArch64-vmpidr_el2.xml
v8.6/SysReg_xml_v86A-2019-12/ext-pmlsr.xml
```
arm register
```python=
if re.match('^[a-zA-Z_]\w*$', name):
# merge any new fields in (mostly to handle external views of regs)
if name in regs:
for f,ss in regs[name][2].items():
if f not in fields:
fields[f] = ss
regs[name] = (long, length, fields, bounds)
print(regs[name])
```
arm register output
```
('Selected Error Record Miscellaneous Register 1', 64, {}, None)
('Debug OS Double Lock Register', 32, {'DLK': [('0', '0')]}, None)
('PL0 Read-Only Software Thread ID Register', 32, {}, None)
('SVE Control Register for EL2', 64, {'LEN': [('3', '0')]}, None)
('Cache Level ID Register', 32, {'ICB': [('31', '30')], 'LoUU': [('29', '27')], 'LoC': [('26', '24')], 'LoUIS': [('23', '21')]}, None)
('CPU Interface Non-secure Active Priorities Registers', 32, {}, ('0', '3'))
('Counter Scale Register', 32, {'ScaleVal': [('31', '0')]}, None)
('Virtual SError Exception Syndrome Register', 32, {'AET': [('15', '14')], 'ExT': [('12', '12')]}, None)
```
refer :
```
https://alastairreid.github.io/using-asli/
https://alastairreid.github.io/dissecting-ARM-MRA/
https://alastairreid.github.io/ARM-v8a-xml-release/
https://alastairreid.github.io/papers/FMCAD_16/
https://github.com/alastairreid/mra_tools#tools-to-extract-arms-machine-readable-architecture-specification
https://github.com/ARM-software/asl-interpreter
https://alastairreid.github.io/asl-lexical-syntax
https://v2.ocaml.org/docs/install.html
https://github.com/ARM-software/asl-interpreter/blob/master/utils.ml
```