一生一芯E4-c语言学习(待更新)

预处理

image

// a.c
#include <stdio.h>
#define MSG "Hello \
World!\n"
#define _str(x) #x
#define _concat(a, b) a##b
int main() {
  printf(MSG /* "hi!\n" */);
#ifdef __riscv
  printf("Hello RISC-V!\n");
#endif
  _concat(pr, intf)(_str(RISC-V));
  return 0;
}

运行gcc -E a.c,gcc过程分为预处理-编译-汇编-链接-E就是做到预处理这一步

_str _concat都是函数式宏定义

ifdef ... #endif条件编译指令:__riscv:这是一个 编译器内置的预定义宏,只有在「编译 RISC-V 架构的程序」时,编译器才会自动定义这个宏;在 x86/x64(电脑常用)、ARM 等架构下,这个宏是未定义的。我电脑运行后 直接跳过他。

运行指令后变为:

# 6 "a.c"
int main() {
  printf("Hello World!\n" );



  printf("RISC-V");
  return 0;
}

image

verbose加入指令后会在终端输出两类关键信息:
1.gcc自身的版本,编译配置信息。2.gcc查找/加载头文件的全过程

终端输出:

#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/11/include
 /usr/local/include
 /usr/include/x86_64-linux-gnu
 /usr/include

image
gcc -I 就是gcc一些新的头文件如果找不到了话用gcc -I 地址既可

image

前面其实都说到了,-risc_v部分

# 6 "a.c"
int main() {
  printf("Hello World!\n" );

  printf("Hello RISC-V!\n");

  printf("RISC-V");
  return 0;
}

image

执行

echo | gcc -dM -E - | sort > x86_64_macros.txt
echo | riscv64-linux-gnu-gcc -dM -E - | sort > riscv64_macros.txt
diff --color=auto x86_64_macros.txt riscv64_macros.txt

多出了这么一坨:
image

编译

image

语法解析与语义分析阶段该阶段对输入文件进行语法解析,将预处理记号转换为语法分析树。在生成语法分析树后,该阶段会执行语义分析,一方面计算表达式的类型,另一方面检查代码的语法合法性。此阶段不仅负责产生大部分编译器警告,还会捕获各类语法解析错误。该阶段的输出产物是抽象语法树(Abstract Syntax Tree,AST)。

image

!4 = !{i32 7, !"frame-pointer", i32 2} 没了,简单查了下这玩意是方便调试的,等于把它删了后gdb不太方便了

image

正如前文讲义所讲:volatile(禁止编译器对变量的优化)会被“严格执行”

image

源代码:

#include <stdio.h>
int main() { // compute 10 + 20
  int x = 10, y = 20;
  int z = x + y;
  printf("z = %d\n", z);
  return 0;
}
x86:
	.text
	.file	"b.c"
	.globl	main                            # -- Begin function main
	.p2align	4, 0x90
	.type	main,@function
main:                                   # @main
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$16, %rsp
	movl	$0, -4(%rbp)
	movl	$10, -8(%rbp)
	movl	$20, -12(%rbp)
	movl	-8(%rbp), %eax
	addl	-12(%rbp), %eax
	movl	%eax, -16(%rbp)
	movl	-16(%rbp), %esi
	leaq	.L.str(%rip), %rdi
	movb	$0, %al
	callq	printf@PLT
	xorl	%eax, %eax
	addq	$16, %rsp
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end0:
	.size	main, .Lfunc_end0-main
	.cfi_endproc
                                        # -- End function
	.type	.L.str,@object                  # @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"z = %d\n"
	.size	.L.str, 8

	.ident	"Ubuntu clang version 14.0.0-1ubuntu1.1"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym printf
risc_v32:
	.text
	.attribute	4, 16
	.attribute	5, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
	.file	"b.c"
	.globl	main                            # -- Begin function main
	.p2align	1
	.type	main,@function
main:                                   # @main
# %bb.0:
	addi	sp, sp, -48                 //开辟栈空间
	sd	ra, 40(sp)                      # 8-byte Folded Spill
	sd	s0, 32(sp)                      # 8-byte Folded Spill
	addi	s0, sp, 48
	li	a0, 0
	sd	a0, -40(s0)                     # 8-byte Folded Spill
	sw	a0, -20(s0)
	li	a0, 10
	sw	a0, -24(s0)                     //从这开始复制相加
	li	a0, 20
	sw	a0, -28(s0)
	lw	a0, -24(s0)
	lw	a1, -28(s0)
	addw	a0, a0, a1
	sw	a0, -32(s0)
	lw	a1, -32(s0)
.LBB0_1:                                # Label of block must be emitted
	auipc	a0, %pcrel_hi(.L.str)
	addi	a0, a0, %pcrel_lo(.LBB0_1)
	call	printf@plt                 // 调用printf
                                        # kill: def $x11 killed $x10
	ld	a0, -40(s0)                     # 8-byte Folded Reload
	ld	ra, 40(sp)                      # 8-byte Folded Reload
	ld	s0, 32(sp)                      # 8-byte Folded Reload
	addi	sp, sp, 48
	ret
.Lfunc_end0:
	.size	main, .Lfunc_end0-main
                                        # -- End function
	.type	.L.str,@object                  # @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"z = %d\n"
	.size	.L.str, 8

	.ident	"Ubuntu clang version 14.0.0-1ubuntu1.1"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym printf
优化后:
	.text
	.attribute	4, 16
	.attribute	5, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
	.file	"b.c"
	.globl	main                            # -- Begin function main
	.p2align	1
	.type	main,@function
main:                                   # @main
# %bb.0:
	addi	sp, sp, -16
	sd	ra, 8(sp)                       # 8-byte Folded Spill
.LBB0_1:                                # Label of block must be emitted
	auipc	a0, %pcrel_hi(.L.str)
	addi	a0, a0, %pcrel_lo(.LBB0_1)
	li	a1, 30                       //直接加载立即数结果了
	call	printf@plt
	li	a0, 0
	ld	ra, 8(sp)                       # 8-byte Folded Reload
	addi	sp, sp, 16
	ret
.Lfunc_end0:
	.size	main, .Lfunc_end0-main
                                        # -- End function
	.type	.L.str,@object                  # @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"z = %d\n"
	.size	.L.str, 8

	.ident	"Ubuntu clang version 14.0.0-1ubuntu1.1"
	.section	".note.GNU-stack","",@progbits
	.addrsig

二进制文件的生成和执行

image

二进制文件其实可以用od 命令来查看
执行

gcc -c a.c
objdump -d a.o //x86架构实现
riscv-linux-gnu-gcc -c a.c
riscv64-linux-gnu-objdump -d a.o//riscv实现
a.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:	f3 0f 1e fa          	endbr64 
   4:	55                   	push   %rbp
   5:	48 89 e5             	mov    %rsp,%rbp
   8:	48 8d 05 00 00 00 00 	lea    0x0(%rip),%rax        # f <main+0xf>
   f:	48 89 c7             	mov    %rax,%rdi
  12:	e8 00 00 00 00       	call   17 <main+0x17>
  17:	48 8d 05 00 00 00 00 	lea    0x0(%rip),%rax        # 1e <main+0x1e>
  1e:	48 89 c7             	mov    %rax,%rdi
  21:	b8 00 00 00 00       	mov    $0x0,%eax
  26:	e8 00 00 00 00       	call   2b <main+0x2b>
  2b:	b8 00 00 00 00       	mov    $0x0,%eax
  30:	5d                   	pop    %rbp
  31:	c3 
---------------------------------------------------------------------
a.o:     file format elf64-littleriscv


Disassembly of section .text:

0000000000000000 <main>:
   0:	1141                	addi	sp,sp,-16
   2:	e406                	sd	ra,8(sp)
   4:	e022                	sd	s0,0(sp)
   6:	0800                	addi	s0,sp,16
   8:	00000517          	auipc	a0,0x0
   c:	00050513          	mv	a0,a0
  10:	00000097          	auipc	ra,0x0
  14:	000080e7          	jalr	ra # 10 <main+0x10>
  18:	00000517          	auipc	a0,0x0
  1c:	00050513          	mv	a0,a0
  20:	00000097          	auipc	ra,0x0
  24:	000080e7          	jalr	ra # 20 <main+0x20>
  28:	00000517          	auipc	a0,0x0
  2c:	00050513          	mv	a0,a0
  30:	00000097          	auipc	ra,0x0
  34:	000080e7          	jalr	ra # 30 <main+0x30>
  38:	4781                	li	a5,0
  3a:	853e                	mv	a0,a5
  3c:	60a2                	ld	ra,8(sp)
  3e:	6402                	ld	s0,0(sp)
  40:	0141                	addi	sp,sp,16
  42:	8082                	ret

image

#include <stdio.h>

int main() {
    const long long max_num = 100000000LL;
    long long sum = 0LL;
    for (long long i = 1; i <= max_num; ++i) {
        sum += i;
    }

    printf("Sum from 1 to %lld is: %lld\n", max_num, sum);

    return 0;
}

优化效果惊人

gcc -O0 sum.c -o sum0
ahu_xj@ahuxj-virtual-machine:~/Desktop/c_test/c_handouts$ time ./sum0
Sum from 1 to 100000000 is: 5000000050000000

real	0m0.109s
user	0m0.106s
sys	0m0.003s
ahu_xj@ahuxj-virtual-machine:~/Desktop/c_test/c_handouts$ gcc -O1 sum.c -o sum1
ahu_xj@ahuxj-virtual-machine:~/Desktop/c_test/c_handouts$ time ./sum1
Sum from 1 to 100000000 is: 5000000050000000

real	0m0.029s
user	0m0.027s
sys	0m0.002s
ahu_xj@ahuxj-virtual-machine:~/Desktop/c_test/c_handouts$ gcc -O2 sum.c -o sum2
ahu_xj@ahuxj-virtual-machine:~/Desktop/c_test/c_handouts$ time ./sum2
Sum from 1 to 100000000 is: 5000000050000000

real	0m0.002s
user	0m0.000s
sys	0m0.002s

image
image

输入

gdb ./sum0
starti

程序是从_start开始的
第二问

gcc -g sum.c -o sum
gdb ./sum
//设置截断点
b sum:13
r
stepi //到return 0
终端显示:
0x00007ffff7c29d90 in __libc_start_call_main (main=main@entry=0x555555555149 <main>, argc=argc@entry=1, argv=argv@entry=0x7fffffffde68) at ../sysdeps/nptl/libc_start_call_main.h:58
58	../sysdeps/nptl/libc_start_call_main.h: No such file or directory.
(gdb) 

main的返回值会被启动代码(_start/__libc_call_main)接收,然后调用 exit ()/exit_group () 等系统调用来完成最终的收尾工作

手册行为和编码规范

image

 cc -g 4.1.c -o 4.1
ahu_xj@ahuxj-virtual-machine:~/Desktop/c_test/c_handouts$ ./4.1
x =2.y=1
ahu_xj@ahuxj-virtual-machine:~/Desktop/c_test/c_handouts$ clang 4.1.c && ./4.1.c
4.1.c:8:5: warning: multiple unsequenced modifications to 'i' [-Wunsequenced]
        f(i++,i++);
           ^   ~~
1 warning generated.
bash: ./4.1.c: Permission denied

clang 直接警告了,下面关闭下

clang 4.1.c -o 4.1 -Wno-unsequenced
ahu_xj@ahuxj-virtual-machine:~/Desktop/c_test/c_handouts$ ./4.1
x =1.y=2

image

image

#include <stdio.h>
int main() {
  int a[10] = {0};
  printf("a[10] = %d\n", a[10]);
  return 0;
}

image

image

比较简单,用电路搭建和写代码就是不一样,写代码快多了

#include <stdint.h>
#include <stdio.h>

// 定义硬件状态,uint8_t固定宽度的无符号 8 位整数类型
uint8_t PC = 0;
uint8_t R[4] = {0, 0, 0, 0};
uint8_t M[16] = {
    0b10001010, // 0: li r0, 10
    0b10010000, // 1: li r1, 0
    0b10100000, // 2: li r2, 0
    0b10110001, // 3: li r3, 1
    0b00010111, // 4: add r1, r1, r3
    0b00101001, // 5: add r2, r2, r1
    0b11010100, // 6: bner0 r1, 4 (注意:你给的末尾是01,但我修正为0100即地址4)
    0b11110111  // 7: bner0 r3, 7 (修正末尾为0111即地址7)
};

void inst_cycle() {
    //取指
    uint8_t inst = M[PC];
    
    //译码并执行
    uint8_t op = (inst >> 6) & 0x3; // 取高2位
    int jumped = 0;
    //li指令
    if (op == 0x2) { 
       uint8_t imm=inst & 0xf;
       uint8_t rd=(inst>>4)&0x03;
       R[rd]=imm;
    } 
    else if (op == 0x0) { 
        uint8_t rd  = (inst >> 4) & 0x3;
        uint8_t rs1 = (inst >> 2) & 0x3;
        uint8_t rs2 = inst & 0x3;
        R[rd] = R[rs1] + R[rs2];
    } 
    else if (op == 0x3) {
        uint8_t rs = (inst >> 4) & 0x3;
        uint8_t addr = inst & 0xF;
        if (R[rs] != R[0]) {
            PC = addr;
            jumped = 1;
        }
    }

    // --- 更新 PC ---
    if (!jumped) {
        PC++;
    }
}

int main() {
    printf("sEMU 启动: 运行数列求和程序\n");
    printf("--------------------------------\n");

    int limit = 200; // 运行步数限制
    while (limit-- > 0) {
        // 如果 PC 指向最后一条指令且不再跳转,说明进入了预期的终点
        if (PC == 7 && R[1] == R[0]) {
            break;
        }

        inst_cycle();
        printf("PC:%d | r0(目标):%2d | r1(i):%2d | r2(sum):%2d\n", 
                PC, R[0], R[1], R[2]);
    }

    printf("--------------------------------\n");
    printf("程序运行结束。\n");
    printf("最终结果: sum = %d", R[2]);

    return 0;
}

image

看了半天也没看到./a.out是啥
独立环境:这个semu就是的,他提供了cpu,程序在这个环境里运行,但是不知道对错,必须人为检查
宿主环境:linux中可以调用printf啥的函数。这些功能不是cpu直接完成的而是程序向环境的请求。
强化运行时:给模拟器加入一个接口,让这里独立的semu可以跨越环境区操作原本你无法触及的比如屏幕啥的。当 sISA 程序执行 out 时,sEMU 捕获到这个请求,并将其翻译成 Linux 听得懂的 printf。这个过程就叫作“强化运行时环境”——你通过模拟器代码,给裸机程序提供了它原本不可能拥有的能力。

#include <stdint.h>
#include <stdio.h>

uint8_t PC = 0;
uint8_t R[4] = {0, 0, 0, 0};

uint8_t M[16] = {
    0b10001010, // 0: li r0, 10
    0b10010000, // 1: li r1, 0
    0b10100000, // 2: li r2, 0
    0b10110001, // 3: li r3, 1
    0b00010111, // 4: add r1, r1, r3
    0b00101001, // 5: add r2, r2, r1
    0b11010100, // 6: bner0 r1, 4 
    0b01100000, // 7: out r2 
    0b11111000  // 8: bner0 r3, 8 
};

void inst_cycle() {
    uint8_t inst = M[PC];
    uint8_t op = (inst >> 6) & 0x3; 
    int jumped = 0;

    switch(op){
    	case 0x2: {//li
    	   uint8_t imm = inst & 0xf;
           uint8_t rd = (inst >> 4) & 0x03;
           R[rd] = imm;}
       break;
    	case 0x0:{//add
    	   uint8_t rd  = (inst >> 4) & 0x3;
           uint8_t rs1 = (inst >> 2) & 0x3;
           uint8_t rs2 = inst & 0x3;
           R[rd] = R[rs1] + R[rs2];}
       break;
    	case 0x3:{//ber0
    	   uint8_t rs = (inst >> 4) & 0x3;
           uint8_t addr = inst & 0xF;
        if (R[rs] != R[0]) {
            PC = addr;
            jumped = 1;
            }}
        break;
    	case 0x1:{//out指令
    	 uint8_t rs = (inst >> 4) & 0x3;
        // sEMU 借助宿主环境的 printf 实现输出功能
        printf("\n>>> [sISA OUT]: Register r%d = %d <<<\n\n", rs, R[rs]);}
        break;
    }
    
     if (!jumped) PC++;
         
}


int main() {
    printf("sEMU 启动: 运行具有输出功能的数列求和程序\n");
    printf("----------------------------------------\n");

    int limit = 200; 
    while ((limit--) > 0) {
        // 停机条件:到达死循环指令 (PC=8)
        if (PC == 8) {
            break;
        }

        inst_cycle();
        
        // 打印流水线状态
        printf("PC:%d | r0:%2d | r1:%2d | r2:%2d\n", PC, R[0], R[1], R[2]);
    }

    printf("----------------------------------------\n");
    printf("程序运行结束。最终结果已通过 OUT 指令输出。\n");

    return 0;
}

image

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

// sEMU 状态定义
uint8_t PC = 0;
uint8_t R[4] = {0};
uint8_t M[16] = {
    0x90, // 0: li r1, 0
    0xA0, // 1: li r2, 0
    0xB1, // 2: li r3, 1
    0x17, // 3: add r1, r1, r3
    0x29, // 4: add r2, r2, r1
    0xD3, // 5: bner0 r1, 3 (注意:地址变为3了)
    0x60, // 6: out r2
    0xF7  // 7: bner0 r3, 7 (死循环结束)
};

void inst_cycle() {
    uint8_t inst = M[PC & 0xF];
    uint8_t op = (inst >> 6) & 0x3;
    bool jumped = false;

    switch (op) {
        case 0x2: // li
            R[(inst >> 4) & 0x3] = inst & 0xF;
            break;
        case 0x0: // add
            R[(inst >> 4) & 0x3] = R[(inst >> 2) & 0x3] + R[inst & 0x3];
            break;
        case 0x3: // bner0
            if (R[(inst >> 4) & 0x3] != R[0]) {
                PC = inst & 0xF;
                jumped = true;
            }
            break;
        case 0x1: // out
            printf("%d\n", R[(inst >> 4) & 0x3]);
            break;
    }

    if (!jumped) PC++;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s <n>\n", argv[0]);
        return 1;
    }

    // --- 运行时环境支持:参数传递 ---
    // 将命令行输入的参数转换为整数并存入 R[0]
    R[0] = (uint8_t)atoi(argv[1]);

    // 运行模拟器
    int limit=200;
    while ((limit--) > 0) {
        if (PC == 7) break;
        inst_cycle();
    }

    return 0;
}

image
image

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MEM_SIZE (1 << 20) // 1MB
uint8_t ROM[MEM_SIZE];
uint8_t RAM[MEM_SIZE];
int32_t R[32] = {0};
uint32_t PC = 0;
uint64_t cycle_counter = 0; // 64位计数器

// 符号扩展
int32_t sign_extend(uint32_t imm, int n) {
    if ((imm >> (n - 1)) & 1) return (int32_t)(imm | (0xFFFFFFFF << n));
    return (int32_t)imm;
}

void inst_cycle() {
    // 1. 取指 (从 ROM 读取)
    uint32_t inst = (uint32_t)ROM[PC] | (ROM[PC+1] << 8) | (ROM[PC+2] << 16) | (ROM[PC+3] << 24);
    
    uint8_t opcode = inst & 0x7F;
    uint8_t rd     = (inst >> 7) & 0x1F;
    uint8_t funct3 = (inst >> 12) & 0x7;
    uint8_t rs1    = (inst >> 15) & 0x1F;
    uint8_t rs2    = (inst >> 20) & 0x1F;
    uint8_t funct7 = (inst >> 25) & 0x7F;

    int jumped = 0;

    switch (opcode) {
        case 0x13: // ADDI
            R[rd] = R[rs1] + sign_extend(inst >> 20, 12);
            break;
        case 0x33: // ADD
            if (funct7 == 0x00) R[rd] = R[rs1] + R[rs2];
            break;
        case 0x37: // LUI
            R[rd] = (inst & 0xFFFFF000);
            break;
        case 0x67: // JALR
            {
                uint32_t next_pc = PC + 4;
                PC = (R[rs1] + sign_extend(inst >> 20, 12)) & ~1;
                R[rd] = next_pc;
                jumped = 1;
            }
            break;
        case 0x03: // LW / LBU
            {
                uint32_t addr = R[rs1] + sign_extend(inst >> 20, 12);
                if (addr < MEM_SIZE) {
                    if (funct3 == 0x2) R[rd] = (int32_t)(RAM[addr] | (RAM[addr+1]<<8) | (RAM[addr+2]<<16) | (RAM[addr+3]<<24));
                    else if (funct3 == 0x4) R[rd] = RAM[addr];
                }
            }
            break;
        case 0x23: // SW / SB
            {
                int32_t imm = sign_extend(((inst >> 25) << 5) | ((inst >> 7) & 0x1F), 12);
                uint32_t addr = R[rs1] + imm;
                if (addr < MEM_SIZE) {
                    if (funct3 == 0x2) {
                        RAM[addr] = R[rs2] & 0xFF; RAM[addr+1] = (R[rs2] >> 8) & 0xFF;
                        RAM[addr+2] = (R[rs2] >> 16) & 0xFF; RAM[addr+3] = (R[rs2] >> 24) & 0xFF;
                    } else if (funct3 == 0x0) RAM[addr] = (uint8_t)(R[rs2] & 0xFF);
                }
            }
            break;
    }

    R[0] = 0;
    if (!jumped) PC += 4;
    cycle_counter++; // 周期计数
}

int main(int argc, char *argv[]) {
    if (argc < 3) {
        printf("Usage: %s <bin_file> <max_cycles>\n", argv[0]);
        return 1;
    }

    // 加载 .bin 文件到 ROM
    FILE *fp = fopen(argv[1], "rb");
    if (!fp) { perror("Failed to open bin file"); return 1; }
    fread(ROM, 1, MEM_SIZE, fp);
    rewind(fp);
    fread(RAM, 1, MEM_SIZE, fp);
    fclose(fp);

    uint64_t max_cycles = strtoull(argv[2], NULL, 10);

    printf("Simulating %s for %lu cycles...\n", argv[1], max_cycles);

    // 执行循环
    while (cycle_counter < max_cycles) {
        inst_cycle();
    }

    // 检查结束状态
    printf("\n--- Simulation Finished ---\n");
    printf("Final PC: 0x%08X\n", PC);
    printf("Final a0 (x10): %d (0x%X)\n", R[10], R[10]);
    
    
    return 0;
}

pc在这三条指令循环满足要求:
image

image

image

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MEM_SIZE (1 << 20) // 1MB
uint8_t ROM[MEM_SIZE];
uint8_t RAM[MEM_SIZE];
int32_t R[32] = {0};
uint32_t PC = 0;
uint64_t cycle_counter = 0; 
int is_halted = 0; //停机标志位

// 符号扩展
int32_t sign_extend(uint32_t imm, int n) {
    if ((imm >> (n - 1)) & 1) return (int32_t)(imm | (0xFFFFFFFF << n));
    return (int32_t)imm;
}

