feat(cpu): Implement Multiply Long ARM instructions
This commit is contained in:
		@@ -18,6 +18,7 @@ const branch = @import("cpu/arm/branch.zig").branch;
 | 
			
		||||
const branchAndExchange = @import("cpu/arm/branch.zig").branchAndExchange;
 | 
			
		||||
const softwareInterrupt = @import("cpu/arm/software_interrupt.zig").softwareInterrupt;
 | 
			
		||||
const multiply = @import("cpu/arm/multiply.zig").multiply;
 | 
			
		||||
const multiplyLong = @import("cpu/arm/multiply_long.zig").multiplyLong;
 | 
			
		||||
 | 
			
		||||
// THUMB Instruction Groups
 | 
			
		||||
const format1 = @import("cpu/thumb/format1.zig").format1;
 | 
			
		||||
@@ -533,6 +534,14 @@ fn armPopulate() [0x1000]ArmInstrFn {
 | 
			
		||||
                lut[i] = multiply(A, S);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (i >> 7 & 0x1F == 0b00001 and i & 0xF == 0b1001) {
 | 
			
		||||
                const U = i >> 6 & 1 == 1;
 | 
			
		||||
                const A = i >> 5 & 1 == 1;
 | 
			
		||||
                const S = i >> 4 & 1 == 1;
 | 
			
		||||
 | 
			
		||||
                lut[i] = multiplyLong(U, A, S);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (i >> 10 & 0x3 == 0b01) {
 | 
			
		||||
                const I = i >> 9 & 1 == 1;
 | 
			
		||||
                const P = i >> 8 & 1 == 1;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								src/cpu/arm/multiply_long.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/cpu/arm/multiply_long.zig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
const std = @import("std");
 | 
			
		||||
 | 
			
		||||
const Bus = @import("../../Bus.zig");
 | 
			
		||||
const Arm7tdmi = @import("../../cpu.zig").Arm7tdmi;
 | 
			
		||||
const InstrFn = @import("../../cpu.zig").ArmInstrFn;
 | 
			
		||||
 | 
			
		||||
pub fn multiplyLong(comptime U: bool, comptime A: bool, comptime S: bool) InstrFn {
 | 
			
		||||
    return struct {
 | 
			
		||||
        fn inner(cpu: *Arm7tdmi, _: *Bus, opcode: u32) void {
 | 
			
		||||
            const rd_hi = opcode >> 16 & 0xF;
 | 
			
		||||
            const rd_lo = opcode >> 12 & 0xF;
 | 
			
		||||
            const rs = opcode >> 8 & 0xF;
 | 
			
		||||
            const rm = opcode & 0xF;
 | 
			
		||||
 | 
			
		||||
            if (U) {
 | 
			
		||||
                // Signed (WHY IS IT U THEN?)
 | 
			
		||||
                var result: i64 = @as(i64, @bitCast(i32, cpu.r[rm])) * @as(i64, @bitCast(i32, cpu.r[rs]));
 | 
			
		||||
                if (A) result += @bitCast(i64, @as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo]));
 | 
			
		||||
 | 
			
		||||
                cpu.r[rd_hi] = @bitCast(u32, @truncate(i32, result >> 32));
 | 
			
		||||
                cpu.r[rd_lo] = @bitCast(u32, @truncate(i32, result));
 | 
			
		||||
            } else {
 | 
			
		||||
                // Unsigned
 | 
			
		||||
                var result: u64 = @as(u64, cpu.r[rm]) * @as(u64, cpu.r[rs]);
 | 
			
		||||
                if (A) result += @as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo]);
 | 
			
		||||
 | 
			
		||||
                cpu.r[rd_hi] = @truncate(u32, result >> 32);
 | 
			
		||||
                cpu.r[rd_lo] = @truncate(u32, result);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (S) {
 | 
			
		||||
                cpu.cpsr.z.write(cpu.r[rd_hi] == 0 and cpu.r[rd_lo] == 0);
 | 
			
		||||
                cpu.cpsr.n.write(cpu.r[rd_hi] >> 31 & 1 == 1);
 | 
			
		||||
                // C and V are set to meaningless values
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }.inner;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user