Cheng gang's profileGumpPhotosBlogListsMore Tools Help

Gump

How many roads must a man walk down, before they call him a man.

gang Cheng

Occupation
Location
Interests
A strange young man
No list items have been added yet.
No list items have been added yet.
There are no music lists on this space.
Fuwa  
Photo 1 of 6
April 15

关于预处理

作为学计算机的,写代码是必然的事,写的代码怎样才能到机器上跑起来呢?这就要经过编译过程,把我们能看懂的代码符号变成机器能看懂的符号,编译过程是个很复杂的过程,做这个工作之前通常有个阶段叫“预处理”,找了一点资料,介绍一点预处理的知识。
 
程序设计语言的预处理的概念:在编译之前进行的处理。
C语言的预处理主要有三个方面的内容:1.宏定义;2.文件包含;3.条件编译。
预处理命令以符号“#”开头。

一.宏定义
1.不带参数的宏定义:
宏定义又称为宏代换、宏替换,简称“宏”。
格式:
#define 标识符 字符串
      其中的标识符就是所谓的符号常量,也称为“宏名”。
预处理(预编译)工作也叫做宏展开:将宏名替换为字符串。掌握"宏"概念的关键是“换”。一切以换为前提、做任何事情之前先要换,准确理解之前就要“换”。即在对相关命令或语句的含义和功能作具体分析之前就要换:
例:
#define PI 3.1415926
把程序中出现的PI全部换成3.1415926
说明:
(1)宏名一般用大写
(2)使用宏可提高程序的通用性和易读性,减少不一致性,减少输入错误和便于修改。例如:数组大小常用宏定义
(3)预处理是在编译之前的处理,而编译工作的任务之一就是语法检查,预处理不做语法检查。
(4)宏定义末尾不加分号;
(5)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头。
(6)可以用#undef命令终止宏定义的作用域
(7)宏定义可以嵌套
(8)字符串" "中永远不包含宏
(9)宏定义不分配内存,变量定义分配内存。
2.带参数的宏:
除了一般的字符串替换,还要做参数代换
格式:
#define 宏名(参数表) 字符串
例如:#define S(a,b) a*b
          area=S(3,2);第一步被换为area=a*b; ,第二步被换为area=3*2;
类似于函数调用,有一个哑实结合的过程:
(1)实参如果是表达式容易出问题
            #define S(r) r*r
            area=S(a+b);第一步换为area=r*r;,第二步被换为area=a+b*a+b;
            正确的宏定义是#define S(r) (r)*(r)
(2)宏名和参数的括号间不能有空格
(3)宏替换只作替换,不做计算,不做表达式求解
(4)函数调用在编译后程序运行时进行,并且分配内存。宏替换在编译前进行,不分配内存
(5)宏的哑实结合不存在类型,也没有类型转换。
(6)函数只有一个返回值,利用宏则可以设法得到多个值
(7)宏展开使源程序变长,函数调用不会
(8)宏展开不占运行时间,只占编译时间,函数调用占运行时间(分配内存、保留现场、值传递、返回值)

二. 文件包含
一个文件包含另一个文件的内容
格式:
#include "文件名"
    或
#include <文件名>
编译时以包含处理以后的文件为编译单位,被包含的文件是源文件的一部分。编译以后只得到一个目标文件.obj。被包含的文件又被称为“标题文件”或“头部文件”、“头文件”,并且常用.h作扩展名。修改头文件后所有包含该文件的文件都要重新编译。
头文件的内容除了函数原型和宏定义外,还可以有结构体定义,全局变量定义:
(1)一个#include命令指定一个头文件;
(2)文件1包含文件2,文件2用到文件3,则文件3的包含命令#include应放在文件1的头部第一行;
(3)包含可以嵌套;
(4)<文件名>称为标准方式,系统到头文件目录查找文件,
         "文件名"则先在当前目录查找,而后到头文件目录查找;
(5)被包含文件中的静态全局变量不用在包含文件中声明。

三. 条件编译
有些语句行希望在条件满足时才编译。
格式:(1)
#ifdef 标识符
    程序段1
#else
    程序段2
#endif

#ifdef
    程序段1
#endif
当标识符已经定义时,程序段1才参加编译。
格式:(2)
#ifndef 标识符
使用条件编译可以使目标程序变小,运行时间变短。

预编译使问题或算法的解决方案增多,有助于我们选择合适的解决方案。此外,还有布局控制:#progma,这也是我们应用预处理的一个重要方面,主要功能是为编译程序提供非常规的控制流信息。
December 22

