| ... | @@ -200,7 +200,7 @@ test "FloatingPointRegister.toX" { | ... | @@ -200,7 +200,7 @@ test "FloatingPointRegister.toX" { |
| 200 | | 200 | |
| 201 | /// Represents an instruction in the AArch64 instruction set | 201 | /// Represents an instruction in the AArch64 instruction set |
| 202 | pub const Instruction = union(enum) { | 202 | pub const Instruction = union(enum) { |
| 203 | MoveWideImmediate: packed struct { | 203 | move_wide_immediate: packed struct { |
| 204 | rd: u5, | 204 | rd: u5, |
| 205 | imm16: u16, | 205 | imm16: u16, |
| 206 | hw: u2, | 206 | hw: u2, |
| ... | @@ -208,14 +208,14 @@ pub const Instruction = union(enum) { | ... | @@ -208,14 +208,14 @@ pub const Instruction = union(enum) { |
| 208 | opc: u2, | 208 | opc: u2, |
| 209 | sf: u1, | 209 | sf: u1, |
| 210 | }, | 210 | }, |
| 211 | PCRelativeAddress: packed struct { | 211 | pc_relative_address: packed struct { |
| 212 | rd: u5, | 212 | rd: u5, |
| 213 | immhi: u19, | 213 | immhi: u19, |
| 214 | fixed: u5 = 0b10000, | 214 | fixed: u5 = 0b10000, |
| 215 | immlo: u2, | 215 | immlo: u2, |
| 216 | op: u1, | 216 | op: u1, |
| 217 | }, | 217 | }, |
| 218 | LoadStoreRegister: packed struct { | 218 | load_store_register: packed struct { |
| 219 | rt: u5, | 219 | rt: u5, |
| 220 | rn: u5, | 220 | rn: u5, |
| 221 | offset: u12, | 221 | offset: u12, |
| ... | @@ -225,7 +225,7 @@ pub const Instruction = union(enum) { | ... | @@ -225,7 +225,7 @@ pub const Instruction = union(enum) { |
| 225 | fixed: u3 = 0b111, | 225 | fixed: u3 = 0b111, |
| 226 | size: u2, | 226 | size: u2, |
| 227 | }, | 227 | }, |
| 228 | LoadStorePairOfRegisters: packed struct { | 228 | load_store_register_pair: packed struct { |
| 229 | rt1: u5, | 229 | rt1: u5, |
| 230 | rn: u5, | 230 | rn: u5, |
| 231 | rt2: u5, | 231 | rt2: u5, |
| ... | @@ -235,20 +235,20 @@ pub const Instruction = union(enum) { | ... | @@ -235,20 +235,20 @@ pub const Instruction = union(enum) { |
| 235 | fixed: u5 = 0b101_0_0, | 235 | fixed: u5 = 0b101_0_0, |
| 236 | opc: u2, | 236 | opc: u2, |
| 237 | }, | 237 | }, |
| 238 | LoadLiteral: packed struct { | 238 | load_literal: packed struct { |
| 239 | rt: u5, | 239 | rt: u5, |
| 240 | imm19: u19, | 240 | imm19: u19, |
| 241 | fixed: u6 = 0b011_0_00, | 241 | fixed: u6 = 0b011_0_00, |
| 242 | opc: u2, | 242 | opc: u2, |
| 243 | }, | 243 | }, |
| 244 | ExceptionGeneration: packed struct { | 244 | exception_generation: packed struct { |
| 245 | ll: u2, | 245 | ll: u2, |
| 246 | op2: u3, | 246 | op2: u3, |
| 247 | imm16: u16, | 247 | imm16: u16, |
| 248 | opc: u3, | 248 | opc: u3, |
| 249 | fixed: u8 = 0b1101_0100, | 249 | fixed: u8 = 0b1101_0100, |
| 250 | }, | 250 | }, |
| 251 | UnconditionalBranchRegister: packed struct { | 251 | unconditional_branch_register: packed struct { |
| 252 | op4: u5, | 252 | op4: u5, |
| 253 | rn: u5, | 253 | rn: u5, |
| 254 | op3: u6, | 254 | op3: u6, |
| ... | @@ -256,15 +256,15 @@ pub const Instruction = union(enum) { | ... | @@ -256,15 +256,15 @@ pub const Instruction = union(enum) { |
| 256 | opc: u4, | 256 | opc: u4, |
| 257 | fixed: u7 = 0b1101_011, | 257 | fixed: u7 = 0b1101_011, |
| 258 | }, | 258 | }, |
| 259 | UnconditionalBranchImmediate: packed struct { | 259 | unconditional_branch_immediate: packed struct { |
| 260 | imm26: u26, | 260 | imm26: u26, |
| 261 | fixed: u5 = 0b00101, | 261 | fixed: u5 = 0b00101, |
| 262 | op: u1, | 262 | op: u1, |
| 263 | }, | 263 | }, |
| 264 | NoOperation: packed struct { | 264 | no_operation: packed struct { |
| 265 | fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111, | 265 | fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111, |
| 266 | }, | 266 | }, |
| 267 | LogicalShiftedRegister: packed struct { | 267 | logical_shifted_register: packed struct { |
| 268 | rd: u5, | 268 | rd: u5, |
| 269 | rn: u5, | 269 | rn: u5, |
| 270 | imm6: u6, | 270 | imm6: u6, |
| ... | @@ -275,7 +275,7 @@ pub const Instruction = union(enum) { | ... | @@ -275,7 +275,7 @@ pub const Instruction = union(enum) { |
| 275 | opc: u2, | 275 | opc: u2, |
| 276 | sf: u1, | 276 | sf: u1, |
| 277 | }, | 277 | }, |
| 278 | AddSubtractImmediate: packed struct { | 278 | add_subtract_immediate: packed struct { |
| 279 | rd: u5, | 279 | rd: u5, |
| 280 | rn: u5, | 280 | rn: u5, |
| 281 | imm12: u12, | 281 | imm12: u12, |
| ... | @@ -285,6 +285,20 @@ pub const Instruction = union(enum) { | ... | @@ -285,6 +285,20 @@ pub const Instruction = union(enum) { |
| 285 | op: u1, | 285 | op: u1, |
| 286 | sf: u1, | 286 | sf: u1, |
| 287 | }, | 287 | }, |
| | 288 | conditional_branch: struct { |
| | 289 | cond: u4, |
| | 290 | o0: u1, |
| | 291 | imm19: u19, |
| | 292 | o1: u1, |
| | 293 | fixed: u7 = 0b0101010, |
| | 294 | }, |
| | 295 | compare_and_branch: struct { |
| | 296 | rt: u5, |
| | 297 | imm19: u19, |
| | 298 | op: u1, |
| | 299 | fixed: u6 = 0b011010, |
| | 300 | sf: u1, |
| | 301 | }, |
| 288 | | 302 | |
| 289 | pub const Shift = struct { | 303 | pub const Shift = struct { |
| 290 | shift: Type = .lsl, | 304 | shift: Type = .lsl, |
| ... | @@ -303,19 +317,73 @@ pub const Instruction = union(enum) { | ... | @@ -303,19 +317,73 @@ pub const Instruction = union(enum) { |
| 303 | }; | 317 | }; |
| 304 | }; | 318 | }; |
| 305 | | 319 | |
| | 320 | pub const Condition = enum(u4) { |
| | 321 | /// Integer: Equal |
| | 322 | /// Floating point: Equal |
| | 323 | eq, |
| | 324 | /// Integer: Not equal |
| | 325 | /// Floating point: Not equal or unordered |
| | 326 | ne, |
| | 327 | /// Integer: Carry set |
| | 328 | /// Floating point: Greater than, equal, or unordered |
| | 329 | cs, |
| | 330 | /// Integer: Carry clear |
| | 331 | /// Floating point: Less than |
| | 332 | cc, |
| | 333 | /// Integer: Minus, negative |
| | 334 | /// Floating point: Less than |
| | 335 | mi, |
| | 336 | /// Integer: Plus, positive or zero |
| | 337 | /// Floating point: Greater than, equal, or unordered |
| | 338 | pl, |
| | 339 | /// Integer: Overflow |
| | 340 | /// Floating point: Unordered |
| | 341 | vs, |
| | 342 | /// Integer: No overflow |
| | 343 | /// Floating point: Ordered |
| | 344 | vc, |
| | 345 | /// Integer: Unsigned higher |
| | 346 | /// Floating point: Greater than, or unordered |
| | 347 | hi, |
| | 348 | /// Integer: Unsigned lower or same |
| | 349 | /// Floating point: Less than or equal |
| | 350 | ls, |
| | 351 | /// Integer: Signed greater than or equal |
| | 352 | /// Floating point: Greater than or equal |
| | 353 | ge, |
| | 354 | /// Integer: Signed less than |
| | 355 | /// Floating point: Less than, or unordered |
| | 356 | lt, |
| | 357 | /// Integer: Signed greater than |
| | 358 | /// Floating point: Greater than |
| | 359 | gt, |
| | 360 | /// Integer: Signed less than or equal |
| | 361 | /// Floating point: Less than, equal, or unordered |
| | 362 | le, |
| | 363 | /// Integer: Always |
| | 364 | /// Floating point: Always |
| | 365 | al, |
| | 366 | /// Integer: Always |
| | 367 | /// Floating point: Always |
| | 368 | nv, |
| | 369 | }; |
| | 370 | |
| 306 | pub fn toU32(self: Instruction) u32 { | 371 | pub fn toU32(self: Instruction) u32 { |
| 307 | return switch (self) { | 372 | return switch (self) { |
| 308 | .MoveWideImmediate => |v| @bitCast(u32, v), | 373 | .move_wide_immediate => |v| @bitCast(u32, v), |
| 309 | .PCRelativeAddress => |v| @bitCast(u32, v), | 374 | .pc_relative_address => |v| @bitCast(u32, v), |
| 310 | .LoadStoreRegister => |v| @bitCast(u32, v), | 375 | .load_store_register => |v| @bitCast(u32, v), |
| 311 | .LoadStorePairOfRegisters => |v| @bitCast(u32, v), | 376 | .load_store_register_pair => |v| @bitCast(u32, v), |
| 312 | .LoadLiteral => |v| @bitCast(u32, v), | 377 | .load_literal => |v| @bitCast(u32, v), |
| 313 | .ExceptionGeneration => |v| @bitCast(u32, v), | 378 | .exception_generation => |v| @bitCast(u32, v), |
| 314 | .UnconditionalBranchRegister => |v| @bitCast(u32, v), | 379 | .unconditional_branch_register => |v| @bitCast(u32, v), |
| 315 | .UnconditionalBranchImmediate => |v| @bitCast(u32, v), | 380 | .unconditional_branch_immediate => |v| @bitCast(u32, v), |
| 316 | .NoOperation => |v| @bitCast(u32, v), | 381 | .no_operation => |v| @bitCast(u32, v), |
| 317 | .LogicalShiftedRegister => |v| @bitCast(u32, v), | 382 | .logical_shifted_register => |v| @bitCast(u32, v), |
| 318 | .AddSubtractImmediate => |v| @bitCast(u32, v), | 383 | .add_subtract_immediate => |v| @bitCast(u32, v), |
| | 384 | // TODO once packed structs work, this can be refactored |
| | 385 | .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25), |
| | 386 | .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31), |
| 319 | }; | 387 | }; |
| 320 | } | 388 | } |
| 321 | | 389 | |
| ... | @@ -329,7 +397,7 @@ pub const Instruction = union(enum) { | ... | @@ -329,7 +397,7 @@ pub const Instruction = union(enum) { |
| 329 | 32 => { | 397 | 32 => { |
| 330 | assert(shift % 16 == 0 and shift <= 16); | 398 | assert(shift % 16 == 0 and shift <= 16); |
| 331 | return Instruction{ | 399 | return Instruction{ |
| 332 | .MoveWideImmediate = .{ | 400 | .move_wide_immediate = .{ |
| 333 | .rd = rd.id(), | 401 | .rd = rd.id(), |
| 334 | .imm16 = imm16, | 402 | .imm16 = imm16, |
| 335 | .hw = @intCast(u2, shift / 16), | 403 | .hw = @intCast(u2, shift / 16), |
| ... | @@ -341,7 +409,7 @@ pub const Instruction = union(enum) { | ... | @@ -341,7 +409,7 @@ pub const Instruction = union(enum) { |
| 341 | 64 => { | 409 | 64 => { |
| 342 | assert(shift % 16 == 0 and shift <= 48); | 410 | assert(shift % 16 == 0 and shift <= 48); |
| 343 | return Instruction{ | 411 | return Instruction{ |
| 344 | .MoveWideImmediate = .{ | 412 | .move_wide_immediate = .{ |
| 345 | .rd = rd.id(), | 413 | .rd = rd.id(), |
| 346 | .imm16 = imm16, | 414 | .imm16 = imm16, |
| 347 | .hw = @intCast(u2, shift / 16), | 415 | .hw = @intCast(u2, shift / 16), |
| ... | @@ -358,7 +426,7 @@ pub const Instruction = union(enum) { | ... | @@ -358,7 +426,7 @@ pub const Instruction = union(enum) { |
| 358 | assert(rd.size() == 64); | 426 | assert(rd.size() == 64); |
| 359 | const imm21_u = @bitCast(u21, imm21); | 427 | const imm21_u = @bitCast(u21, imm21); |
| 360 | return Instruction{ | 428 | return Instruction{ |
| 361 | .PCRelativeAddress = .{ | 429 | .pc_relative_address = .{ |
| 362 | .rd = rd.id(), | 430 | .rd = rd.id(), |
| 363 | .immlo = @truncate(u2, imm21_u), | 431 | .immlo = @truncate(u2, imm21_u), |
| 364 | .immhi = @truncate(u19, imm21_u >> 2), | 432 | .immhi = @truncate(u19, imm21_u >> 2), |
| ... | @@ -522,7 +590,7 @@ pub const Instruction = union(enum) { | ... | @@ -522,7 +590,7 @@ pub const Instruction = union(enum) { |
| 522 | .str, .strh, .strb => 0b00, | 590 | .str, .strh, .strb => 0b00, |
| 523 | }; | 591 | }; |
| 524 | return Instruction{ | 592 | return Instruction{ |
| 525 | .LoadStoreRegister = .{ | 593 | .load_store_register = .{ |
| 526 | .rt = rt.id(), | 594 | .rt = rt.id(), |
| 527 | .rn = rn.id(), | 595 | .rn = rn.id(), |
| 528 | .offset = off, | 596 | .offset = off, |
| ... | @@ -544,7 +612,7 @@ pub const Instruction = union(enum) { | ... | @@ -544,7 +612,7 @@ pub const Instruction = union(enum) { |
| 544 | }; | 612 | }; |
| 545 | } | 613 | } |
| 546 | | 614 | |
| 547 | fn loadStorePairOfRegisters( | 615 | fn loadStoreRegisterPair( |
| 548 | rt1: Register, | 616 | rt1: Register, |
| 549 | rt2: Register, | 617 | rt2: Register, |
| 550 | rn: Register, | 618 | rn: Register, |
| ... | @@ -557,7 +625,7 @@ pub const Instruction = union(enum) { | ... | @@ -557,7 +625,7 @@ pub const Instruction = union(enum) { |
| 557 | assert(-256 <= offset and offset <= 252); | 625 | assert(-256 <= offset and offset <= 252); |
| 558 | const imm7 = @truncate(u7, @bitCast(u9, offset >> 2)); | 626 | const imm7 = @truncate(u7, @bitCast(u9, offset >> 2)); |
| 559 | return Instruction{ | 627 | return Instruction{ |
| 560 | .LoadStorePairOfRegisters = .{ | 628 | .load_store_register_pair = .{ |
| 561 | .rt1 = rt1.id(), | 629 | .rt1 = rt1.id(), |
| 562 | .rn = rn.id(), | 630 | .rn = rn.id(), |
| 563 | .rt2 = rt2.id(), | 631 | .rt2 = rt2.id(), |
| ... | @@ -572,7 +640,7 @@ pub const Instruction = union(enum) { | ... | @@ -572,7 +640,7 @@ pub const Instruction = union(enum) { |
| 572 | assert(-512 <= offset and offset <= 504); | 640 | assert(-512 <= offset and offset <= 504); |
| 573 | const imm7 = @truncate(u7, @bitCast(u9, offset >> 3)); | 641 | const imm7 = @truncate(u7, @bitCast(u9, offset >> 3)); |
| 574 | return Instruction{ | 642 | return Instruction{ |
| 575 | .LoadStorePairOfRegisters = .{ | 643 | .load_store_register_pair = .{ |
| 576 | .rt1 = rt1.id(), | 644 | .rt1 = rt1.id(), |
| 577 | .rn = rn.id(), | 645 | .rn = rn.id(), |
| 578 | .rt2 = rt2.id(), | 646 | .rt2 = rt2.id(), |
| ... | @@ -591,7 +659,7 @@ pub const Instruction = union(enum) { | ... | @@ -591,7 +659,7 @@ pub const Instruction = union(enum) { |
| 591 | switch (rt.size()) { | 659 | switch (rt.size()) { |
| 592 | 32 => { | 660 | 32 => { |
| 593 | return Instruction{ | 661 | return Instruction{ |
| 594 | .LoadLiteral = .{ | 662 | .load_literal = .{ |
| 595 | .rt = rt.id(), | 663 | .rt = rt.id(), |
| 596 | .imm19 = imm19, | 664 | .imm19 = imm19, |
| 597 | .opc = 0b00, | 665 | .opc = 0b00, |
| ... | @@ -600,7 +668,7 @@ pub const Instruction = union(enum) { | ... | @@ -600,7 +668,7 @@ pub const Instruction = union(enum) { |
| 600 | }, | 668 | }, |
| 601 | 64 => { | 669 | 64 => { |
| 602 | return Instruction{ | 670 | return Instruction{ |
| 603 | .LoadLiteral = .{ | 671 | .load_literal = .{ |
| 604 | .rt = rt.id(), | 672 | .rt = rt.id(), |
| 605 | .imm19 = imm19, | 673 | .imm19 = imm19, |
| 606 | .opc = 0b01, | 674 | .opc = 0b01, |
| ... | @@ -618,7 +686,7 @@ pub const Instruction = union(enum) { | ... | @@ -618,7 +686,7 @@ pub const Instruction = union(enum) { |
| 618 | imm16: u16, | 686 | imm16: u16, |
| 619 | ) Instruction { | 687 | ) Instruction { |
| 620 | return Instruction{ | 688 | return Instruction{ |
| 621 | .ExceptionGeneration = .{ | 689 | .exception_generation = .{ |
| 622 | .ll = ll, | 690 | .ll = ll, |
| 623 | .op2 = op2, | 691 | .op2 = op2, |
| 624 | .imm16 = imm16, | 692 | .imm16 = imm16, |
| ... | @@ -637,7 +705,7 @@ pub const Instruction = union(enum) { | ... | @@ -637,7 +705,7 @@ pub const Instruction = union(enum) { |
| 637 | assert(rn.size() == 64); | 705 | assert(rn.size() == 64); |
| 638 | | 706 | |
| 639 | return Instruction{ | 707 | return Instruction{ |
| 640 | .UnconditionalBranchRegister = .{ | 708 | .unconditional_branch_register = .{ |
| 641 | .op4 = op4, | 709 | .op4 = op4, |
| 642 | .rn = rn.id(), | 710 | .rn = rn.id(), |
| 643 | .op3 = op3, | 711 | .op3 = op3, |
| ... | @@ -652,7 +720,7 @@ pub const Instruction = union(enum) { | ... | @@ -652,7 +720,7 @@ pub const Instruction = union(enum) { |
| 652 | offset: i28, | 720 | offset: i28, |
| 653 | ) Instruction { | 721 | ) Instruction { |
| 654 | return Instruction{ | 722 | return Instruction{ |
| 655 | .UnconditionalBranchImmediate = .{ | 723 | .unconditional_branch_immediate = .{ |
| 656 | .imm26 = @bitCast(u26, @intCast(i26, offset >> 2)), | 724 | .imm26 = @bitCast(u26, @intCast(i26, offset >> 2)), |
| 657 | .op = op, | 725 | .op = op, |
| 658 | }, | 726 | }, |
| ... | @@ -671,7 +739,7 @@ pub const Instruction = union(enum) { | ... | @@ -671,7 +739,7 @@ pub const Instruction = union(enum) { |
| 671 | 32 => { | 739 | 32 => { |
| 672 | assert(shift.amount < 32); | 740 | assert(shift.amount < 32); |
| 673 | return Instruction{ | 741 | return Instruction{ |
| 674 | .LogicalShiftedRegister = .{ | 742 | .logical_shifted_register = .{ |
| 675 | .rd = rd.id(), | 743 | .rd = rd.id(), |
| 676 | .rn = rn.id(), | 744 | .rn = rn.id(), |
| 677 | .imm6 = shift.amount, | 745 | .imm6 = shift.amount, |
| ... | @@ -685,7 +753,7 @@ pub const Instruction = union(enum) { | ... | @@ -685,7 +753,7 @@ pub const Instruction = union(enum) { |
| 685 | }, | 753 | }, |
| 686 | 64 => { | 754 | 64 => { |
| 687 | return Instruction{ | 755 | return Instruction{ |
| 688 | .LogicalShiftedRegister = .{ | 756 | .logical_shifted_register = .{ |
| 689 | .rd = rd.id(), | 757 | .rd = rd.id(), |
| 690 | .rn = rn.id(), | 758 | .rn = rn.id(), |
| 691 | .imm6 = shift.amount, | 759 | .imm6 = shift.amount, |
| ... | @@ -710,7 +778,7 @@ pub const Instruction = union(enum) { | ... | @@ -710,7 +778,7 @@ pub const Instruction = union(enum) { |
| 710 | shift: bool, | 778 | shift: bool, |
| 711 | ) Instruction { | 779 | ) Instruction { |
| 712 | return Instruction{ | 780 | return Instruction{ |
| 713 | .AddSubtractImmediate = .{ | 781 | .add_subtract_immediate = .{ |
| 714 | .rd = rd.id(), | 782 | .rd = rd.id(), |
| 715 | .rn = rn.id(), | 783 | .rn = rn.id(), |
| 716 | .imm12 = imm12, | 784 | .imm12 = imm12, |
| ... | @@ -726,6 +794,43 @@ pub const Instruction = union(enum) { | ... | @@ -726,6 +794,43 @@ pub const Instruction = union(enum) { |
| 726 | }; | 794 | }; |
| 727 | } | 795 | } |
| 728 | | 796 | |
| | 797 | fn conditionalBranch( |
| | 798 | o0: u1, |
| | 799 | o1: u1, |
| | 800 | cond: Condition, |
| | 801 | offset: i21, |
| | 802 | ) Instruction { |
| | 803 | assert(offset & 0b11 == 0b00); |
| | 804 | return Instruction{ |
| | 805 | .conditional_branch = .{ |
| | 806 | .cond = @enumToInt(cond), |
| | 807 | .o0 = o0, |
| | 808 | .imm19 = @bitCast(u19, @intCast(i19, offset >> 2)), |
| | 809 | .o1 = o1, |
| | 810 | }, |
| | 811 | }; |
| | 812 | } |
| | 813 | |
| | 814 | fn compareAndBranch( |
| | 815 | op: u1, |
| | 816 | rt: Register, |
| | 817 | offset: i21, |
| | 818 | ) Instruction { |
| | 819 | assert(offset & 0b11 == 0b00); |
| | 820 | return Instruction{ |
| | 821 | .compare_and_branch = .{ |
| | 822 | .rt = rt.id(), |
| | 823 | .imm19 = @bitCast(u19, @intCast(i19, offset >> 2)), |
| | 824 | .op = op, |
| | 825 | .sf = switch (rt.size()) { |
| | 826 | 32 => 0b0, |
| | 827 | 64 => 0b1, |
| | 828 | else => unreachable, // unexpected register size |
| | 829 | }, |
| | 830 | }, |
| | 831 | }; |
| | 832 | } |
| | 833 | |
| 729 | // Helper functions for assembly syntax functions | 834 | // Helper functions for assembly syntax functions |
| 730 | | 835 | |
| 731 | // Move wide (immediate) | 836 | // Move wide (immediate) |
| ... | @@ -821,19 +926,19 @@ pub const Instruction = union(enum) { | ... | @@ -821,19 +926,19 @@ pub const Instruction = union(enum) { |
| 821 | }; | 926 | }; |
| 822 | | 927 | |
| 823 | pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction { | 928 | pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction { |
| 824 | return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), true); | 929 | return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), true); |
| 825 | } | 930 | } |
| 826 | | 931 | |
| 827 | pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction { | 932 | pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction { |
| 828 | return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, true); | 933 | return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, true); |
| 829 | } | 934 | } |
| 830 | | 935 | |
| 831 | pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction { | 936 | pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction { |
| 832 | return loadStorePairOfRegisters(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), false); | 937 | return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @enumToInt(offset.encoding), false); |
| 833 | } | 938 | } |
| 834 | | 939 | |
| 835 | pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction { | 940 | pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction { |
| 836 | return loadStorePairOfRegisters(rt1, rt2, rn, offset, 0, false); | 941 | return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, false); |
| 837 | } | 942 | } |
| 838 | | 943 | |
| 839 | // Exception generation | 944 | // Exception generation |
| ... | @@ -885,7 +990,7 @@ pub const Instruction = union(enum) { | ... | @@ -885,7 +990,7 @@ pub const Instruction = union(enum) { |
| 885 | // Nop | 990 | // Nop |
| 886 | | 991 | |
| 887 | pub fn nop() Instruction { | 992 | pub fn nop() Instruction { |
| 888 | return Instruction{ .NoOperation = .{} }; | 993 | return Instruction{ .no_operation = .{} }; |
| 889 | } | 994 | } |
| 890 | | 995 | |
| 891 | // Logical (shifted register) | 996 | // Logical (shifted register) |
| ... | @@ -939,6 +1044,22 @@ pub const Instruction = union(enum) { | ... | @@ -939,6 +1044,22 @@ pub const Instruction = union(enum) { |
| 939 | pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { | 1044 | pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { |
| 940 | return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift); | 1045 | return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift); |
| 941 | } | 1046 | } |
| | 1047 | |
| | 1048 | // Conditional branch |
| | 1049 | |
| | 1050 | pub fn bCond(cond: Condition, offset: i21) Instruction { |
| | 1051 | return conditionalBranch(0b0, 0b0, cond, offset); |
| | 1052 | } |
| | 1053 | |
| | 1054 | // Compare and branch |
| | 1055 | |
| | 1056 | pub fn cbz(rt: Register, offset: i21) Instruction { |
| | 1057 | return compareAndBranch(0b0, rt, offset); |
| | 1058 | } |
| | 1059 | |
| | 1060 | pub fn cbnz(rt: Register, offset: i21) Instruction { |
| | 1061 | return compareAndBranch(0b1, rt, offset); |
| | 1062 | } |
| 942 | }; | 1063 | }; |
| 943 | | 1064 | |
| 944 | test { | 1065 | test { |
| ... | @@ -1092,6 +1213,14 @@ test "serialize instructions" { | ... | @@ -1092,6 +1213,14 @@ test "serialize instructions" { |
| 1092 | .inst = Instruction.subs(.x0, .x5, 11, true), | 1213 | .inst = Instruction.subs(.x0, .x5, 11, true), |
| 1093 | .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000, | 1214 | .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000, |
| 1094 | }, | 1215 | }, |
| | 1216 | .{ // b.hi #-4 |
| | 1217 | .inst = Instruction.bCond(.hi, -4), |
| | 1218 | .expected = 0b0101010_0_1111111111111111111_0_1000, |
| | 1219 | }, |
| | 1220 | .{ // cbz x10, #40 |
| | 1221 | .inst = Instruction.cbz(.x10, 40), |
| | 1222 | .expected = 0b1_011010_0_0000000000000001010_01010, |
| | 1223 | }, |
| 1095 | }; | 1224 | }; |
| 1096 | | 1225 | |
| 1097 | for (testcases) |case| { | 1226 | for (testcases) |case| { |