fixed broken merge commit

This commit is contained in:
2026-03-13 16:48:14 +00:00
parent f8a99ac9b3
commit 57ed7eb029
5 changed files with 302 additions and 389 deletions
-67
View File
@@ -1,67 +0,0 @@
pub enum AsmOpcode {
Nop,
// move
Mov,
CMov,
// load
Ldb,
Ldbs,
Ldh,
Ldhs,
Ldw,
// store
Stb,
Sth,
Stw,
// load immediate
Lli,
Lui,
Lwi,
// comparison
Ieq,
Ine,
Ilt,
Ile,
Igt,
Ige,
// jump
Jmp,
Jez,
Jnz,
Jic,
Jnc,
// bitwise
And,
Nand,
Or,
Nor,
Xor,
Xnor,
Not,
// arithmetic
Add,
Sub,
Shl,
Shr,
Addi,
Subi,
// utility
Push,
Pop,
Call,
Ret,
// system
Int,
IRet,
Hlt,
}
@@ -2,29 +2,21 @@ use std::{
hint::unlikely, hint::unlikely,
ops::AddAssign, ops::AddAssign,
sync::{ sync::{
Arc,
atomic::Ordering, atomic::Ordering,
mpsc::{self, TryRecvError}, mpsc::{self, TryRecvError},
Arc,
}, },
thread, thread,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use common::isa::instructions::{Instruction, Opcode};
use common::isa::register::Register;
use crate::{ use crate::{
<<<<<<< HEAD:dsa/emulator/src/processor/processor.rs
config::{IoMapping, MemoryMap, RegionType},
io::{IoDevice, MappedDevice},
memory::{mmu::MMU, ram::RandomAccessMemory},
processor::{interrupts::Interrupt, state::SharedState},
Page,
=======
MemoryBank, Page, SharedState, MemoryBank, Page, SharedState,
backend::{memory::mmu::MMU, processor::interrupts::Interrupt}, backend::{memory::mmu::MMU, processor::interrupts::Interrupt},
config::{IoMapping, MemoryMap, RegionType}, config::{MemoryMap, RegionType},
>>>>>>> refs/remotes/origin/main:dsa/emulator/src/backend/processor/processor.rs
}; };
use common::isa::instructions::{Instruction, Opcode};
use common::isa::register::Register;
pub struct Emulator { pub struct Emulator {
internal_state: ProcessorSnapshot, internal_state: ProcessorSnapshot,
+298 -296
View File
@@ -1,330 +1,332 @@
use common::isa::instructions::Instruction; // use common::isa::instructions::Instruction;
use dsa::{BulkAllocStore, Emulator, Page, RandomAccessMemory}; // use dsa::{Emulator, MemoryBank, Page};
/// DSA Emulator Benchmark // /// DSA Emulator Benchmark
/// // ///
/// Place this in `dsa/src/bin/bench.rs` and run with: // /// Place this in `dsa/src/bin/bench.rs` and run with:
/// cargo run --bin bench --release // /// cargo run --bin bench --release
/// // ///
/// Three workloads are tested: // /// Three workloads are tested:
/// 1. ALU-heavy — tight arithmetic loop, no memory, no branches // /// 1. ALU-heavy — tight arithmetic loop, no memory, no branches
/// 2. Memory-heavy — repeated load/store to a working set of addresses // /// 2. Memory-heavy — repeated load/store to a working set of addresses
/// 3. Branch-heavy — the bf.dsa dispatch pattern (ieq + jnz chains) // /// 3. Branch-heavy — the bf.dsa dispatch pattern (ieq + jnz chains)
/// // ///
/// Each workload is a hand-assembled flat binary loaded directly into // /// Each workload is a hand-assembled flat binary loaded directly into
/// the emulator, bypassing all the args/display/IO plumbing. // /// the emulator, bypassing all the args/display/IO plumbing.
use std::{ // use std::{
thread, // thread,
time::{Duration, Instant}, // time::{Duration, Instant},
u16, // u16,
}; // };
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
// Minimal no-op memory map + IO so the emulator boots without a config file. // // Minimal no-op memory map + IO so the emulator boots without a config file.
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
fn make_emulator() -> Emulator<BulkAllocStore> { // fn make_emulator() -> Emulator {
use dsa::{ // use dsa::{
config::{MemoryMap, Region, RegionType}, // config::{MemoryMap, Region, RegionType},
io::display::DisplayDevice, // io::display::Display,
}; // };
let mmap = MemoryMap { // let mmap = MemoryMap {
table_addr: 0x40000, // table_addr: 0x40000,
regions: vec![ // regions: vec![
Region { // Region {
base: 0x0000_0000, // base: 0x0000_0000,
size: 0x0010_0000, // 1 MiB RAM // size: 0x0010_0000, // 1 MiB RAM
region_type: RegionType::Usable, // region_type: RegionType::Usable,
identity_map_on_boot: true, // identity_map_on_boot: true,
}, // },
Region { // Region {
base: 0x0020_0000, // base: 0x0020_0000,
size: 0x0002_0000, // 128 KiB MMIO (display) // size: 0x0002_0000, // 128 KiB MMIO (display)
region_type: RegionType::MMIO, // region_type: RegionType::MMIO,
identity_map_on_boot: false, // identity_map_on_boot: false,
}, // },
], // ],
}; // };
let iomap = vec![dsa::config::IoMapping { // // let iomap = vec![dsa::config::IoMapping {
device: dsa::io::DeviceId::Display, // // device: dsa::io::DeviceId::Display,
base: 0x0020_0000, // // base: 0x0020_0000,
size: 0x0000_07D0, // // size: 0x0000_07D0,
}]; // // }];
let (display, _handle) = DisplayDevice::new(80, 25); // // let (display, _handle) = Display::new(80, 25);
Emulator::new(BulkAllocStore::new()) // // Emulator::new(MemoryBank::new())
.with_device(display) // // .with_device(display)
.apply_memory_map(mmap) // // .apply_memory_map(mmap)
.apply_io_map(iomap) // // .apply_io_map(iomap)
.unwrap() // // .unwrap()
} // }
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
// Instruction encoding helpers (little-endian words) // // Instruction encoding helpers (little-endian words)
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
/// Encode an I-type instruction: [op:6][src:5][dst:5][imm:16] // /// Encode an I-type instruction: [op:6][src:5][dst:5][imm:16]
fn enc_i(op: u8, src: u8, dst: u8, imm: u16) -> u32 { // fn enc_i(op: u8, src: u8, dst: u8, imm: u16) -> u32 {
((op as u32 & 0x3F) << 26) // ((op as u32 & 0x3F) << 26)
| ((src as u32 & 0x1F) << 21) // | ((src as u32 & 0x1F) << 21)
| ((dst as u32 & 0x1F) << 16) // | ((dst as u32 & 0x1F) << 16)
| imm as u32 // | imm as u32
} // }
/// Encode an R-type instruction: [op:6][r1:5][r2:5][r3:5][r4:5][u6:6] // /// Encode an R-type instruction: [op:6][r1:5][r2:5][r3:5][r4:5][u6:6]
fn enc_r(op: u8, r1: u8, r2: u8, r3: u8, r4: u8, u6: u8) -> u32 { // fn enc_r(op: u8, r1: u8, r2: u8, r3: u8, r4: u8, u6: u8) -> u32 {
((op as u32 & 0x3F) << 26) // ((op as u32 & 0x3F) << 26)
| ((r1 as u32 & 0x1F) << 21) // | ((r1 as u32 & 0x1F) << 21)
| ((r2 as u32 & 0x1F) << 16) // | ((r2 as u32 & 0x1F) << 16)
| ((r3 as u32 & 0x1F) << 11) // | ((r3 as u32 & 0x1F) << 11)
| ((r4 as u32 & 0x1F) << 6) // | ((r4 as u32 & 0x1F) << 6)
| (u6 as u32 & 0x3F) // | (u6 as u32 & 0x3F)
} // }
// Register indices — must match your Register enum discriminants // // Register indices — must match your Register enum discriminants
const RG0: u8 = 0; // const RG0: u8 = 0;
const RG1: u8 = 1; // const RG1: u8 = 1;
const RG2: u8 = 2; // const RG2: u8 = 2;
const RG3: u8 = 3; // const RG3: u8 = 3;
const RG4: u8 = 4; // const RG4: u8 = 4;
const RG5: u8 = 5; // const RG5: u8 = 5;
const ZERO: u8 = 16; // const ZERO: u8 = 16;
// Opcodes — must match your Opcode enum discriminants. // // Opcodes — must match your Opcode enum discriminants.
// Fill these in from your ISA.md / encode.rs. // // Fill these in from your ISA.md / encode.rs.
const OP_NOP: u8 = 0x0D; // adjust to match your actual opcode values // const OP_NOP: u8 = 0x0D; // adjust to match your actual opcode values
const OP_HLT: u8 = 0x2B; // const OP_HLT: u8 = 0x2B;
const OP_ADD: u8 = 0x22; // const OP_ADD: u8 = 0x22;
const OP_ADDI: u8 = 0x23; // const OP_ADDI: u8 = 0x23;
const OP_SUBI: u8 = 0x24; // const OP_SUBI: u8 = 0x24;
const OP_LDW: u8 = 0x07; // const OP_LDW: u8 = 0x07;
const OP_STW: u8 = 0x0A; // const OP_STW: u8 = 0x0A;
const OP_LLI: u8 = 0x0B; // const OP_LLI: u8 = 0x0B;
const OP_LUI: u8 = 0x0C; // const OP_LUI: u8 = 0x0C;
const OP_IEQ: u8 = 0x0E; // const OP_IEQ: u8 = 0x0E;
const OP_JNZ: u8 = 0x15; // const OP_JNZ: u8 = 0x15;
const OP_JMP: u8 = 0x12; // const OP_JMP: u8 = 0x12;
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
// Workload 1: ALU-heavy // // Workload 1: ALU-heavy
// // //
// Counts down from 10_000_000 using subi, jumps back to top. // // Counts down from 10_000_000 using subi, jumps back to top.
// Pure register arithmetic, no memory accesses after init. // // Pure register arithmetic, no memory accesses after init.
// Instruction mix: lli, subi, ieq, jnz, hlt // // Instruction mix: lli, subi, ieq, jnz, hlt
// // //
// Layout (each word at address = index * 4): // // Layout (each word at address = index * 4):
// 0: lli rg0, 0 (upper half of count) [lui follows] // // 0: lli rg0, 0 (upper half of count) [lui follows]
// 4: lui rg0, <high> // // 4: lui rg0, <high>
// 8: loop: subi rg0, 1, rg0 // // 8: loop: subi rg0, 1, rg0
// 12: ieq rg0, zero, rg1 // // 12: ieq rg0, zero, rg1
// 16: jnz rg1, zero, 8 [jump to loop] // // 16: jnz rg1, zero, 8 [jump to loop]
// 20: hlt // // 20: hlt
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
fn alu_workload() -> Vec<u8> { // fn alu_workload() -> Vec<u8> {
let count: u32 = 10_000_000; // let count: u32 = 10_000_000;
let lo = (count & 0xFFFF) as u16; // let lo = (count & 0xFFFF) as u16;
let hi = ((count >> 16) & 0xFFFF) as u16; // let hi = ((count >> 16) & 0xFFFF) as u16;
let words: &[u32] = &[ // let words: &[u32] = &[
enc_i(OP_LLI, 0, RG0, lo), // 0x00: lli rg0, lo(count) // enc_i(OP_LLI, 0, RG0, lo), // 0x00: lli rg0, lo(count)
enc_i(OP_LUI, 0, RG0, hi), // 0x04: lui rg0, hi(count) // enc_i(OP_LUI, 0, RG0, hi), // 0x04: lui rg0, hi(count)
// loop @ 0x08: // // loop @ 0x08:
enc_i(OP_SUBI, RG0, RG0, 1), // 0x08: subi rg0, rg0, 1 // enc_i(OP_SUBI, RG0, RG0, 1), // 0x08: subi rg0, rg0, 1
enc_r(OP_IEQ, RG0, ZERO, RG1, 0, 0), // 0x0C: ieq rg0, zero, rg1 // enc_r(OP_IEQ, RG0, ZERO, RG1, 0, 0), // 0x0C: ieq rg0, zero, rg1
enc_i(OP_JNZ, RG1, ZERO, 0x0008), // 0x10: jnz rg1, zero, 0x08 <- BUG: jnz jumps when rg1!=0 // enc_i(OP_JNZ, RG1, ZERO, 0x0008), // 0x10: jnz rg1, zero, 0x08 <- BUG: jnz jumps when rg1!=0
// rg1=1 when rg0==0, so we want jez here to keep looping // // rg1=1 when rg0==0, so we want jez here to keep looping
// fix: use jez (jump when rg1==0, i.e. rg0!=0) // // fix: use jez (jump when rg1==0, i.e. rg0!=0)
enc_i(OP_HLT, 0, 0, 0), // 0x14: hlt // enc_i(OP_HLT, 0, 0, 0), // 0x14: hlt
]; // ];
// Note: replace OP_JNZ above with your JEZ opcode so the loop continues // // Note: replace OP_JNZ above with your JEZ opcode so the loop continues
// while rg0 != 0. JNZ exits when rg1 != 0, i.e. when rg0 == 0 (done). // // while rg0 != 0. JNZ exits when rg1 != 0, i.e. when rg0 == 0 (done).
// The ieq sets rg1=1 only when rg0==0, so jnz rg1 exits the loop correctly. // // The ieq sets rg1=1 only when rg0==0, so jnz rg1 exits the loop correctly.
// Actually this IS correct: loop while ieq returns 0 (rg0 != 0), // // Actually this IS correct: loop while ieq returns 0 (rg0 != 0),
// exit when ieq returns 1 (rg0 == 0). jnz rg1 = jump when rg1 != 0 = jump when done. // // exit when ieq returns 1 (rg0 == 0). jnz rg1 = jump when rg1 != 0 = jump when done.
// We want to jump BACK while not done, so we need jez: // // We want to jump BACK while not done, so we need jez:
// jez rg1, zero, 0x08 = jump back when rg1==0 (rg0 != 0, not done yet) // // jez rg1, zero, 0x08 = jump back when rg1==0 (rg0 != 0, not done yet)
// Swap OP_JNZ for your JEZ opcode. // // Swap OP_JNZ for your JEZ opcode.
words_to_bytes(words) // words_to_bytes(words)
} // }
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
// Workload 2: Memory-heavy // // Workload 2: Memory-heavy
// // //
// Repeatedly writes and reads a 64-word working set. // // Repeatedly writes and reads a 64-word working set.
// Tests page table lookup performance under repeated memory access. // // Tests page table lookup performance under repeated memory access.
// // //
// rg0 = base address (0x1000, well within RAM, page-aligned) // // rg0 = base address (0x1000, well within RAM, page-aligned)
// rg1 = loop counter (1000 outer iterations) // // rg1 = loop counter (1000 outer iterations)
// rg2 = inner counter (64 words per pass) // // rg2 = inner counter (64 words per pass)
// rg3 = scratch for store value // // rg3 = scratch for store value
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
fn memory_workload() -> Vec<u8> { // fn memory_workload() -> Vec<u8> {
let base: u32 = 0x1000; // let base: u32 = 0x1000;
let outer: u16 = 1000; // let outer: u16 = 1000;
let inner: u16 = 64; // let inner: u16 = 64;
let words: &[u32] = &[ // let words: &[u32] = &[
// init // // init
enc_i(OP_LLI, 0, RG0, (base & 0xFFFF) as u16), // rg0 = base // enc_i(OP_LLI, 0, RG0, (base & 0xFFFF) as u16), // rg0 = base
enc_i(OP_LLI, 0, RG1, outer), // rg1 = outer count // enc_i(OP_LLI, 0, RG1, outer), // rg1 = outer count
// outer_loop @ 0x08: // // outer_loop @ 0x08:
enc_i(OP_LLI, 0, RG2, inner), // rg2 = inner count // enc_i(OP_LLI, 0, RG2, inner), // rg2 = inner count
enc_i(OP_LLI, 0, RG3, 0xABCD), // rg3 = value to write // enc_i(OP_LLI, 0, RG3, 0xABCD), // rg3 = value to write
// inner_loop @ 0x10: // // inner_loop @ 0x10:
enc_i(OP_STW, RG3, RG0, 0), // stw rg3, rg0, 0 // enc_i(OP_STW, RG3, RG0, 0), // stw rg3, rg0, 0
enc_i(OP_LDW, RG0, RG3, 0), // ldw rg0, rg3, 0 (read back) // enc_i(OP_LDW, RG0, RG3, 0), // ldw rg0, rg3, 0 (read back)
enc_i(OP_ADDI, RG0, RG0, 4), // rg0 += 4 // enc_i(OP_ADDI, RG0, RG0, 4), // rg0 += 4
enc_i(OP_SUBI, RG2, RG2, 1), // rg2 -= 1 // enc_i(OP_SUBI, RG2, RG2, 1), // rg2 -= 1
enc_r(OP_IEQ, RG2, ZERO, RG4, 0, 0), // ieq rg2, zero, rg4 // enc_r(OP_IEQ, RG2, ZERO, RG4, 0, 0), // ieq rg2, zero, rg4
enc_i(OP_JNZ, RG4, ZERO, 0x0010), // jez rg4 -> inner_loop (swap opcode) // enc_i(OP_JNZ, RG4, ZERO, 0x0010), // jez rg4 -> inner_loop (swap opcode)
// restore base, dec outer // // restore base, dec outer
enc_i(OP_LLI, 0, RG0, (base & 0xFFFF) as u16), // enc_i(OP_LLI, 0, RG0, (base & 0xFFFF) as u16),
enc_i(OP_SUBI, RG1, RG1, 1), // enc_i(OP_SUBI, RG1, RG1, 1),
enc_r(OP_IEQ, RG1, ZERO, RG4, 0, 0), // enc_r(OP_IEQ, RG1, ZERO, RG4, 0, 0),
enc_i(OP_JNZ, RG4, ZERO, 0x0008), // jez rg4 -> outer_loop (swap opcode) // enc_i(OP_JNZ, RG4, ZERO, 0x0008), // jez rg4 -> outer_loop (swap opcode)
enc_i(OP_HLT, 0, 0, 0), // enc_i(OP_HLT, 0, 0, 0),
]; // ];
words_to_bytes(words) // words_to_bytes(words)
} // }
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
// Workload 3: Branch-heavy // // Workload 3: Branch-heavy
// // //
// Mimics the bf.dsa dispatch pattern: compare a value against 8 constants, // // Mimics the bf.dsa dispatch pattern: compare a value against 8 constants,
// branch on each. Worst case for branch predictor. // // branch on each. Worst case for branch predictor.
// rg0 = current "instruction" (cycles through 8 values) // // rg0 = current "instruction" (cycles through 8 values)
// rg8-rgf = the 8 bf opcode constants // // rg8-rgf = the 8 bf opcode constants
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
fn branch_workload() -> Vec<u8> { // fn branch_workload() -> Vec<u8> {
// 8 bf opcodes: + - > < . , [ ] // // 8 bf opcodes: + - > < . , [ ]
let opcodes: [u16; 8] = [43, 45, 62, 60, 46, 44, 91, 93]; // let opcodes: [u16; 8] = [43, 45, 62, 60, 46, 44, 91, 93];
// We'll cycle rg0 through these values and do the full dispatch chain. // // We'll cycle rg0 through these values and do the full dispatch chain.
// To keep it self-contained: load opcodes, set outer loop counter, // // To keep it self-contained: load opcodes, set outer loop counter,
// inner loop cycles rg0 through all 8 values doing ieq+jnz for each. // // inner loop cycles rg0 through all 8 values doing ieq+jnz for each.
let outer: u16 = u16::MAX; // let outer: u16 = u16::MAX;
let mut w: Vec<u32> = Vec::new(); // let mut w: Vec<u32> = Vec::new();
// Load 8 opcode constants into rg8-rgf (regs 8-15) // // Load 8 opcode constants into rg8-rgf (regs 8-15)
for (i, &op) in opcodes.iter().enumerate() { // for (i, &op) in opcodes.iter().enumerate() {
w.push(enc_i(OP_LLI, 0, 8 + i as u8, op)); // w.push(enc_i(OP_LLI, 0, 8 + i as u8, op));
} // }
// rg1 = outer counter // // rg1 = outer counter
w.push(enc_i(OP_LLI, 0, RG1, outer)); // w.push(enc_i(OP_LLI, 0, RG1, outer));
// outer_loop: // // outer_loop:
let outer_loop_addr = (w.len() * 4) as u16; // let outer_loop_addr = (w.len() * 4) as u16;
// rg5 = inner counter (8 opcodes) // // rg5 = inner counter (8 opcodes)
w.push(enc_i(OP_LLI, 0, RG5, 8)); // w.push(enc_i(OP_LLI, 0, RG5, 8));
// rg2 = pointer into opcode table (we'll use addi to step rg0 through values) // // rg2 = pointer into opcode table (we'll use addi to step rg0 through values)
// For simplicity: just set rg0 to each opcode in sequence via lli each iteration // // For simplicity: just set rg0 to each opcode in sequence via lli each iteration
// This is branch-heavy, not arithmetic-heavy, so the lli overhead is fine. // // This is branch-heavy, not arithmetic-heavy, so the lli overhead is fine.
for (i, &op) in opcodes.iter().enumerate() { // for (i, &op) in opcodes.iter().enumerate() {
let next_offset = ((w.len() + 4) * 4) as u16; // addr after the jnz // let next_offset = ((w.len() + 4) * 4) as u16; // addr after the jnz
w.push(enc_i(OP_LLI, 0, RG0, op)); // rg0 = opcode // w.push(enc_i(OP_LLI, 0, RG0, op)); // rg0 = opcode
w.push(enc_r(OP_IEQ, RG0, 8 + i as u8, RG4, 0, 0)); // ieq rg0, rgX, rg4 // w.push(enc_r(OP_IEQ, RG0, 8 + i as u8, RG4, 0, 0)); // ieq rg0, rgX, rg4
w.push(enc_i(OP_JNZ, RG4, ZERO, next_offset)); // jnz rg4 (jez to skip) // w.push(enc_i(OP_JNZ, RG4, ZERO, next_offset)); // jnz rg4 (jez to skip)
w.push(enc_i(OP_NOP, 0, 0, 0)); // "handler" nop // w.push(enc_i(OP_NOP, 0, 0, 0)); // "handler" nop
} // }
// dec outer, loop // // dec outer, loop
let after_dispatch = (w.len() * 4) as u16; // let after_dispatch = (w.len() * 4) as u16;
w.push(enc_i(OP_SUBI, RG1, RG1, 1)); // w.push(enc_i(OP_SUBI, RG1, RG1, 1));
w.push(enc_r(OP_IEQ, RG1, ZERO, RG4, 0, 0)); // w.push(enc_r(OP_IEQ, RG1, ZERO, RG4, 0, 0));
w.push(enc_i(OP_JNZ, RG4, ZERO, outer_loop_addr)); // jez -> outer_loop // w.push(enc_i(OP_JNZ, RG4, ZERO, outer_loop_addr)); // jez -> outer_loop
w.push(enc_i(OP_HLT, 0, 0, 0)); // w.push(enc_i(OP_HLT, 0, 0, 0));
words_to_bytes(&w) // words_to_bytes(&w)
} // }
fn words_to_bytes(words: &[u32]) -> Vec<u8> { // fn words_to_bytes(words: &[u32]) -> Vec<u8> {
words.iter().flat_map(|w| w.to_le_bytes()).collect() // words.iter().flat_map(|w| w.to_le_bytes()).collect()
} // }
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
// Runner // // Runner
// --------------------------------------------------------------------------- // // ---------------------------------------------------------------------------
struct BenchResult { // struct BenchResult {
name: &'static str, // name: &'static str,
instructions: u64, // instructions: u64,
elapsed: Duration, // elapsed: Duration,
mips: f64, // mips: f64,
} // }
fn run_bench(name: &'static str, binary: Vec<u8>) -> BenchResult { // fn run_bench(name: &'static str, binary: Vec<u8>) -> BenchResult {
let mut emu = make_emulator(); // let mut emu = make_emulator();
let handle = emu.state_handle(); // let handle = emu.state_handle();
let pages: Vec<Page> = Page::paginate(&binary).collect(); // let pages: Vec<Page> = Page::paginate(&binary).collect();
for (i, page) in pages.iter().enumerate() { // for (i, page) in pages.iter().enumerate() {
emu.memory_mut().write_page(i as u32 * 4096, page); // emu.memory_mut().write_page(i as u32 * 4096, page);
} // }
let start = Instant::now(); // let start = Instant::now();
// run() blocks until HLT // // run() blocks until HLT
emu.run().expect("emulator run failed"); // emu.run().expect("emulator run failed");
let elapsed = start.elapsed(); // let elapsed = start.elapsed();
// read clock from emulator — we need to expose it. // // read clock from emulator — we need to expose it.
// For now, estimate from elapsed + target MIPS. // // For now, estimate from elapsed + target MIPS.
// TODO: expose emulator.clock() -> u64 and use that directly. // // TODO: expose emulator.clock() -> u64 and use that directly.
let instructions = handle.proc.load().clock as u64; // let instructions = handle.proc.load().clock as u64;
let mips = instructions as f64 / elapsed.as_micros() as f64; // let mips = instructions as f64 / elapsed.as_micros() as f64;
BenchResult { // BenchResult {
name, // name,
instructions, // instructions,
elapsed, // elapsed,
mips, // mips,
} // }
} // }
fn main() { // fn main() {
println!("DSA Emulator Benchmark"); // println!("DSA Emulator Benchmark");
println!("======================"); // println!("======================");
println!(); // println!();
// NOTE: you need to expose `pub fn clock(&self) -> usize` on Emulator // // NOTE: you need to expose `pub fn clock(&self) -> usize` on Emulator
// and ensure `run()` returns normally on HLT without blocking in idle_wait. // // and ensure `run()` returns normally on HLT without blocking in idle_wait.
// The idle_wait loop currently spins forever after HLT — for benchmarking, // // The idle_wait loop currently spins forever after HLT — for benchmarking,
// you want run() to return when the program halts. Add a flag or check: // // you want run() to return when the program halts. Add a flag or check:
// if !self.internal_state.running { break 'emu; } // // if !self.internal_state.running { break 'emu; }
// after the HLT handler sets running=false. // // after the HLT handler sets running=false.
let workloads: &[(&'static str, fn() -> Vec<u8>)] = &[ // let workloads: &[(&'static str, fn() -> Vec<u8>)] = &[
("ALU-heavy (10M countdown)", alu_workload), // ("ALU-heavy (10M countdown)", alu_workload),
("Memory-heavy (64K rw ops)", memory_workload), // ("Memory-heavy (64K rw ops)", memory_workload),
("Branch-heavy (bf dispatch)", branch_workload), // ("Branch-heavy (bf dispatch)", branch_workload),
]; // ];
let mut results = Vec::new(); // let mut results = Vec::new();
for &(name, build) in workloads { // for &(name, build) in workloads {
print!("Running {}... ", name); // print!("Running {}... ", name);
let binary = build(); // let binary = build();
let result = run_bench(name, binary); // let result = run_bench(name, binary);
println!("done ({:.1}ms)", result.elapsed.as_secs_f64() * 1000.0); // println!("done ({:.1}ms)", result.elapsed.as_secs_f64() * 1000.0);
results.push(result); // results.push(result);
} // }
println!(); // println!();
println!( // println!(
"{:<35} {:>12} {:>12} {:>10}", // "{:<35} {:>12} {:>12} {:>10}",
"Workload", "Instructions", "Time", "MIPS" // "Workload", "Instructions", "Time", "MIPS"
); // );
println!("{}", "-".repeat(72)); // println!("{}", "-".repeat(72));
for r in &results { // for r in &results {
println!( // println!(
"{:<35} {:>12} {:>10.1}ms {:>10.1}", // "{:<35} {:>12} {:>10.1}ms {:>10.1}",
r.name, // r.name,
r.instructions, // r.instructions,
r.elapsed.as_secs_f64() * 1000.0, // r.elapsed.as_secs_f64() * 1000.0,
r.mips, // r.mips,
); // );
} // }
let avg_mips: f64 = results.iter().map(|r| r.mips).sum::<f64>() / results.len() as f64; // let avg_mips: f64 = results.iter().map(|r| r.mips).sum::<f64>() / results.len() as f64;
println!("{}", "-".repeat(72)); // println!("{}", "-".repeat(72));
println!("{:<35} {:>35.1} MIPS avg", "Overall", avg_mips); // println!("{:<35} {:>35.1} MIPS avg", "Overall", avg_mips);
} // }
fn main() {}
-14
View File
@@ -1,17 +1,4 @@
use clap::Parser; use clap::Parser;
<<<<<<< HEAD
use common::isa::instructions::Instruction;
use dsa::{
args::DsaArgs, io::display::{DisplayDevice, DisplayHandle}, BulkAllocStore, Emulator, Page,
RandomAccessMemory,
SharedState,
};
use std::{
sync::{atomic::Ordering, Arc},
thread,
time::Duration,
};
=======
use common::prelude::Instruction; use common::prelude::Instruction;
use dsa::{Emulator, Page, args::DsaArgs, frontend::run_app}; use dsa::{Emulator, Page, args::DsaArgs, frontend::run_app};
@@ -19,7 +6,6 @@ use std::thread;
const STACK_SIZE: usize = 1024 * 1024 * 16; const STACK_SIZE: usize = 1024 * 1024 * 16;
>>>>>>> refs/remotes/origin/main
fn main() { fn main() {
let args = DsaArgs::parse(); let args = DsaArgs::parse();
Binary file not shown.