冯·诺伊曼体系结构及工作原理理解

第1关:数据移动指令模拟

任务描述

根据给出的数据移动类指令,填写正确参数,完成指令的运行。

相关知识

为了完成本关任务,你需要掌握:1.如何理解 TOY 类汇编指令,2.如何理解数据移动类 mov 指令的含义。

数据移动类指令解析
  • mov1 指令:mov1 Rx mem ,将主存单元 mem 中的值移入寄存器 Rx 中,这里的 mem 是主存单元地址;
  • mov2 指令:mov2 mem Rx ,将寄存器 Rx 中的值移入主存单元 mem 中,这里的 mem 是主存单元地址;
  • mov3 指令:mov3 Rx n ,将数字 n 放入寄存器 Rx 中。
指令示例

000 mov3 1 12

  • 该指令表示将数字 12 写入寄存器 1 中,其中指令左侧的000表示的是该指令放置在主存的哪个单元中。
  • 该指令若要被执行,首先需要将程序计数器 pReg 中的值设置为该指令在主存中的地址,这里是000, 接着 CPU 的控制器根据程序计数器中的值到对应的主存单元中读取该指令放入指令寄存器 iReg 中,然后进行指令译码、执行和写结果这些后续操作。

操作要求

在右侧弹出的操作页面左上部给出了本关需要完成的指令,在右侧给出的主存区间中该指令被标黄显示。点击右侧“启动”按钮,在弹出的页面中根据要完成的指令内容在各个编辑框中填写正确的内容,填写完成后点击“确认”按钮。若填写错误,请根据系统给出的提示信息进行修改;若填写正确,系统将给出该指令执行的完整过程演示,请仔细观察并理解该指令的含义。


开始你的任务吧,祝你成功!

完成指令解析 009 mov2 100 2
pReg:(009)
寄存器:(2) 值:(100)
内存地址:(100)

第2关:运算指令模拟

任务描述

根据给出的运算类指令,填写正确参数,完成指令的运行。

相关知识

为了完成本关任务,你需要掌握:1.如何运行汇编运算式指令。

运算类指令解析
加法指令:add Rx Ry ,寄存器 Rx 中的值加上 Ry 中的值,结果存入 Rx;

减法指令:sub Rx Ry ,寄存器 Rx 中的值减去 Ry 中的值,结果存入 Rx;

乘法指令:mul Rx Ry ,寄存器 Rx 中的值乘以 Ry 中的值,结果存入 Rx;

除法指令:div Rx Ry ,寄存器 Rx 中的值除以 Ry 中的值,结果存入 Rx;
指令示例

002 add 0 1

  • 该指令表示将寄存器 0 中的数值和寄存器 1 中数值执行加法运算,结果写入寄存器 0 中,其中指令左侧的002表示的是该指令存放在主存单元地址。
  • 该指令若要被执行,首先需要将程序计数器 pReg 中的值设置为该指令在主存中的地址,这里是002, 接着 CPU 的控制器根据程序计数器中的值到对应的主存单元中读取该指令放入指令寄存器 iReg 中,然后进行指令译码、执行和写结果这些后续操作。

操作要求

在右侧弹出的操作页面左上部给出了本关需要完成的指令,在右侧给出的主存区间中该指令被标黄显示。点击右侧“启动”按钮,在弹出的页面中根据要完成的指令内容在各个编辑框中填写正确的内容,填写完成后点击“确认”按钮。若填写错误,请根据系统给出的提示信息进行修改;若填写正确,系统将给出该指令执行的完整过程演示,请仔细观察并理解该指令的含义。


开始你的任务吧,祝你成功!

完成指令解析 005 operator 1 2
pReg:(005)
操作数1:(1) 操作数2:(2)
选择:op(+)

第3关:无条件和条件跳转指令模拟

任务描述

根据给出的跳转类指令,填写正确参数,成功运行条件跳转指令和无条件跳转指令。

相关知识

跳转类指令解析
  • 无条件跳转指令:jmp mem ,程序直接跳转到主存地址 mem 处继续执行,即将程序计数器中的值改写为 mem,这样,下一条要执行的指令就是存放在主存地址 mem 处的指令;

  • 条件跳转指令:jz Rx mem ,程序是否跳转要根据寄存器 Rx 中的值进行判定;若寄存器 Rx 中的值为 0 ,则跳转到主存地址 mem 处执行,否则不跳转,顺序执行下一条指令。

指令示例

012 jz 4 009

  • 该指令为条件跳转指令,若寄存器 4 中的数值为 0 ,则程序跳转到主存地址 009 处执行对应单元中的指令,即将 009 写入程序计数器 pReg 中,其中指令左侧的012表示的是该跳转指令存放在主存单元的地址。
  • 该指令若要被执行,首先需要将程序计数器 pReg 中的值设置为该指令在主存中的地址,这里是012, 接着 CPU 的控制器根据程序计数器中的值到对应的主存单元中读取该指令放入指令寄存器 iReg 中,然后进行指令译码、执行这些后续操作。

操作要求

在右侧弹出的操作页面左上部给出了本关需要完成的指令,在右侧给出的主存区间中该指令被标黄显示。点击右侧“启动”按钮,在弹出的页面中根据要完成的指令内容在各个编辑框中填写正确的内容,填写完成后点击“确认”按钮。若填写错误,请根据系统给出的提示信息进行修改;若填写正确,系统将给出该指令执行的完整过程演示,请仔细观察并理解该指令的含义。


开始你的任务吧,祝你成功!

完成指令解析 003 jmp 003
pReg:(003)
内存地址:(003)

第4关:输入输出指令模拟

任务描述

根据给出的输入输出指令,填写正确参数,完成指令的运行。

