381 lines
8.8 KiB
Vue
381 lines
8.8 KiB
Vue
|
|
<template>
|
|||
|
|
<div class="cpu-architecture-demo">
|
|||
|
|
<div class="demo-label">
|
|||
|
|
CPU 核心组件与指令执行周期演示 ── 点击"时钟脉冲"执行一个指令周期
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="cpu-container">
|
|||
|
|
<div class="cpu-frame">
|
|||
|
|
<h3 class="cpu-title">CPU (中央处理器)</h3>
|
|||
|
|
|
|||
|
|
<div class="components-grid">
|
|||
|
|
<!-- Control Unit -->
|
|||
|
|
<div
|
|||
|
|
class="cu-box component"
|
|||
|
|
:class="{ active: currentStage === 1 || currentStage === 2 }"
|
|||
|
|
>
|
|||
|
|
<div class="comp-title">控制单元 (CU)</div>
|
|||
|
|
<div class="comp-state">{{ cuState }}</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- ALU -->
|
|||
|
|
<div
|
|||
|
|
class="alu-box component"
|
|||
|
|
:class="{ active: currentStage === 3 }"
|
|||
|
|
>
|
|||
|
|
<div class="comp-title">算术逻辑单元 (ALU)</div>
|
|||
|
|
<div class="comp-state">{{ aluState }}</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- Registers -->
|
|||
|
|
<div
|
|||
|
|
class="reg-box component"
|
|||
|
|
:class="{ active: currentStage === 4 }"
|
|||
|
|
>
|
|||
|
|
<div class="comp-title">寄存器组</div>
|
|||
|
|
<div class="reg-list">
|
|||
|
|
<span class="reg">R0: {{ r0 }}</span>
|
|||
|
|
<span class="reg">R1: {{ r1 }}</span>
|
|||
|
|
<span class="reg">PC: {{ pc }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- Memory -->
|
|||
|
|
<div
|
|||
|
|
class="mem-frame component"
|
|||
|
|
:class="{ active: currentStage === 1 || currentStage === 4 }"
|
|||
|
|
>
|
|||
|
|
<h3 class="cpu-title">内存 (Memory)</h3>
|
|||
|
|
<div class="mem-list">
|
|||
|
|
<div class="mem-loc" :class="{ 'hl-mem': pc === 10 }">
|
|||
|
|
<span class="addr">M[10]</span> 取指:LOAD R0, #5
|
|||
|
|
</div>
|
|||
|
|
<div class="mem-loc" :class="{ 'hl-mem': pc === 11 }">
|
|||
|
|
<span class="addr">M[11]</span> 译码:ADD R1, R0
|
|||
|
|
</div>
|
|||
|
|
<div class="mem-loc" :class="{ 'hl-mem': pc === 12 }">
|
|||
|
|
<span class="addr">M[12]</span> 执行:ALU 计算
|
|||
|
|
</div>
|
|||
|
|
<div class="mem-loc" :class="{ 'hl-mem': pc === 13 }">
|
|||
|
|
<span class="addr">M[13]</span> 写回:将结果保存
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- Stages progress -->
|
|||
|
|
<div class="pipeline">
|
|||
|
|
<div class="stage" :class="{ active: currentStage === 1 }">
|
|||
|
|
<span class="step-num">1. Fetch</span>
|
|||
|
|
<span class="step-desc">取指</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="stage" :class="{ active: currentStage === 2 }">
|
|||
|
|
<span class="step-num">2. Decode</span>
|
|||
|
|
<span class="step-desc">译码</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="stage" :class="{ active: currentStage === 3 }">
|
|||
|
|
<span class="step-num">3. Execute</span>
|
|||
|
|
<span class="step-desc">执行</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="stage" :class="{ active: currentStage === 4 }">
|
|||
|
|
<span class="step-num">4. WriteBack</span>
|
|||
|
|
<span class="step-desc">写回</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="controls">
|
|||
|
|
<button class="clock-btn" @click="nextStage">
|
|||
|
|
<span class="clock-icon">⟳</span> 给一个时钟脉冲 (Next Stage)
|
|||
|
|
</button>
|
|||
|
|
<button class="reset-btn" @click="reset">重置</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="logic-explain">
|
|||
|
|
<p>
|
|||
|
|
当前阶段状态:<strong>{{ statusMsg }}</strong>
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import { ref, computed } from 'vue'
|
|||
|
|
|
|||
|
|
const currentStage = ref(0) // 0 = Idle, 1 = Fetch, 2 = Decode, 3 = Execute, 4 = Writeback
|
|||
|
|
const cycleCount = ref(0)
|
|||
|
|
|
|||
|
|
const pc = ref(10)
|
|||
|
|
const r0 = ref(0)
|
|||
|
|
const r1 = ref(0)
|
|||
|
|
|
|||
|
|
const cuState = ref('等待时钟信号...')
|
|||
|
|
const aluState = ref('空闲')
|
|||
|
|
|
|||
|
|
const instructions = [
|
|||
|
|
'LOAD R0, #5',
|
|||
|
|
'LOAD R1, #3',
|
|||
|
|
'ADD R0, R1',
|
|||
|
|
'STORE M[14], R0'
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
const statusMsg = computed(() => {
|
|||
|
|
if (currentStage.value === 0)
|
|||
|
|
return '系统启动,等待接收时钟脉冲开始运行程序。'
|
|||
|
|
if (currentStage.value === 1)
|
|||
|
|
return `CPU 内部的控制单元根据程序计数器 (PC=${pc.value}),从内存取出当前指令。`
|
|||
|
|
if (currentStage.value === 2)
|
|||
|
|
return `控制单元翻译指令为硬件控制信号:准备执行操作。`
|
|||
|
|
if (currentStage.value === 3)
|
|||
|
|
return `ALU 进行计算或控制流转移,当前在处理实际数据...`
|
|||
|
|
if (currentStage.value === 4)
|
|||
|
|
return `将运算结果写入寄存器组或写回内存,更新程序计数器(PC)。`
|
|||
|
|
return ''
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
function nextStage() {
|
|||
|
|
if (currentStage.value === 0 || currentStage.value === 4) {
|
|||
|
|
currentStage.value = 1
|
|||
|
|
cuState.value = `取指: 读取指令`
|
|||
|
|
aluState.value = '空闲'
|
|||
|
|
if (currentStage.value === 4) pc.value++
|
|||
|
|
} else if (currentStage.value === 1) {
|
|||
|
|
currentStage.value = 2
|
|||
|
|
cuState.value = `译码: 准备相关电路`
|
|||
|
|
} else if (currentStage.value === 2) {
|
|||
|
|
currentStage.value = 3
|
|||
|
|
cuState.value = '等待 ALU 结果'
|
|||
|
|
aluState.value = '计算进行中...'
|
|||
|
|
} else if (currentStage.value === 3) {
|
|||
|
|
currentStage.value = 4
|
|||
|
|
cuState.value = '完成'
|
|||
|
|
aluState.value = '结果输出'
|
|||
|
|
// Fake logic update
|
|||
|
|
if (cycleCount.value === 0) r0.value = 5
|
|||
|
|
if (cycleCount.value === 1) r1.value = 3
|
|||
|
|
if (cycleCount.value === 2) r0.value = r0.value + r1.value
|
|||
|
|
cycleCount.value++
|
|||
|
|
if (pc.value >= 13) {
|
|||
|
|
pc.value = 9
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function reset() {
|
|||
|
|
currentStage.value = 0
|
|||
|
|
cycleCount.value = 0
|
|||
|
|
pc.value = 10
|
|||
|
|
r0.value = 0
|
|||
|
|
r1.value = 0
|
|||
|
|
cuState.value = '等待时钟信号...'
|
|||
|
|
aluState.value = '空闲'
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped>
|
|||
|
|
.cpu-architecture-demo {
|
|||
|
|
border: 1px solid var(--vp-c-divider);
|
|||
|
|
border-radius: 8px;
|
|||
|
|
background: var(--vp-c-bg-soft);
|
|||
|
|
padding: 1rem 1.2rem;
|
|||
|
|
margin: 1rem 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.demo-label {
|
|||
|
|
font-size: 0.78rem;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: var(--vp-c-text-2);
|
|||
|
|
margin-bottom: 0.75rem;
|
|||
|
|
letter-spacing: 0.2px;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.cpu-container {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 1.5rem;
|
|||
|
|
margin-bottom: 1.5rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.cpu-frame {
|
|||
|
|
flex: 2;
|
|||
|
|
border: 2px dashed var(--vp-c-brand-1);
|
|||
|
|
border-radius: 8px;
|
|||
|
|
padding: 1rem;
|
|||
|
|
background: var(--vp-c-bg);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.mem-frame {
|
|||
|
|
flex: 1;
|
|||
|
|
border: 2px solid var(--vp-c-divider);
|
|||
|
|
border-radius: 8px;
|
|||
|
|
padding: 1rem;
|
|||
|
|
background: var(--vp-c-bg-alt);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.cpu-title {
|
|||
|
|
margin: 0 0 1rem 0;
|
|||
|
|
font-size: 0.95rem;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: var(--vp-c-brand-1);
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.components-grid {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 1rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.component {
|
|||
|
|
border: 1px solid var(--vp-c-divider);
|
|||
|
|
background: var(--vp-c-bg-soft);
|
|||
|
|
padding: 0.8rem;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
transition: all 0.3s ease;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.component.active {
|
|||
|
|
background: var(--vp-c-brand-soft);
|
|||
|
|
border-color: var(--vp-c-brand-1);
|
|||
|
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.comp-title {
|
|||
|
|
font-size: 0.8rem;
|
|||
|
|
font-weight: bold;
|
|||
|
|
color: var(--vp-c-text-2);
|
|||
|
|
margin-bottom: 0.3rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.comp-state {
|
|||
|
|
font-size: 0.75rem;
|
|||
|
|
color: var(--vp-c-text-1);
|
|||
|
|
font-family: monospace;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.reg-list {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 0.5rem;
|
|||
|
|
}
|
|||
|
|
.reg {
|
|||
|
|
font-family: monospace;
|
|||
|
|
font-size: 0.75rem;
|
|||
|
|
background: var(--vp-c-bg);
|
|||
|
|
padding: 0.2rem 0.4rem;
|
|||
|
|
border-radius: 3px;
|
|||
|
|
border: 1px solid var(--vp-c-divider);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.mem-list {
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
gap: 0.5rem;
|
|||
|
|
font-family: monospace;
|
|||
|
|
font-size: 0.75rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.mem-loc {
|
|||
|
|
padding: 0.3rem 0.5rem;
|
|||
|
|
background: var(--vp-c-bg);
|
|||
|
|
border-radius: 4px;
|
|||
|
|
border: 1px solid var(--vp-c-divider);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.mem-loc.hl-mem {
|
|||
|
|
background: #fef08a;
|
|||
|
|
color: #a16207;
|
|||
|
|
border-color: #a16207;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.addr {
|
|||
|
|
color: var(--vp-c-text-3);
|
|||
|
|
margin-right: 0.5rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Pipeline Stages */
|
|||
|
|
.pipeline {
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
margin-bottom: 1.5rem;
|
|||
|
|
background: var(--vp-c-bg);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
border: 1px solid var(--vp-c-divider);
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.stage {
|
|||
|
|
flex: 1;
|
|||
|
|
text-align: center;
|
|||
|
|
padding: 0.5rem 0;
|
|||
|
|
border-right: 1px solid var(--vp-c-divider);
|
|||
|
|
transition: all 0.2s;
|
|||
|
|
}
|
|||
|
|
.stage:last-child {
|
|||
|
|
border-right: none;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.stage.active {
|
|||
|
|
background: var(--vp-c-brand-1);
|
|||
|
|
color: white;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.step-num {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 0.7rem;
|
|||
|
|
font-weight: 600;
|
|||
|
|
margin-bottom: 0.1rem;
|
|||
|
|
}
|
|||
|
|
.step-desc {
|
|||
|
|
display: block;
|
|||
|
|
font-size: 0.8rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Controls */
|
|||
|
|
.controls {
|
|||
|
|
display: flex;
|
|||
|
|
gap: 1rem;
|
|||
|
|
justify-content: center;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.clock-btn,
|
|||
|
|
.reset-btn {
|
|||
|
|
padding: 0.5rem 1rem;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
font-size: 0.85rem;
|
|||
|
|
font-weight: bold;
|
|||
|
|
cursor: pointer;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.clock-btn {
|
|||
|
|
background: var(--vp-c-brand-1);
|
|||
|
|
color: white;
|
|||
|
|
border: none;
|
|||
|
|
}
|
|||
|
|
.clock-btn:hover {
|
|||
|
|
background: var(--vp-c-brand-2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.reset-btn {
|
|||
|
|
background: transparent;
|
|||
|
|
border: 1px solid var(--vp-c-divider);
|
|||
|
|
color: var(--vp-c-text-2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.logic-explain {
|
|||
|
|
margin-top: 1rem;
|
|||
|
|
padding: 0.8rem;
|
|||
|
|
background: var(--vp-c-bg);
|
|||
|
|
border-radius: 6px;
|
|||
|
|
font-size: 0.85rem;
|
|||
|
|
text-align: center;
|
|||
|
|
color: var(--vp-c-text-2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@media (max-width: 600px) {
|
|||
|
|
.cpu-container {
|
|||
|
|
flex-direction: column;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</style>
|