void inst_cycle() {
    // 1. 取指
    uint32_t inst = (uint32_t)ROM[PC] | (ROM[PC+1] << 8) | (ROM[PC+2] << 16) | (ROM[PC+3] << 24);
    
    // ebreak:0x00100073
    if (inst == 0x00100073) {
        is_halted = 1;
        return;
    }

    uint8_t opcode = inst & 0x7F;
    uint8_t rd     = (inst >> 7) & 0x1F;
    uint8_t funct3 = (inst >> 12) & 0x7;
    uint8_t rs1    = (inst >> 15) & 0x1F;
    uint8_t rs2    = (inst >> 20) & 0x1F;
    uint8_t funct7 = (inst >> 25) & 0x7F;

    int jumped = 0;

    switch (opcode) {
        case 0x13: // ADDI
            R[rd] = R[rs1] + sign_extend(inst >> 20, 12);
            break;
        case 0x33: // ADD
            if (funct7 == 0x00) R[rd] = R[rs1] + R[rs2];
            break;
        case 0x37: // LUI
            R[rd] = (inst & 0xFFFFF000);
            break;
        case 0x67: // JALR
            {
                uint32_t next_pc = PC + 4;
                PC = (R[rs1] + sign_extend(inst >> 20, 12)) & ~1;
                R[rd] = next_pc;
                jumped = 1;
            }
            break;
        case 0x03: // LW / LBU
            {
                uint32_t addr = R[rs1] + sign_extend(inst >> 20, 12);
                if (addr < MEM_SIZE) {
                    if (funct3 == 0x2) R[rd] = (int32_t)(RAM[addr] | (RAM[addr+1]<<8) | (RAM[addr+2]<<16) | (RAM[addr+3]<<24));
                    else if (funct3 == 0x4) R[rd] = RAM[addr];
                }
            }
            break;
        case 0x23: // SW / SB
            {
                int32_t imm = sign_extend(((inst >> 25) << 5) | ((inst >> 7) & 0x1F), 12);
                uint32_t addr = R[rs1] + imm;
                if (addr < MEM_SIZE) {
                    if (funct3 == 0x2) {
                        RAM[addr] = R[rs2] & 0xFF; RAM[addr+1] = (R[rs2] >> 8) & 0xFF;
                        RAM[addr+2] = (R[rs2] >> 16) & 0xFF; RAM[addr+3] = (R[rs2] >> 24) & 0xFF;
                    } else if (funct3 == 0x0) RAM[addr] = (uint8_t)(R[rs2] & 0xFF);
                }
            }
            break;
        default:
           
            break;
    }

    R[0] = 0;
    if (!jumped) PC += 4;
    cycle_counter++; 
}

int main(int argc, char *argv[]) {
    if (argc < 3) {
        printf("Usage: %s <bin_file> <max_cycles>\n", argv[0]);
        return 1;
    }

    FILE *fp = fopen(argv[1], "rb");
    if (!fp) { perror("Failed to open bin file"); return 1; }
    
    // 加载二进制文件
    size_t bytes_read = fread(ROM, 1, MEM_SIZE, fp);
    rewind(fp);
    fread(RAM, 1, MEM_SIZE, fp);
    fclose(fp);
    ROM[0x00001218+0]=0x73;
    ROM[0x00001218+1]=0x00;
    ROM[0x00001218+2]=0x10;
    ROM[0x00001218+3]=0x00;
    
    RAM[0x00001218+0]=0x73;
    RAM[0x00001218+1]=0x00;
    RAM[0x00001218+2]=0x10;
    RAM[0x00001218+3]=0x00;
    uint64_t max_cycles = strtoull(argv[2], NULL, 10);

    printf("Simulating %s (Max Cycles: %lu)...\n", argv[1], max_cycles);

    while (cycle_counter < max_cycles && !is_halted) {
        inst_cycle();
    }

    printf("\n--- Simulation Finished ---\n");
    if (is_halted) {
        printf("Reason: ebreak instruction encountered.\n");
    } else {
        printf("Reason: Maximum cycles reached.\n");
    }
    
    printf("Final PC: 0x%08X\n", PC);
    printf("Final a0 (x10): %d (0x%X)\n", R[10], R[10]);
    printf("Total Cycles: %lu\n", cycle_counter);
    
    return 0;
}

image

posted @ 2026-01-03 18:42  与非或非门  阅读(4)  评论(0)    收藏  举报