相关知识

输入输出类指令解析
  • 输入指令:in Rx ,读取键盘输入的整数,放入寄存器 Rx 中;

  • 输出指令:out Rx ,将寄存器 Rx 中的值输出到屏幕。

指令示例

020 out 1

  • 该指令为输出指令,将寄存器 1 中的数值输出到显示器上,其中指令左侧的020表示的是该输出指令存放在主存单元的地址。
  • 该指令若要被执行,首先需要将程序计数器 pReg 中的值设置为该指令在主存中的地址,这里是020, 接着 CPU 的控制器根据程序计数器中的值到对应的主存单元中读取该指令放入指令寄存器 iReg 中,然后进行指令译码、执行这些后续操作。

操作要求

在右侧弹出的操作页面左上部给出了本关需要完成的指令,在右侧给出的主存区间中该指令被标黄显示。点击右侧“启动”按钮,在弹出的页面中根据要完成的指令内容在各个编辑框中填写正确的内容,填写完成后点击“确认”按钮。若填写错误,请根据系统给出的提示信息进行修改;若填写正确,系统将给出该指令执行的完整过程演示,请仔细观察并理解该指令的含义。


开始你的任务吧,祝你成功!

完成指令解析 008 out 1
pReg:(008)
寄存器:(1)
带输出值:(1)

第5关:完整指令集验证

任务描述

根据操作提示,运行一个能够执行完整运算功能的程序。

相关知识

为了完成本关任务,你需要掌握 TOY 指令集中的指令含义。

关于 TOY 指令集中各条指令的含义详见本实训首页介绍,以及第 1 关至第 4 关的相关知识介绍,此处不再重复介绍。

操作要求

本关使用 TOY 指令集中的指令编写了一段包含 5 条指令的程序代码,可实现加、减、乘、除四则运算功能。你需要为这一段程序代码选择正确的 TOY 指令。具体操作步骤和要求如下:

  1. 点击右侧操作页面右上部的“选择运算”按钮,选择一种运算,在弹出的对话框中输入运算数;
  2. 点击“加载”按钮,系统会将完成上面选择的运算功能的 5 条程序代码放置到主存单元 000 开始的区域内,并遮挡为不可见状态;
  3. 根据程序计数器 pReg 给出的主存地址,为对应的单元选择正确的指令,若选择错误,请根据系统给出的提示信息进行修改;若选择正确,系统将给出该指令执行的完整过程演示,请仔细观察并理解该指令的含义。
  4. 继续反复执行步骤 3 ,直至所有指令执行完毕。

开始你的任务吧,祝你成功!

+ 1 2
mov3
mov3
add
out
halt

第6关:软件模拟 - 模拟硬件初始化

任务描述

  对使用变量模拟的 TOY 计算机的部分硬件装置,进行初始化赋值。

相关知识

图1


图 1 TOY 计算机结构

  如图 1 所示,TOY 计算机的核心硬件装置主要包括主存和 CPU。   TOY 主存用来存储正在执行的 TOY 程序和相关数据, TOY 的主存共包含 1000 个主存单元,主存单元的地址依次为 000 ~ 999,每个主存单元可以存储一条 TOY 指令或一个相关数据。   TOY 的 CPU 是用来执行 TOY 指令的,每次执行一条指令。在 CPU 中,通用寄存器是用来存储临时数据的,如执行完 mov3 1 12mov3 2 13 两条指令后,第 1 号和第 2 号寄存器中的值分别为 12 和 13,这两个数据会在后面的指令中被用到,TOY 计算机中共有 10 个通用寄存器,编号从 0 到 9;指令寄存器中存储了正在被执行的指令,如图 1 中,正在被 CPU 执行的指令是 add 1 2 指令;程序计数器用来存储下一条指令的地址,如图 1 中,程序计数器的值为 003,表示下一条被执行的指令是第 003 号主存单元中的指令。

编程要求

  在右侧编辑区的 Begin-End 区间中,补全函数init()的代码,该函数使用mem列表模拟 TOY 计算机 1000 个主存单元,reg列表模拟 CPU 的 10 个通用寄存器,pReg变量模拟程序计数器,iReg变量模拟指令寄存器,请为上述这些变量进行初始化赋值,要求全部赋值为 0 。注意:不要改动 Begin-End 区间之外的代码。

测试说明

  本关将测试上述变量的赋值结果,与编程要求相同则通过测试。


开始你的任务吧,祝你成功!

# 初始化
def init():
    ########## Begin ##########
    mem = [0] * 1000  # 主存,1000个单元
    reg = [0] * 10  # 通用寄存器,10个
    pReg = 0  # 程序计数器,1个
    iReg = 0  # 指令寄存器,1个
    ########## End ##########
    print(mem, reg, pReg, iReg)

第7关:软件模拟 - 程序加载

任务描述

  将存放在文件中的程序指令加载到 TOY 计算机的主存中。

相关知识

  加载 TOY 程序是指把 TOY 程序从外存载入到 TOY 的主存,从而使 CPU 可以执行程序中的各指令,其实就是把 .toy 文件中的程序指令放入到对应的主存单元(即列表 mem 中的对应位置),如果没有特意说明,就表示从主存地址 000 对应的单元开始连续存放。例如,若将图 1 中 add.toy 文件加载到主存,则 add.toy 文件第 3 行002 add 1 2中的指令add 1 2将被放入主存第 002 号单元,也就是将列表 mem 中下标为 2 的元素赋值为add 1 2

图1


