MIPS汇编输出错误随机位,无法替换syscall41为42的问题
Mars MIPS汇编生成随机位异常解决
问题分析
- syscall 41输出全1:Mars中syscall 41用于生成32位随机整数,但如果未先初始化随机数生成器,默认会返回-1(二进制全1),取最低位后自然每次得到1,导致输出全1序列。
- syscall 42报错:syscall 42用于生成指定范围的随机数,要求
$a1传入正整数作为上界(生成范围为[0, $a1-1])。直接修改syscall编号但未设置$a1参数,寄存器中残留的垃圾值(可能为负数)会触发"Upper bound cannot be negative"错误。
解决方案
必须先初始化随机数生成器,再选择正确的syscall生成随机位:
方案1:修复syscall 41的使用
先调用syscall 40初始化随机数生成器(可使用当前时间或固定值作为种子),再用syscall 41生成随机数并取最低位。
方案2:正确使用syscall 42生成0/1随机位
syscall 42传入上界2,直接生成0或1的随机数,无需额外处理即可作为结果返回。
修改后的完整代码
#vim:sw=2 syntax=asm .data random_id: .word 0 .globl main # Memory layout of the Configuration # | eca | tape | tape_len | rule | skip | column | # | 1 word | 1 word | 1 byte | 1 byte | 1 byte | 1 byte | automaton: .word 1 # eca .word 252 # tape .byte 8 # tape_len .byte 106 # rule .byte 1 # skip .byte 5 # column syscall_error_msg: .asciiz "Error: Random number generator syscall failed" .text .globl gen_byte, gen_bit main: # 初始化随机数生成器:用当前时间作为种子 li $v0, 40 # syscall 40 = 初始化随机数生成器 lw $a0, random_id # 使用默认生成器ID 0 li $a1, 0 # 传入0表示用当前时间作为种子(Mars支持) syscall # Arguments: # $a0 : address of configuration in memory # 0($a0): eca (1 word) # 4($a0): tape (1 word) # 8($a0): tape_len (1 byte) # 9($a0): rule (1 byte) # 10($a0): skip (1 byte) # 11($a0): column (1 byte) # Return value: # Compute the next valid byte (00, 01, 10) and put into $v0 # If 11 would be returned, produce two new bits until valid loopcounter: li $s0 30 # loop counter loop: beqz $s0 terminate subi $s0 $s0 1 la $a0 automaton jal gen_bit # print returned value move $a0 $v0 li $v0 1 syscall j loop terminate: li $v0 10 syscall gen_byte: li $v0, 0 gen_byte_loop: jal gen_bit move $t1, $v0 # 存储第一个bit sll $t1, $t1, 1 # 左移一位,预留第二个bit的位置 jal gen_bit or $t1, $t1, $v0 # 合并两个bit # 若生成11(十进制3)则重新生成 beq $t1, 3, gen_byte_loop gen_byte_end: srl $t0, $t1, 1 move $v0, $t0 jr $ra # Arguments: # $a0 : address of configuration in memory # 0($a0): eca (1 word) # 4($a0): tape (1 word) # 8($a0): tape_len (1 byte) # 9($a0): rule (1 byte) # 10($a0): skip (1 byte) # 11($a0): column (1 byte) # # Return value: # Look at the field {eca} and use the associated random number generator to generate one bit. # Put the computed bit into $v0 gen_bit: # 方案1:使用syscall41生成随机数取最低位 li $v0, 41 lw $a0, random_id syscall bltz $v0, syscall_failed andi $v0, $v0, 1 # 取最低位作为随机bit # ------------------------------ # 方案2:使用syscall42直接生成0/1 # li $v0, 42 # lw $a0, random_id # li $a1, 2 # 上界为2,生成0或1 # syscall # bltz $v0, syscall_failed # # $v0直接是0或1,无需额外处理 # ------------------------------ jr $ra syscall_failed: li $v0, 4 la $a0, syscall_error_msg syscall li $v0, 10 syscall
额外说明
- 初始化随机数生成器时,若传入固定种子(如
li $a1, 1234),每次运行会得到相同的随机序列,方便调试;传入0则用当前时间作为种子,每次序列不同。 gen_byte函数原逻辑存在错误:仅判断00的情况,漏掉了01和10的合法情况,修改为判断是否等于3(二进制11),若为非法值则重新生成。
内容的提问来源于stack exchange,提问作者ByBlackyDZN
相关产品推荐
相关产品推荐

