|
| 1 | +/* LoadStoreRegister: LDR and STR */ |
| 2 | +val decodeLoadStoreRegister : (bits(2), bits(5), bits(3), bit, bits(5), bits(5)) -> option(ast) |
| 3 | + |
| 4 | +function clause decode (0b11@0b111@0b0@0b00@(opc:bits(2))@0b1@(Rm:bits(5))@(option_v:bits(3))@[S]@0b10@(Rn:bits(5))@(Rt:bits(5))) = { |
| 5 | + decodeLoadStoreRegister(opc, Rm, option_v, S, Rn, Rt) |
| 6 | +} |
| 7 | + |
| 8 | +function decodeLoadStoreRegister (opc, Rm, option_v, S, Rn, Rt) = { |
| 9 | + let t : reg_index = unsigned(Rt); |
| 10 | + let n : reg_index = unsigned(Rn); |
| 11 | + let m : reg_index = unsigned(Rm); |
| 12 | + /* option_v == 0b011 and S == 1 means that the offset in Rm is used as is and not shifted or extended */ |
| 13 | + if option_v != 0b011 | S == bitone then None () |
| 14 | + else if opc == 0b01 |
| 15 | + then Some(LoadRegister((t,n,m))) |
| 16 | + else if opc == 0b00 |
| 17 | + then Some(StoreRegister((t,n,m))) |
| 18 | + else None (); |
| 19 | +} |
| 20 | + |
| 21 | +/* LDR Xt, [Xn, Xm] */ |
| 22 | +function clause execute LoadRegister(t, n, m) = { |
| 23 | + /* Ask for the value of register Xn and record it in the local |
| 24 | + * variable base_addr */ |
| 25 | + let base_addr = X(n); |
| 26 | + /* Ask for the value of register Xm and record it in the local |
| 27 | + * variable offset */ |
| 28 | + let offset = X(m); |
| 29 | + /* Compute the address */ |
| 30 | + let addr = base_addr + offset; |
| 31 | + let accdesc = create_readAccessDescriptor(); |
| 32 | + /* Translate the virtual address into the physical address. |
| 33 | + * In the user mode, `translate_address` returns input address. */ |
| 34 | + let addr : bits(addr_size) = |
| 35 | + match translate_address(addr, accdesc) { |
| 36 | + Some(addr) => addr, |
| 37 | + None() => return () // A translation fault is handled in `translate_address`. |
| 38 | + }; |
| 39 | + /* The instruction can't fault now (in a real model), so update the PC */ |
| 40 | + _PC = _PC + 4; |
| 41 | + /* Ask for the eight-byte value in memory starting from location |
| 42 | + addr and record it in the local variable data */ |
| 43 | + let data = rMem(addr, accdesc); |
| 44 | + /* Ask for the value of data to be written to register Xt */ |
| 45 | + X(t) = data; |
| 46 | +} |
| 47 | + |
| 48 | +/* STR Xt, [Xn, Xm] */ |
| 49 | +function clause execute StoreRegister(t, n, m) = { |
| 50 | + /* Ask for the value of register Xn and record it in the local |
| 51 | + * variable base_addr */ |
| 52 | + let base_addr = X(n); |
| 53 | + /* Ask for the value of register Xm and record it in the local |
| 54 | + * variable offset */ |
| 55 | + let offset = X(m); |
| 56 | + /* Compute the address */ |
| 57 | + let addr = base_addr + offset; |
| 58 | + let accdesc = create_writeAccessDescriptor(); |
| 59 | + /* Translate the virtual address into the physical address. |
| 60 | + * In the user mode, `translate_address` returns input address. */ |
| 61 | + let addr : bits(addr_size) = |
| 62 | + match translate_address(addr, accdesc) { |
| 63 | + Some(addr) => addr, |
| 64 | + None() => return () // A translation fault is handled in `translate_address`. |
| 65 | + }; |
| 66 | + /* Announce that a store into the eight bytes of memory starting |
| 67 | + * from location addr will be performed later */ |
| 68 | + wMem_Addr(addr); |
| 69 | + /* The instruction can't fault now (in a real model), so update the PC */ |
| 70 | + _PC = _PC + 4; |
| 71 | + /* Ask for the value of register Xt and record it in the local |
| 72 | + * variable data */ |
| 73 | + let data = X(t); |
| 74 | + /* Ask for the value of data to be stored into the eight bytes of |
| 75 | + * memory starting from location addr */ |
| 76 | + wMem(addr, data, accdesc); |
| 77 | +} |
| 78 | + |
| 79 | +/* Exclusive OR: EOR */ |
| 80 | +val decodeExclusiveOr : (bit, bits(2), bit, bits(5), bits(6), bits(5), bits(5)) -> option(ast) |
| 81 | + |
| 82 | +function clause decode ([sf]@0b10@0b01010@(shift:bits(2))@[N]@(Rm:bits(5))@(imm6:bits(6))@(Rn:bits(5))@(Rd:bits(5))) = { |
| 83 | + decodeExclusiveOr(sf, shift, N, Rm, imm6, Rn, Rd) |
| 84 | +} |
| 85 | + |
| 86 | +function decodeExclusiveOr (sf, shift, N, Rm, imm6, Rn, Rd) = { |
| 87 | + let d : reg_index = unsigned(Rd); |
| 88 | + let n : reg_index = unsigned(Rn); |
| 89 | + let m : reg_index = unsigned(Rm); |
| 90 | + |
| 91 | + if sf == bitzero & imm6[5] == bitone then None () |
| 92 | + else if imm6 != 0b000000 then None () |
| 93 | + else Some(ExclusiveOr((d,n,m))); |
| 94 | +} |
| 95 | + |
| 96 | +/* EOR Xd, Xn, Xm */ |
| 97 | +function clause execute ExclusiveOr(d, n, m) = { |
| 98 | + /* Increment the program counter, at the start, since no branching out possible */ |
| 99 | + _PC = _PC + 4; |
| 100 | + /* Ask for the value of register Xn and record it in the local |
| 101 | + * variable operand1 */ |
| 102 | + let operand1 = X(n); |
| 103 | + /* Ask for the value of register Xm and record it in the local |
| 104 | + * variable operand2 */ |
| 105 | + let operand2 = X(m); |
| 106 | + /* Compute the bitwise exclusive OR, and ask for the value of |
| 107 | + * the result to be written to register Xd */ |
| 108 | + X(d) = operand1 ^ operand2; |
| 109 | +} |
| 110 | + |
| 111 | +/* Data Barrier */ |
| 112 | +val decodeDataBarrier : (bits(4), bool) -> option(ast) |
| 113 | + |
| 114 | +function decodeDataBarrier(CRm, is_sync) = { |
| 115 | + let types : MBReqTypes = |
| 116 | + match CRm[1..0] { |
| 117 | + 0b01 => MBReqTypes_Reads, |
| 118 | + 0b10 => MBReqTypes_Writes, |
| 119 | + 0b11 => MBReqTypes_All, |
| 120 | + _ => return None() |
| 121 | + }; |
| 122 | + |
| 123 | + if is_sync then |
| 124 | + Some(DataSynchronizationBarrier(types)) |
| 125 | + else |
| 126 | + Some(DataMemoryBarrier(types)) |
| 127 | +} |
| 128 | + |
| 129 | +/* DMB */ |
| 130 | +function clause decode (0b1101010100@0b0@0b00@0b011@0b0011@(CRm : bits(4))@0b1@0b01@0b11111) = { |
| 131 | + decodeDataBarrier(CRm, false) |
| 132 | +} |
| 133 | + |
| 134 | +function clause execute DataMemoryBarrier(types) = { |
| 135 | + // Update the PC |
| 136 | + _PC = _PC + 4; |
| 137 | + // Then perform the barrier |
| 138 | + dataMemoryBarrier(types); |
| 139 | +} |
| 140 | + |
| 141 | +/* DSB */ |
| 142 | +function clause decode (0b11010101000000110011@(CRm:bits(4))@0b100@0b11111) = { |
| 143 | + decodeDataBarrier(CRm, true) |
| 144 | +} |
| 145 | + |
| 146 | +function clause execute DataSynchronizationBarrier(types) = { |
| 147 | + // Update the PC |
| 148 | + _PC = _PC + 4; |
| 149 | + // Then perform the barrier |
| 150 | + dataSynchronizationBarrer(types) |
| 151 | +} |
| 152 | + |
| 153 | +/* ISB */ |
| 154 | +function clause decode (0b11010101000000110011@(CRm:bits(4))@0b110@0b11111) = { |
| 155 | + Some(InstructionSynchronizationBarrier()) |
| 156 | +} |
| 157 | + |
| 158 | +function clause execute InstructionSynchronizationBarrier() = { |
| 159 | + // Update the PC |
| 160 | + _PC = _PC + 4; |
| 161 | + // Then perform the barrier |
| 162 | + instructionSynchronizationBarrier() |
| 163 | +} |
| 164 | + |
| 165 | +/* CompareAndBranch: CBZ */ |
| 166 | +val decodeCompareAndBranch : (bits(19), bits(5)) -> option(ast) |
| 167 | + |
| 168 | +function clause decode (0b1@0b011010@0b0@(imm19:bits(19))@(Rt:bits(5))) = { |
| 169 | + decodeCompareAndBranch(imm19, Rt) |
| 170 | +} |
| 171 | + |
| 172 | +function decodeCompareAndBranch(imm19, Rt) = { |
| 173 | + let t : reg_index = unsigned(Rt); |
| 174 | + let offset : bits(64) = sail_sign_extend(imm19@0b00,64); |
| 175 | + |
| 176 | + Some(CompareAndBranch(t,offset)); |
| 177 | +} |
| 178 | + |
| 179 | +/* CBZ Xt, <offset> */ |
| 180 | +function clause execute CompareAndBranch(t, offset) = { |
| 181 | + /* Ask for the value of register Xt and record it in the local |
| 182 | + * variable operand */ |
| 183 | + let operand = X(t); |
| 184 | + /* Check if operand is 0 */ |
| 185 | + if operand == 0x0000000000000000 then { |
| 186 | + /* Ask for the value of the program counter register and record it |
| 187 | + * in the local variable base */ |
| 188 | + let base = PC(); |
| 189 | + /* Compute the address */ |
| 190 | + let addr = base + offset; |
| 191 | + /* Ask for the value of result to be written to the program counter |
| 192 | + * register */ |
| 193 | + PC() = addr; |
| 194 | + } |
| 195 | + else _PC = _PC + 4; |
| 196 | +} |
| 197 | + |
| 198 | +// This catch-all clause MUST be the last clause for the `decode` function. |
| 199 | +function clause decode(_) = { None() } |
0 commit comments