图 1 TOY 程序示例

  【小贴士】严格来说, .toy 文件中指令前的地址是逻辑地址,主存单元的地址是物理地址,一条指令的物理地址不一定等于它的逻辑地址,将逻辑地址转换为物理地址的过程称为地址重定位。本实训中,不同的测试集会给出程序加载到主存时第一条指令存放的物理地址,例如,若程序的第一条指令存放在物理地址 100 对应的单元中,则表明从主存物理地址 100 开始的主存单元连续存放该程序的所有指令,这时程序中一条指令的逻辑地址和其物理地址相差 100。图 2 给出了 add.toy 程序加载到主存物理地址 100 的存放示意图。这时,如果 CPU 执行 add.toy 程序,则必须首先将程序计数器 pReg 的值设为 100,使其能够将程序的第一条指令mov3 1 12取到指令寄存器 iReg。


图 2 程序装载到主存地址重定位示例图

  下面先介绍 Python 读写文件的方法和全局变量的概念。

读写文件

  利用 Python 读写文件的过程一般是先打开文件,然后进行读写,最后关闭文件。下面的程序 1 给出了写文件的示例。

程序 1

txt = open('D:/MyPython/add.toy', 'w')  # 打开文件
txt.write('000 mov3 1 12\n')  # 写文件
txt.write('001 mov3 2 13\n')
txt.write('002 add 1 2\n')
txt.write('003 out 1\n')
txt.write('004 halt\n')
txt.close()  # 关闭文件

  该程序首先用 open(file, mode) 函数打开一个文件,file 给出的是文件的路径,通常若程序 1 所在目录为程序执行目录,则当程序 1 和 add.toy 文件存放在同一个目录下时只需要写文件名即可,如程序 2 中所示;mode 表示打开文件的模式,主要有:

  • r:读模式,以此模式打开的文件只能进行读操作,不能进行写操作;
  • w:写模式,以此模式打开的文件只能进行写操作,不能进行读操作,当文件不存在时会自动创建该文件;
  • a:也是写模式,它与 w 模式的区别在于,在 w 模式中,程序写入的内容会覆盖文件打开前已有的内容,而在 a 模式中,文件已有内容不会被覆盖,程序写入的内容会被追加到已有内容之后。

  所以,程序 1 第 1 行的意思是以写模式打开D:\MyPython\add.toy文件,若文件不存在则自动创建该文件,若文件已存在则清空之前的内容;然后利用 write 函数往文件中写入 5 条 TOY 指令,write 函数在写文件时不会自动换行,所以要在每条指令最后加上换行符\n,否则 5 条指令会被写到同一行;最后关闭文件。所以程序执行完毕后,在D:\MyPython文件夹下会存在add.toy文件,文件内容就是图 1 中add.toy的内容。   程序 2 给出的是读文件的示例,程序首先以读模式打开文件,然后读取并打印文件中所有内容,最后关闭文件。

程序 2

# add.toy文件和程序2文件存放在同一目录,且程序2所在目录为执行目录
txt = open('add.toy', 'r')
while True:
    line = txt.readline()  # 整行读取
    if line == '':  # 此处是两个单引号,判断是否读到文件尾
        break
    print(line)  # print函数会在输出结束后再打印输出一个换行符
txt.close()

  程序 2 的执行结果如下,:

000 mov3 1 12

001 mov3 2 13

002 add 1 2

003 out 1

004 halt

  函数 readline 的功能是读取文件中的某一行,首次使用 readline 函数时读取的是文件第 1 行,下次再使用 readline 时会读文件第 2 行,第 i 次调用 readline 读取的就是文件第 i 行。因此,可以利用循环依次读取文件中的每一行。因为在读取之前不知道文件总共有多少行,也就是不知道确切的循环次数,所以程序使用了 while 循环。while 的条件表达式为 True,即条件永远成立,所以该条件表达式不能使循环结束,使循环结束的是循环体中的 break 语句,执行 break 语句的条件是line=='',即读出来的这一行是空字符串,也就是什么都没读到,这表示文件已经读到最后,此时可结束循环。   除 readline 之外,还可以使用函数 read()readlines() 读取文件,这两个函数的功能都是读取文件中所有内容,区别在于以何种形式存放读取到的内容,read 函数将文件中的所有内容存放在一个字符串中,而 readlines 将结果存于一个列表,列表中的一个元素对应文件中的一行。例如,add.toy 是程序 1 生成的文件,则在程序 3 中,变量 s 的值为'000 mov3 1 12\n001 mov3 2 13\n002 add 1 2\n003 out 1\n004 halt\n' ,而在程序 4 中,s 的值为['000 mov3 1 12\n', '001 mov3 2 13\n', '002 add 1 2\n', '003 out 1\n', '004 halt\n']

程序 3

txt = open('add.toy', 'r')
s = txt.read()
print(s)
txt.close()

  程序 3 的执行结果如下,注意输出时换行符'\n'直接执行换行操作:

000 mov3 1 12
001 mov3 2 13
002 add 1 2
003 out 1
004 halt

程序 4

txt = open('add.toy', 'r')
s = txt.readlines()
print(s)
txt.close()

  程序 4 的执行结果如下:

['000 mov3 1 12\n', '001 mov3 2 13\n', '002 add 1 2\n', '003 out 1\n', '004 halt\n']
全局变量

  在函数体中可以读取函数外部定义的变量(但一般不建议这么做,一般建议通过参数传递的方式将外部变量的值传递到函数体中),如在程序 5 中,变量 a 是在 test 函数外部定义的变量,而在 test 函数中,可以读取 a 的值,所以该程序执行结束后,会打印 a 的值 1。

程序 5

a = 1


def test():
    b = a  # 读取外部变量a
    print(b)


test()  # 打印结果为1

  程序 5 的执行结果如下:

1

  但是,在函数体中修改外部变量的值并不会对外部变量起作用,如在程序 6 中,atest 函数外部的变量,虽然在函数体中将 a 的值修改为 2,但在函数体外,该修改并不会生效,所以最后的 print 语句打印出的还是 1。

程序 6

a = 1


def test():
    a = 2  # 修改外部变量a


test()
print(a)  # 打印结果仍为1

  程序 6 的执行结果如下:

1

  有些时候,希望函数体中对外部变量的修改能够在函数外部生效,此时可使用关键字 global 进行全局变量的声明。例如,在程序 7 中,test 函数首先声明变量 a 为全局变量,然后再对 a 进行修改,此时的修改会在函数外部生效,所以 print 语句打印出的是修改后的结果 2。

程序 7

a = 1


def test():
    global a  # 声明a为全局变量
    a = 2  # 对a的修改会在外部生效


test()
print(a)  # 打印结果为2,证明函数体中的修改已生效

  程序 7 的执行结果如下:

2

编程要求

  和本实训的第一关一样,我们继续使用mem列表模拟 TOY 计算机的主存。本关需要补全右侧编辑区loadProgram函数中 Begin-End 之间的代码,将存放在文件file中的程序指令放入 TOY 计算机主存mem中,放入的起始地址为address,从而实现模拟计算机程序加载的功能。其中,file文件名、address地址由测试用例输入,经函数loadProgram参数传入,你无需编写相关输入代码。

提醒:

1.文件file中每行指令从左至右依次由逻辑地址、指令操作码、指令操作数 1、指令操作数       2、组成,各部分之间使用若干数量不等的空格相间隔,将指令加载到主存mem时,需要将     每行指令前面的逻辑地址去除掉,只加载指令本身;同时,需要将指令操作码左侧、最后     一个操作数右侧可能存在的空格去除掉。

2.不要改动 Begin-End 区间之外的代码。

测试说明

  平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。测试样例如下所示:

  第一个输入的是需要加载的程序所在文件名,第二个输入的是程序第一条指令加载到主存的物理地址。   

测试输入:
 

add.toy

0   

预期输出:

['mov3 1 12', 'mov3 2 13', 'add 1 2', 'out 1', 'halt', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

关于平台执行用户程序的说明:(与本地执行不同) 用户点击“评测”按钮,平台会进入用户的版本库代码下载目录/data/workspace/myshixun,在此启动 python、java、c,或者其它程序,我们将这个目录称为程序工作目录。因此:

(1)若要在命令行加载用户程序/data/workspace/myshixun/step1/fileop.py,应进入/data/workspace/myshixun目录,执行 python step1/fileop.py命令。

(2)用户编写代码时应将此程序工作目录视为根目录,例如,若用户程序fileop.py放在 /data/workspace/myshixun/step1/ 文件夹中,执行时需要读取文件夹/data/workspace/myshixun/下的a.txt文件,则打开文件的代码为open(“a.txt”, ‘r’) 即可;若a.txt文件与fileop.py在同一个文件夹/data/workspace/myshixun/step1/ 中,则打开文件的代码应改写为open(“step1/a.txt”, ‘r’)


开始你的任务吧,祝你成功!

# 程序加载
def loadProgram(file, mem, address):
    ########## Begin ##########
    txt = open(file, 'r')
    s = txt.readlines()
    for x in s:
        l = len(x)
        bg, L = 0, []
        while bg <= l - 1:
            mdl = ''
            flag = False
            while x[bg] != ' ':
                mdl = mdl + x[bg]
                bg += 1
                if bg == l - 1:
                    flag = True
                    break
            while x[bg] == ' ':
                if bg == l - 1:
                    flag = True
                    break
                bg += 1
            L.append(mdl)
            if flag:
                break
        # L
        L.pop(0)
        mem[address] = ' '.join(L)
        address = address + 1
    ########## End ##########
    print(mem)

第8关:软件模拟 - 取指令

任务描述

  模拟计算机取指令操作,将内存中的指令取到指令寄存器中来,同时程序计数器加一,指向下一条要执行的指令地址。

相关知识

  CPU 的功能是依次执行程序中的各条指令,在执行一条指令时其工作过程如下:

  • 取指令:按照程序计数器的值,取出对应主存单元中的指令,存入指令寄存器,并将程序计数器的值加 1,以便下个指令周期取出的是下一条指令;
  • 译码:对指令寄存器中的指令进行分析,取出操作码和各操作数;
  • 执行和写结果:根据操作码对操作数进行处理,并将处理结果放入指令指定的地方。

编程要求

  在右侧编辑区函数fetch中补全 Begin-End 区间的代码,模拟实现 CPU 取指令的操作,根据程序计数器pReg给出的指令地址,从主存mem中取出指令放入指令寄存器iReg,注意,指令取出后,程序计数器pReg需要自增 1 。

说明:

  • mem列表:模拟 TOY 计算机的主存;
  • pReg变量:模拟程序计数器;
  • iReg变量:模拟指令寄存器。

测试说明

  平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。 mem列表模拟的 TOY 计算机主存中存放的程序来自于测试用例输入的.toy文件,测试程序将调用 2 次函数fetch,实现 2 次取指令操作,因此程序执行后将输出.toy文件中的前 2 条指令。 测试样例如下所示:

  测试输入:add.toy   

       预期输出:

mov3 1 12
mov3 1 13

开始你的任务吧,祝你成功!

# 取指令:根据程序计数器给出的地址取出主存对应的指令放入指令寄存器
def fetch(mem, pReg):
    ########## Begin ##########
    # print(pReg)
    iReg = mem[pReg]
    pReg = pReg + 1
    ########## End ##########
    print(iReg)
    return pReg, iReg

第9关:软件模拟 - 指令译码

任务描述

  对程序寄存器中的指令进行解析,得到操作码和操作数。

相关知识

  参考之前关卡。

编程要求

  在右侧编辑区补全函数 decode 中 Begin-End 区间的代码,模拟实现 CPU 指令译码的操作,对参数 iReg中存放的指令进行解析,并将指令操作码和操作数以元组的方式返回。函数返回的元组应包含 3 个元素,其中第 1 个元素为操作码,第 2、3 个元素分别对应第 1 、2 个操作数,若操作数不存在,则用 None表示。   提醒:由于使用列表模拟通用寄存器和主存,因而当 TOY 计算机指令中的操作数为某个寄存器和主存单元地址时,使用列表元素下标表示,故此时操作数的数据类型应为整型。

测试说明

  平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。测试样例如下所示:

   测试输入:mov3 1 0 # 函数参数iReg中存放的待解析指令   

        预期输出:('mov3', 1, 0)

   测试输入:out 1 # 函数参数iReg中存放的待解析指令   

        预期输出:('out', 1, None)


开始你的任务吧,祝你成功!

# 指令译码:解析指令寄存器中的指令
def decode(iReg):
    ########## Begin ##########
    l = len(iReg)
    cnt, i = 0, 0
    L = []
    while i < l:
        while i < l and iReg[i] == ' ':
            i = i + 1
        if i == l:
            break;
        cnt = cnt + 1;
        mdl = ''
        while i < l and iReg[i] != ' ':
            mdl = mdl + iReg[i]
            i = i + 1
        if cnt > 1:
            bg = 0
            while bg < len(mdl) and mdl[bg] == '0':
                bg = bg + 1
            mdl = mdl[bg:]
        L.append(mdl)
    while cnt < 3:
        L.append('None')
        cnt = cnt + 1
    ret = '(' + "'" + L[0] + "'" + ',' + ' ' + L[1] + ',' + ' ' + L[2] + ')'
    return ret
    ########## End ##########

第10关:软件模拟 - 指令执行

任务描述

  根据 TOY 计算机指令译码结果,编程模拟指令执行及写结果的操作。

相关知识

  参考实训首页 TOY 计算机指令集介绍,及前面关卡的相关知识。

,

编程要求

  在右侧编辑区补全函数 execute 中 Begin-End 区间的代码,结合上图对指令功能的描述编程模拟实现 CPU 指令执行及写结果的操作。其中,参数opcode对应指令操作码、op1op2对应 2 个操作数,参数 regmempReg分别表示通用寄存器、主存和程序计数器。 execute 函数的返回值规定如下:若操作码是addsubmuldivmov1mov2mov3inout,则返回第 1 个操作数对应位置存放的值;若操作码是jmpjz,返回程序计数器pReg中的值;若操作码是halt,返回False

  说明:

  1. 本关 execute函数中,opcode,op1op2的参数值来自于第 4 关指令译码函数decode执行后得到的元组(opcode,op1, op2)
  2. 本关待执行的指令已经由评测文件放入指令寄存器pReg中。
  3. 本关待执行的指令所在文件 .toy 被评测文件装入主存时,统一从主存地址000开始存放,即指令在程序中的逻辑地址(.toy 文件中指令前面的编号)和其被装入主存后的物理地址一致。

测试说明

  平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。   本关卡共有 5 个测试集,测试集输入数据主要分为 2 个部分,第 1 部分是使用 TOY 计算机指令集编写的测试代码文件,分别命名为 test1.toy ~ test5.toy,这些代码文件主要用于测试各种指令是否能够正确执行,故不考虑代码的完整性和功能性;第 2 部分是测试代码需要的输入数据,若程序代码中无in输入指令,则缺省第 2 部分的输入数据。

  测试样例如下所示。   测试输入:test1.toy   预期输出:10

  测试输入:test5.toy 10   预期输出:40

  test1.toy ~ test5.toy 的测试代码如下所示。

#test1.toy
000 mov3 0 1
001 mov3 1 11
002 sub 1 0
003 mov2 2 1

#test2.toy
000 mov3 3 10
001 mov3 4 3
002 div 3 4
003 add 4 4
004 jz 3 002
005 out 3

#test3.toy
000 mov3 1 22
001 mov2 0 1
002 mov1 0 0

#test4.toy
000 mov3 0 4
001 jmp 003
002 mov2 990 0
003 halt

#test5.toy
000 mov3 8 4
001 in 9
002 mul 8 9

开始你的任务吧,祝你成功!

# 执行和写结果
def execute(opcode, op1, op2, reg, mem, pReg):
    ########## Begin ##########
    global iReg
    if opcode == 'mov1':
        reg[op1] = eval(mem[op2])
        result = reg[op1]
    elif opcode == 'mov2':
        mem[op1] = str(reg[op2])
        result = mem[op1]
    elif opcode == 'mov3':
        reg[op1] = op2
        result = reg[op1]
    elif opcode == 'add':
        reg[op1] += reg[op2]
        result = reg[op1]
    elif opcode == 'sub':
        reg[op1] -= reg[op2]
        result = reg[op1]
    elif opcode == 'mul':
        reg[op1] *= reg[op2]
        result = reg[op1]
    elif opcode == 'div':
        reg[op1] = reg[op1] // reg[op2]
        result = reg[op1]
    elif opcode == 'jmp':
        iReg = mem[op1]
        # pReg = eval(mem[op1])
        return pReg
    elif opcode == 'jz':
        if reg[op1] == 0:
            # pReg = eval(mem[op2]
            iReg = mem[op2]
        result = pReg
    elif opcode == 'in':
        reg[op1] = eval(input())
        result = reg[op1]
    elif opcode == 'out':
        # print(reg[op1])
        result = reg[op1]
    else:
        result = False
    ########## End ##########
    return result

第11关:软件模拟 - TOY计算机执行程序的完整过程

任务描述

  本关任务是将前面关卡的功能结合起来,模拟一个程序在 CPU 中的完整执行过程。

相关知识

  参考之前关卡。

编程要求

  仔细阅读右侧编辑器给出的代码框架及注释,在指定的 Begin-End 区间编写程序,将使用 TOY 计算机指令集编写的.toy文件,根据给定的主存地址address加载到主存mem指定区域(连续存放),并控制 CPU 执行.toy文件中的程序代码,得到执行结果。   你需要补充完整 5 个函数:

  1. 函数loadProgram(file, mem, address)实现程序加载功能:从主存memaddress地址开始存放file文件,无返回值。
  2. 函数fetch(mem, pReg)实现取指令功能:根据程序计数器给出的地址取出主存对应的指令放入指令寄存器,程序计数器自增 1,函数返回pRegiReg的值。
  3. 函数decode(iReg)实现指令译码功能:解析指令寄存器中的指令,不存在的操作数置为None,函数返回操作码opcode,和 2 个操作数op1,op2
  4. 函数execute(opcode, op1, op2, reg, mem, address)实现执行和写结果功能:根据指令解析的操作码执行对应的操作,若为停机指令返回False,其余指令返回 True特别说明:1)执行跳转指令jmpjz时,需要考虑程序中代码的逻辑地址(.toy 文件中指令前面的编号)和放入主存后的物理地址的不一致之处,两个地址间存在固定的偏移量差值(address);2)指令mov1mov2读写的是主存中存放的数据(不是指令),这里直接使用指令中给出的物理地址实现读写访问。
  5. 函数run(file, addr)实现完整过程模拟功能:程序加载、取指令、指令译码、指令执行和写结果,无返回值。注意,在执行程序前,需要将第一条指令代码在主存中的地址(即addr)放入程序计数器pReg中,为第一次取指令做好准备。

  

