123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418(****************************************************************
* ASL primitive types and operations
*
* Copyright Arm Limited (c) 2017-2019
* SPDX-Licence-Identifier: BSD-3-Clause
****************************************************************)(** ASL primitive types and operations *)moduleAST=Asl_ast(****************************************************************)(** {2 Boolean primops} *)(****************************************************************)letprim_eq_bool(x:bool)(y:bool):bool=x=yletprim_ne_bool(x:bool)(y:bool):bool=x<>yletprim_and_bool(x:bool)(y:bool):bool=x&&yletprim_or_bool(x:bool)(y:bool):bool=x||yletprim_equiv_bool(x:bool)(y:bool):bool=x=yletprim_not_bool(x:bool):bool=notx(****************************************************************)(** {2 Integer primops} *)(****************************************************************)typebigint=Z.tletprim_eq_int(x:bigint)(y:bigint):bool=Z.equalxyletprim_ne_int(x:bigint)(y:bigint):bool=not(Z.equalxy)letprim_le_int(x:bigint)(y:bigint):bool=Z.leqxyletprim_lt_int(x:bigint)(y:bigint):bool=Z.ltxyletprim_ge_int(x:bigint)(y:bigint):bool=Z.geqxyletprim_gt_int(x:bigint)(y:bigint):bool=Z.gtxyletprim_is_pow2_int(x:bigint):bool=Z.equal(Z.logandx(Z.subxZ.one))Z.zeroletprim_neg_int(x:bigint):bigint=Z.negxletprim_add_int(x:bigint)(y:bigint):bigint=Z.addxyletprim_sub_int(x:bigint)(y:bigint):bigint=Z.subxyletprim_shl_int(x:bigint)(y:bigint):bigint=Z.shift_leftx(Z.to_inty)letprim_shr_int(x:bigint)(y:bigint):bigint=Z.shift_rightx(Z.to_inty)letprim_mul_int(x:bigint)(y:bigint):bigint=Z.mulxyletprim_zdiv_int(x:bigint)(y:bigint):bigint=Z.divxyletprim_zrem_int(x:bigint)(y:bigint):bigint=Z.remxyletprim_fdiv_int(x:bigint)(y:bigint):bigint=Z.fdivxyletprim_frem_int(x:bigint)(y:bigint):bigint=Z.subx(Z.muly(Z.fdivxy))letprim_mod_pow2_int(x:bigint)(y:bigint):bigint=letmask=Z.sub(Z.shift_leftZ.one(Z.to_inty))Z.oneinZ.logandxmaskletprim_align_int(x:bigint)(y:bigint):bigint=lety'=Z.to_intyin(* todo: not very efficient *)Z.shift_left(Z.shift_right_truncxy')y'letprim_pow2_int(x:bigint):bigint=Z.shift_leftZ.one(Z.to_intx)letprim_pow_int_int(x:bigint)(y:bigint):bigint=lety'=Z.to_intyinassert(y'>=0);Z.powxy'(****************************************************************)(** {2 Real primops} *)(****************************************************************)typereal=Q.tletprim_cvt_int_real(x:bigint):real=Q.of_bigintxletprim_eq_real(x:real)(y:real):bool=Q.equalxyletprim_ne_real(x:real)(y:real):bool=not(Q.equalxy)letprim_le_real(x:real)(y:real):bool=Q.leqxyletprim_lt_real(x:real)(y:real):bool=Q.ltxyletprim_ge_real(x:real)(y:real):bool=Q.geqxyletprim_gt_real(x:real)(y:real):bool=Q.gtxyletprim_neg_real(x:real):real=Q.negxletprim_add_real(x:real)(y:real):real=Q.addxyletprim_sub_real(x:real)(y:real):real=Q.subxyletprim_mul_real(x:real)(y:real):real=Q.mulxyletprim_div_real(x:real)(y:real):real=Q.divxyletprim_pow2_real(x:bigint):real=letx'=Z.to_intxinifx'>=0thenQ.mul_2expQ.onex'elseQ.div_2expQ.one(-x')letprim_round_tozero_real(x:real):bigint=Q.to_bigintxletprim_round_down_real(x:real):bigint=ifQ.signx>=0thenbeginQ.to_bigintxendelseifZ.equalZ.one(Q.denx)thenbegin(* exact int *)Q.to_bigintxendelsebeginZ.subZ.one(Q.to_bigintx)endletprim_round_up_real(x:real):bigint=ifQ.signx<=0thenbeginQ.to_bigintxendelseifZ.equalZ.one(Q.denx)thenbegin(* exact int *)Q.to_bigintxendelsebeginZ.addZ.one(Q.to_bigintx)endletprim_sqrt_real(x:real):real=failwith"prim_sqrt_real"(****************************************************************)(** {2 Bitvector primops} *)(****************************************************************)(** Invariants:
- the bigint part of a bitvector is positive
- the bigint part of an N-bit bitvector is less than 2^N
*)typebitvector={n:int;v:Z.t}letempty_bits={n=0;v=Z.zero}(* workaround: ZArith library doesn't like zero-length extracts *)letchecked_extractfvofflen=iflen>0thenfvofflenelseZ.zeroletz_extract=checked_extractZ.extractletz_signed_extract=checked_extractZ.signed_extract(* primary way of creating bitvector satisfying invariants *)letmkBits(n:int)(v:bigint):bitvector=(assert(n>=0);{n;v=z_extractv0n})(* utility function for use in implementing binary operators
* that checks that size of left operand and of right operand were the same
*)letmkBits2(n1:int)(n2:int)(v:bigint):bitvector=(assert(n1=n2);assert(n1>=0);{n=n1;v=z_extractv0n1})letprim_length_bits(x:bitvector):int=x.nletprim_cvt_int_bits(n:bigint)(i:bigint):bitvector=(assert(Z.geqnZ.zero);letn'=Z.to_intnin{n=n';v=z_extracti0n'})letprim_cvt_bits_sint(x:bitvector):bigint=z_signed_extractx.v0x.nletprim_cvt_bits_uint(x:bitvector):bigint=z_extractx.v0x.nletprim_eq_bits(x:bitvector)(y:bitvector):bool=assert(x.n=y.n);Z.equalx.vy.vletprim_ne_bits(x:bitvector)(y:bitvector):bool=assert(x.n=y.n);not(Z.equalx.vy.v)letprim_add_bits(x:bitvector)(y:bitvector):bitvector=mkBits2x.ny.n(Z.addx.vy.v)letprim_sub_bits(x:bitvector)(y:bitvector):bitvector=mkBits2x.ny.n(Z.subx.vy.v)(* Note that because mul_bits produces the same size result as its inputs, the
* result is the same whether you consider bits to be signed or unsigned
*)letprim_mul_bits(x:bitvector)(y:bitvector):bitvector=mkBits2x.ny.n(Z.mulx.vy.v)letprim_and_bits(x:bitvector)(y:bitvector):bitvector=mkBitsx.n(Z.logandx.vy.v)letprim_or_bits(x:bitvector)(y:bitvector):bitvector=mkBitsx.n(Z.logorx.vy.v)letprim_eor_bits(x:bitvector)(y:bitvector):bitvector=mkBitsx.n(Z.logxorx.vy.v)letprim_not_bits(x:bitvector):bitvector=mkBitsx.n(Z.lognotx.v)letprim_zeros_bits(x:bigint):bitvector=mkBits(Z.to_intx)Z.zeroletprim_ones_bits(x:bigint):bitvector=mkBits(Z.to_intx)Z.minus_oneletprim_append_bits(x:bitvector)(y:bitvector):bitvector=mkBits(x.n+y.n)(Z.logor(Z.shift_leftx.vy.n)y.v)letprim_replicate_bits(x:bitvector)(y:bigint):bitvector=(* Tail recursive helper to calculate "x : ... : x : r" with c copies of x *)letrecpowerxcr=ifc=0thenrelseletr'=if(cland1)=0thenrelseprim_append_bitsxrinpower(prim_append_bitsxx)(c/2)r'inassert(Z.signy>=0);powerx(Z.to_inty)empty_bitsletprim_extract(x:bitvector)(i:bigint)(w:bigint):bitvector=leti'=Z.to_intiinletw'=Z.to_intwinassert(0<=i');assert(0<=w');assert(i'+w'<=x.n);mkBitsw'(z_extractx.vi'w')letprim_extract_int(x:Z.t)(i:bigint)(w:bigint):bitvector=leti'=Z.to_intiinletw'=Z.to_intwinassert(0<=i');assert(0<=w');mkBitsw'(z_extractxi'w')letprim_insert(x:bitvector)(i:bigint)(w:bigint)(y:bitvector):bitvector=leti'=Z.to_intiinletw'=Z.to_intwinassert(0<=i');assert(0<=w');assert(i'+w'<=x.n);assert(w'=y.n);letmsk=(Z.sub(Z.shift_leftZ.one(i'+w'))(Z.shift_leftZ.onei'))inletnmsk=Z.lognotmskinlety'=Z.shift_left(z_extracty.v0w')i'inmkBitsx.n(Z.logor(Z.logandnmskx.v)(Z.logandmsky'))(****************************************************************)(** {2 Mask primops} *)(****************************************************************)typemask={n:int;v:Z.t;m:Z.t}letmkMask(n:int)(v:Z.t)(m:Z.t):mask=assert(Z.equalv(Z.logandvm));{n;v;m}letprim_in_mask(x:bitvector)(m:mask):bool=Z.equal(Z.logandx.vm.m)m.vletprim_notin_mask(x:bitvector)(m:mask):bool=not(prim_in_maskxm)(****************************************************************)(** {2 Exception primops} *)(****************************************************************)typeexc=|Exc_ConstrainedUnpredictable|Exc_ExceptionTaken|Exc_ImpDefinedofstring|Exc_SEEofstring|Exc_Undefined|Exc_Unpredictableletprim_is_cunpred_exc(x:exc):bool=(matchxwithExc_ConstrainedUnpredictable->true|_->false)letprim_is_exctaken_exc(x:exc):bool=(matchxwithExc_ExceptionTaken->true|_->false)letprim_is_impdef_exc(x:exc):bool=(matchxwithExc_ImpDefined_->true|_->false)letprim_is_see_exc(x:exc):bool=(matchxwithExc_SEE_->true|_->false)letprim_is_undefined_exc(x:exc):bool=(matchxwithExc_Undefined->true|_->false)letprim_is_unpred_exc(x:exc):bool=(matchxwithExc_Unpredictable->true|_->false)(****************************************************************)(** {2 String primops} *)(****************************************************************)letprim_eq_str(x:string)(y:string):bool=x=yletprim_ne_str(x:string)(y:string):bool=x<>yletprim_append_str(x:string)(y:string):string=x^yletprim_cvt_int_hexstr(x:bigint):string=Z.format"%x"xletprim_cvt_int_decstr(x:bigint):string=Z.to_stringxletprim_cvt_bool_str(x:bool):string=ifxthen"TRUE"else"FALSE"letprim_cvt_bits_str(n:bigint)(x:bitvector):string=ifZ.equalnZ.zerothenbegin"''"endelsebeginlets=Z.format"%0b"x.vinletpad=String.make(Z.to_intn-String.lengths)'0'inZ.to_stringn^"'"^pad^s^"'"endletprim_cvt_real_str(x:real):string=letr=Q.to_stringxinifString.containsr'/'thenrelser^"/1"(****************************************************************)(** {2 Immutable Array type} *)(****************************************************************)moduleIndex=structtypet=intletcomparexy=Stdlib.comparexyendmoduleImmutableArray=Map.Make(Index)letprim_empty_array:'aImmutableArray.t=ImmutableArray.emptyletprim_read_array(x:'aImmutableArray.t)(i:int)(default:'a):'a=(matchImmutableArray.find_optixwith|Somer->r|None->default)letprim_write_array(x:'aImmutableArray.t)(i:int)(v:'a):'aImmutableArray.t=ImmutableArray.addivx(****************************************************************)(** {2 Mutable RAM type} *)(****************************************************************)(** RAM is implemented as a paged data structure and pages are
allocated on demand and initialized with a specified default
value.
*)modulePages=structincludeMap.Make(structtypet=bigintletcompare=Z.compareend)endtyperam={mutablecontents:Bytes.tPages.t;mutabledefault:char}letlogPageSize=16letpageSize=1lsllogPageSizeletpageMask=Z.of_int(pageSize-1)letpageIndexOfAddr(a:bigint):bigint=Z.shift_rightalogPageSizeletpageOffsetOfAddr(a:bigint):bigint=Z.logandapageMaskletinit_ram(d:char):ram={contents=Pages.empty;default=d}letclear_ram(mem:ram)(d:char):unit=mem.contents<-Pages.empty;mem.default<-dletreadByte_ram(mem:ram)(addr:bigint):char=letindex=pageIndexOfAddraddrinletoffset=pageOffsetOfAddraddrin(matchPages.find_optindexmem.contentswith|Somebs->Bytes.getbs(Z.to_intoffset)|None->mem.default)letwriteByte_ram(mem:ram)(addr:bigint)(v:char):unit=letindex=pageIndexOfAddraddrinletoffset=pageOffsetOfAddraddrinletbs=(matchPages.find_optindexmem.contentswith|Somebs->bs|None->letbs=Bytes.makepageSizemem.defaultinmem.contents<-Pages.addindexbsmem.contents;bs)inBytes.setbs(Z.to_intoffset)vletprim_init_ram(asz:bigint)(dsz:bigint)(mem:ram)(init:bitvector):unit=clear_rammem(char_of_int(Z.to_intinit.v))letprim_read_ram(asz:bigint)(dsz:bigint)(mem:ram)(addr:bigint):bitvector=letr=refZ.zeroinletrecread(i:int):unit=ifi<(Z.to_intdsz)thenletb=readByte_rammem(Z.addaddr(Z.of_inti))inr:=Z.logor(Z.shift_left(Z.of_int(int_of_charb))(8*i))!r;read(i+1)inread0;iffalsethenPrintf.printf"Read %Lx from address %Lx\n"(Z.to_int64!r)(Z.to_int64addr);mkBits(8*(Z.to_intdsz))!rletprim_write_ram(asz:bigint)(dsz:bigint)(mem:ram)(addr:bigint)(v:bitvector):unit=letrecwrite(i:int):unit=ifi<(Z.to_intdsz)thenletb=char_of_int(Z.to_int(z_extractv.v(i*8)8))inwriteByte_rammem(Z.addaddr(Z.of_inti))b;write(i+1)inwrite0(****************************************************************)(** {2 File primops} *)(****************************************************************)(** These are not part of the official ASL language but they are
useful when implementing the infrastructure needed in simulators.
*)letprim_open_file(name:string)(mode:string):bigint=failwith"open_file"letprim_write_file(fd:bigint)(data:string):unit=failwith"write_file"letprim_getc_file(fd:bigint):bigint=failwith"getc_file"letprim_print_str(data:string):unit=Printf.printf"%s"dataletprim_print_char(data:bigint):unit=Printf.printf"%c"(char_of_int(Z.to_intdata))(****************************************************************)(** {2 Trace primops} *)(****************************************************************)(** These are not part of the official ASL language but they are
useful when implementing the infrastructure needed in simulators.
*)letprim_trace_memory_read(asz:bigint)(dsz:bigint)(mem:ram)(addr:bigint)(v:bitvector):unit=()letprim_trace_memory_write(asz:bigint)(dsz:bigint)(mem:ram)(addr:bigint)(v:bitvector):unit=()letprim_trace_event(msg:string):unit=()(****************************************************************
* End
****************************************************************)