| ... | ... | @@ -195,12 +195,12 @@ test "FloatingPointRegister.toX" { |
| 195 | 195 | |
| 196 | 196 | /// Represents an instruction in the AArch64 instruction set |
| 197 | 197 | pub const Instruction = union(enum) { |
| 198 | | MoveWideWithZero: packed struct { |
| 198 | MoveWideImmediate: packed struct { |
| 199 | 199 | rd: u5, |
| 200 | 200 | imm16: u16, |
| 201 | 201 | hw: u2, |
| 202 | 202 | fixed: u6 = 0b100101, |
| 203 | | opc: u2 = 0b10, |
| 203 | opc: u2, |
| 204 | 204 | sf: u1, |
| 205 | 205 | }, |
| 206 | 206 | ExceptionGeneration: packed struct { |
| ... | ... | @@ -226,7 +226,7 @@ pub const Instruction = union(enum) { |
| 226 | 226 | |
| 227 | 227 | pub fn toU32(self: Instruction) u32 { |
| 228 | 228 | return switch (self) { |
| 229 | | .MoveWideWithZero => |v| @bitCast(u32, v), |
| 229 | .MoveWideImmediate => |v| @bitCast(u32, v), |
| 230 | 230 | .ExceptionGeneration => |v| @bitCast(u32, v), |
| 231 | 231 | .UnconditionalBranchRegister => |v| @bitCast(u32, v), |
| 232 | 232 | .UnconditionalBranchImmediate => |v| @bitCast(u32, v), |
| ... | ... | @@ -235,24 +235,33 @@ pub const Instruction = union(enum) { |
| 235 | 235 | |
| 236 | 236 | // Helper functions for assembly syntax functions |
| 237 | 237 | |
| 238 | | fn moveWideWithZero(rd: Register, imm16: u16, shift: u2) Instruction { |
| 238 | fn moveWideImmediate( |
| 239 | opc: u2, |
| 240 | rd: Register, |
| 241 | imm16: u16, |
| 242 | shift: u6, |
| 243 | ) Instruction { |
| 239 | 244 | switch (rd.size()) { |
| 240 | 245 | 32 => { |
| 246 | assert(shift % 16 == 0 and shift <= 16); |
| 241 | 247 | return Instruction{ |
| 242 | | .MoveWideWithZero = .{ |
| 248 | .MoveWideImmediate = .{ |
| 243 | 249 | .rd = rd.id(), |
| 244 | 250 | .imm16 = imm16, |
| 245 | | .hw = 0b01 & shift, // TODO shift should be an enum |
| 251 | .hw = @intCast(u2, shift / 16), |
| 252 | .opc = opc, |
| 246 | 253 | .sf = 0, |
| 247 | 254 | }, |
| 248 | 255 | }; |
| 249 | 256 | }, |
| 250 | 257 | 64 => { |
| 258 | assert(shift % 16 == 0 and shift <= 48); |
| 251 | 259 | return Instruction{ |
| 252 | | .MoveWideWithZero = .{ |
| 260 | .MoveWideImmediate = .{ |
| 253 | 261 | .rd = rd.id(), |
| 254 | 262 | .imm16 = imm16, |
| 255 | | .hw = shift, |
| 263 | .hw = @intCast(u2, shift / 16), |
| 264 | .opc = opc, |
| 256 | 265 | .sf = 1, |
| 257 | 266 | }, |
| 258 | 267 | }; |
| ... | ... | @@ -284,6 +293,8 @@ pub const Instruction = union(enum) { |
| 284 | 293 | rn: Register, |
| 285 | 294 | op4: u5, |
| 286 | 295 | ) Instruction { |
| 296 | assert(rn.size() == 64); |
| 297 | |
| 287 | 298 | return Instruction{ |
| 288 | 299 | .UnconditionalBranchRegister = .{ |
| 289 | 300 | .op4 = op4, |
| ... | ... | @@ -301,16 +312,24 @@ pub const Instruction = union(enum) { |
| 301 | 312 | ) Instruction { |
| 302 | 313 | return Instruction{ |
| 303 | 314 | .UnconditionalBranchImmediate = .{ |
| 304 | | .imm26 = @bitCast(u26, @intCast(i26, imm26 >> 2)), |
| 315 | .imm26 = @bitCast(u26, @intCast(i26, offset >> 2)), |
| 305 | 316 | .op = op, |
| 306 | 317 | }, |
| 307 | 318 | }; |
| 308 | 319 | } |
| 309 | 320 | |
| 310 | | // movz |
| 321 | // Move wide (immediate) |
| 322 | |
| 323 | pub fn movn(rd: Register, imm16: u16, shift: u6) Instruction { |
| 324 | return moveWideImmediate(0b00, rd, imm16, shift); |
| 325 | } |
| 326 | |
| 327 | pub fn movz(rd: Register, imm16: u16, shift: u6) Instruction { |
| 328 | return moveWideImmediate(0b10, rd, imm16, shift); |
| 329 | } |
| 311 | 330 | |
| 312 | | pub fn movz(rd: Register, imm16: u16, shift: u2) Instruction { |
| 313 | | return moveWideWithZero(rd, imm16, shift); |
| 331 | pub fn movk(rd: Register, imm16: u16, shift: u6) Instruction { |
| 332 | return moveWideImmediate(0b11, rd, imm16, shift); |
| 314 | 333 | } |
| 315 | 334 | |
| 316 | 335 | // Exception generation |
| ... | ... | @@ -338,7 +357,6 @@ pub const Instruction = union(enum) { |
| 338 | 357 | // Unconditional branch (register) |
| 339 | 358 | |
| 340 | 359 | pub fn br(rn: Register) Instruction { |
| 341 | | assert(rn.size() == 64); |
| 342 | 360 | return unconditionalBranchRegister(0b0000, 0b11111, 0b000000, rn, 0b00000); |
| 343 | 361 | } |
| 344 | 362 | |
| ... | ... | @@ -368,28 +386,20 @@ test "serialize instructions" { |
| 368 | 386 | }; |
| 369 | 387 | |
| 370 | 388 | const testcases = [_]Testcase{ |
| 371 | | .{ // svc #0 |
| 372 | | .inst = Instruction.svc(0), |
| 373 | | .expected = 0b1101_0100_000_0000000000000000_00001, |
| 374 | | }, |
| 375 | | .{ // svc #0x80 ; typical on Darwin |
| 376 | | .inst = Instruction.svc(0x80), |
| 377 | | .expected = 0b1101_0100_000_0000000010000000_00001, |
| 378 | | }, |
| 379 | 389 | .{ // movz x1 #4 |
| 380 | 390 | .inst = Instruction.movz(.x1, 4, 0), |
| 381 | 391 | .expected = 0b1_10_100101_00_0000000000000100_00001, |
| 382 | 392 | }, |
| 383 | 393 | .{ // movz x1, #4, lsl 16 |
| 384 | | .inst = Instruction.movz(.x1, 4, 1), |
| 394 | .inst = Instruction.movz(.x1, 4, 16), |
| 385 | 395 | .expected = 0b1_10_100101_01_0000000000000100_00001, |
| 386 | 396 | }, |
| 387 | 397 | .{ // movz x1, #4, lsl 32 |
| 388 | | .inst = Instruction.movz(.x1, 4, 2), |
| 398 | .inst = Instruction.movz(.x1, 4, 32), |
| 389 | 399 | .expected = 0b1_10_100101_10_0000000000000100_00001, |
| 390 | 400 | }, |
| 391 | 401 | .{ // movz x1, #4, lsl 48 |
| 392 | | .inst = Instruction.movz(.x1, 4, 3), |
| 402 | .inst = Instruction.movz(.x1, 4, 48), |
| 393 | 403 | .expected = 0b1_10_100101_11_0000000000000100_00001, |
| 394 | 404 | }, |
| 395 | 405 | .{ // movz w1, #4 |
| ... | ... | @@ -397,9 +407,25 @@ test "serialize instructions" { |
| 397 | 407 | .expected = 0b0_10_100101_00_0000000000000100_00001, |
| 398 | 408 | }, |
| 399 | 409 | .{ // movz w1, #4, lsl 16 |
| 400 | | .inst = Instruction.movz(.w1, 4, 1), |
| 410 | .inst = Instruction.movz(.w1, 4, 16), |
| 401 | 411 | .expected = 0b0_10_100101_01_0000000000000100_00001, |
| 402 | 412 | }, |
| 413 | .{ // svc #0 |
| 414 | .inst = Instruction.svc(0), |
| 415 | .expected = 0b1101_0100_000_0000000000000000_00001, |
| 416 | }, |
| 417 | .{ // svc #0x80 ; typical on Darwin |
| 418 | .inst = Instruction.svc(0x80), |
| 419 | .expected = 0b1101_0100_000_0000000010000000_00001, |
| 420 | }, |
| 421 | .{ // ret |
| 422 | .inst = Instruction.ret(null), |
| 423 | .expected = 0b1101_011_00_10_11111_0000_00_11110_00000, |
| 424 | }, |
| 425 | .{ // bl #0x10 |
| 426 | .inst = Instruction.bl(0x10), |
| 427 | .expected = 0b1_00101_00_0000_0000_0000_0000_0000_0100, |
| 428 | }, |
| 403 | 429 | }; |
| 404 | 430 | |
| 405 | 431 | for (testcases) |case| { |