测试说明

  平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。   本关卡共有 3 个测试集,测试集的输入数据中,第 1 个是使用 TOY 计算机指令集编写的测试代码文件,分别命名为 add.toy、sum100.toy、sum.toy,这些代码文件主要用于测试模拟程序的编写是否正确,故不考虑代码的完整性和功能性;第 2 个是给定的主存地址address;若.toy中的测试代码需要输入数据,则排在第 3 个位置。评测输出为.toy中测试代码的输出内容,即out指令的执行结果。   测试样例如下所示:

  测试输入:add.toy 0   

       预期输出:25

  测试输入:sum.toy 20 51   

       预期输出:1275      

       add.toy、sum100.toy、sum.toy 的测试代码如下所示。

#add.toy
000 mov3 1 12
001 mov3 2 13
002 add 1 2
003 out 1
004 halt

#sum100.toy
000 mov3 1 0
001 mov3 2 1
002 mov3 3 1
003 add 1 2
004 add 2 3
005 mov3 4 101
006 sub 4 2
007 jz 4 009
008 jmp 003
009 out 1
010 halt

#sum.toy
000 in 4
001 mov2 999 4
002 mov3 1 0
003 mov3 2 1
004 mov3 3 1
005 add 1 2
006 add 2 3
007 mov1 4 999
008 sub 4 2
009 jz 4 011
010 jmp 005
011 out 1
012 halt

开始你的任务吧,祝你成功!

# 模拟 CPU 执行完整程序代码的全部过程
# 初始化主存、通用寄存器、指令寄存器和程序计数器
mem = [''] * 1000  # 主存
reg = [0] * 10  # 通用寄存器
pReg = 0  # 程序计数器
iReg = ''  # 指令寄存器


def loadProgram(file, mem, address):
    txt = open(file, 'r')
    s = txt.readlines()
    for x in s:
        l = len(x)
        bg, L = 0, []
        while bg < l:
            mdl = ''
            while bg < l and x[bg] != ' ':
                mdl = mdl + x[bg]
                bg += 1
            while bg < l and x[bg] == ' ':
                bg += 1
            L.append(mdl)
        L.pop(0)
        mem[address] = ' '.join(L)
        address = address + 1


def fetch(mem, pReg):
    iReg = mem[pReg]
    return pReg, iReg


def decode(iReg):
    l = len(iReg)
    cnt, i = 0, 0
    L = []
    while i < l:
        while i < l and iReg[i] == ' ':
            i = i + 1
        if i == l:
            break
        cnt = cnt + 1;
        mdl = ''
        while i < l and iReg[i] != ' ':
            mdl = mdl + iReg[i]
            i = i + 1
        if cnt > 1:
            bg = 0
            while bg < len(mdl) and mdl[bg] == '0':
                bg = bg + 1
            mdl = mdl[bg:]
        L.append(mdl)
    tmp = cnt
    while cnt < 3:
        L.append('None')
        cnt = cnt + 1
    if tmp == 1:
        return L[0], 0, 0
    elif tmp == 2:
        if L[1] == '' or L[1] == '\n':
            return L[0], 0, 0
        return L[0], eval(L[1]), 0
    else:
        ret1, ret2 = 0, 0
        if L[1] != '' and L[1] != '\n':
            ret1 = eval(L[1])
        if L[2] != '' and L[2] != '\n':
            ret2 = eval(L[2])
        return L[0], ret1, ret2


