diff options
Diffstat (limited to 'riscv')
| -rw-r--r-- | riscv/riscv.sail | 194 | ||||
| -rw-r--r-- | riscv/riscv_step.sail | 14 | ||||
| -rw-r--r-- | riscv/riscv_sys.sail | 19 |
3 files changed, 148 insertions, 79 deletions
diff --git a/riscv/riscv.sail b/riscv/riscv.sail index 2b388f7c..fd42df21 100644 --- a/riscv/riscv.sail +++ b/riscv/riscv.sail @@ -6,7 +6,8 @@ scattered function decode val decodeCompressed : bits(16) -> option(ast) effect pure scattered function decodeCompressed -val execute : ast -> unit effect {escape, wreg, rreg, wmv, eamem, rmem, barr, exmem} +/* returns whether an instruction was retired, used for computing minstret */ +val execute : ast -> bool effect {escape, wreg, rreg, wmv, eamem, rmem, barr, exmem} scattered function execute val cast print_insn : ast -> string @@ -23,8 +24,10 @@ function clause execute UTYPE(imm, rd, op) = let ret : xlenbits = match op { RISCV_LUI => off, RISCV_AUIPC => PC + off - } in - X(rd) = ret + } in { + X(rd) = ret; + true + } function clause print_insn UTYPE(imm, rd, op) = match (op) { @@ -42,6 +45,7 @@ function clause execute (RISCV_JAL(imm, rd)) = { X(rd) = nextPC; /* compatible with JAL and C.JAL */ let offset : xlenbits = EXTS(imm); nextPC = pc + offset; + true } function clause print_insn (RISCV_JAL(imm, rd)) = @@ -58,6 +62,7 @@ function clause execute (RISCV_JALR(imm, rs1, rd)) = { X(rd) = nextPC; /* compatible with JALR, C.JR and C.JALR */ let newPC : xlenbits = X(rs1) + EXTS(imm); nextPC = newPC[63..1] @ 0b0; + true } function clause print_insn (RISCV_JALR(imm, rs1, rd)) = @@ -83,9 +88,10 @@ function clause execute (BTYPE(imm, rs2, rs1, op)) = RISCV_BGE => rs1_val >=_s rs2_val, RISCV_BLTU => rs1_val <_u rs2_val, RISCV_BGEU => rs1_val >=_u rs2_val - } in - if taken then - nextPC = PC + EXTS(imm) + } in { + if taken then nextPC = PC + EXTS(imm); + true + } function clause print_insn (BTYPE(imm, rs2, rs1, op)) = let insn : string = @@ -119,8 +125,10 @@ function clause execute (ITYPE (imm, rs1, rd, op)) = RISCV_XORI => rs1_val ^ immext, RISCV_ORI => rs1_val | immext, RISCV_ANDI => rs1_val & immext - } in - X(rd) = result + } in { + X(rd) = result; + true + } function clause print_insn (ITYPE(imm, rs1, rd, op)) = let insn : string = @@ -147,9 +155,10 @@ function clause execute (SHIFTIOP(shamt, rs1, rd, op)) = RISCV_SLLI => rs1_val << shamt, RISCV_SRLI => rs1_val >> shamt, RISCV_SRAI => shift_right_arith64(rs1_val, shamt) - } in - X(rd) = result - + } in { + X(rd) = result; + true + } function clause print_insn (SHIFTIOP(shamt, rs1, rd, op)) = let insn : string = @@ -188,8 +197,10 @@ function clause execute (RTYPE(rs2, rs1, rd, op)) = RISCV_SRA => shift_right_arith64(rs1_val, rs2_val[5..0]), RISCV_OR => rs1_val | rs2_val, RISCV_AND => rs1_val & rs2_val - } in - X(rd) = result + } in { + X(rd) = result; + true + } function clause print_insn (RTYPE(rs2, rs1, rd, op)) = let insn : string = @@ -224,17 +235,17 @@ function extend_value(is_unsigned, value) = match (value) { MemException(e) => MemException(e) } -val process_load : forall 'n, 0 < 'n <= 8. (regbits, xlenbits, MemoryOpResult(bits(8 * 'n)), bool) -> unit effect {escape, rreg, wreg} +val process_load : forall 'n, 0 < 'n <= 8. (regbits, xlenbits, MemoryOpResult(bits(8 * 'n)), bool) -> bool effect {escape, rreg, wreg} function process_load(rd, addr, value, is_unsigned) = match (extend_value(is_unsigned, value)) { - MemValue(result) => X(rd) = result, - MemException(e) => handle_mem_exception(addr, e) + MemValue(result) => { X(rd) = result; true }, + MemException(e) => { handle_mem_exception(addr, e); false } } function clause execute(LOAD(imm, rs1, rd, is_unsigned, width, aq, rl)) = let vaddr : xlenbits = X(rs1) + EXTS(imm) in match translateAddr(vaddr, Read, Data) { - TR_Failure(e) => handle_mem_exception(vaddr, e), + TR_Failure(e) => { handle_mem_exception(vaddr, e); false }, TR_Address(addr) => match width { BYTE => process_load(rd, vaddr, mem_read(addr, 1, aq, rl, false), is_unsigned), @@ -272,7 +283,7 @@ function clause decode imm7 : bits(7) @ rs2 : regbits @ rs1 : regbits @ 0b011 @ function clause execute (STORE(imm, rs2, rs1, width, aq, rl)) = let vaddr : xlenbits = X(rs1) + EXTS(imm) in match translateAddr(vaddr, Write, Data) { - TR_Failure(e) => handle_mem_exception(vaddr, e), + TR_Failure(e) => { handle_mem_exception(vaddr, e); false }, TR_Address(addr) => let eares : MemoryOpResult(unit) = match width { BYTE => mem_write_ea(addr, 1, aq, rl, false), @@ -281,7 +292,7 @@ function clause execute (STORE(imm, rs2, rs1, width, aq, rl)) = DOUBLE => mem_write_ea(addr, 8, aq, rl, false) } in match (eares) { - MemException(e) => handle_mem_exception(addr, e), + MemException(e) => { handle_mem_exception(addr, e); false }, MemValue(_) => { let rs2_val = X(rs2) in let res : MemoryOpResult(unit) = match width { @@ -291,8 +302,8 @@ function clause execute (STORE(imm, rs2, rs1, width, aq, rl)) = DOUBLE => mem_write_value(addr, 8, rs2_val, aq, rl, false) } in match (res) { - MemValue(_) => (), - MemException(e) => handle_mem_exception(addr, e) + MemValue(_) => true, + MemException(e) => { handle_mem_exception(addr, e); false } } } } @@ -314,9 +325,11 @@ union clause ast = ADDIW : (bits(12), regbits, regbits) function clause decode imm : bits(12) @ rs1 : regbits @ 0b000 @ rd : regbits @ 0b0011011 = Some(ADDIW(imm, rs1, rd)) -function clause execute (ADDIW(imm, rs1, rd)) = - let result : xlenbits = EXTS(imm) + X(rs1) in - X(rd) = EXTS(result[31..0]) +function clause execute (ADDIW(imm, rs1, rd)) = { + let result : xlenbits = EXTS(imm) + X(rs1); + X(rd) = EXTS(result[31..0]); + true +} function clause print_insn (ADDIW(imm, rs1, rd)) = "addiw " ^ rd ^ ", " ^ rs1 ^ ", " ^ BitStr(imm) @@ -334,8 +347,10 @@ function clause execute (SHIFTW(shamt, rs1, rd, op)) = RISCV_SLLI => rs1_val << shamt, RISCV_SRLI => rs1_val >> shamt, RISCV_SRAI => shift_right_arith32(rs1_val, shamt) - } in - X(rd) = EXTS(result) + } in { + X(rd) = EXTS(result); + true + } function clause print_insn (SHIFTW(shamt, rs1, rd, op)) = let insn : string = @@ -364,8 +379,10 @@ function clause execute (RTYPEW(rs2, rs1, rd, op)) = RISCV_SLLW => rs1_val << (rs2_val[4..0]), RISCV_SRLW => rs1_val >> (rs2_val[4..0]), RISCV_SRAW => shift_right_arith32(rs1_val, rs2_val[4..0]) - } in - X(rd) = EXTS(result) + } in { + X(rd) = EXTS(result); + true + } function clause print_insn (RTYPEW(rs2, rs1, rd, op)) = let insn : string = @@ -392,8 +409,10 @@ function clause execute (MUL(rs2, rs1, rd, high, signed1, signed2)) = let rs1_int : int = if signed1 then signed(rs1_val) else unsigned(rs1_val) in let rs2_int : int = if signed2 then signed(rs2_val) else unsigned(rs2_val) in let result128 = to_bits(128, rs1_int * rs2_int) in - let result = if high then result128[127..64] else result128[63..0] in - X(rd) = result + let result = if high then result128[127..64] else result128[63..0] in { + X(rd) = result; + true + } function clause print_insn (MUL(rs2, rs1, rd, high, signed1, signed2)) = let insn : string = @@ -415,7 +434,10 @@ function clause execute (DIV(rs2, rs1, rd, s)) = let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val) in let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val) in let q : int = if rs2_int == 0 then -1 else quot_round_zero(rs1_int, rs2_int) in - let q': int = if s & q > xlen_max_signed then xlen_min_signed else q in /* check for signed overflow */ X(rd) = to_bits(xlen, q') + let q': int = if s & q > xlen_max_signed then xlen_min_signed else q in /* check for signed overflow */ { + X(rd) = to_bits(xlen, q'); + true + } function clause print_insn (DIV(rs2, rs1, rd, s)) = let insn : string = if s then "div " else "divu " in @@ -430,9 +452,11 @@ function clause execute (REM(rs2, rs1, rd, s)) = let rs2_val = X(rs2) in let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val) in let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val) in - let r : int = if rs2_int == 0 then rs1_int else rem_round_zero(rs1_int, rs2_int) in + let r : int = if rs2_int == 0 then rs1_int else rem_round_zero(rs1_int, rs2_int) in { /* signed overflow case returns zero naturally as required due to -1 divisor */ - X(rd) = to_bits(xlen, r) + X(rd) = to_bits(xlen, r); + true + } function clause print_insn (REM(rs2, rs1, rd, s)) = let insn : string = if s then "rem " else "remu " in @@ -447,8 +471,10 @@ function clause execute (MULW(rs2, rs1, rd)) = let rs1_int : int = signed(rs1_val) in let rs2_int : int = signed(rs2_val) in let result32 = to_bits(64, rs1_int * rs2_int)[31..0] in /* XXX surprising behaviour of to_bits requires exapnsion to 64 bits followed by truncation... */ - let result : xlenbits = EXTS(result32) in - X(rd) = result + let result : xlenbits = EXTS(result32) in { + X(rd) = result; + true + } function clause print_insn (MULW(rs2, rs1, rd)) = "mulw " ^ rd ^ ", " ^ rs1 ^ ", " ^ rs2 @@ -463,8 +489,10 @@ function clause execute (DIVW(rs2, rs1, rd, s)) = let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val) in let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val) in let q : int = if rs2_int == 0 then -1 else quot_round_zero(rs1_int, rs2_int) in - let q': int = if s & q > (2 ^ 31 - 1) then (0 - 2^31) else q in /* check for signed overflow */ - X(rd) = EXTS(to_bits(32, q')) + let q': int = if s & q > (2 ^ 31 - 1) then (0 - 2^31) else q in /* check for signed overflow */ { + X(rd) = EXTS(to_bits(32, q')); + true + } function clause print_insn (DIVW(rs2, rs1, rd, s)) = let insn : string = if s then "divw " else "divuw " in @@ -479,9 +507,11 @@ function clause execute (REMW(rs2, rs1, rd, s)) = let rs2_val = X(rs2)[31..0] in let rs1_int : int = if s then signed(rs1_val) else unsigned(rs1_val) in let rs2_int : int = if s then signed(rs2_val) else unsigned(rs2_val) in - let r : int = if rs2_int == 0 then rs1_int else rem_round_zero(rs1_int, rs2_int) in - /* signed overflow case returns zero naturally as required due to -1 divisor */ - X(rd) = EXTS(to_bits(32, r)) + let r : int = if rs2_int == 0 then rs1_int else rem_round_zero(rs1_int, rs2_int) in { + /* signed overflow case returns zero naturally as required due to -1 divisor */ + X(rd) = EXTS(to_bits(32, r)); + true + } function clause print_insn (REMW(rs2, rs1, rd, s)) = let insn : string = if s then "remw " else "remuw " in @@ -501,7 +531,8 @@ function clause execute (FENCE(pred, succ)) = { (0b0001, 0b0001) => MEM_fence_w_w(), _ => { print("FIXME: unsupported fence"); () } - } + }; + true } /* FIXME */ @@ -513,7 +544,7 @@ union clause ast = FENCEI : unit function clause decode 0b000000000000 @ 0b00000 @ 0b001 @ 0b00000 @ 0b0001111 = Some(FENCEI()) -function clause execute FENCEI() = MEM_fence_i() +function clause execute FENCEI() = { MEM_fence_i(); true } function clause print_insn (FENCEI()) = "fence.i" @@ -529,9 +560,11 @@ function clause execute ECALL() = User => E_U_EnvCall, Supervisor => E_S_EnvCall, Machine => E_M_EnvCall - }, - excinfo = (None() : option(xlenbits)) } in - nextPC = handle_exception(cur_privilege, CTL_TRAP(t), PC) + }, + excinfo = (None() : option(xlenbits)) } in { + nextPC = handle_exception(cur_privilege, CTL_TRAP(t), PC); + false + } function clause print_insn (ECALL()) = "ecall" @@ -545,7 +578,8 @@ function clause execute MRET() = { if cur_privilege == Machine then nextPC = handle_exception(cur_privilege, CTL_MRET(), PC) else - handle_illegal() + handle_illegal(); + false } function clause print_insn (MRET()) = @@ -556,14 +590,16 @@ union clause ast = SRET : unit function clause decode 0b0001000 @ 0b00010 @ 0b00000 @ 0b000 @ 0b00000 @ 0b1110011 = Some(SRET()) -function clause execute SRET() = +function clause execute SRET() = { match cur_privilege { User => handle_illegal(), Supervisor => if mstatus.TSR() == true then handle_illegal() else nextPC = handle_exception(cur_privilege, CTL_SRET(), PC), Machine => nextPC = handle_exception(cur_privilege, CTL_SRET(), PC) - } + }; + false +} function clause print_insn (SRET()) = "sret" @@ -573,8 +609,10 @@ union clause ast = EBREAK : unit function clause decode 0b000000000001 @ 0b00000 @ 0b000 @ 0b00000 @ 0b1110011 = Some(EBREAK()) -function clause execute EBREAK() = - handle_mem_exception(PC, E_Breakpoint) +function clause execute EBREAK() = { + handle_mem_exception(PC, E_Breakpoint); + false +} function clause print_insn (EBREAK()) = "ebreak" @@ -591,7 +629,9 @@ function clause execute WFI() = { then handle_illegal() else (), User => handle_illegal() - } + }; + /* NOTE: since WFI is always interrupted, it should never retire. TODO: Confirm this. */ + false } function clause print_insn (WFI()) = @@ -606,13 +646,14 @@ function clause execute SFENCE_VMA(rs1, rs2) = { /* FIXME: spec leaves unspecified what happens if this is executed in M-mode. We assume it is the same as S-mode, which is definitely wrong. */ - if cur_privilege == User then handle_illegal() + if cur_privilege == User then { handle_illegal(); false } else match (architecture(mstatus.SXL()), mstatus.TVM()) { - (Some(RV64), true) => handle_illegal(), + (Some(RV64), true) => { handle_illegal(); false }, (Some(RV64), false) => { let addr : option(vaddr39) = if rs1 == 0 then None() else Some(X(rs1)[38 .. 0]); let asid : option(asid64) = if rs2 == 0 then None() else Some(X(rs2)[15 .. 0]); - flushTLB(asid, addr) + flushTLB(asid, addr); + true }, (_, _) => internal_error("unimplemented sfence architecture") } @@ -632,7 +673,7 @@ val process_loadres : forall 'n, 0 < 'n <= 8. (regbits, xlenbits, MemoryOpResult function clause execute(LOADRES(aq, rl, rs1, width, rd)) = let vaddr : xlenbits = X(rs1) in match translateAddr(vaddr, Read, Data) { - TR_Failure(e) => handle_mem_exception(vaddr, e), + TR_Failure(e) => { handle_mem_exception(vaddr, e); false }, TR_Address(addr) => match width { WORD => process_load(rd, addr, mem_read(addr, 4, aq, rl, true), false), @@ -663,10 +704,10 @@ function clause execute (STORECON(aq, rl, rs2, rs1, width, rd)) = { status : bits(1) = if speculate_conditional_success() then 0b0 else 0b1; X(rd) = EXTZ(status); - if status == 0b1 then () else { + if status == 0b1 then true else { vaddr : xlenbits = X(rs1); match translateAddr(vaddr, Write, Data) { - TR_Failure(e) => handle_mem_exception(vaddr, e), + TR_Failure(e) => { handle_mem_exception(vaddr, e); false }, TR_Address(addr) => { let eares : MemoryOpResult(unit) = match width { WORD => mem_write_ea(addr, 4, aq, rl, true), @@ -674,7 +715,7 @@ function clause execute (STORECON(aq, rl, rs2, rs1, width, rd)) = { _ => internal_error("STORECON expected word or double") }; match (eares) { - MemException(e) => handle_mem_exception(addr, e), + MemException(e) => { handle_mem_exception(addr, e); false }, MemValue(_) => { rs2_val = X(rs2); let res : MemoryOpResult(unit) = match width { @@ -683,8 +724,8 @@ function clause execute (STORECON(aq, rl, rs2, rs1, width, rd)) = { _ => internal_error("STORECON expected word or double") } in match (res) { - MemValue(_) => (), - MemException(e) => handle_mem_exception(addr, e) + MemValue(_) => true, + MemException(e) => { handle_mem_exception(addr, e); false } } } } @@ -730,7 +771,7 @@ function clause decode 0b11100 @ [aq] @ [rl] @ rs2 : regbits @ rs1 : regbits @ 0 function clause execute (AMO(op, aq, rl, rs2, rs1, width, rd)) = { vaddr : xlenbits = X(rs1); match translateAddr(vaddr, ReadWrite, Data) { - TR_Failure(e) => handle_mem_exception(vaddr, e), + TR_Failure(e) => { handle_mem_exception(vaddr, e); false }, TR_Address(addr) => { let eares : MemoryOpResult(unit) = match width { WORD => mem_write_ea(addr, 4, aq & rl, rl, true), @@ -738,7 +779,7 @@ function clause execute (AMO(op, aq, rl, rs2, rs1, width, rd)) = { _ => internal_error ("AMO expected WORD or DOUBLE") }; match (eares) { - MemException(e) => handle_mem_exception(addr, e), + MemException(e) => { handle_mem_exception(addr, e); false }, MemValue(_) => { let rval : MemoryOpResult(xlenbits) = match width { WORD => extend_value(false, mem_read(addr, 4, aq, aq & rl, true)), @@ -746,7 +787,7 @@ function clause execute (AMO(op, aq, rl, rs2, rs1, width, rd)) = { _ => internal_error ("AMO expected WORD or DOUBLE") }; match (rval) { - MemException(e) => handle_mem_exception(addr, e), + MemException(e) => { handle_mem_exception(addr, e); false }, MemValue(loaded) => { rs2_val : xlenbits = X(rs2); result : xlenbits = @@ -770,8 +811,8 @@ function clause execute (AMO(op, aq, rl, rs2, rs1, width, rd)) = { _ => internal_error("AMO expected WORD or DOUBLE") }; match (wval) { - MemValue(_) => X(rd) = loaded, - MemException(e) => handle_mem_exception(addr, e) + MemValue(_) => { X(rd) = loaded; true }, + MemException(e) => { handle_mem_exception(addr, e); false } } } } @@ -895,6 +936,11 @@ function writeCSR (csr : csreg, value : xlenbits) -> unit = /* trigger/debug */ 0x7a0 => { tselect = value; Some(tselect) }, + /* counters */ + 0xC00 => { mcycle = value; Some(mcycle) }, + /* FIXME: it is not clear whether writable mtime is platform-dependent. */ + 0xC02 => { minstret = value; minstret_written = true; Some(minstret) }, + _ => None() } in match res { @@ -909,7 +955,7 @@ function clause execute CSR(csr, rs1, rd, is_imm, op) = _ => if is_imm then unsigned(rs1_val) != 0 else unsigned(rs1) != 0 } in if ~ (check_CSR(csr, cur_privilege, isWrite)) - then handle_illegal() + then { handle_illegal(); false } else { let csr_val = readCSR(csr); /* could have side-effects, so technically shouldn't perform for CSRW[I] with rd == 0 */ if isWrite then { @@ -920,7 +966,8 @@ function clause execute CSR(csr, rs1, rd, is_imm, op) = } in writeCSR(csr, new_val) }; - X(rd) = csr_val + X(rd) = csr_val; + true } function clause print_insn (CSR(csr, rs1, rd, is_imm, op)) = @@ -944,7 +991,7 @@ function clause decodeCompressed (0b000 @ nzi1 : bits(1) @ 0b00000 @ (nzi0 : bit else None() } -function clause execute NOP() = () +function clause execute NOP() = true function clause print_insn (NOP()) = "nop" @@ -954,7 +1001,7 @@ union clause ast = ILLEGAL : unit function clause decodeCompressed (0b0000 @ 0b00000 @ 0b00000 @ 0b00) : bits(16) = Some(ILLEGAL()) -function clause execute ILLEGAL() = handle_illegal () +function clause execute ILLEGAL() = { handle_illegal(); false } function clause print_insn (ILLEGAL()) = "illegal" @@ -1081,10 +1128,11 @@ function clause execute (C_JAL(imm)) = { } function clause execute (C_ADDIW(imm, rsd)) = { - let imm : bits(32) = EXTS(imm) in - let rs_val = X(rsd) in - let res : bits(32) = rs_val[31..0] + imm in - X(rsd) = EXTS(res) + let imm : bits(32) = EXTS(imm); + let rs_val = X(rsd); + let res : bits(32) = rs_val[31..0] + imm; + X(rsd) = EXTS(res); + true } function clause print_insn (C_JAL(imm)) = diff --git a/riscv/riscv_step.sail b/riscv/riscv_step.sail index 9be11a8c..36f633ef 100644 --- a/riscv/riscv_step.sail +++ b/riscv/riscv_step.sail @@ -66,8 +66,7 @@ function step(step_no) = { Some(ast) => { print("[" ^ string_of_int(step_no) ^ "] " ^ BitStr(PC) ^ " (" ^ BitStr(h) ^ ") " ^ ast); nextPC = PC + 2; - execute(ast); - true + execute(ast) } } }, @@ -81,8 +80,7 @@ function step(step_no) = { Some(ast) => { print("[" ^ string_of_int(step_no) ^ "] " ^ BitStr(PC) ^ " (" ^ BitStr(w) ^ ") " ^ ast); nextPC = PC + 4; - execute(ast); - true + execute(ast) } } } @@ -97,9 +95,13 @@ function loop (tohost_addr) = { i : int = 0; while true do { tick_clock(); - let retired : bool = step(i); + minstret_written = false; /* see note for minstret */ + let retired = step(i); PC = nextPC; - if retired then i = i + 1; + if retired then { + i = i + 1; + retire_instruction() + }; /* check htif exit */ if htif_done then { diff --git a/riscv/riscv_sys.sail b/riscv/riscv_sys.sail index b423b08f..8af1155a 100644 --- a/riscv/riscv_sys.sail +++ b/riscv/riscv_sys.sail @@ -265,7 +265,24 @@ function legalize_scounteren(c : Counteren, v : xlenbits) -> Counteren = { register mcycle : xlenbits register mtime : xlenbits + +/* minstret is an architectural register, and can be written to. The + spec says that minstret increments on instruction retires need to + occur before any explicit writes to instret. However, in our + simulation loop, we need to execute an instruction to find out + whether it retired, and hence can only increment instret after + execution. To avoid doing this in the case minstret was explicitly + written to, we track writes to it in a separate model-internal + register. +*/ register minstret : xlenbits +register minstret_written : bool + +function retire_instruction() -> unit = { + if minstret_written == true + then minstret_written = false + else minstret = minstret + 1 +} /* informational registers */ register mvendorid : xlenbits @@ -785,6 +802,8 @@ function init_sys() -> unit = { mhartid = EXTZ(0b0); mcounteren->bits() = EXTZ(0b0); + minstret = EXTZ(0b0); + minstret_written = false; } function tick_clock() -> unit = { |
