前言
前面提到过写程序的过程:根据各种需求,构建程序模型(逻辑模型),再用代码实现.本贴关于程序自身的模型以及函数模型,以及推导硬件标准从逻辑到代码的思路.
程序自身的模型
如图
应用APP
接受输入---鼠标动作,键盘输入的字符等,得到结果---画面,显示数据等.
工具
包括框架和编程语言等都属于编程工具,工具是程序员学习的主要部分.经典描述---程序=数据结构+算法.工具解决的两大问题:数据的表达,以及逻辑的建立.逻辑表现在函数的定义(函数模型在后面讲述).数据和逻辑两大部分和硬件有着对应关系,机器关注的也是数据和逻辑,只是表现形式不一样,逻辑被化作指令码,数据化成地址.所以一个好的程序员对指令集也应该有一定理解.
程序的输出最终会成为硬件状态的变化.框架封装硬件标准来控制硬件(后面讨论硬件实现的思路).
编译
程序员在IDE(集成开发环境)里写的内容叫做"代码",是一个包含空白符(空格,换行符,tab)的字符串,芯片不认识代码.所以需要用编译器,使代码成为具有一定语义的单词,这个过程就是编译.编译的意义之一是认识到所有的语言,或者程序员的写下的字符都是工具,通过编译才让这些字符有了意义.
目标语言
可以被芯片识别和执行的指令.物理形式是二进制数(很多和计算机有关的图片喜欢用一连串的0和1,就是表达在底层起作用的是0和1的组合).内容仍然是数据和逻辑.表示逻辑的二进制数交给PC(程序计数器),表示数据的二进制数表示数值或者地址.地址用于数据传递,数值表示结果.
机器码很难读,所以把他化成较为容易理解的汇编指令.汇编指令也不是很多,常见的有立即数,寻址,跳转,移动(move),在高级语言如C语言中有对应的定义.除非高级语言中没有对应定义(如时钟)再考虑底层的内容.
函数模型
函数是把逻辑和实现结合起来的一种形式.函数名称是程序员要做的事,函数内容是如何实现这件事,函数形参是做这件事需要处理的数据,把他们结合起来就是如何用数据的变化来做成想做的事.
函数可能有返回值也可能没有返回值.返回值和逻辑本身没有联系.返回值给调用函数一个结果.这个结果可能会用到下一个函数调用中.
/*伪代码*/
void fun(){ //函数名表示逻辑,没有参数传入/*函数体*/.... //语句---数据变化
}
抽象和推导
笔者把人的思考方式简单分成抽象和推导两种.思考能力相应分为抽象能力和推导能力.
抽象是从现象中抽取普遍规律,形成公理,定理或规则的过程.推导与抽象相反,是从已知的公理/定理/规则出发,得到结论,关系,模型的过程.两者相比,抽象比推导难,科学界的许多成果都是建立在抽象的基础上(并验证).
思考能力和人的聪明程度是正相关的.学习能力强的人会思考.学习是一种模仿,方法有推导,记忆,有穷假设等.有的人学习时候没注意这方面能力的培养,单单采用反复记忆加练习(当然即使思维能力强,这两项也是必须的).推导能力强的人学习效果更好.所以在学习的过程中,时常要训练自己的思维,让自己的学习能力变强.
从<简单逻辑学>这本书里,推导有个简单的公式,离散数学里也有提到
A∈B,B→C,则A→C
当A属于B的范畴,B能得到C,则A也能推导出C
硬件标准实现的思路
以下为笔者推导思路,不保证准确.
硬件作为一个程序中的模块,以文件形式被某种语言的主程序调用.假设硬件标准中有一个画直线的函数,该如何实现呢?
1>从物理结构上看,硬件以含若干根导线的接口和计算机相连接.操作系统可以访问这些端口并把数据写入,以达到交换数据控制硬件的目的.那么操作系统是怎么识别到端口的呢?笔者想应该是由硬件驱动程序来完成.硬件驱动程序指明通信的端口,操作系统通信时调用驱动来实现数据传送.
2>端口导线通常不会很多,直接控制寄存器是不够的.例如8根线的端口只能控制8位.假设硬件有128M空间,那么应该有一种机制来保证数据能传给这128M空间.假设端口就是8位的,那么和8位端口直连的硬件部分作为数据缓冲区,另外想办法把缓冲区数据传递出去.
3>为了实现缓冲区和硬件寄存器区的数据传递,在硬件的控制电路中设置一个模式,在这种模式下定义一个硬件标准,先指明传递数据的地址,再传数据过去.
假设data_on()函数用于操作系统传递数据给硬件,change_on()用于硬件内部传递数据.
/*伪代码*/
//端口地址由驱动给出,可以作为全局变量或局部变量,如果作为局部变量,要在data_on()函数内定义形参
int addr=端口地址; /*把数据传给缓冲区*/
void data_on(int value){int *p=addr;*p=value;
}
change_on()和data_on()互斥,此时操作系统和硬件不能传递数据,用于硬件内部数据传递.
在此基础上,写出伪代码---buf是缓冲区,pointer是硬件内部数据指针
/*伪代码---标准的实现*/
void line(int x_start,int y_start,int x_end,int y_end){/*第一次传8位数据给pointer指向的地址*/data_on();change_on();move(buf,pointer);/*第二次传8位数据给pointer指向的地址*/data_on();change_on();move(buf,pointer+8);
}
写到这里,相信新的问题又给看出来了.pointer这个硬件寄存器的指针如何实现?很容易想到的是在操作系统端实现这个指针.即硬件设计为操作系统操作端口数据,来控制硬件寄存器.
/*主程序端伪代码*/line(2,3,3,5); //从坐标2,3到3,5画一条直线
这个例子只为了思路锻炼,不必在意正确与否,或者和实际比较起来会走很多弯路
小结
程序自身模型,函数模型的演示,硬件标准如何实现的思路