| ... | @@ -195,12 +195,12 @@ test "FloatingPointRegister.toX" { | ... | @@ -195,12 +195,12 @@ test "FloatingPointRegister.toX" { |
| 195 | | 195 | |
| 196 | /// Represents an instruction in the AArch64 instruction set | 196 | /// Represents an instruction in the AArch64 instruction set |
| 197 | pub const Instruction = union(enum) { | 197 | pub const Instruction = union(enum) { |
| 198 | MoveWideWithZero: packed struct { | 198 | MoveWideImmediate: packed struct { |
| 199 | rd: u5, | 199 | rd: u5, |
| 200 | imm16: u16, | 200 | imm16: u16, |
| 201 | hw: u2, | 201 | hw: u2, |
| 202 | fixed: u6 = 0b100101, | 202 | fixed: u6 = 0b100101, |
| 203 | opc: u2 = 0b10, | 203 | opc: u2, |
| 204 | sf: u1, | 204 | sf: u1, |
| 205 | }, | 205 | }, |
| 206 | ExceptionGeneration: packed struct { | 206 | ExceptionGeneration: packed struct { |
| ... | @@ -226,7 +226,7 @@ pub const Instruction = union(enum) { | ... | @@ -226,7 +226,7 @@ pub const Instruction = union(enum) { |
| 226 | | 226 | |
| 227 | pub fn toU32(self: Instruction) u32 { | 227 | pub fn toU32(self: Instruction) u32 { |
| 228 | return switch (self) { | 228 | return switch (self) { |
| 229 | .MoveWideWithZero => |v| @bitCast(u32, v), | 229 | .MoveWideImmediate => |v| @bitCast(u32, v), |
| 230 | .ExceptionGeneration => |v| @bitCast(u32, v), | 230 | .ExceptionGeneration => |v| @bitCast(u32, v), |
| 231 | .UnconditionalBranchRegister => |v| @bitCast(u32, v), | 231 | .UnconditionalBranchRegister => |v| @bitCast(u32, v), |
| 232 | .UnconditionalBranchImmediate => |v| @bitCast(u32, v), | 232 | .UnconditionalBranchImmediate => |v| @bitCast(u32, v), |
| ... | @@ -235,24 +235,33 @@ pub const Instruction = union(enum) { | ... | @@ -235,24 +235,33 @@ pub const Instruction = union(enum) { |
| 235 | | 235 | |
| 236 | // Helper functions for assembly syntax functions | 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 | switch (rd.size()) { | 244 | switch (rd.size()) { |
| 240 | 32 => { | 245 | 32 => { |
| | 246 | assert(shift % 16 == 0 and shift <= 16); |
| 241 | return Instruction{ | 247 | return Instruction{ |
| 242 | .MoveWideWithZero = .{ | 248 | .MoveWideImmediate = .{ |
| 243 | .rd = rd.id(), | 249 | .rd = rd.id(), |
| 244 | .imm16 = imm16, | 250 | .imm16 = imm16, |
| 245 | .hw = 0b01 & shift, // TODO shift should be an enum | 251 | .hw = @intCast(u2, shift / 16), |
| | 252 | .opc = opc, |
| 246 | .sf = 0, | 253 | .sf = 0, |
| 247 | }, | 254 | }, |
| 248 | }; | 255 | }; |
| 249 | }, | 256 | }, |
| 250 | 64 => { | 257 | 64 => { |
| | 258 | assert(shift % 16 == 0 and shift <= 48); |
| 251 | return Instruction{ | 259 | return Instruction{ |
| 252 | .MoveWideWithZero = .{ | 260 | .MoveWideImmediate = .{ |
| 253 | .rd = rd.id(), | 261 | .rd = rd.id(), |
| 254 | .imm16 = imm16, | 262 | .imm16 = imm16, |
| 255 | .hw = shift, | 263 | .hw = @intCast(u2, shift / 16), |
| | 264 | .opc = opc, |
| 256 | .sf = 1, | 265 | .sf = 1, |
| 257 | }, | 266 | }, |
| 258 | }; | 267 | }; |
| ... | @@ -284,6 +293,8 @@ pub const Instruction = union(enum) { | ... | @@ -284,6 +293,8 @@ pub const Instruction = union(enum) { |
| 284 | rn: Register, | 293 | rn: Register, |
| 285 | op4: u5, | 294 | op4: u5, |
| 286 | ) Instruction { | 295 | ) Instruction { |
| | 296 | assert(rn.size() == 64); |
| | 297 | |
| 287 | return Instruction{ | 298 | return Instruction{ |
| 288 | .UnconditionalBranchRegister = .{ | 299 | .UnconditionalBranchRegister = .{ |
| 289 | .op4 = op4, | 300 | .op4 = op4, |
| ... | @@ -301,16 +312,24 @@ pub const Instruction = union(enum) { | ... | @@ -301,16 +312,24 @@ pub const Instruction = union(enum) { |
| 301 | ) Instruction { | 312 | ) Instruction { |
| 302 | return Instruction{ | 313 | return Instruction{ |
| 303 | .UnconditionalBranchImmediate = .{ | 314 | .UnconditionalBranchImmediate = .{ |
| 304 | .imm26 = @bitCast(u26, @intCast(i26, imm26 >> 2)), | 315 | .imm26 = @bitCast(u26, @intCast(i26, offset >> 2)), |
| 305 | .op = op, | 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 { | 331 | pub fn movk(rd: Register, imm16: u16, shift: u6) Instruction { |
| 313 | return moveWideWithZero(rd, imm16, shift); | 332 | return moveWideImmediate(0b11, rd, imm16, shift); |
| 314 | } | 333 | } |
| 315 | | 334 | |
| 316 | // Exception generation | 335 | // Exception generation |
| ... | @@ -338,7 +357,6 @@ pub const Instruction = union(enum) { | ... | @@ -338,7 +357,6 @@ pub const Instruction = union(enum) { |
| 338 | // Unconditional branch (register) | 357 | // Unconditional branch (register) |
| 339 | | 358 | |
| 340 | pub fn br(rn: Register) Instruction { | 359 | pub fn br(rn: Register) Instruction { |
| 341 | assert(rn.size() == 64); | | |
| 342 | return unconditionalBranchRegister(0b0000, 0b11111, 0b000000, rn, 0b00000); | 360 | return unconditionalBranchRegister(0b0000, 0b11111, 0b000000, rn, 0b00000); |
| 343 | } | 361 | } |
| 344 | | 362 | |
| ... | @@ -368,28 +386,20 @@ test "serialize instructions" { | ... | @@ -368,28 +386,20 @@ test "serialize instructions" { |
| 368 | }; | 386 | }; |
| 369 | | 387 | |
| 370 | const testcases = [_]Testcase{ | 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 | .{ // movz x1 #4 | 389 | .{ // movz x1 #4 |
| 380 | .inst = Instruction.movz(.x1, 4, 0), | 390 | .inst = Instruction.movz(.x1, 4, 0), |
| 381 | .expected = 0b1_10_100101_00_0000000000000100_00001, | 391 | .expected = 0b1_10_100101_00_0000000000000100_00001, |
| 382 | }, | 392 | }, |
| 383 | .{ // movz x1, #4, lsl 16 | 393 | .{ // movz x1, #4, lsl 16 |
| 384 | .inst = Instruction.movz(.x1, 4, 1), | 394 | .inst = Instruction.movz(.x1, 4, 16), |
| 385 | .expected = 0b1_10_100101_01_0000000000000100_00001, | 395 | .expected = 0b1_10_100101_01_0000000000000100_00001, |
| 386 | }, | 396 | }, |
| 387 | .{ // movz x1, #4, lsl 32 | 397 | .{ // movz x1, #4, lsl 32 |
| 388 | .inst = Instruction.movz(.x1, 4, 2), | 398 | .inst = Instruction.movz(.x1, 4, 32), |
| 389 | .expected = 0b1_10_100101_10_0000000000000100_00001, | 399 | .expected = 0b1_10_100101_10_0000000000000100_00001, |
| 390 | }, | 400 | }, |
| 391 | .{ // movz x1, #4, lsl 48 | 401 | .{ // movz x1, #4, lsl 48 |
| 392 | .inst = Instruction.movz(.x1, 4, 3), | 402 | .inst = Instruction.movz(.x1, 4, 48), |
| 393 | .expected = 0b1_10_100101_11_0000000000000100_00001, | 403 | .expected = 0b1_10_100101_11_0000000000000100_00001, |
| 394 | }, | 404 | }, |
| 395 | .{ // movz w1, #4 | 405 | .{ // movz w1, #4 |
| ... | @@ -397,9 +407,25 @@ test "serialize instructions" { | ... | @@ -397,9 +407,25 @@ test "serialize instructions" { |
| 397 | .expected = 0b0_10_100101_00_0000000000000100_00001, | 407 | .expected = 0b0_10_100101_00_0000000000000100_00001, |
| 398 | }, | 408 | }, |
| 399 | .{ // movz w1, #4, lsl 16 | 409 | .{ // movz w1, #4, lsl 16 |
| 400 | .inst = Instruction.movz(.w1, 4, 1), | 410 | .inst = Instruction.movz(.w1, 4, 16), |
| 401 | .expected = 0b0_10_100101_01_0000000000000100_00001, | 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 | for (testcases) |case| { | 431 | for (testcases) |case| { |