【转】虚拟机安装ubuntu7.04

 
软件:VMware6.0+ubuntu7.04

   一 在VMware6.0中新建一个虚拟机
这个到没什么可难度,vmware使用起来很简单,也很方便,就不多说了,安装UBUNTU也是傻瓜式的,一路默认就完了,主要是安装vmtools,因为以前没有自己安装过,下面记录下自己安装的过程

二 安装VMtools
VMware虚拟出的机器中的硬件也需要一些驱动才能正常工作,VMtools就包含了这些驱动和设置工具,下面就来安装这些工具:
在VMware6.0的VM菜单中选择Install VMware Tools 菜单,这个时候虚拟机将产生一个虚拟光驱连接到Ubuntu;
在Ubuntu的终端中执行如下命令:
$sudo mkdir /mnt/cdrom                  #创建光驱的挂载目录
$sudo mount /dev/cdrom /mnt/cdrom       #将/dev/cdrom目录(即:虚拟光驱)挂载到/mnt/cdrom目录
$cd /mnt/cdrom                          #进入/mnt/cdrom目录   
这时就可以看到虚拟光驱中的VMware Tools的安装包了,有如下两个文件:
VMwareTools-6.0.0-45731.i386.rpm
VMwareTools-6.0.0-45731.tar.gz
我们只需要使用VMwareTools-6.0.0-45731.tar.gz进行安装
$cp VMwareTools-6.0.0-45731.tar.gz /home/fei     #将安装包拷贝到我的用户目录/home/fei
$cd /home/fei
$tar xvfz VMwareTools-6.0.0-45731.tar.gz         #解包,解包后在当前目录产生vmware-tools-distrib目录
$cd vmware-tools-distrib                         #进入vmware安装包目录
$sudo ./vmware-install.pl                             #执行安装脚本文件
这样就安装完毕了,执行脚本之后会提示你选择:
安装的路径等 :默认安装到/usr/bin   我均选择默认
最后还会提示你是否现在就进行VMtools配置(选择yes则立即为你调用/usr/bin/vmware-config-tools.pl命令,你也可以在以后再调用此命令进行配置)
要卸载VMtools调用/usr/bin/vmware-uninstall-tools.pl命令即可

三 设置VMtools
安装完毕之后,VMtools还不可以使用,必须执行配置,如果在第二步中没有执行/usr/bin/vmware-config-tools.pl命令,可以在之后自己执行配置会提示你:
1 是否在主机和客户机之间实现共享
我们选yes配置完成之后,就可以在主机和客户机之间共享文件了,共享目录在linux中为/mnt/hgfs/shared目录(shared是我自己设置的名称)
2 让你选择屏幕的分辨率
选个合适的就可以了
这样重启之后,VMtools开始生效
$cd /mnt/hgfs/shared
$ls
这时可以看到windows系统中的E:盘中的文件(因为我将E:盘设置为了共享目录)安装成功!!!!!!!!
October 21

Framebuffer

引用:http://zerocool60.blog.163.com/

Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。Framebuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过Framebuffer的读写直接对显存进行操作。用户可以将Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer设备驱动来完成的。但Framebuffer本身不具备任何运算数据的能力,就只好比是一个暂时存放水的水池.CPU将运算后的结果放到这个水池,水池再将结果流到显示器.中间不会对数据做处理. 应用程序也可以直接读写这个水池的内容.在这种机制下,尽管Framebuffer需要真正的显卡驱动的支持,但所有显示任务都有CPU完成,因此CPU负担很重.

framebuffer的设备文件一般是 /dev/fb0、/dev/fb1 等等。

可以用命令: #dd if=/dev/zero of=/dev/fb 清空屏幕.

如果显示模式是 1024x768-8 位色,用命令:$ dd if=/dev/zero of=/dev/fb0 bs=1024 count=768 清空屏幕

用命令: #dd if=/dev/fb of=fbfile  可以将fb中的内容保存下来;

可以重新写回屏幕: #dd if=fbfile of=/dev/fb

在使用Framebuffer时,Linux是将显卡置于图形模式下的. 在应用程序中,一般通过将 FrameBuffer 设备映射到进程地址空间的方式使用,比如下面的程序就打开 /dev/fb0 设备,并通过 mmap 系统调用进行地址映射,随后用 memset 将屏幕清空(这里假设显示模式是 1024x768-8 位色模式,线性内存模式):

int fb;

unsigned char* fb_mem;

fb = open ("/dev/fb0", O_RDWR);

fb_mem = mmap (NULL, 1024*768, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);

memset (fb_mem, 0, 1024*768);

