ICS Lab Note

本校的Lab体验总结

lab1

  1. 实际上通过编写发现,为了编写方便,我将ASCII模板0和存放文件起始地址的位置调换(即0x3013和0x3012),并将文件的内容连续(consecutively)放在从0x3013处的开始;随之变动的也有将LDR R3, x3013改为LEA R3, x3013,最开始没有注意到这个问题debug发现其实x3013里我设的值为’H’即x0048,按照原来的执行,它会提取x0048处的内容,因此单步执行到这行机器代码直接halt掉了,且估计是因为ACV异常导致的结果。
  2. 编写bin文件转化为obj之后调试发现,bin文件第一行的内容并没有被显示在主存中。因此可以推断第一行为程序执行的起始地址(可能是因为我没有仔细看实验手册吧:)。
  3. fgets执行成功文件指针自动后移; 格式化写入文件fprintf;
  4. a+: 以追加、可读写的方式打开文件,允许读写。若进行读操作,则从头开始读;若进行写操作,则将内容添加在末尾。若文件不存在,则创建文件。打开成功后返回文件指针,位置指针指向文件头部。
  • 完成时间3h

lab2

  1. Bug: Loop的次数不是所期望的3,因此需要改变影响loop次数的BR,将BRzp改为BRp,即可达到所期望的3次,结果为30.
  2. Bug: 应该把LDR改为LEA这样就可以提取存储单元的内容,而不是提取存储单元内容的内容(相当于间接寻址),修改过后就为正确的了。
  3. Bug: x300C和x300B行应该调换位置。因为实际上R3寄存器的设置是作为loop的次数,同时LDR同样也可以生成条件码,这会导致意想不到的错误(比如对应文件地址里存储的是负数或者0就会终止循环得到意想不到的结果)
  4. Bug: 如果x3400地址单元内存的值为0,那么就会出现死循环的问题,单步调试之后发现在x3003处的BR指令并没有判断取数为0的情况,因此我做出了这样的调整。在x3003处将BRn改为BRnz
  • 完成时间2h

lab3

  1. 将输入的 大写/小写字母 转化为 小写/大写字母 输出到显示屏上,如果是别的字符则输出error.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
           .ORIG  x3000           ; program start at x3000
    LD R2, TERM ; Load negative of ASCII 7
    AGAIN TRAP x23 ; input syscall
    ; judge the range of R0
    LD R5, UPMIN
    ADD R5, R5, R0
    BRn OTH ; if input < A, jump to OTH
    LD R5, UPMAX
    ADD R5, R5, R0
    BRnz U2L ; if input <= Z, jump to U2L
    LD R5, LOWMIN
    ADD R5, R5, R0
    BRn OTH ; if input < a, jump to OTH
    LD R5, LOWMAX
    ADD R5, R5, R0
    BRnz L2U ; if input <= z, jump to L2U
    BR OTH ; the rest range of input.
    U2L LD R3, ASCII ; load difference value
    BR OUTPUT
    L2U LD R3, ASCII2
    ;
    ; handle alpha
    ;
    OUTPUT ADD R1, R2, R0 ; if input 7, jump to halt.
    BRz EXIT ; exit
    ADD R0, R0, R3 ; trasforming u2l/l2u
    TRAP x21 ; output syscall
    BR AGAIN ; unconditional loop
    ;
    ; if the character not an alpha, handle from there
    ;
    OTH ADD R1, R2, R0
    BRz EXIT
    LEA R3, ERROR ; load prompt pointer
    LOOP LDR R0, R3, #0 ; load character
    BRz AGAIN
    TRAP x21 ; it may change the value in R1
    ADD R3, R3, #1 ; load next character
    BR LOOP
    TERM .FILL xFFC9 ; xFFC9 is negative of ASCII 7(x0037)
    ASCII .FILL x0020 ; The difference value between upper case and lower case
    ASCII2 .FILL xFFE0 ; xFFE0 is negative of -20
    UPMIN .FILL xFFBF ; xFFBF is negative of ASCII A
    UPMAX .FILL xFFA6 ; xFFA6 is negative of ASCII Z
    LOWMIN .FILL xFF9F ; xFF9F is negative of ASCII a
    LOWMAX .FILL xFF86 ; xFF86 is negative of ASCII z
    EXIT TRAP x25 ; halt
    ERROR .STRINGZ "Input character error!"
    .END
  2. gets函不包含换行符(\n)
  • 完成时间2h

lab4

汇编语言

