重读基础—计算机硬件及组成原理学习笔记(十,十一)

读完了第十,十一章,由于阅读本书的目的是为了了解CPU基本体系结构,而非为了编写汇编语言,所以对各平台的指令部分只是略读。重点关注的是寄存器,寻址方式,状态寄存器,指令类型及执行过程中的异同。

现总结如下:

名称 68k 8086/X86 ARM
指令类型 CISC CISC(Pentium后采用CISC指令+译码为RISC执行) RISC
寄存器 地址寄存器+数据寄存器+状态寄存器 地址寄存器+数据寄存器+状态寄存器 通用寄存器+状态寄存器X2
寻址方式 寄存器寻址+存储器寻址 寄存器寻址+存储器寻址(分段寻址),80386后由于地址线增加,故不需再使用段寻址。 寄存器寻址(使用Load和Store与存储器进行数据交换),由于指令定长,所以立即数只能通过4偏移X2+8位进行计算,这样做的弊端在于不能表示所有的32位立即数,当立即数并非在此区间时,需要多条指令来计算此立即数。
指令长度 不定长,执行需要多个时钟周期 不定长,执行需要多个时钟周期 定长(32bit),多数情况下单时钟周期即可执行完毕,只有少数指令需要多个时钟周期,支持较为复杂的汇编指令,如MOVES
其他 除了地址寄存器A7和A7‘,其他数据寄存器之间和地址寄存器之间是通用的。 某些指令必须指定固定的寄存器,比如乘法必须使用AX,且结果放入AX中。 乘法累加器(用于计算积分),桶形移位器(MOVE+位移,由于是异步的,所以单时钟周期即可完成)

[转]命令,不要去询问。

这里有一篇关于面向对象的文章,解释了一些曾经思考过但没有答案的问题,比如用户阅读文章时,该如何去写,是user.read(article)还是ariticleService.read(user,article),我觉得这篇文章给了个不错的说明,所以转过来和分享一下。原文地址 : 点击这里

命令,不要去询问(Tell, Don’t Ask)

前些时间我曾经翻译过一篇叫做《这里我说了算!》的文章,里面作者讲述了关于“命令,不要去询问(Tell, Don’t Ask)”原则:

我看到的最多被违反的原则是“命令,不要去询问(Tell, Don’t Ask)”原则。这个原则讲的是,一个对象应该命令其它对象该做什么,而不是去查询其它对象的状态来决定做什么(查询其它对象的状态来决定做什么也被称作‘功能嫉妒(Feature Envy)’)。

这篇文章里有个很生动的例子,我至今记忆犹新:

if (person.getAddress().getCountry() == “Australia”) {

这违反了得墨忒耳定律,因为这个调用者跟Person过于亲密。它知道Person里有一个Address,而Address里还有一个country。它实际上应该写成这样:

if (person.livesIn(“Australia”)) {

非常的明了。今天我又看到一个关于“Tell, Don’t Ask”原则的文章,里面提供了4个关于这个原则的例子,都很有价值。

例一

不好:

<% if current_user.admin? %>
  <%= current_user.admin_welcome_message %>
<% else %>
  <%= current_user.user_welcome_message %>

<% end %>

好:

<%= current_user.welcome_message %>

例二

不好:

def check_for_overheating(system_monitor)

  if system_monitor.temperature > 100
    system_monitor.sound_alarms
  end

end

好:

system_monitor.check_for_overheating

class SystemMonitor
  def check_for_overheating

    if temperature > 100
      sound_alarms
    end
  end

end

例三

不好:

class Post
  def send_to_feed

    if user.is_a?(TwitterUser)
      user.send_to_feed(contents)
    end

  end
end

好:

class Post
  def send_to_feed

    user.send_to_feed(contents)
  end
end

class TwitterUser
  def send_to_feed(contents)

    twitter_client.post_to_feed(contents)
  end
end

class EmailUser
  def send_to_feed(contents)

    # no-op.
  end
end

例四

不好:

def street_name(user)

  if user.address
    user.address.street_name
  else

    'No street name on file'
  end
end

好:

def street_name(user)

  user.address.street_name
end

class User
  def address

    @address || NullAddress.new
  end
end

class NullAddress

  def street_name
    'No street name on file'
  end
end

好的面向对象编程是告诉对象你要做什么,而不是询问对象的状态后根据状态做行动。数据和依赖这些数据的操作都应该属于同一个对象。

命令,不要去询问!

[英文原文:Tell, Don’t Ask ]

重读基础—计算机硬件及组成原理学习笔记(八,九)

这两张讲的内容比较相近,所以放在一起写.
主要内容有两点:
68k的主要寻址模式
68k的指令集相关

这两点知识引申出了许多的内容
1.CPU存储部分主要包含 数据寄存器,地址寄存器,状态寄存器,指令地址寄存器,管理栈指针(A7和A7`,这里牵涉到用户态和管态,详细内容参考操作系统)

当使用计算等操作时,如果产生了溢出,除零,结果为0等状态,其状态寄存器的相应位置都会被置有效,而后方便CMP(比较)或者BEQ(条件转移)等指令进行判断和处理.

2.栈指针地址寄存器是由高到低变化的,方便实现LIFO.

当使用跳转指令进入子程序时,一般的处理方法是子程序内负责保存当前各寄存器的数值到栈中,在结束运行时,再进行恢复,而后才会跳转回上级.—–了解了这条知识以后,很自然的就联想到了尾递归的实现,结果经过查找,发现C语言对于尾递归果然是需要编译器加优化参数才可以实现的 🙂  参考材料点击 这里

3.假如要做可控范围内的一个循环,那么简单的将指令堆积,运算速度最快.这种不需要进行转移或者循环的内联代码,计算机处理效率最高,原因以后在学习到流水线的时候会讲到.

4.C语言到汇编的过程中,由于编译程序会考虑所有的情况,所以编译后的代码中会有很多无用的代码,这也是为什么手写汇编会比C语言快一些.

5.简单的阐述了一下由机器码反汇编的知识.主要是汇编到机器码的一些映射规则,这些由于比较细节,所以只是简单了解了一下.

重读基础-C程序设计语言(一)

这周忘记带《计算机硬件及组成原理》回家了,所以抽了C语言来补补课。第一章课后习题有一题比较有意思:

编写一个删除C语言程序中所有的注释语句。要正确处理带引号的字符串与字符常量。在C语言中,注释不允许嵌套。

之前了解过一些编译原理中状态机的原理,早就想做一个试试,所以就抽了点时间写了一个,状态转换图如下:

C语言 注释移除器 状态机

源代码点击  这里 下载