FrameBuffer 设备还提供了若干 ioctl 命令,通过这些命令,可以获得显示设备的一些固定信息(比如显示内存大小)、与显示模式相关的可变信息(比如分辨率、象素结构、每扫描线的字节宽度),以及伪彩色模式下的调色板信息等等。 通过 FrameBuffer 设备,还可以获得当前内核所支持的加速显示卡的类型(通过固定信息得到),这种类型通常是和特定显示芯片相关的。比如目前最新的内核(2.4.9)中,就包含有对 S3、Matrox、nVidia、3Dfx 等等流行显示芯片的加速支持。在获得了加速芯片类型之后,应用程序就可以将 PCI 设备的内存I/O(memio)映射到进程的地址空间。这些 memio 一般是用来控制显示卡的寄存器,通过对这些寄存器的操作,应用程序就可以控制特定显卡的加速功能。

PCI 设备可以将自己的控制寄存器映射到物理内存空间,而后,对这些控制寄存器的访问,给变成了对物理内存的访问。因此,这些寄存器又被称为"memio"。一旦被映射到物理内存,Linux 的普通进程就可以通过 mmap 将这些内存 I/O 映射到进程地址空间,这样就可以直接访问这些寄存器了。当然,因为不同的显示芯片具有不同的加速能力,对memio 的使用和定义也各自不同,这时,就需要针对加速芯片的不同类型来编写实现不同的加速功能。比如大多数芯片都提供了对矩形填充的硬件加速支持,但不同的芯片实现方式不同,这时,就需要针对不同的芯片类型编写不同的用来完成填充矩形的函数。

FrameBuffer 只是一个提供显示内存和显示芯片寄存器从物理内存映射到进程地址空间中的设备。所以,对于应用程序而言,如果希望在 FrameBuffer 之上进行图形编程,还需要自己动手完成其他许多工作。

FrameBuffer在LINUX中实现和机制

Framebuffer对应的源文件在linux/drivers/video/目录下。总的抽象设备文件为fbcon.c,在这个目录下还有与各种显卡驱动相关的源文件。

一、分析Framebuffer设备驱动

    需要特别提出的是在INTEL平台上,老式的VESA 1.2 卡,如CGA/EGA卡,是不能支持Framebuffer的,因为Framebuffer要求显卡支持线性帧缓冲,即CPU可以访问显缓冲中的每一位,但是VESA 1.2 卡只能允许CPU一次访问64K的地址空间。

FrameBuffer设备驱动基于如下两个文件:

1) linux/include/linux/fb.h
2) linux/drivers/video/fbmem.c

下面分析这两个文件。

1、fb.h

几乎主要的结构都是在这个中文件定义的。这些结构包括:

1)fb_var_screeninfo

这个结构描述了显示卡的特性:

struct fb_var_screeninfo

{
__u32 xres; /* visible resolution */
__u32 yres;
__u32 xres_virtual; /* virtual resolution */
__u32 yres_virtual;
__u32 xoffset; /* offset from virtual to visible resolution */
__u32 yoffset;

__u32 bits_per_pixel; /* guess what */
__u32 grayscale; /* != 0 Gray levels instead of colors */

struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */

__u32 nonstd; /* != 0 Non standard pixel format */

__u32 activate; /* see FB_ACTIVATE_* */

__u32 height; /* height of picture in mm */
__u32 width; /* width of picture in mm */

__u32 accel_flags; /* acceleration flags (hints) */

/* Timing: All values in pixclocks, except pixclock (of course) */
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture */
__u32 right_margin; /* time from picture to sync */
__u32 upper_margin; /* time from sync to picture */
__u32 lower_margin;
__u32 hsync_len; /* length of horizontal sync */
__u32 vsync_len; /* length of vertical sync */
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 reserved[6]; /* Reserved for future compatibility */
};

2) fb_fix_screeninfon
这个结构在显卡被设定模式后创建,它描述显示卡的属性,并且系统运行时不能被修改;比如FrameBuffer内存的起始地址。它依赖于被设定的模式,当一个模式被设定后,内存信息由显示卡硬件给出,内存的位置等信息就不可以修改。

struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
__u32 smem_len; /* Length of frame buffer mem */
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /* zero if no hardware panning */
__u16 ypanstep; /* zero if no hardware panning */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* length of a line in bytes */
unsigned long mmio_start; /* Start of Memory Mapped I/O */
/* (physical address) */
__u32 mmio_len; /* Length of Memory Mapped I/O */
__u32 accel; /* Type of acceleration available */
__u16 reserved[3]; /* Reserved for future compatibility */
};

3) fb_cmap
描述设备无关的颜色映射信息。可以通过FBIOGETCMAP 和 FBIOPUTCMAP 对应的ioctl操作设定或获取颜色映射信息.

struct fb_cmap {
__u32 start; /* First entry */
__u32 len; /* Number of entries */
__u16 *red; /* Red values */
__u16 *green;
__u16 *blue;
__u16 *transp; /* transparency, can be NULL */
};

4) fb_info
定义当显卡的当前状态;fb_info结构仅在内核中可见,在这个结构中有一个fb_ops指针, 指向驱动设备工作所需的函数集。

struct fb_info {
char modename[40]; /* default video mode */
kdev_t node;
int flags;
int open; /* Has this been open already ? */
#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct fb_cmap cmap; /* Current cmap */
struct fb_ops *fbops;
char *screen_base; /* Virtual address */
struct display *disp; /* initial display variable */
struct vc_data *display_fg; /* Console visible on this display */
char fontname[40]; /* default font name */
devfs_handle_t devfs_handle; /* Devfs handle for new name */
devfs_handle_t devfs_lhandle; /* Devfs handle for compat. symlink */
int (*changevar)(int); /* tell console var has changed */
int (*switch_con)(int, struct fb_info*);
/* tell fb to switch consoles */
int (*updatevar)(int, struct fb_info*);
/* tell fb to update the vars */
void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */
/* arg = 0: unblank */
/* arg > 0: VESA level (arg-1) */
void *pseudo_palette; /* Fake palette of 16 colors and
the cursor's color for non
palette mode */
/* From here on everything is device dependent */
void *par;
};

5) struct fb_ops
用户应用可以使用ioctl()系统调用来操作设备,这个结构就是用一支持ioctl()的这些操作的。

struct fb_ops {
/* open/release and usage marking */
struct module *owner;
int (*fb_open)(struct fb_info *info, int user);
int (*fb_release)(struct fb_info *info, int user);
/* get non settable parameters */
int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);
/* get settable parameters */
int (*fb_get_var)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
/* set settable parameters */
int (*fb_set_var)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
/* get colormap */
int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
/* set colormap */
int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
/* pan display (optional) */
int (*fb_pan_display)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
/* perform fb specific ioctl (optional) */
int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg, int con, struct fb_info *info);
/* perform fb specific mmap */
int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
/* switch to/from raster image mode */
int (*fb_rasterimg)(struct fb_info *info, int start);
};

6) structure map
struct fb_info_gen | struct fb_info | fb_var_screeninfo
| | fb_fix_screeninfo
| | fb_cmap
| | modename[40]
| | fb_ops ---|--->ops on var
| | ... | fb_open
| | | fb_release
| | | fb_ioctl
| | | fb_mmap
| struct fbgen_hwswitch -|-> detect
| | encode_fix
| | encode_var
| | decode_fix
| | decode_var
| | get_var
| | set_var
| | getcolreg
| | setcolreg
| | pan_display
| | blank
| | set_disp

[编排有点困难,第一行的第一条竖线和下面的第一列竖线对齐,第一行的第二条竖线和下面的第二列竖线对齐就可以了]
这个结构 fbgen_hwswitch抽象了硬件的操作.虽然它不是必需的,但有时候很有用.

2、 fbmem.c
fbmem.c 处于Framebuffer设备驱动技术的中心位置.它为上层应用程序提供系统调用 也为下一层的特定硬件驱动提供接口;那些底层硬件驱动需要用到这儿的接口来向系统内核注册它们自己. fbmem.c 为所有支持FrameBuffer的设备驱动提供了通用的接口,避免重复工作.

1) 全局变量

struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;


这两变量记录了所有fb_info 结构的实例,fb_info 结构描述显卡的当前状态,所有设备对应的fb_info 结构都保存在这个数组中,当一个FrameBuffer设备驱动向系统注册自己时,其对应的fb_info 结构就会添加到这个结构中,同时num_registered_fb 为自动加1.

static struct {
const char *name;
int (*init)(void);
int (*setup)(void);
} fb_drivers[] __initdata= { ....};

如果FrameBuffer设备被静态链接到内核,其对应的入口就会添加到这个表中;如果是动态加载的,即使用insmod/rmmod,就不需要关心这个表。

static struct file_operations fb_ops ={
owner: THIS_MODULE,
read: fb_read,
write: fb_write,
ioctl: fb_ioctl,
mmap: fb_mmap,
open: fb_open,
release: fb_release
};
这是一个提供给应用程序的接口.

2)fbmem.c 实现了如下函数.

register_framebuffer(struct fb_info *fb_info);
unregister_framebuffer(struct fb_info *fb_info);

这两个是提供给下层FrameBuffer设备驱动的接口,设备驱动通过这两函数向系统注册或注销自己。几乎底层设备驱动所要做的所有事情就是填充fb_info结构然后向系统注册或注销它。

二、一个LCD显示芯片的驱动实例

以Skeleton LCD 控制器驱动为例,在LINUX中存有一个/fb/skeleton.c的skeleton的Framebuffer驱动程序,很简单,仅仅是填充了fb_info结构,并且注册/注销自己。设备驱动是向用户程序提供系统调用接口,所以我们需要实现底层硬件操作并且定义file_operations结构来向系统提供系统调用接口,从而实现更有效的LCD控制器驱动程序。

1)在系统内存中分配显存
在fbmem.c文件中可以看到, file_operations 结构中的open()和release()操作不需底层支持,但read()、write()和 mmap()操作需要函数fb_get_fix()的支持.因此需要重新实现函数fb_get_fix()。另外还需要在系统内存中分配显存空间,大多数的LCD控制器都没有自己的显存空间,被分配的地址空间的起始地址与长度将会被填充到fb_fix_screeninfo 结构的smem_start 和smem_len 的两个变量中.被分配的空间必须是物理连续的。

2)实现 fb_ops 中的函数
用户应用程序通过ioctl()系统调用操作硬件,fb_ops 中的函数就用于支持这些操作。(注: fb_ops结构与file_operations 结构不同,fb_ops是底层操作的抽象,而file_operations是提供给上层系统调用的接口,可以直接调用.
ioctl()系统调用在文件fbmem.c中实现,通过观察可以发现ioctl()命令与fb_ops’s 中函数的关系:
FBIOGET_VSCREENINFO fb_get_var
FBIOPUT_VSCREENINFO fb_set_var
FBIOGET_FSCREENINFO fb_get_fix
FBIOPUTCMAP fb_set_cmap
FBIOGETCMAP fb_get_cmap
FBIOPAN_DISPLAY fb_pan_display

如果我们定义了fb_XXX_XXX 方法,用户程序就可以使用FBIOXXXX宏的ioctl()操作来操作硬件。

文件linux/drivers/video/fbgen.c或者linux/drivers/video目录下的其它设备驱动是比较好的参考资料。在所有的这些函数中fb_set_var()是最重要的,它用于设定显示卡的模式和其它属性,下面是函数fb_set_var()的执行步骤:

1)检测是否必须设定模式
2)设定模式

3)设定颜色映射

4) 根据以前的设定重新设置LCD控制器的各寄存器。

第四步表明了底层操作到底放置在何处。在系统内存中分配显存后,显存的起始地址及长度将被设定到LCD控制器的各寄存器中(一般通过fb_set_var() 函数),显存中的内容将自动被LCD控制器输出到屏幕上。另一方面,用户程序通过函数mmap()将显存映射到用户进程地址空间中,然后用户进程向映射空间发送的所有数据都将会被显示到LCD显示器上。

三、FrameBuffer的应用

一个使用FrameBuffer的例子

1、FrameBuffer主要是根据VESA标准的实现的,所以只能实现最简单的功能。

2、由于涉及内核的问题,FrameBuffer是不允许在系统起来后修改显示模式等一系列操作。(好象很多人都想要这样干,这是不被允许的,当然如果你自己写驱动的话,是可以实现的).

3、对FrameBuffer的操作,会直接影响到本机的所有控制台的输出,包括XWIN的图形界面。

好,现在可以让我们开始实现直接写屏:

1、打开一个FrameBuffer设备

2、通过mmap调用把显卡的物理内存空间映射到用户空间

3、直接写内存。

/********************************

File name : fbtools.h

*/

#ifndef _FBTOOLS_H_

#define _FBTOOLS_H_

#i nclude <linux/fb.h>

//a framebuffer device structure;

typedef struct fbdev{

       int fb;

       unsigned long fb_mem_offset;

       unsigned long fb_mem;

       struct fb_fix_screeninfo fb_fix;

       struct fb_var_screeninfo fb_var;

       char dev[20];

} FBDEV, *PFBDEV;

//open & init a frame buffer

//to use this function,

//you must set FBDEV.dev="/dev/fb0"

//or "/dev/fbX"

//it's your frame buffer.

int fb_open(PFBDEV pFbdev);

//close a frame buffer

int fb_close(PFBDEV pFbdev);

//get display depth

int get_display_depth(PFBDEV pFbdev);

//full screen clear

void fb_memset(void *addr, int c, size_t len);

#endif

 

/******************

File name : fbtools.c

*/

#i nclude <stdio.h>

#i nclude <stdlib.h>

#i nclude <fcntl.h>

#i nclude <unistd.h>

#i nclude <string.h>

#i nclude <sys/ioctl.h>

#i nclude <sys/mman.h>

#i nclude <asm/page.h>

#i nclude "fbtools.h"

#define TRUE        1

#define FALSE       0

#define MAX(x,y)        ((x)>(y)?(x):(y))

#define MIN(x,y)        ((x)<(y)?(x):(y))

//open & init a frame buffer

int fb_open(PFBDEV pFbdev)

{

       pFbdev->fb = open(pFbdev->dev, O_RDWR);

       if(pFbdev->fb < 0)

       {

              printf("Error opening %s: %m. Check kernel config\n", pFbdev->dev);

              return FALSE;

       }

       if (-1 == ioctl(pFbdev->fb,FBIOGET_VSCREENINFO,&(pFbdev->fb_var)))

       {

              printf("ioctl FBIOGET_VSCREENINFO\n");

              return FALSE;

       }

       if (-1 == ioctl(pFbdev->fb,FBIOGET_FSCREENINFO,&(pFbdev->fb_fix)))

       {

              printf("ioctl FBIOGET_FSCREENINFO\n");

              return FALSE;

       }

       //map physics address to virtual address

       pFbdev->fb_mem_offset = (unsigned long)(pFbdev->fb_fix.smem_start) & (~PAGE_MASK);

       pFbdev->fb_mem = (unsigned long int)mmap(NULL, pFbdev->fb_fix.smem_len + pFbdev->fb_mem_offset,              PROT_READ | PROT_WRITE, MAP_SHARED, pFbdev->fb, 0);

       if (-1L == (long) pFbdev->fb_mem)

       {

              printf("mmap error! mem:%d offset:%d\n", pFbdev->fb_mem, pFbdev->fb_mem_offset);

              return FALSE;

       }

       return TRUE;

}

//close frame buffer

int fb_close(PFBDEV pFbdev)

{

       close(pFbdev->fb);

       pFbdev->fb=-1;

}

//get display depth

int get_display_depth(PFBDEV pFbdev);

{

       if(pFbdev->fb<=0)

       {

              printf("fb device not open, open it first\n");

              return FALSE;

       }

       return pFbdev->fb_var.bits_per_pixel;

}

//full screen clear

void fb_memset (void *addr, int c, size_t len)

{

    memset(addr, c, len);

}

//use by test

#define DEBUG

#ifdef DEBUG

main()

{

       FBDEV fbdev;

       memset(&fbdev, 0, sizeof(FBDEV));

       strcpy(fbdev.dev, "/dev/fb0");

       if(fb_open(&fbdev)==FALSE)

       {

              printf("open frame buffer error\n");

              return;

       }

       fb_memset(fbdev.fb_mem + fbdev.fb_mem_offset, 0, fbdev.fb_fix.smem_len);

       fb_close(&fbdev);

}

起点

一直以来有些偷懒的情绪,看过一些比较好的文章,然后顺手就“顺过来”,贴在我的地盘上,总觉得这样还是有些欠妥。我的地盘我做主,还是得写写自己的东西。决定以后看过一些东西后,动动手,写出来,不管是基础的概念,还是对大一点问题的讨论,东西嘛,学过来,再说一遍,反复一下,记忆会深刻一些,最后变成自己的财富。年纪大了,过一下,不回味,没几天就忘了。当然,现在自己是个胸无点墨的贫困户,还是会多多引用人家的东西,汲取养分,以后自己丰富了再吐出点自己的东西来,做点贡献。
无志之人常立志,有志之人立长志,好好学习,天天向上,从今天做起。
是为记。
August 12

买办是亡国之祸——中日CPU工业发展道路的比较

转自强国论坛
 
近一段时间忙,没有时间写文章。其实是文章好写,资料难收集。不久前在网上看到一篇文章《尴尬中国芯:龙芯CPU的艰涩之旅》,感觉到龙芯CPU前途很不妙。正好自己的工作与CPU有些关联,正好轻车熟路写写日本CPU的发展。对照看看龙芯CPU为什么会陷入困境。
说到日本的CPU,很多人会问,日本有CPU吗?确实,我们日常接触的计算机基本都是wintel,CPU基本都是米国公司的。其实日本有很多种CPU,在中国也被广泛应用,只是我们很难看到它,被嵌入了,不象有个什么“Intel inside”的牌子。

当然,在中国嵌入式开发领域,日本CPU的应用也比较少,低端的多为51、PIC、AVR系列,高端的则是ARM一统天下,总之是八国联军。我想大概是因为日本CPU的相关支持工具和文档资料大多用日文写的,一般中国人看不懂。相比之下,欧美的CPU就比较好接受。看起来,CPU这东西,自己的文化弱了,推广起来也比较困难。不过,在日本,日本CPU绝对是主流,从低端到高端。从我使用的情况看,比欧美系的CPU好用,功能全面集成度高。日本的CPU大概叫关起门来自己爽。

谈CPU先要谈与CPU直接相关的基础产业----半导体。日本的半导体产业起步不算早。直到70年代初,日本半导体需要量的7-8成还需要依靠进口。当时中国正处于文化大革命,经济崩溃,知识分子被关牛棚,工农兵大学生和外行领导内行导致科研机构一片混乱。即使这样,日本当年还需要从中国进口半导体制造设备。

这时候,日本的电电公社,现在NTT的前身,相当于中国电信,发挥了很大作用。

电电公社坚决采购国产电话交换机,并坚持使用国产的半导体,组织协调日本的半导体企业协作攻关。反面则是电电公社搞垄断,高昂的电话初装费和软预算赤字财政。1976年,日本政府成立半导体的国家实验室,国家的力量进行攻关。国家战略的结果,使日本半导体生产技术达到了世界领先水平。

国家扶持和计划,使日本半导体产业与米国有很大的不同。最大的特点是大而全,小而全,自产自销。在初期,半导体的生产几乎100%在本企业或本集团内消费了。即使现在,也有很大比例是在本企业本集团内消费。这与米国半导体企业基本外销很不相同。比如,日立生产的半导体,很大比例在日立集团内部消费了,

如日立的家电、精机、重机、工厂等等。而Intel的半导体则很少自己用,绝大多数都卖给其它用户。原因是日本半导体的起点低,性能质量价格面并没有优势,只能自产自销,大而全小而全,发展半导体是作为国家及本企业集团的战略,而不是一时的经济效益。要经济效益还不如直接买米国的。

日本的这种做法,引起米国的不满,认为这是计划经济违反了市场经济规律云云。日本人也颇不满,自己的电电公社虽然搞软预算赤字财政,毕竟还是企业。而米国的国防部则完全是软预算,完全不讲经济效益。就中国是市场经济的信徒,

在日本半导体突飞猛进的时候,中国迎来了改革开放的春风,引进市场机制的葵花宝典,半导体产业就挥刀自宫了。同时自宫的产业还有很多。自宫的结果,使中国这近30年取得了世人瞩目的经济成就。欲练神功需要挥刀自宫,这是颠扑不破的真理。

国家战略和计划的引领下,日本半导体生产工艺突飞猛进,但需要高超设计技巧的CPU却没有很大突破。中国经历了10年文革的摧残,1977年研制成功了专用的弹载16位CPU。米国的CPU在1970年代末期形成了Intel的86系和Motorola的68系CPU。

两强争霸,都想扩大市场占有率树立事实上的标准,但又受限于产能不足。于是找到日本厂家,日本厂家以许可证方式生产与米国兼容的CPU,作为第二供货方,这是日本CPU的起步。

日立承接的是Motorola的MC680X和MC68000,日立生产的MC68就叫HD68。NEC则承接Intel的86,形成V20、V30系的 CPU。日本没有与国际接轨,融入国际社会的心思,喜欢自定标准,自搞一套。当80年代初IBM PC风靡全球时,日本自搞了一个PC98。手机也是自成系统。这以中国不同,在中国与国际接轨是政治正确,雄心壮志早被阉了,想自立体系想都不敢想。当然,PC98最终没有抵抗住IBM PC,在几年前还是最终放弃了,但毕竟日本曾经奋斗过,很多事也是谋事在人成事在天,但奋斗的心不能死。

1984 年,作为日本国策的TRON项目开始实施。TRON项目是集计算机OS和CPU设计一体的大型计划。涵盖的目标非常广泛,从实时控制到桌面系统,从工厂自动化到商业应用,无所不包。目的要建立日本独立的计算机软硬件体系。即阻止外国系统对日本的渗透,又想在世界中树立日本的标准。

1984 年也是中国关键的一年。是年年底,通过了城市改革的决议,拉开了城市改革的序幕。这一年还是“鬼门关”,无论项目是否成功,这一年都必须下马停止。时隔 20年后,许多项目才重新开始,或者再也没有可能开始了。这一年大概可以称为中国的“自宫年”。中国需要集中精力发展经济,改善生活。我们的目的是喝水,再也不能干挖井的蠢事了,这些“奇技淫巧”还是算了吧。

作为TRON项目的结果。1987年,日立发布了H8/H16/H32三款CPU,分别是8位/16位/32位。其时日本产品在欧美市场上咄咄逼人,即便作为86和68系 CPU的第二供货商,也有喧宾夺主侵夺米国原厂商市场份额的势头。这些引发了日美贸易摩擦,米国政府向日本政府施加压力,小胳膊毕竟没有扭过大腿。 TRON计划被大幅度缩小,只限定在实时嵌入式领域。Intel和Motorola分别向NEC和日立提起诉讼,禁止它们再生产销售与86和68系兼容的芯片。这些诉讼最后都在庭外和解了,作为和解的结果,H16由于酷似Motorola的68被放弃了,H32由于TRON项目缩小也被放弃了。H8虽然也大量承袭了68的设计,但总算被保留了下来。

日本历史上有过多次失败,但雄心壮志从来就没有熄灭过。虽然有时必须认命,

被外力宫去大半,但雄心不死,还有重生的机会。中国则精神上萎靡了,不用别人动手,就自宫了。即便有人劝说中国能行,但始终坚挺不起来。

日立的H8虽然是8位的CISC设计,随着时代发展,逐步扩展到16位和32位。并在此基础上发展了RISC型的SuperH系列 SH1/SH2/SH3/SH4。SH1/SH2定位于实时控制领域,SH3/SH4则定位于信息处理。NEC则发展了自己独自的78和V850系列。

这些CPU都定位于嵌入式领域,避免与米国直接冲突。嵌入式领域市场庞大并被细分,手机、游戏机、汽车、各种家用电器、各种生产装置……,这些领域都是日本的强势领域。这些东西和我们日常生活密切相关,但我们往往觉察不到它们里面计算机的存在。在嵌入式领域对CPU的性能要求并不很高,很难出现赢家通吃的局面。日本CPU的最高主频目前还没有超过1GHz,NEC的V850的一款CPU号称是世界上主频最低的32位RISC CPU,只有20MHz,但却有着极低的功耗。嵌入式领域性能不是主要因素,有自己的特色就可以在市场中找到定位点。

嵌入式应用需要丰富的接口,光CPU远远不够。日本的CPU一大特点是集成了丰富的接口,A/D、D/A、PWM、定时器/技数器、各种通信协议、图象声音的编解码器、Flash、SRAM甚至还集成了大容量的DRAM。包含接口的不同,形成一个完整的系列,根据具体应用的需要选择具体的CPU型号。往往一个单片就可以构造一个完整的应用系统。

软件系统虽然TRON被大幅度缩小,成了uITRON,TRON前面的uI分别代表微型和工业的意思。小有小的好处,正好适应这种资源严重受限的嵌入式应用环境。WindowsCE和 Linux则庞大笨重,于是uITRON占了日本近一半的市场份额。uITRON只是一个标准,并不是具体实现,具体的软件有好几种,其中也有免费开源的 uITRON。当然这些日本CPU也能运行Windows CE和Linux。据说SH3是世界上第一种运行WindowsCE的CPU。

软件和硬件系统的结合,使日本的CPU在日本市场上成为主导,外国CPU占的市场份额很小。这与中国不同,中国则是被八国联军占领了。日本的出版教育界也功不可没。有名的CQ出版社出版的电子杂志详细介绍这些本国CPU用法和特点,还免费赠送这些CPU的实验板。还免费提供这些CPU的软核,在FPGA中实现自己的系统,用于研究和教学。学生时代的教育就使用本国的CPU,工作后自然而然就使用本国的CPU。中国的教育原来是Z80,后来是8051,于是学生毕业后就用这些外国CPU。

国家战略、科研、教育、产业相结合,使日本 CPU产业从无到有,由弱到强,独树一帜。中国这四个方面相互脱节,国家战略是建立市场经济体制,不惜摧毁自己独立的科研和产业体系。科研面是单打独斗,在整个国家当作点缀存在。教育是面向世界,为留学和外企培养人才。产业则基本被卖掉了,外资企业挑大梁。这样的环境中,发展自己的CPU产业何等艰难。聪明如陈进的,一开始就认为事不可为,打磨芯片交差,科研经费落袋。方舟则是在中途醒悟,还是搞房地产来钱快。就剩下愚公龙芯继续奋斗,但不知道红旗能打多久。