1.编写完程序之后发现有报错log, 于是配合上vscode+vim插件可以直接在代码中定位错误信息,将报错log(主要时label名字输入错误)全部修改正确。

2.汇编成功后,debug发现书上有两个小错误,最开始以为x-0A是0x0A但后面发现并不是,而是0x0A的取补数来判定值, 还有x-03和x-09也是一样的。后来ADD后面只能跟5个Bit的值,遂用#-10表示,因此改为:

Image

3.debug发现这一段条件码判断的有问题,应该是照着敲的时候敲错了太粗心了…!第一步和负的ASCII的0比较应该是判断BRn才为NOT A integer, 事实上我写成了BRp才造成了这样的错误,而且还漏写了大于9的边界判断,下面是Debug错误图:

ImageImage

正确应该改为:

Image

4.输入+测试会crash,随后我设置断点缩小了BUG的范围,找到了对应的位置,最后确定是因为这一段代码输入错,可以能是因为重复恢复R5寄存器,也可能是以为忘记恢复R7寄存器的值。crash的图片:

Image

错误代码的图片:

Image

改正了这部分代码, 恢复正常:

Image

5.debug排错技巧,先在某个特定的函数位置打好断点再看源代码是否有误,并屏感觉有不合理的地方对照课本,最后走一遍单步调试.

6.仔细查看这行代码并没有实际的意义,于是对照可课本发现确实是敲错了:

Image

7.查看了Display的源代码发现显示的其实是栈顶元素(一个符号位三个数字),也就是刚输入的ASCIIBUFF。衍生出了一个问题,如果上上次输入的是一个3位数字,且上次输入的是一个2位数字,那么ASCIIBUF的2位数字会和3位数字的百位一起显示吗?因为实际上在ASCIItoBinary函数中会覆盖掉之前的内容。

8.测试了一下栈内一共可以存10个元素,于是看了一下地址分布,又确认了一下确实是这样(1 stackbase location + 9 stackmax locations):

Image

9.实际上POP和PUSH操作在发生underflow/overflow时是不会移动栈顶指针的,而是直接打印信息改变寄存器R5的值然后返回:

Image

10.每一次ADD操作弹栈取两个操作后求和,会检查值是否超出范围([-999, 999]).

11.MULT操作专门有一个寄存器存放sign bit, 方便两个操作数进行累加来完成乘法。还有如果其中有一个操作数为0则直接将这个值压入栈中,退出乘法操作。而且乘法只需要将作为累加次数的乘数的值变为正数即可,最后根据符号位取结果的时候,可以发现四种结果都是正确的。

12.发现有个BUG,在console中输入一个数字之后又backtrace将它清除再输入一个数回车就会出现Not a integer的报错,看了一下它的VALUE_LOOP的实现发现确实是有这么一个缺陷。

13.PUSH和POP默认操作的都是R0寄存器

14.查看clear函数源码,发现仅仅是将栈顶指针初始化为空(即初始化为stackbase再-1)

15.又发现一个BUG:输入百位数Display显示乱码,进而导致相加的结果出错。有两个原因:1.push值到栈中出错(PUSH_VALUE)A2B。2.或者B2A的过程中出错。经过定位之后发现输入到ASCIIBUFF中的三个数字是完整的存在里面的,难道是转换出错?开始往Display函数上打断点,可以发现在单步执行通过Binary2ASCII前后ASCIIBUF的值发生了变化,经过之前:

Image
Image

经过之后,可以看出ASCIIBUFF中的值已经发生了变化:

Image
Image

接下来又试了一下两位数,经过这个函数后显示的结果是正确的,难道是课本代码出错???Not!又进一步精确了错误的位置,发现如果是两位数,在发现在栈中的值就是所输入的两位数的值,而三位数的时候就变成了随机的值,因此可以推断问题不是出在B2A而是处在A2B往栈中存的值不正确导致最后Display从栈中取二进制数时打印出错!(刚好就只剩A2B的源代码没看哈哈哈)。以下是输入123,栈中值错误:

Image

仔细阅读了A2B的源代码定位到了错误(从十六进制转化为十进制时使用MASK的对象应该是R4,也就是刚LD过来的内容):

Image

修改过后,成功了!:

Image

16.最后说一下A2B的设计,我本以为是数位的ASCII码来和’0’做减,没想到是和x000F的MASK取模也行,太妙了!

  • 完成时间5h

C语言

1.难受了windows下是carriage return + linefeed, 我提取的字符是一位….我很难受。遂换一个策略

2.scanf后面接个getchar吸收换行符

  • 完成时间5h