def execute(opcode, op1, op2, reg, mem, addr):
    global pReg
    flag = False
    if opcode == 'mov1':
        reg[op1] = eval(mem[op2])
    elif opcode == 'mov2':
        mem[op1] = str(reg[op2])
    elif opcode == 'mov3':
        reg[op1] = op2
    elif opcode == 'add':
        reg[op1] += reg[op2]
    elif opcode == 'sub':
        reg[op1] -= reg[op2]
    elif opcode == 'mul':
        reg[op1] *= reg[op2]
    elif opcode == 'div':
        reg[op1] = reg[op1] // reg[op2]
    elif opcode == 'jmp':
        iReg = mem[op1]
        pReg = op1 + addr
        flag = True
    elif opcode == 'jz':
        if reg[op1] == 0:
            flag = True
            iReg = mem[op2]
            pReg = op2 + addr
    elif opcode == 'in':
        reg[op1] = eval(input())
    elif opcode == 'out':
        print(reg[op1])
    if flag == False:
        pReg = pReg + 1
    if opcode != 'halt' and opcode != 'halt\n':
        result = True
    else:
        result = False
    return result


def run(file, addr):
    global pReg, iReg
    pReg = addr
    loadProgram(file, mem, addr)
    while True:
        pReg, iReg = fetch(mem, pReg)
        L, op1, op2 = decode(iReg)
        mdl = execute(L, op1, op2, reg, mem, addr)
        if mdl == False:
            break


file = input()
address = int(input())
run(file, address)

第12关:软件模拟 - 扩展 TOY 计算机指令集

任务描述

本关任务:修改给定的程序代码,使其支持执行使用 TOY 计算机扩展指令集编写的程序代码。

相关知识

下面的表 1 列出了 TOY 计算机指令集中的所有指令。

表1 TOY计算机的指令集

本关在上面表 1 指令集的基础上新增 3 条指令,如表 2 所示。

表2 TOY计算机的扩展指令

编程要求

仔细阅读右侧编辑区给出的程序代码框架,基于第 6 关实现的 TOY 计算机模拟程序,添加表 2 中的 3 条指令,使其能够正确执行使用 TOY 扩展指令集编写的程序。你需要在 Begin-End 区间补充完整 6 个函数的代码:

  1. 函数init()实现初始化工作:将主存mem( 1000 个单元),通用寄存器reg( 10 个),程序计数器pReg,指令寄存器iReg,状态寄存器CF,全部初始化为 0 值,无返回值。
  2. 函数loadProgram(file, mem, address)实现程序加载功能:从主存memaddress地址开始存放file文件,无返回值。
  3. 函数fetch()实现取指令功能:根据程序计数器给出的地址取出主存对应的指令放入指令寄存器,程序计数器自增 1,无返回值。
  4. 函数decode()实现指令译码功能:解析指令寄存器中的指令,不存在的操作数置为None,函数返回操作码和 2 个操作数。
  5. 函数execute(opcode,op1,op2,address)实现执行和写结果功能:根据指令解析的操作码执行对应的操作,若为停机指令返回False,其余指令返回 True;要求能够模拟 TOY 扩展指令集 15 条指令的执行。特别说明:1)执行跳转指令jmpjz时,需要考虑程序中代码的逻辑地址(.toy 文件中指令前面的编号)和放入主存后的物理地址的不一致之处,两个地址间存在固定的偏移量差值(address);2)指令mov1mov2读写的是主存中存放的数据(不是指令),这里直接使用指令中给出的物理地址实现读写访问。
  6. 函数run(file, addr)实现完整过程模拟功能:程序加载、取指令、指令译码、指令执行和写结果,无返回值。注意,在执行程序前,需要将第一条指令代码在主存中的地址(即addr)放入程序计数器pReg中,为第一次取指令做好准备。

评测文件会调用你写的函数实现从初始化、读取 .toy 程序文件名称,到执行 .toy 程序的全部过程。

提醒:不能将第 6 关代码直接放到本关,两关代码存在一定差异。

测试说明

平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。

本关卡共有 3 个测试集,测试集的输入数据中,第 1 个是使用 TOY 计算机指令集编写的测试代码文件,分别命名为 expand.toy、expand2.toy、expand3.toy,这些代码文件主要用于测试模拟程序的编写是否正确,故不考虑代码的完整性和功能性;第 2 个是给定的主存地址address;若 .toy 中的测试代码需要输入数据,则排在第 3 个位置。评测输出为 .toy 中程序代码的输出内容,即out指令的执行结果。

测试样例如下所示:

测试输入:expand.toy

     2

预期输出:500500

测试输入:expand3.toy

     10

     3

     10

预期输出:3

expand.toy、expand2.toy、expand3.toy 的代码指令如下所示。

#expand.toy
000 mov3 0 0
001 mov3 1 1
002 add 0 1
003 add2 1 1
004 cmp 1 1000
005 mov3 2 002
006 ble 2
007 out 0
008 halt

#expand2.toy
000 mov3 4 1
001 mov3 5 2
002 mul 4 5
003 add2 5 1
004 cmp 5 6
005 mov3 6 002
006 ble 6
007 out 4
008 halt

#expand3.toy
000 in 0
001 in 1
002 div 1 0
003 out 1
004 halt

开始你的任务吧,祝你成功!

mem = [''] * 1000  # 主存
reg = [0] * 10  # 通用寄存器
pReg = 0  # 程序计数器
iReg = ''  # 指令寄存器
CF = 0


def init():
    global mem, reg, pReg, iReg, CF
    ########## Begin ##########
    mem = [''] * 1000  # 主存
    reg = [0] * 10  # 通用寄存器
    pReg = 0  # 程序计数器
    iReg = ''  # 指令寄存器
    CF = 0


