Compare commits
2 Commits
90d5c19e01
...
11727fe46d
Author | SHA1 | Date |
---|---|---|
Rekai Nyangadzayi Musuka | 11727fe46d | |
Rekai Nyangadzayi Musuka | f8c2479ed9 |
|
@ -3,8 +3,8 @@
|
||||||
.version = "0.1.0",
|
.version = "0.1.0",
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.@"zba-util" = .{
|
.@"zba-util" = .{
|
||||||
.url = "https://git.musuka.dev/paoda/zba-util/archive/e616cf09e53f5c402c8f040d14baa211683e70e3.tar.gz",
|
.url = "https://git.musuka.dev/paoda/zba-util/archive/73577e9a6369f8393f25a73dfe73dcfaf8caf4a8.tar.gz",
|
||||||
.hash = "1220b80b2c0989dcc47275ab9d7d70da4858ef3c1fe1f934e8d838e65028127f6ef3",
|
.hash = "1220dad50e323a5edd843ed15aa0840dc876ca743049869727e759201e89d63bfa34",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,13 @@ fn BitType(comptime FieldType: type, comptime ValueType: type, comptime shamt: u
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(self: anytype) ValueType {
|
pub fn read(self: anytype) ValueType {
|
||||||
return @bitCast(ValueType, @truncate(u1, self.bits.field().* >> shamt));
|
return @as(ValueType, @bitCast(@as(u1, @truncate(self.bits.field().* >> shamt))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since these are mostly used with MMIO, I want to avoid
|
// Since these are mostly used with MMIO, I want to avoid
|
||||||
// reading the memory just to write it again, also races
|
// reading the memory just to write it again, also races
|
||||||
pub fn write(self: anytype, val: ValueType) void {
|
pub fn write(self: anytype, val: ValueType) void {
|
||||||
if (@bitCast(bool, val)) {
|
if (@as(bool, @bitCast(val))) {
|
||||||
self.set();
|
self.set();
|
||||||
} else {
|
} else {
|
||||||
self.unset();
|
self.unset();
|
||||||
|
@ -67,17 +67,17 @@ pub fn Bitfield(comptime FieldType: type, comptime shamt: usize, comptime num_bi
|
||||||
dummy: FieldType,
|
dummy: FieldType,
|
||||||
|
|
||||||
fn field(self: anytype) PtrCastPreserveCV(@This(), @TypeOf(self), FieldType) {
|
fn field(self: anytype) PtrCastPreserveCV(@This(), @TypeOf(self), FieldType) {
|
||||||
return @ptrCast(PtrCastPreserveCV(@This(), @TypeOf(self), FieldType), self);
|
return @as(PtrCastPreserveCV(@This(), @TypeOf(self), FieldType), @ptrCast(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(self: anytype, val: ValueType) void {
|
pub fn write(self: anytype, val: ValueType) void {
|
||||||
self.field().* &= ~self_mask;
|
self.field().* &= ~self_mask;
|
||||||
self.field().* |= @intCast(FieldType, val) << shamt;
|
self.field().* |= @as(FieldType, @intCast(val)) << shamt;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(self: anytype) ValueType {
|
pub fn read(self: anytype) ValueType {
|
||||||
const val: FieldType = self.field().*;
|
const val: FieldType = self.field().*;
|
||||||
return @intCast(ValueType, (val & self_mask) >> shamt);
|
return @as(ValueType, @intCast((val & self_mask) >> shamt));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
10
src/arm.zig
10
src/arm.zig
|
@ -174,7 +174,7 @@ pub fn Arm32(comptime arch: Architecture) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setCpsr(self: *Self, value: u32) void {
|
pub fn setCpsr(self: *Self, value: u32) void {
|
||||||
if (value & 0x1F != self.cpsr.raw & 0x1F) self.changeModeFromIdx(@truncate(u5, value & 0x1F));
|
if (value & 0x1F != self.cpsr.raw & 0x1F) self.changeModeFromIdx(@as(u5, @truncate(value & 0x1F)));
|
||||||
self.cpsr.raw = value;
|
self.cpsr.raw = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,7 +257,7 @@ pub fn Arm32(comptime arch: Architecture) type {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
self.cpsr.mode.write(@enumToInt(next));
|
self.cpsr.mode.write(@intFromEnum(next));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(self: *Self) void {
|
pub fn step(self: *Self) void {
|
||||||
|
@ -267,12 +267,12 @@ pub fn Arm32(comptime arch: Architecture) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.cpsr.t.read()) {
|
if (self.cpsr.t.read()) {
|
||||||
const opcode = @truncate(u16, self.pipe.step(self, u16) orelse return);
|
const opcode = @as(u16, @truncate(self.pipe.step(self, u16) orelse return));
|
||||||
thumb.lut[thumb.idx(opcode)](self, self.bus, opcode);
|
thumb.lut[thumb.idx(opcode)](self, self.bus, opcode);
|
||||||
} else {
|
} else {
|
||||||
const opcode = self.pipe.step(self, u32) orelse return;
|
const opcode = self.pipe.step(self, u32) orelse return;
|
||||||
|
|
||||||
if (self.cpsr.check(@truncate(u4, opcode >> 28))) {
|
if (self.cpsr.check(@as(u4, @truncate(opcode >> 28)))) {
|
||||||
arm.lut[arm.idx(opcode)](self, self.bus, opcode);
|
arm.lut[arm.idx(opcode)](self, self.bus, opcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -391,7 +391,7 @@ pub const PSR = extern union {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn check(self: @This(), cond: u4) bool {
|
pub inline fn check(self: @This(), cond: u4) bool {
|
||||||
const flags = @truncate(u4, self.raw >> 28);
|
const flags = @as(u4, @truncate(self.raw >> 28));
|
||||||
|
|
||||||
return condition_lut[cond] & (@as(u16, 1) << flags) != 0;
|
return condition_lut[cond] & (@as(u16, 1) << flags) != 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ pub fn blockDataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: b
|
||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
fn inner(cpu: Arm32, bus: Bus, opcode: u32) void {
|
fn inner(cpu: Arm32, bus: Bus, opcode: u32) void {
|
||||||
const rn = @truncate(u4, opcode >> 16 & 0xF);
|
const rn = @as(u4, @truncate(opcode >> 16 & 0xF));
|
||||||
const rlist = opcode & 0xFFFF;
|
const rlist = opcode & 0xFFFF;
|
||||||
const r15 = rlist >> 15 & 1 == 1;
|
const r15 = rlist >> 15 & 1 == 1;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ pub fn blockDataTransfer(comptime InstrFn: type, comptime P: bool, comptime U: b
|
||||||
var write_to_base = true;
|
var write_to_base = true;
|
||||||
|
|
||||||
while (i < 16) : (i += 1) {
|
while (i < 16) : (i += 1) {
|
||||||
const r = @truncate(u4, 15 - i);
|
const r = @as(u4, @truncate(15 - i));
|
||||||
if (rlist >> r & 1 == 1) {
|
if (rlist >> r & 1 == 1) {
|
||||||
first = r;
|
first = r;
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|
|
@ -8,16 +8,16 @@ pub fn dataProcessing(comptime InstrFn: type, comptime I: bool, comptime S: bool
|
||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
fn inner(cpu: Arm32, _: Bus, opcode: u32) void {
|
||||||
const rd = @truncate(u4, opcode >> 12 & 0xF);
|
const rd = @as(u4, @truncate(opcode >> 12 & 0xF));
|
||||||
const rn = opcode >> 16 & 0xF;
|
const rn = opcode >> 16 & 0xF;
|
||||||
const old_carry = @boolToInt(cpu.cpsr.c.read());
|
const old_carry = @intFromBool(cpu.cpsr.c.read());
|
||||||
|
|
||||||
// If certain conditions are met, PC is 12 ahead instead of 8
|
// If certain conditions are met, PC is 12 ahead instead of 8
|
||||||
// TODO: Why these conditions?
|
// TODO: Why these conditions?
|
||||||
if (!I and opcode >> 4 & 1 == 1) cpu.r[15] += 4;
|
if (!I and opcode >> 4 & 1 == 1) cpu.r[15] += 4;
|
||||||
const op1 = cpu.r[rn];
|
const op1 = cpu.r[rn];
|
||||||
|
|
||||||
const amount = @truncate(u8, (opcode >> 8 & 0xF) << 1);
|
const amount = @as(u8, @truncate((opcode >> 8 & 0xF) << 1));
|
||||||
const op2 = if (I) ror(S, &cpu.cpsr, opcode & 0xFF, amount) else exec(S, cpu, opcode);
|
const op2 = if (I) ror(S, &cpu.cpsr, opcode & 0xFF, amount) else exec(S, cpu, opcode);
|
||||||
|
|
||||||
// Undo special condition from above
|
// Undo special condition from above
|
||||||
|
@ -164,7 +164,7 @@ pub fn dataProcessing(comptime InstrFn: type, comptime I: bool, comptime S: bool
|
||||||
pub fn sbc(left: u32, right: u32, old_carry: u1) u32 {
|
pub fn sbc(left: u32, right: u32, old_carry: u1) u32 {
|
||||||
// TODO: Make your own version (thanks peach.bot)
|
// TODO: Make your own version (thanks peach.bot)
|
||||||
const subtrahend = @as(u64, right) -% old_carry +% 1;
|
const subtrahend = @as(u64, right) -% old_carry +% 1;
|
||||||
const ret = @truncate(u32, left -% subtrahend);
|
const ret = @as(u32, @truncate(left -% subtrahend));
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt
|
||||||
|
|
||||||
var result: u32 = undefined;
|
var result: u32 = undefined;
|
||||||
if (L) {
|
if (L) {
|
||||||
switch (@truncate(u2, opcode >> 5)) {
|
switch (@as(u2, @truncate(opcode >> 5))) {
|
||||||
0b01 => {
|
0b01 => {
|
||||||
// LDRH
|
// LDRH
|
||||||
const value = bus.read(u16, address);
|
const value = bus.read(u16, address);
|
||||||
|
@ -34,14 +34,14 @@ pub fn halfAndSignedDataTransfer(comptime InstrFn: type, comptime P: bool, compt
|
||||||
0b11 => {
|
0b11 => {
|
||||||
// LDRSH
|
// LDRSH
|
||||||
const value = bus.read(u16, address);
|
const value = bus.read(u16, address);
|
||||||
result = if (address & 1 == 1) sext(u32, u8, @truncate(u8, value >> 8)) else sext(u32, u16, value);
|
result = if (address & 1 == 1) sext(u32, u8, @as(u8, @truncate(value >> 8))) else sext(u32, u16, value);
|
||||||
},
|
},
|
||||||
0b00 => unreachable, // SWP
|
0b00 => unreachable, // SWP
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (opcode >> 5 & 0x01 == 0x01) {
|
if (opcode >> 5 & 0x01 == 0x01) {
|
||||||
// STRH
|
// STRH
|
||||||
bus.write(u16, address, @truncate(u16, cpu.r[rd]));
|
bus.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
||||||
} else unreachable; // SWP
|
} else unreachable; // SWP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub fn multiply(comptime InstrFn: type, comptime A: bool, comptime S: bool) Inst
|
||||||
const rm = opcode & 0xF;
|
const rm = opcode & 0xF;
|
||||||
|
|
||||||
const temp: u64 = @as(u64, cpu.r[rm]) * @as(u64, cpu.r[rs]) + if (A) cpu.r[rn] else 0;
|
const temp: u64 = @as(u64, cpu.r[rm]) * @as(u64, cpu.r[rs]) + if (A) cpu.r[rn] else 0;
|
||||||
const result = @truncate(u32, temp);
|
const result = @as(u32, @truncate(temp));
|
||||||
cpu.r[rd] = result;
|
cpu.r[rd] = result;
|
||||||
|
|
||||||
if (S) {
|
if (S) {
|
||||||
|
@ -35,18 +35,18 @@ pub fn multiplyLong(comptime InstrFn: type, comptime U: bool, comptime A: bool,
|
||||||
|
|
||||||
if (U) {
|
if (U) {
|
||||||
// Signed (WHY IS IT U THEN?)
|
// Signed (WHY IS IT U THEN?)
|
||||||
var result: i64 = @as(i64, @bitCast(i32, cpu.r[rm])) * @as(i64, @bitCast(i32, cpu.r[rs]));
|
var result: i64 = @as(i64, @as(i32, @bitCast(cpu.r[rm]))) * @as(i64, @as(i32, @bitCast(cpu.r[rs])));
|
||||||
if (A) result +%= @bitCast(i64, @as(u64, cpu.r[rd_hi]) << 32 | @as(u64, cpu.r[rd_lo]));
|
if (A) result +%= @as(i64, @bitCast(@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_hi] = @as(u32, @bitCast(@as(i32, @truncate(result >> 32))));
|
||||||
cpu.r[rd_lo] = @bitCast(u32, @truncate(i32, result));
|
cpu.r[rd_lo] = @as(u32, @bitCast(@as(i32, @truncate(result))));
|
||||||
} else {
|
} else {
|
||||||
// Unsigned
|
// Unsigned
|
||||||
var result: u64 = @as(u64, cpu.r[rm]) * @as(u64, cpu.r[rs]);
|
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]);
|
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_hi] = @as(u32, @truncate(result >> 32));
|
||||||
cpu.r[rd_lo] = @truncate(u32, result);
|
cpu.r[rd_lo] = @as(u32, @truncate(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S) {
|
if (S) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ pub fn psrTransfer(comptime InstrFn: type, comptime I: bool, comptime R: bool, c
|
||||||
},
|
},
|
||||||
0b10 => {
|
0b10 => {
|
||||||
// MSR
|
// MSR
|
||||||
const field_mask = @truncate(u4, opcode >> 16 & 0xF);
|
const field_mask = @as(u4, @truncate(opcode >> 16 & 0xF));
|
||||||
const rm_idx = opcode & 0xF;
|
const rm_idx = opcode & 0xF;
|
||||||
const right = if (I) rotr(u32, opcode & 0xFF, (opcode >> 8 & 0xF) * 2) else cpu.r[rm_idx];
|
const right = if (I) rotr(u32, opcode & 0xFF, (opcode >> 8 & 0xF) * 2) else cpu.r[rm_idx];
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ pub fn psrTransfer(comptime InstrFn: type, comptime I: bool, comptime R: bool, c
|
||||||
fn fieldMask(psr: *const PSR, field_mask: u4, right: u32) u32 {
|
fn fieldMask(psr: *const PSR, field_mask: u4, right: u32) u32 {
|
||||||
// This bitwise ORs bits 3 and 0 of the field mask into a u2
|
// This bitwise ORs bits 3 and 0 of the field mask into a u2
|
||||||
// We do this because we only care about bits 7:0 and 31:28 of the CPSR
|
// We do this because we only care about bits 7:0 and 31:28 of the CPSR
|
||||||
const bits = @truncate(u2, (field_mask >> 2 & 0x2) | (field_mask & 1));
|
const bits = @as(u2, @truncate((field_mask >> 2 & 0x2) | (field_mask & 1)));
|
||||||
|
|
||||||
const mask: u32 = switch (bits) {
|
const mask: u32 = switch (bits) {
|
||||||
0b00 => 0x0000_0000,
|
0b00 => 0x0000_0000,
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub fn singleDataSwap(comptime InstrFn: type, comptime B: bool) InstrFn {
|
||||||
if (B) {
|
if (B) {
|
||||||
// SWPB
|
// SWPB
|
||||||
const value = bus.read(u8, address);
|
const value = bus.read(u8, address);
|
||||||
bus.write(u8, address, @truncate(u8, cpu.r[rm]));
|
bus.write(u8, address, @as(u8, @truncate(cpu.r[rm])));
|
||||||
cpu.r[rd] = value;
|
cpu.r[rd] = value;
|
||||||
} else {
|
} else {
|
||||||
// SWP
|
// SWP
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub fn singleDataTransfer(comptime InstrFn: type, comptime I: bool, comptime P:
|
||||||
if (B) {
|
if (B) {
|
||||||
// STRB
|
// STRB
|
||||||
const value = cpu.r[rd] + if (rd == 0xF) 4 else @as(u32, 0); // PC is 12 ahead
|
const value = cpu.r[rd] + if (rd == 0xF) 4 else @as(u32, 0); // PC is 12 ahead
|
||||||
bus.write(u8, address, @truncate(u8, value));
|
bus.write(u8, address, @as(u8, @truncate(value)));
|
||||||
} else {
|
} else {
|
||||||
// STR
|
// STR
|
||||||
const value = cpu.r[rd] + if (rd == 0xF) 4 else @as(u32, 0);
|
const value = cpu.r[rd] + if (rd == 0xF) 4 else @as(u32, 0);
|
||||||
|
|
|
@ -16,9 +16,9 @@ pub fn exec(comptime S: bool, cpu: anytype, opcode: u32) u32 {
|
||||||
fn register(comptime S: bool, cpu: anytype, opcode: u32) u32 {
|
fn register(comptime S: bool, cpu: anytype, opcode: u32) u32 {
|
||||||
const rs_idx = opcode >> 8 & 0xF;
|
const rs_idx = opcode >> 8 & 0xF;
|
||||||
const rm = cpu.r[opcode & 0xF];
|
const rm = cpu.r[opcode & 0xF];
|
||||||
const rs = @truncate(u8, cpu.r[rs_idx]);
|
const rs = @as(u8, @truncate(cpu.r[rs_idx]));
|
||||||
|
|
||||||
return switch (@truncate(u2, opcode >> 5)) {
|
return switch (@as(u2, @truncate(opcode >> 5))) {
|
||||||
0b00 => lsl(S, &cpu.cpsr, rm, rs),
|
0b00 => lsl(S, &cpu.cpsr, rm, rs),
|
||||||
0b01 => lsr(S, &cpu.cpsr, rm, rs),
|
0b01 => lsr(S, &cpu.cpsr, rm, rs),
|
||||||
0b10 => asr(S, &cpu.cpsr, rm, rs),
|
0b10 => asr(S, &cpu.cpsr, rm, rs),
|
||||||
|
@ -27,12 +27,12 @@ fn register(comptime S: bool, cpu: anytype, opcode: u32) u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn immediate(comptime S: bool, cpu: anytype, opcode: u32) u32 {
|
pub fn immediate(comptime S: bool, cpu: anytype, opcode: u32) u32 {
|
||||||
const amount = @truncate(u8, opcode >> 7 & 0x1F);
|
const amount = @as(u8, @truncate(opcode >> 7 & 0x1F));
|
||||||
const rm = cpu.r[opcode & 0xF];
|
const rm = cpu.r[opcode & 0xF];
|
||||||
|
|
||||||
var result: u32 = undefined;
|
var result: u32 = undefined;
|
||||||
if (amount == 0) {
|
if (amount == 0) {
|
||||||
switch (@truncate(u2, opcode >> 5)) {
|
switch (@as(u2, @truncate(opcode >> 5))) {
|
||||||
0b00 => {
|
0b00 => {
|
||||||
// LSL #0
|
// LSL #0
|
||||||
result = rm;
|
result = rm;
|
||||||
|
@ -44,19 +44,19 @@ pub fn immediate(comptime S: bool, cpu: anytype, opcode: u32) u32 {
|
||||||
},
|
},
|
||||||
0b10 => {
|
0b10 => {
|
||||||
// ASR #0 aka ASR #32
|
// ASR #0 aka ASR #32
|
||||||
result = @bitCast(u32, @bitCast(i32, rm) >> 31);
|
result = @as(u32, @bitCast(@as(i32, @bitCast(rm)) >> 31));
|
||||||
if (S) cpu.cpsr.c.write(result >> 31 & 1 == 1);
|
if (S) cpu.cpsr.c.write(result >> 31 & 1 == 1);
|
||||||
},
|
},
|
||||||
0b11 => {
|
0b11 => {
|
||||||
// ROR #0 aka RRX
|
// ROR #0 aka RRX
|
||||||
const carry: u32 = @boolToInt(cpu.cpsr.c.read());
|
const carry: u32 = @intFromBool(cpu.cpsr.c.read());
|
||||||
if (S) cpu.cpsr.c.write(rm & 1 == 1);
|
if (S) cpu.cpsr.c.write(rm & 1 == 1);
|
||||||
|
|
||||||
result = (carry << 31) | (rm >> 1);
|
result = (carry << 31) | (rm >> 1);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (@truncate(u2, opcode >> 5)) {
|
switch (@as(u2, @truncate(opcode >> 5))) {
|
||||||
0b00 => result = lsl(S, &cpu.cpsr, rm, amount),
|
0b00 => result = lsl(S, &cpu.cpsr, rm, amount),
|
||||||
0b01 => result = lsr(S, &cpu.cpsr, rm, amount),
|
0b01 => result = lsr(S, &cpu.cpsr, rm, amount),
|
||||||
0b10 => result = asr(S, &cpu.cpsr, rm, amount),
|
0b10 => result = asr(S, &cpu.cpsr, rm, amount),
|
||||||
|
@ -68,7 +68,7 @@ pub fn immediate(comptime S: bool, cpu: anytype, opcode: u32) u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lsl(comptime S: bool, cpsr: *CPSR, rm: u32, total_amount: u8) u32 {
|
pub fn lsl(comptime S: bool, cpsr: *CPSR, rm: u32, total_amount: u8) u32 {
|
||||||
const amount = @truncate(u5, total_amount);
|
const amount = @as(u5, @truncate(total_amount));
|
||||||
const bit_count: u8 = @typeInfo(u32).Int.bits;
|
const bit_count: u8 = @typeInfo(u32).Int.bits;
|
||||||
|
|
||||||
var result: u32 = 0x0000_0000;
|
var result: u32 = 0x0000_0000;
|
||||||
|
@ -77,7 +77,7 @@ pub fn lsl(comptime S: bool, cpsr: *CPSR, rm: u32, total_amount: u8) u32 {
|
||||||
result = rm << amount;
|
result = rm << amount;
|
||||||
|
|
||||||
if (S and total_amount != 0) {
|
if (S and total_amount != 0) {
|
||||||
const carry_bit = @truncate(u5, bit_count - amount);
|
const carry_bit = @as(u5, @truncate(bit_count - amount));
|
||||||
cpsr.c.write(rm >> carry_bit & 1 == 1);
|
cpsr.c.write(rm >> carry_bit & 1 == 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -95,7 +95,7 @@ pub fn lsl(comptime S: bool, cpsr: *CPSR, rm: u32, total_amount: u8) u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lsr(comptime S: bool, cpsr: *CPSR, rm: u32, total_amount: u32) u32 {
|
pub fn lsr(comptime S: bool, cpsr: *CPSR, rm: u32, total_amount: u32) u32 {
|
||||||
const amount = @truncate(u5, total_amount);
|
const amount = @as(u5, @truncate(total_amount));
|
||||||
const bit_count: u8 = @typeInfo(u32).Int.bits;
|
const bit_count: u8 = @typeInfo(u32).Int.bits;
|
||||||
|
|
||||||
var result: u32 = 0x0000_0000;
|
var result: u32 = 0x0000_0000;
|
||||||
|
@ -119,16 +119,16 @@ pub fn lsr(comptime S: bool, cpsr: *CPSR, rm: u32, total_amount: u32) u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asr(comptime S: bool, cpsr: *CPSR, rm: u32, total_amount: u8) u32 {
|
pub fn asr(comptime S: bool, cpsr: *CPSR, rm: u32, total_amount: u8) u32 {
|
||||||
const amount = @truncate(u5, total_amount);
|
const amount = @as(u5, @truncate(total_amount));
|
||||||
const bit_count: u8 = @typeInfo(u32).Int.bits;
|
const bit_count: u8 = @typeInfo(u32).Int.bits;
|
||||||
|
|
||||||
var result: u32 = 0x0000_0000;
|
var result: u32 = 0x0000_0000;
|
||||||
if (total_amount < bit_count) {
|
if (total_amount < bit_count) {
|
||||||
result = @bitCast(u32, @bitCast(i32, rm) >> amount);
|
result = @as(u32, @bitCast(@as(i32, @bitCast(rm)) >> amount));
|
||||||
if (S and total_amount != 0) cpsr.c.write(rm >> (amount - 1) & 1 == 1);
|
if (S and total_amount != 0) cpsr.c.write(rm >> (amount - 1) & 1 == 1);
|
||||||
} else {
|
} else {
|
||||||
// ASR #32 and ASR #>32 have the same result
|
// ASR #32 and ASR #>32 have the same result
|
||||||
result = @bitCast(u32, @bitCast(i32, rm) >> 31);
|
result = @as(u32, @bitCast(@as(i32, @bitCast(rm)) >> 31));
|
||||||
if (S) cpsr.c.write(result >> 31 & 1 == 1);
|
if (S) cpsr.c.write(result >> 31 & 1 == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ pub fn fmt4(comptime InstrFn: type, comptime op: u4) InstrFn {
|
||||||
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
||||||
const rs = opcode >> 3 & 0x7;
|
const rs = opcode >> 3 & 0x7;
|
||||||
const rd = opcode & 0x7;
|
const rd = opcode & 0x7;
|
||||||
const carry = @boolToInt(cpu.cpsr.c.read());
|
const carry = @intFromBool(cpu.cpsr.c.read());
|
||||||
|
|
||||||
const op1 = cpu.r[rd];
|
const op1 = cpu.r[rd];
|
||||||
const op2 = cpu.r[rs];
|
const op2 = cpu.r[rs];
|
||||||
|
@ -26,12 +26,12 @@ pub fn fmt4(comptime InstrFn: type, comptime op: u4) InstrFn {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
0x0 => result = op1 & op2, // AND
|
0x0 => result = op1 & op2, // AND
|
||||||
0x1 => result = op1 ^ op2, // EOR
|
0x1 => result = op1 ^ op2, // EOR
|
||||||
0x2 => result = lsl(true, &cpu.cpsr, op1, @truncate(u8, op2)), // LSL
|
0x2 => result = lsl(true, &cpu.cpsr, op1, @as(u8, @truncate(op2))), // LSL
|
||||||
0x3 => result = lsr(true, &cpu.cpsr, op1, @truncate(u8, op2)), // LSR
|
0x3 => result = lsr(true, &cpu.cpsr, op1, @as(u8, @truncate(op2))), // LSR
|
||||||
0x4 => result = asr(true, &cpu.cpsr, op1, @truncate(u8, op2)), // ASR
|
0x4 => result = asr(true, &cpu.cpsr, op1, @as(u8, @truncate(op2))), // ASR
|
||||||
0x5 => result = adc(&overflow, op1, op2, carry), // ADC
|
0x5 => result = adc(&overflow, op1, op2, carry), // ADC
|
||||||
0x6 => result = sbc(op1, op2, carry), // SBC
|
0x6 => result = sbc(op1, op2, carry), // SBC
|
||||||
0x7 => result = ror(true, &cpu.cpsr, op1, @truncate(u8, op2)), // ROR
|
0x7 => result = ror(true, &cpu.cpsr, op1, @as(u8, @truncate(op2))), // ROR
|
||||||
0x8 => result = op1 & op2, // TST
|
0x8 => result = op1 & op2, // TST
|
||||||
0x9 => result = 0 -% op2, // NEG
|
0x9 => result = 0 -% op2, // NEG
|
||||||
0xA => result = op1 -% op2, // CMP
|
0xA => result = op1 -% op2, // CMP
|
||||||
|
@ -42,7 +42,7 @@ pub fn fmt4(comptime InstrFn: type, comptime op: u4) InstrFn {
|
||||||
overflow = tmp[1];
|
overflow = tmp[1];
|
||||||
},
|
},
|
||||||
0xC => result = op1 | op2, // ORR
|
0xC => result = op1 | op2, // ORR
|
||||||
0xD => result = @truncate(u32, @as(u64, op2) * @as(u64, op1)),
|
0xD => result = @as(u32, @truncate(@as(u64, op2) * @as(u64, op1))),
|
||||||
0xE => result = op1 & ~op2,
|
0xE => result = op1 & ~op2,
|
||||||
0xF => result = ~op2,
|
0xF => result = ~op2,
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ pub fn fmt14(comptime InstrFn: type, comptime L: bool, comptime R: bool) InstrFn
|
||||||
|
|
||||||
return struct {
|
return struct {
|
||||||
fn inner(cpu: Arm32, bus: Bus, opcode: u16) void {
|
fn inner(cpu: Arm32, bus: Bus, opcode: u16) void {
|
||||||
const count = @boolToInt(R) + countRlist(opcode);
|
const count = @intFromBool(R) + countRlist(opcode);
|
||||||
const start = cpu.r[13] - if (!L) count * 4 else 0;
|
const start = cpu.r[13] - if (!L) count * 4 else 0;
|
||||||
|
|
||||||
var end = cpu.r[13];
|
var end = cpu.r[13];
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub fn fmt1(comptime InstrFn: type, comptime op: u2, comptime offset: u5) InstrF
|
||||||
// ASR
|
// ASR
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
cpu.cpsr.c.write(cpu.r[rs] >> 31 & 1 == 1);
|
cpu.cpsr.c.write(cpu.r[rs] >> 31 & 1 == 1);
|
||||||
break :blk @bitCast(u32, @bitCast(i32, cpu.r[rs]) >> 31);
|
break :blk @as(u32, @bitCast(@as(i32, @bitCast(cpu.r[rs])) >> 31));
|
||||||
} else {
|
} else {
|
||||||
break :blk asr(true, &cpu.cpsr, cpu.r[rs], offset);
|
break :blk asr(true, &cpu.cpsr, cpu.r[rs], offset);
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ pub fn fmt2(comptime InstrFn: type, comptime I: bool, is_sub: bool, rn: u3) Inst
|
||||||
return struct {
|
return struct {
|
||||||
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
fn inner(cpu: Arm32, _: Bus, opcode: u16) void {
|
||||||
const rs = opcode >> 3 & 0x7;
|
const rs = opcode >> 3 & 0x7;
|
||||||
const rd = @truncate(u3, opcode);
|
const rd = @as(u3, @truncate(opcode));
|
||||||
const op1 = cpu.r[rs];
|
const op1 = cpu.r[rs];
|
||||||
const op2: u32 = if (I) rn else cpu.r[rn];
|
const op2: u32 = if (I) rn else cpu.r[rn];
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub fn fmt78(comptime InstrFn: type, comptime op: u2, comptime T: bool) InstrFn
|
||||||
switch (op) {
|
switch (op) {
|
||||||
0b00 => {
|
0b00 => {
|
||||||
// STRH
|
// STRH
|
||||||
bus.write(u16, address, @truncate(u16, cpu.r[rd]));
|
bus.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
||||||
},
|
},
|
||||||
0b01 => {
|
0b01 => {
|
||||||
// LDSB
|
// LDSB
|
||||||
|
@ -47,7 +47,7 @@ pub fn fmt78(comptime InstrFn: type, comptime op: u2, comptime T: bool) InstrFn
|
||||||
0b11 => {
|
0b11 => {
|
||||||
// LDRSH
|
// LDRSH
|
||||||
const value = bus.read(u16, address);
|
const value = bus.read(u16, address);
|
||||||
cpu.r[rd] = if (address & 1 == 1) sext(u32, u8, @truncate(u8, value >> 8)) else sext(u32, u16, value);
|
cpu.r[rd] = if (address & 1 == 1) sext(u32, u8, @as(u8, @truncate(value >> 8))) else sext(u32, u16, value);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -59,7 +59,7 @@ pub fn fmt78(comptime InstrFn: type, comptime op: u2, comptime T: bool) InstrFn
|
||||||
},
|
},
|
||||||
0b01 => {
|
0b01 => {
|
||||||
// STRB
|
// STRB
|
||||||
bus.write(u8, address, @truncate(u8, cpu.r[rd]));
|
bus.write(u8, address, @as(u8, @truncate(cpu.r[rd])));
|
||||||
},
|
},
|
||||||
0b10 => {
|
0b10 => {
|
||||||
// LDR
|
// LDR
|
||||||
|
@ -99,7 +99,7 @@ pub fn fmt9(comptime InstrFn: type, comptime B: bool, comptime L: bool, comptime
|
||||||
if (B) {
|
if (B) {
|
||||||
// STRB
|
// STRB
|
||||||
const address = cpu.r[rb] + offset;
|
const address = cpu.r[rb] + offset;
|
||||||
bus.write(u8, address, @truncate(u8, cpu.r[rd]));
|
bus.write(u8, address, @as(u8, @truncate(cpu.r[rd])));
|
||||||
} else {
|
} else {
|
||||||
// STR
|
// STR
|
||||||
const address = cpu.r[rb] + (@as(u32, offset) << 2);
|
const address = cpu.r[rb] + (@as(u32, offset) << 2);
|
||||||
|
@ -126,7 +126,7 @@ pub fn fmt10(comptime InstrFn: type, comptime L: bool, comptime offset: u5) Inst
|
||||||
cpu.r[rd] = rotr(u32, value, 8 * (address & 1));
|
cpu.r[rd] = rotr(u32, value, 8 * (address & 1));
|
||||||
} else {
|
} else {
|
||||||
// STRH
|
// STRH
|
||||||
bus.write(u16, address, @truncate(u16, cpu.r[rd]));
|
bus.write(u16, address, @as(u16, @truncate(cpu.r[rd])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.inner;
|
}.inner;
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn arm(comptime Arm32: type) type {
|
||||||
|
|
||||||
/// Determine index into ARM InstrFn LUT
|
/// Determine index into ARM InstrFn LUT
|
||||||
pub fn idx(opcode: u32) u12 {
|
pub fn idx(opcode: u32) u12 {
|
||||||
return @truncate(u12, opcode >> 20 & 0xFF) << 4 | @truncate(u12, opcode >> 4 & 0xF);
|
return @as(u12, @truncate(opcode >> 20 & 0xFF)) << 4 | @as(u12, @truncate(opcode >> 4 & 0xF));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undefined ARM Instruction handler
|
// Undefined ARM Instruction handler
|
||||||
|
@ -117,7 +117,7 @@ pub fn thumb(comptime Arm32: type) type {
|
||||||
|
|
||||||
/// Determine index into THUMB InstrFn LUT
|
/// Determine index into THUMB InstrFn LUT
|
||||||
pub fn idx(opcode: u16) u10 {
|
pub fn idx(opcode: u16) u10 {
|
||||||
return @truncate(u10, opcode >> 6);
|
return @as(u10, @truncate(opcode >> 6));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Undefined THUMB Instruction Handler
|
/// Undefined THUMB Instruction Handler
|
||||||
|
|
34
src/lib.zig
34
src/lib.zig
|
@ -64,71 +64,69 @@ pub const Bus = struct {
|
||||||
std.debug.assert(info.Pointer.size == .One); // Single-Item Pointer
|
std.debug.assert(info.Pointer.size == .One); // Single-Item Pointer
|
||||||
std.debug.assert(@typeInfo(info.Pointer.child) == .Struct); // Pointer Child is a `struct`
|
std.debug.assert(@typeInfo(info.Pointer.child) == .Struct); // Pointer Child is a `struct`
|
||||||
|
|
||||||
const alignment = info.Pointer.alignment;
|
|
||||||
|
|
||||||
const impl = struct {
|
const impl = struct {
|
||||||
fn read8(ptr: *anyopaque, address: u32) u8 {
|
fn read8(ptr: *anyopaque, address: u32) u8 {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
return self.read(u8, address);
|
return self.read(u8, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read16(ptr: *anyopaque, address: u32) u16 {
|
fn read16(ptr: *anyopaque, address: u32) u16 {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
return self.read(u16, address);
|
return self.read(u16, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read32(ptr: *anyopaque, address: u32) u32 {
|
fn read32(ptr: *anyopaque, address: u32) u32 {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
return self.read(u32, address);
|
return self.read(u32, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write8(ptr: *anyopaque, address: u32, value: u8) void {
|
fn write8(ptr: *anyopaque, address: u32, value: u8) void {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
self.write(u8, address, value);
|
self.write(u8, address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write16(ptr: *anyopaque, address: u32, value: u16) void {
|
fn write16(ptr: *anyopaque, address: u32, value: u16) void {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
self.write(u16, address, value);
|
self.write(u16, address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write32(ptr: *anyopaque, address: u32, value: u32) void {
|
fn write32(ptr: *anyopaque, address: u32, value: u32) void {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
self.write(u32, address, value);
|
self.write(u32, address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbgRead8(ptr: *anyopaque, address: u32) u8 {
|
fn dbgRead8(ptr: *anyopaque, address: u32) u8 {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
return self.dbgRead(u8, address);
|
return self.dbgRead(u8, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbgRead16(ptr: *anyopaque, address: u32) u16 {
|
fn dbgRead16(ptr: *anyopaque, address: u32) u16 {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
return self.dbgRead(u16, address);
|
return self.dbgRead(u16, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbgRead32(ptr: *anyopaque, address: u32) u32 {
|
fn dbgRead32(ptr: *anyopaque, address: u32) u32 {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
return self.dbgRead(u32, address);
|
return self.dbgRead(u32, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbgWrite8(ptr: *anyopaque, address: u32, value: u8) void {
|
fn dbgWrite8(ptr: *anyopaque, address: u32, value: u8) void {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
self.dbgWrite(u8, address, value);
|
self.dbgWrite(u8, address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbgWrite16(ptr: *anyopaque, address: u32, value: u16) void {
|
fn dbgWrite16(ptr: *anyopaque, address: u32, value: u16) void {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
self.dbgWrite(u16, address, value);
|
self.dbgWrite(u16, address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dbgWrite32(ptr: *anyopaque, address: u32, value: u32) void {
|
fn dbgWrite32(ptr: *anyopaque, address: u32, value: u32) void {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
self.dbgWrite(u32, address, value);
|
self.dbgWrite(u32, address, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(ptr: *anyopaque) void {
|
fn reset(ptr: *anyopaque) void {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
self.reset();
|
self.reset();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -213,16 +211,14 @@ pub const Scheduler = struct {
|
||||||
std.debug.assert(info.Pointer.size == .One); // Single-Item Pointer
|
std.debug.assert(info.Pointer.size == .One); // Single-Item Pointer
|
||||||
std.debug.assert(@typeInfo(info.Pointer.child) == .Struct); // Pointer Child is a `struct`
|
std.debug.assert(@typeInfo(info.Pointer.child) == .Struct); // Pointer Child is a `struct`
|
||||||
|
|
||||||
const alignment = info.Pointer.alignment;
|
|
||||||
|
|
||||||
const impl = struct {
|
const impl = struct {
|
||||||
fn now(ptr: *anyopaque) u64 {
|
fn now(ptr: *anyopaque) u64 {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
return self.now();
|
return self.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(ptr: *anyopaque) void {
|
fn reset(ptr: *anyopaque) void {
|
||||||
const self = @ptrCast(P, @alignCast(alignment, ptr));
|
const self: P = @ptrCast(@alignCast(ptr));
|
||||||
self.reset();
|
self.reset();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue