feat: implement dedicated Barrel Shifter SHL and SHR
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -2,3 +2,5 @@
 | 
				
			|||||||
/bin
 | 
					/bin
 | 
				
			||||||
/zig-cache
 | 
					/zig-cache
 | 
				
			||||||
/zig-out
 | 
					/zig-out
 | 
				
			||||||
 | 
					/docs
 | 
				
			||||||
 | 
					**/*.log
 | 
				
			||||||
@@ -2,8 +2,10 @@ const std = @import("std");
 | 
				
			|||||||
const util = @import("util.zig");
 | 
					const util = @import("util.zig");
 | 
				
			||||||
const bitfield = @import("bitfield");
 | 
					const bitfield = @import("bitfield");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BarrelShifter = @import("cpu/barrel_shifter.zig");
 | 
				
			||||||
const Bus = @import("bus.zig").Bus;
 | 
					const Bus = @import("bus.zig").Bus;
 | 
				
			||||||
const Scheduler = @import("scheduler.zig").Scheduler;
 | 
					const Scheduler = @import("scheduler.zig").Scheduler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Bitfield = bitfield.Bitfield;
 | 
					const Bitfield = bitfield.Bitfield;
 | 
				
			||||||
const Bit = bitfield.Bit;
 | 
					const Bit = bitfield.Bit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -160,7 +162,7 @@ fn populate() [0x1000]InstrFn {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const CPSR = extern union {
 | 
					pub const CPSR = extern union {
 | 
				
			||||||
    mode: Bitfield(u32, 0, 5),
 | 
					    mode: Bitfield(u32, 0, 5),
 | 
				
			||||||
    t: Bit(u32, 5),
 | 
					    t: Bit(u32, 5),
 | 
				
			||||||
    f: Bit(u32, 6),
 | 
					    f: Bit(u32, 6),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										83
									
								
								src/cpu/barrel_shifter.zig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/cpu/barrel_shifter.zig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					const std = @import("std");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const arm = @import("../cpu.zig");
 | 
				
			||||||
 | 
					const Arm7tdmi = arm.Arm7tdmi;
 | 
				
			||||||
 | 
					const CPSR = arm.CPSR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub inline fn exec(cpu: *Arm7tdmi, opcode: u32) u32 {
 | 
				
			||||||
 | 
					    var shift_amt: u8 = undefined;
 | 
				
			||||||
 | 
					    if (opcode >> 4 & 1 == 1) {
 | 
				
			||||||
 | 
					        shift_amt = @truncate(u8, cpu.r[opcode >> 8 & 0xF]);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        shift_amt = @truncate(u8, opcode >> 7 & 0x1F);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const rm = cpu.r[opcode & 0xF];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return switch (@truncate(u2, opcode >> 5)) {
 | 
				
			||||||
 | 
					        0b00 => logical_left(&cpu.cpsr, rm, shift_amt),
 | 
				
			||||||
 | 
					        0b01 => logical_right(&cpu.cpsr, rm, shift_amt),
 | 
				
			||||||
 | 
					        0b10 => arithmetic_right(&cpu.cpsr, rm, shift_amt),
 | 
				
			||||||
 | 
					        0b11 => rotate_right(&cpu.cpsr, rm, shift_amt),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub inline fn logical_left(cpsr: *CPSR, rm: u32, shift_byte: u8) u32 {
 | 
				
			||||||
 | 
					    const shift_amt = @truncate(u5, shift_byte);
 | 
				
			||||||
 | 
					    const bit_count: u8 = @typeInfo(u32).Int.bits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var result: u32 = 0x0000_0000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (shift_byte < bit_count) {
 | 
				
			||||||
 | 
					        // We can perform a well-defined shift here
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // FIXME: We assume cpu.r[rs] == 0 and imm_shift == 0 are equivalent
 | 
				
			||||||
 | 
					        if (shift_amt != 0) {
 | 
				
			||||||
 | 
					            const carry_bit = @truncate(u5, bit_count - shift_amt);
 | 
				
			||||||
 | 
					            cpsr.c.write(rm >> carry_bit & 1 == 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = rm << shift_amt;
 | 
				
			||||||
 | 
					    } else if (shift_byte == bit_count) {
 | 
				
			||||||
 | 
					        // Shifted all bits out, carry bit is bit 0 of rm
 | 
				
			||||||
 | 
					        cpsr.c.write(rm & 1 == 1);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // Shifted all bits out, carry bit has also been shifted out
 | 
				
			||||||
 | 
					        cpsr.c.write(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub inline fn logical_right(cpsr: *CPSR, rm: u32, shift_byte: u8) u32 {
 | 
				
			||||||
 | 
					    const shift_amt = @truncate(u5, shift_byte);
 | 
				
			||||||
 | 
					    const bit_count: u8 = @typeInfo(u32).Int.bits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var result: u32 = 0x0000_0000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (shift_byte == 0 or shift_byte == bit_count) {
 | 
				
			||||||
 | 
					        // Actualy LSR #32
 | 
				
			||||||
 | 
					        cpsr.c.write(rm >> 31 & 1 == 1);
 | 
				
			||||||
 | 
					    } else if (shift_byte < bit_count) {
 | 
				
			||||||
 | 
					        // We can perform a well-defined shift
 | 
				
			||||||
 | 
					        const carry_bit = shift_amt - 1;
 | 
				
			||||||
 | 
					        cpsr.c.write(rm >> carry_bit & 1 == 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = rm >> shift_amt;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // All bits have been shifted out, including carry bit
 | 
				
			||||||
 | 
					        cpsr.c.write(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn arithmetic_right(_: *CPSR, _: u32, _: u8) u32 {
 | 
				
			||||||
 | 
					    // @bitCast(u32, @bitCast(i32, r_val) >> @truncate(u5, amount))
 | 
				
			||||||
 | 
					    std.debug.panic("[BarrelShifter] implement arithmetic shift right", .{});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn rotate_right(_: *CPSR, _: u32, _: u8) u32 {
 | 
				
			||||||
 | 
					    // std.math.rotr(u32, r_val, amount)
 | 
				
			||||||
 | 
					    std.debug.panic("[BarrelShifter] implement rotate right", .{});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,9 +1,10 @@
 | 
				
			|||||||
const std = @import("std");
 | 
					const std = @import("std");
 | 
				
			||||||
const processor = @import("../cpu.zig");
 | 
					const arm = @import("../cpu.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BarrelShifter = @import("barrel_shifter.zig");
 | 
				
			||||||
const Bus = @import("../bus.zig").Bus;
 | 
					const Bus = @import("../bus.zig").Bus;
 | 
				
			||||||
const Arm7tdmi = processor.Arm7tdmi;
 | 
					const Arm7tdmi = arm.Arm7tdmi;
 | 
				
			||||||
const InstrFn = processor.InstrFn;
 | 
					const InstrFn = arm.InstrFn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn comptimeDataProcessing(comptime I: bool, comptime S: bool, comptime instrKind: u4) InstrFn {
 | 
					pub fn comptimeDataProcessing(comptime I: bool, comptime S: bool, comptime instrKind: u4) InstrFn {
 | 
				
			||||||
    return struct {
 | 
					    return struct {
 | 
				
			||||||
@@ -15,7 +16,7 @@ pub fn comptimeDataProcessing(comptime I: bool, comptime S: bool, comptime instr
 | 
				
			|||||||
            if (I) {
 | 
					            if (I) {
 | 
				
			||||||
                op2 = std.math.rotr(u32, opcode & 0xFF, (opcode >> 8 & 0xF) << 1);
 | 
					                op2 = std.math.rotr(u32, opcode & 0xFF, (opcode >> 8 & 0xF) << 1);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                op2 = registerOp2(cpu, opcode);
 | 
					                op2 = BarrelShifter.exec(cpu, opcode);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            switch (instrKind) {
 | 
					            switch (instrKind) {
 | 
				
			||||||
@@ -53,22 +54,22 @@ pub fn comptimeDataProcessing(comptime I: bool, comptime S: bool, comptime instr
 | 
				
			|||||||
    }.dataProcessing;
 | 
					    }.dataProcessing;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn registerOp2(cpu: *const Arm7tdmi, opcode: u32) u32 {
 | 
					// fn registerOp2(cpu: *const Arm7tdmi, opcode: u32) u32 {
 | 
				
			||||||
    var amount: u32 = undefined;
 | 
					//     var amount: u32 = undefined;
 | 
				
			||||||
    if (opcode >> 4 & 0x01 == 0x01) {
 | 
					//     if (opcode >> 4 & 0x01 == 0x01) {
 | 
				
			||||||
        amount = cpu.r[opcode >> 8 & 0xF] & 0xFF;
 | 
					//         amount = cpu.r[opcode >> 8 & 0xF] & 0xFF;
 | 
				
			||||||
    } else {
 | 
					//     } else {
 | 
				
			||||||
        amount = opcode >> 7 & 0x1F;
 | 
					//         amount = opcode >> 7 & 0x1F;
 | 
				
			||||||
    }
 | 
					//     }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const rm = opcode & 0xF;
 | 
					//     const rm = opcode & 0xF;
 | 
				
			||||||
    const r_val = cpu.r[rm];
 | 
					//     const r_val = cpu.r[rm];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return switch (opcode >> 5 & 0x03) {
 | 
					//     return switch (opcode >> 5 & 0x03) {
 | 
				
			||||||
        0b00 => r_val << @truncate(u5, amount),
 | 
					//         0b00 => r_val << @truncate(u5, amount),
 | 
				
			||||||
        0b01 => r_val >> @truncate(u5, amount),
 | 
					//         0b01 => r_val >> @truncate(u5, amount),
 | 
				
			||||||
        0b10 => @bitCast(u32, @bitCast(i32, r_val) >> @truncate(u5, amount)),
 | 
					//         0b10 => @bitCast(u32, @bitCast(i32, r_val) >> @truncate(u5, amount)),
 | 
				
			||||||
        0b11 => std.math.rotr(u32, r_val, amount),
 | 
					//         0b11 => std.math.rotr(u32, r_val, amount),
 | 
				
			||||||
        else => unreachable,
 | 
					//         else => unreachable,
 | 
				
			||||||
    };
 | 
					//     };
 | 
				
			||||||
}
 | 
					// }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
const std = @import("std");
 | 
					const std = @import("std");
 | 
				
			||||||
const processor = @import("../cpu.zig");
 | 
					const arm = @import("../cpu.zig");
 | 
				
			||||||
const util = @import("../util.zig");
 | 
					const util = @import("../util.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Bus = @import("../bus.zig").Bus;
 | 
					const Bus = @import("../bus.zig").Bus;
 | 
				
			||||||
const Arm7tdmi = processor.Arm7tdmi;
 | 
					const Arm7tdmi = arm.Arm7tdmi;
 | 
				
			||||||
const InstrFn = processor.InstrFn;
 | 
					const InstrFn = arm.InstrFn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn comptimeHalfSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: bool, comptime W: bool, comptime L: bool) InstrFn {
 | 
					pub fn comptimeHalfSignedDataTransfer(comptime P: bool, comptime U: bool, comptime I: bool, comptime W: bool, comptime L: bool) InstrFn {
 | 
				
			||||||
    return struct {
 | 
					    return struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,11 @@
 | 
				
			|||||||
const std = @import("std");
 | 
					const std = @import("std");
 | 
				
			||||||
const util = @import("../util.zig");
 | 
					const util = @import("../util.zig");
 | 
				
			||||||
const processor = @import("../cpu.zig");
 | 
					const arm = @import("../cpu.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const BarrelShifter = @import("barrel_shifter.zig");
 | 
				
			||||||
const Bus = @import("../bus.zig").Bus;
 | 
					const Bus = @import("../bus.zig").Bus;
 | 
				
			||||||
const Arm7tdmi = processor.Arm7tdmi;
 | 
					const Arm7tdmi = arm.Arm7tdmi;
 | 
				
			||||||
const InstrFn = processor.InstrFn;
 | 
					const InstrFn = arm.InstrFn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn comptimeSingleDataTransfer(comptime I: bool, comptime P: bool, comptime U: bool, comptime B: bool, comptime W: bool, comptime L: bool) InstrFn {
 | 
					pub fn comptimeSingleDataTransfer(comptime I: bool, comptime P: bool, comptime U: bool, comptime B: bool, comptime W: bool, comptime L: bool) InstrFn {
 | 
				
			||||||
    return struct {
 | 
					    return struct {
 | 
				
			||||||
@@ -48,15 +49,14 @@ pub fn comptimeSingleDataTransfer(comptime I: bool, comptime P: bool, comptime U
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn registerOffset(cpu: *Arm7tdmi, opcode: u32) u32 {
 | 
					fn registerOffset(cpu: *Arm7tdmi, opcode: u32) u32 {
 | 
				
			||||||
    const amount = opcode >> 7 & 0x1F;
 | 
					    const shift_byte = @truncate(u8, opcode >> 7 & 0x1F);
 | 
				
			||||||
    const rm = opcode & 0xF;
 | 
					 | 
				
			||||||
    const r_val = cpu.r[rm];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return switch (opcode >> 5 & 0x03) {
 | 
					    const rm = cpu.r[opcode & 0xF];
 | 
				
			||||||
        0b00 => r_val << @truncate(u5, amount),
 | 
					
 | 
				
			||||||
        0b01 => r_val >> @truncate(u5, amount),
 | 
					    return switch (@truncate(u2, opcode >> 5)) {
 | 
				
			||||||
        0b10 => @bitCast(u32, @bitCast(i32, r_val) >> @truncate(u5, amount)),
 | 
					        0b00 => BarrelShifter.logical_left(&cpu.cpsr, rm, shift_byte),
 | 
				
			||||||
        0b11 => std.math.rotr(u32, r_val, amount),
 | 
					        0b01 => BarrelShifter.logical_right(&cpu.cpsr, rm, shift_byte),
 | 
				
			||||||
        else => unreachable,
 | 
					        0b10 => BarrelShifter.arithmetic_right(&cpu.cpsr, rm, shift_byte),
 | 
				
			||||||
 | 
					        0b11 => BarrelShifter.rotate_right(&cpu.cpsr, rm, shift_byte),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user