def loadProgram(file, mem, address):
    txt = open(file, 'r')
    s = txt.readlines()
    for x in s:
        l = len(x)
        bg, L = 0, []
        while bg < l:
            mdl = ''
            while bg < l and x[bg] != ' ' and x[bg] != '\t':
                mdl = mdl + x[bg]
                bg += 1
            while bg < l and (x[bg] == ' ' or x[bg] == '\t'):
                bg += 1
            L.append(mdl)
        L.pop(0)
        mem[address] = ' '.join(L)
        address = address + 1


# 取指令:根据程序计数器给出的地址取出主存对应的指令放入指令寄存器
def fetch():
    global mem, pReg, iReg
    iReg = mem[pReg]
    return pReg, iReg


# 指令译码:解析指令寄存器中的指令,不存在的操作数置为None
def decode():
    global iReg
    l = len(iReg)
    cnt, i = 0, 0
    L = []
    while i < l:
        while i < l and iReg[i] == ' ':
            i = i + 1
        if i == l:
            break
        cnt = cnt + 1;
        mdl = ''
        while i < l and iReg[i] != ' ':
            mdl = mdl + iReg[i]
            i = i + 1
        if cnt > 1:
            bg = 0
            while bg < len(mdl) and mdl[bg] == '0':
                bg = bg + 1
            mdl = mdl[bg:]
        L.append(mdl)
    tmp = cnt
    while cnt < 3:
        L.append('None')
        cnt = cnt + 1
    if tmp == 1:
        return L[0], 0, 0
    elif tmp == 2:
        if L[1] == '' or L[1] == '\n':
            return L[0], 0, 0
        return L[0], eval(L[1]), 0
    else:
        ret1, ret2 = 0, 0
        if L[1] != '' and L[1] != '\n':
            ret1 = eval(L[1])
        if L[2] != '' and L[2] != '\n':
            ret2 = eval(L[2])
        return L[0], ret1, ret2
    ########## End ##########


# 执行和写结果:根据指令解析的操作码执行对应的操作,若为停机指令返回 False,其余指令返回 True
##opcode为操作码,op1为第一个操作数,op2为第二个操作数
def execute(opcode, op1, op2, address):
    global reg, pReg, CF, mem
    flag = False
    if opcode == 'mov1':
        reg[op1] = eval(mem[op2])
    elif opcode == 'mov2':
        mem[op1] = str(reg[op2])
    elif opcode == 'mov3':
        reg[op1] = op2
    elif opcode == 'add':
        reg[op1] += reg[op2]
    elif opcode == 'sub':
        reg[op1] -= reg[op2]
    elif opcode == 'mul':
        reg[op1] *= reg[op2]
    elif opcode == 'div':
        reg[op1] = reg[op1] // reg[op2]
    elif opcode == 'jmp':
        iReg = mem[op1]
        pReg = op1 + address
        flag = True
    elif opcode == 'jz':
        if reg[op1] == 0:
            flag = True
            iReg = mem[op2]
            pReg = op2 + address
    elif opcode == 'in':
        reg[op1] = eval(input())
    elif opcode == 'out':
        print(reg[op1])
    elif opcode == 'add2':
        reg[op1] += op2
    elif opcode == 'cmp':
        if reg[op1] <= op2:
            CF = 1
        else:
            CF = 0
    elif opcode == 'ble':
        if CF:
            pReg = reg[op1] + address
            flag = True
    if flag == False:
        pReg = pReg + 1
    if opcode != 'halt' and opcode != 'halt\n':
        result = True
    else:
        result = False
    ########## End ##########
    return result


# 完整过程模拟:程序加载、取指令、指令译码、指令执行和写结果
def run(file, addr):
    global pReg, iReg, reg
    ######## Begin ########
    pReg = addr
    loadProgram(file, mem, addr)
    while True:
        pReg, iReg = fetch()
        L, op1, op2 = decode()
        mdl = execute(L, op1, op2, addr)
        if mdl == False:
            break

    ########## End ##########

本文灵感(特别鸣谢):【Educoder作业】※ 冯·诺依曼体系结构模拟

  • 32
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
这段代码是用CSS来创建一个具有下拉菜单功能的导航栏。以下是每一行代码的注释: ```css *{margin:0; padding:0;font-size:12px;} /* 设置全局样式 */ ul,ol,li {list-style: none;} /* 去除列表默认样式 */ #nav {width: 100px;margin:0 auto;} /* 设置导航栏宽度和居中对齐 */ #nav li{height:36px;} /* 设置每个菜单项的高度 */ #nav li span{ /* 设置每个菜单项的图标样式 */ display: block; float: right; width: 35px; height: 35px; border-bottom-left-radius: 5px; border-top-left-radius: 5px; background: #7a6e6e url("插图11/toolbars.png") no-repeat; } #nav li:nth-of-type(1) span{background-position: 0px -15px;} /* 设置第一个菜单项的图标背景位置 */ #nav li:nth-of-type(2) span{background-position: 0px -57px;} /* 设置第二个菜单项的图标背景位置 */ #nav li:nth-of-type(3) span{background-position: 1px -106px;} /* 设置第三个菜单项的图标背景位置 */ #nav li:nth-of-type(4) span{background-position: 0px -156px;} /* 设置第四个菜单项的图标背景位置 */ #nav li:nth-of-type(5) span{background-position: 0px -200px;} /* 设置第五个菜单项的图标背景位置 */ #nav li:nth-of-type(6) span{background-position: 2px -265px;} /* 设置第六个菜单项的图标背景位置 */ #nav li p{ /* 设置每个菜单项的下拉内容样式 */ height: 35px; text-align: left; background: #c81623; color: #ffffff; border-bottom-left-radius: 5px; border-top-left-radius: 5px; line-height: 35px; padding-left: 10px; display: none; /* 初始状态下隐藏下拉内容 */ } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在远方的眺望

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值