Pmon显卡支持

 因为显卡bios中的指令是x86的,因此龙芯执行显卡bios中的程序初始化显卡采用的集成一个x86模拟器,解释运行的方法。
有两种模拟,一种是模拟int10(从freex86移植过来的),一种是直接模拟.
当模拟int10时
INCLUDES=   -I. -I${S}/include -I./machine -I${S} /
        -I${S}/x86emu/int10/x86emu/include -I${S}/x86emu/int10/x86emu/src/x86emu/x86emu/ /
        -I${S}/sys/arch/${MACHINE}/include -I${S}/sys /
        -I${TARGET} -I${COMPILEDIR} -nostdinc
否则
INCLUDES=   -I. -I${S}/include -I./machine -I${S} /
        -I${S}/x86emu/src/x86emu -I${S}/x86emu/src /
        -I${S}/sys/arch/${MACHINE}/include -I${S}/sys /
        -I${TARGET} -I${COMPILEDIR} -nostdinc
X86模拟器包括几个部分:
内存
系统中断向量,0地址模拟
Sys bios模拟
显存地址0xa0000模拟
显卡bios地址0xc0000模拟
寄存器
Cpu 寄存器的模拟
指令模拟

vga_bios_init的流程
1)分配xf86Int10InfoPtr
xf86Int10InfoPtr用来存储模拟环境
typedef struct {
    int entityIndex;
    int scrnIndex;
    pointer cpuRegs;
    CARD16  BIOSseg;
    CARD16  inb40time;
    pointer private;
    struct _int10Mem* mem;
    int num;
    int ax;
    int bx;
    int cx;
    int dx;
    int si;
    int di;
    int es;
    int bp;
    int flags;
    int stackseg;
    struct pci_device *pdev;
} xf86Int10InfoRec, *xf86Int10InfoPtr;
2)xf86Int10ExecSetup函数设置
X86EMU_setupMemFuncs
X86EMU_setupPioFuncs
X86EMU_setupIntrFuncs

pInt->cpuRegs = &M;
    M.mem_base = 0;
M.mem_size = 1024*1024 + 1024;
for (i=0;i<256;i++)
        intFuncs[i] = x86emu_do_int;
X86EMU_setupIntrFuncs(intFuncs);
void X86EMU_setupIntrFuncs(
        X86EMU_intrFuncs funcs[])
{
    int i;
   
        for (i=0; i < 256; i++)
                _X86EMU_intrTab[i] = NULL;
        if (funcs) {
                for (i = 0; i < 256; i++)
                        _X86EMU_intrTab[i] = funcs[i];
                }
}

void x86emuOp_int_IMM(u8 X86EMU_UNUSED(op1))
{
    u8 intnum;

    START_OF_INSTR();
    DECODE_PRINTF("INT/t");
    intnum = fetch_byte_imm();
    DECODE_PRINTF2("%x/n", intnum);
    TRACE_AND_STEP();
    if (_X86EMU_intrTab[intnum]) {
                (*_X86EMU_intrTab[intnum])(intnum);
    } else {
        push_word((u16)M.x86.R_FLG);
        CLEAR_FLAG(F_IF);
        CLEAR_FLAG(F_TF);
        push_word(M.x86.R_CS);
        M.x86.R_CS = mem_access_word(intnum * 4 + 2);
        push_word(M.x86.R_IP);
        M.x86.R_IP = mem_access_word(intnum * 4);
    }
    DECODE_CLEAR_SEGOVR();
    END_OF_INSTR();
}

3)几个关键的内存变量的分配

typedef struct {
    int shift;
    int entries;
    void* base;
    void* vRam;
    void* sysMem;
    char* alloc;
} genericInt10Priv;

这几个变量就是pInt-> private->base,vRam,sysMem。

#define INTPriv(x) ((genericInt10Priv*)x->private)
#        define vgaram_base 0xb00a0000

pInt->mem = &genericMem;
    pInt->private = (pointer)calloc(1,sizeof(genericInt10Priv));
    pInt->scrnIndex = 0; /* screen */
    base = INTPriv(pInt)->base = 0x80000000+memorysize-0x100000;
/*
     * we need to map video RAM MMIO as some chipsets map mmio
     * registers into this range.
     */
INTPriv(pInt)->vRam=vgaram_base;

    if (!sysMem) {
        sysMem = malloc(BIOS_SIZE);
        setup_system_bios(sysMem);
    }
INTPriv(pInt)->sysMem = sysMem;
vbiosMem = (char *)base + V_BIOS;

这三个变量的作用
INTPriv(pInt)->base设置在内存的顶端,0xC0000以上区域用来存放显卡的rom程序。


vgaram_base是显卡的Framebuffer的地址。
Bios在扫描pci设备的时候建立了设备链,每个桥上的pci设备用单向链表parent->bridge.child链接起来,而设备上的内存被连接到&pd->parent->bridge.memspace,io被链接到&pd->parent->bridge.memspace。
在后面调用_pci_setup_windows分配pci设备内存的时候,沿dev->bridge.memspace和dev->bridge.iospace分配内存、io并脱链。也就是说dev->bridge.memspace和dev->bridge.iospace记录的是期待分配内存的pci内存窗口,当分配内存后就从dev->bridge.memspace和dev->bridge.iospace中脱链。
我们重点关心的是跟显卡相关的内存分配。
for (pm = dev->bridge.memspace; pm != NULL; pm = next) {

        pd = pm->device;
        if (PCI_ISCLASS(pd->pa.pa_class, PCI_CLASS_DISPLAY, PCI_SUBCLASS_DISPLAY_VGA))
                vga_dev = pd;
#if 0
        /*
         * If this is the first VGA card we find, set the BIOS rom
         * at address c0000 if PCI base address is 0x00000000.
         */
        if (pm->reg == PCI_MAPREG_ROM && !have_vga &&
            dev->bridge.secbus->minpcimemaddr == 0 &&
            (PCI_ISCLASS(pd->pa.pa_class,
                PCI_CLASS_PREHISTORIC, PCI_SUBCLASS_PREHISTORIC_VGA) ||
            PCI_ISCLASS(pd->pa.pa_class,
                PCI_CLASS_DISPLAY, PCI_SUBCLASS_DISPLAY_VGA))) {
                have_vga = pd->pa.pa_tag;
                pm->address = 0x000c0000;        /* XXX PCI MEM @ 0x000!!! */
        }
#endif
        if (pm->reg == PCI_MAPREG_ROM) {
            /* expansion rom */
                if (_pciverbose >= 2)
                    _pci_tagprintf (pd->pa.pa_tag, "exp @%p, %d bytes/n",
                        pm->address, pm->size);
            _pci_conf_write(pd->pa.pa_tag, pm->reg, pm->address | PCI_MAPREG_TYPE_ROM);
        }
        next = pm->next;
        dev->bridge.memspace = next;
        pfree(pm);
    }
可见只是设置了全局变量vga_dev,并没有其他的特别操作。ROM在x86分配的地址为0xc0000,在mips中没有特别的要求。

显卡模拟下面的代码将显卡程序rom中的内容拷贝到vbiosMem中,以后解析运行的程序都从vbiosMem中读取。

#define V_RAM 0xA0000
#define VRAM_SIZE 0x20000
#define SYS_SIZE 0x100000
#define SYS_BIOS 0xF0000
#define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE)))
#define V_ADDR_WW(addr,val) /
        if(VRAM(addr)) /
            MMIO_OUT16((CARD16*)VRAM_BASE,VRAM_ADDR(addr),val); /
        else /
            stw_u(val,(pointer)(V_ADDR(addr)));
#define SYS(addr) ((addr) >= SYS_BIOS)
#define V_ADDR(addr) /
          (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - SYS_BIOS) /
           : ((char*)(INTPriv(pInt)->base) + addr))
从上面的定义我们可以看出几块内存的影射关系。
4)初始化工作
vga_bios_init是整个初始化的开始,在tgt_devconfig处被调用。

模拟过程中定义了好多的变量和函数。
在windows中采用debug命令
Debug
-u f000:f065
F000:F065 CF            IRET
在bios的模拟中不可避免的要采用中断模拟,这是因为bios采用bios软中断来调用bios的系统调用。
要模拟和显卡相关的bios的系统调用。
Xf86int10.c 因为bios video的中断号为0x10,因此这个文件就是用来模拟显卡的bios的。
Vga_bios_init>setup_int_vect>:
void
setup_int_vect(xf86Int10InfoPtr pInt)
{
    int i;
    printf("in setup_int_vect!");
    /* let the int vects point to the SYS_BIOS seg */
    for (i = 0; i < 0x80; i++) {
        MEM_WW(pInt, i << 2, 0);
        MEM_WW(pInt, (i << 2) + 2, SYS_BIOS >> 4);
    }

    reset_int_vect(pInt);
setup_int_vect
设置中断向量 8086实模式下的中断向量的地址在0地址处,每个中断占四个字节。
setup_int_vect将所有中断向量的地址指向0xF0000:0,即0xF0000。
0x1000
设置中断向量0x1d,0x10,0x42,0x6d。
0x10指向VideoParms
其他指向0xff065
/*
     * This table is normally located at 0xF000:0xF0A4.  However, int 0x42,
     * function 0 (Mode Set) expects it (or a copy) somewhere in the bottom
     * 64kB.  Note that because this data doesn't survive POST, int 0x42 should
     * only be used during EGA/VGA BIOS initialisation.
     */
Debug
-d F000:F0A4
在windows中采用debug命令
Debug
-u f000:f065
F000:F065 CF            IRET
Vga_bios_init>setup_int_vect>:

/* font tables default location (int 1F) */
MEM_WW(pInt,0x1f<<2,0xfa6e);
    /* int 11 default location (Get Equipment Configuration) */
    MEM_WW(pInt, 0x11 << 2, 0xf84d);
    /* int 12 default location (Get Conventional Memory Size) */
    MEM_WW(pInt, 0x12 << 2, 0xf841);
    /* int 15 default location (I/O System Extensions) */
    MEM_WW(pInt, 0x15 << 2, 0xf859);
    /* int 1A default location (RTC, PCI and others) */
    MEM_WW(pInt, 0x1a << 2, 0xff6e);
    /* int 05 default location (Bound Exceeded) */
    MEM_WW(pInt, 0x05 << 2, 0xff54);
    /* int 08 default location (Double Fault) */
    MEM_WW(pInt, 0x08 << 2, 0xfea5);
    /* int 13 default location (Disk) */
    MEM_WW(pInt, 0x13 << 2, 0xec59);
    /* int 0E default location (Page Fault) */
    MEM_WW(pInt, 0x0e << 2, 0xef57);
    /* int 17 default location (Parallel Port) */
MEM_WW(pInt, 0x17 << 2, 0xefd2);
    /* fdd table default location (int 1e) */
    MEM_WW(pInt, 0x1e << 2, 0xefc7);
    MEM_WB(pInt, 0x0410, 0x67);
    MEM_WB(pInt, 0x0411, 0x42);
    printf("done!");
    /* XXX Perhaps setup more of the BDA here.  See also int42(0x00). */
}
40:10处的含义:
  10h    WORD    Installed hardware:
             bits 15-14: number of parallel devices
             bit     13: [Conv] Internal modem
             bit     12: reserved
             bits 11- 9: number of serial devices
             bit      8: reserved
             bits  7- 6: number of diskette drives minus one
             bits  5- 4: Initial video mode:
                     00b = EGA,VGA,PGA
                     01b = 40 x 25 color
                     10b = 80 x 25 color
                     11b = 80 x 25 mono
             bit      3: reserved
             bit      2: [PS] =1 if pointing device
                 [non-PS] reserved
             bit      1: =1 if math co-processor
             bit      0: =1 if diskette available for boot

vga_bios_init>:
  printf("set return trap/n");
    set_return_trap(pInt);
vga_bios_init> set_return_trap>:
void
set_return_trap(xf86Int10InfoPtr pInt)
{
    /*
     * Here we set the exit condition:  We return when we encounter
     * 'hlt' (=0xf4), which we locate at address 0x600 in x86 memory.
     */
    MEM_WB(pInt, 0x0600, 0xf4);

    /*
     * Allocate a segment for the stack
     */
    pInt->stackseg=0x1000;
}

define vgaram_base 0xb00a0000
INTPriv(pInt)->vRam=vgaram_base;

int
setup_system_bios(void *base_addr)
{
    char *base = (char *) base_addr;
    /*
     * we trap the "industry standard entry points" to the BIOS
     * and all other locations by filling them with "hlt"
     * TODO: implement hlt-handler for these
     */
    memset(base, 0xf4, 0x10000);

    /* int11 handler: push ds; push 0040; pop ds; mov ax,[0010]; pop ds; iret16
     */
    *(base + 0xf84d + 0) = 0x1e;
    *(base + 0xf84d + 1) = 0x68;
    *(base + 0xf84d + 2) = 0x40;
    *(base + 0xf84d + 3) = 0x00;
    *(base + 0xf84d + 4) = 0x1f;
    *(base + 0xf84d + 5) = 0xa1;
    *(base + 0xf84d + 6) = 0x10;
    *(base + 0xf84d + 7) = 0x00;
    *(base + 0xf84d + 8) = 0x1f;
    *(base + 0xf84d + 9) =  0xcf;

    /* set bios date */
    strcpy(base + 0x0FFF5, "06/11/99");
    /* set up eisa ident string */
    strcpy(base + 0x0FFD9, "PCI_ISA");
    /* write system model id for IBM-AT */
    *((unsigned char *)(base + 0x0FFFE)) = 0xfc;

    return 1;
}

base = INTPriv(pInt)->base = 0x80000000+memorysize-0x100000;
#define V_BIOS 0xC0000
vbiosMem = (char *)base + V_BIOS;
            // zhb if (PCI_VENDOR(pdev->pa.pa_id) == 0x1002 && pdev->pa.pa_device == 0x4750)
            if (PCI_VENDOR(pdev->pa.pa_id) == 0x1002 && PCI_PRODUCT(pdev->pa.pa_id) == 0x4750) {
                    printf("yes/n");                    
                    MEM_WW(pInt,0xc015e,0x4750);
            }
#define V_RAM 0xA0000
#define VRAM_SIZE 0x20000
#define SYS_SIZE 0x100000
#define SYS_BIOS 0xF0000
#define VRAM(addr) ((addr >= V_RAM) && (addr < (V_RAM + VRAM_SIZE)))
#define V_ADDR_WW(addr,val) /
        if(VRAM(addr)) /
            MMIO_OUT16((CARD16*)VRAM_BASE,VRAM_ADDR(addr),val); /
        else /
            stw_u(val,(pointer)(V_ADDR(addr)));
#define SYS(addr) ((addr) >= SYS_BIOS)
#define V_ADDR(addr) /
          (SYS(addr) ? ((char*)INTPriv(pInt)->sysMem) + (addr - SYS_BIOS) /
           : ((char*)(INTPriv(pInt)->base) + addr))

base = INTPriv(pInt)->base = 0x80000000+memorysize-0x100000;

    /*
     * we need to map video RAM MMIO as some chipsets map mmio
     * registers into this range.
     */
    INTPriv(pInt)->vRam=vgaram_base;
    if (!sysMem) {
        sysMem = malloc(BIOS_SIZE);
        setup_system_bios(sysMem);
    }
    INTPriv(pInt)->sysMem = sysMem;
    printf("memorysize=%lx,base=%lx,sysMem=%lx,vram=%lx/n",memorysize,INTPriv(pInt)->base,sysMem,INTPriv(pInt)->vRam);
    printf("set up int/n");
    setup_int_vect(pInt);
    printf("set return trap/n");
    set_return_trap(pInt);

vbiosMem = (char *)base + V_BIOS;
….

    pInt->BIOSseg = V_BIOS >> 4;
    pInt->num = 0xe6;
    printf("lock vga/n");
    LockLegacyVGA(screen, &vga);
    printf("starting bios emu.../n");
    //X86EMU_trace_on();
    printf("ax=%lx,bx=%lx,cx=%lx,dx=%lx/n",pInt->ax,pInt->bx,pInt->cx,pInt->dx);
    xf86ExecX86int10(pInt);
    printf("bios emu done/n");


void
xf86ExecX86int10(xf86Int10InfoPtr pInt)
{
    int sig = setup_int(pInt);

    if (sig < 0)
        return;

    if (int_handler(pInt)) {
        X86EMU_exec();
    }

    finish_int(pInt, sig);
}

int
setup_int(xf86Int10InfoPtr pInt)
{
    if (pInt != Int10Current) {
        if (!MapCurrentInt10(pInt))
            return -1;
        Int10Current = pInt;
    }
    X86_EAX = (CARD32) pInt->ax;
    X86_EBX = (CARD32) pInt->bx;
    X86_ECX = (CARD32) pInt->cx;
    X86_EDX = (CARD32) pInt->dx;
    X86_ESI = (CARD32) pInt->si;
    X86_EDI = (CARD32) pInt->di;
    X86_EBP = (CARD32) pInt->bp;
    X86_ESP = 0x1000; X86_SS = pInt->stackseg >> 4;
    X86_EIP = 0x0600; X86_CS = 0x0;        /* address of 'hlt' */
    X86_DS = 0x40;                        /* standard pc ds */
    X86_ES = pInt->es;
    X86_FS = 0;
    X86_GS = 0;
    X86_EFLAGS = X86_IF_MASK | X86_IOPL_MASK;

    return 0;
}
int
int_handler(xf86Int10InfoPtr pInt)
{
    int num = pInt->num;
    int ret = 0;

    printf("int_handler called,int=%x/n",num);

    switch (num) {
#ifndef _PC
    case 0x10:
    case 0x42:
    case 0x6D:
        if (getIntVect(pInt, num) == I_S_DEFAULT_INT_VECT) {
            printf("default int10 called,intno=%x/n",num);
            ret = int42_handler(pInt);
        }
        break;
    case 0x15:
        ret = int15_handler(pInt);
        break;
#endif
    case 0x1A:
        ret = int1A_handler(pInt);
        break;
    case 0xe6:
        ret = intE6_handler(pInt);
        break;
    default:
        break;
    }

    if (!ret) {
        ret = run_bios_int(num, pInt);
        //if(num==0x10) X86EMU_trace_on();
        printf("run_bios_int,intno=%x,ret=%x/n",num,ret);
    }

    if (!ret) {
        printf( "Halting on int 0x%2.2x!/n", num);
        dump_registers(pInt);
        stack_trace(pInt);
    }

    return ret;
}

/*
* handle initialization
*/
static int
intE6_handler(xf86Int10InfoPtr pInt)
{
    struct pci_device *pdev;

    if ((pdev = pInt->pdev))
        X86_AX = (pdev->pa.pa_bus << 8) | (pdev->pa.pa_device << 3) | (pdev->pa.pa_function & 0x7);
    pushw(pInt, X86_CS);
    pushw(pInt, X86_IP);
    X86_CS = pInt->BIOSseg;
    X86_EIP = 0x0003;
    X86_ES = 0;                  /* standard pc es */
    return 1;
}

可以看出当handler返回1的时候,表示需要模拟器来模拟。
pushw(pInt, X86_CS);
    pushw(pInt, X86_IP);
这个操作来模仿call的执行。
最先执行的代码是0xC000:3
C000:0这个地址应该影射到显卡的bios的rom地址。

PMON终端显示
pmon的输入输出分析:
//pmon/fs/termio.c

static FileSystem termfs =
{
    "tty", FS_TTY,
    term_open,
    term_read,
    term_write,
    NULL,
    term_close,
    term_ioctl
};

static void init_fs __P((void)) __attribute__ ((constructor));

static void
   init_fs()
{
    //SBD_DISPLAY ("DEVI", CHKPNT_DEVI);
    SBD_DISPLAY ("TTYI", CHKPNT_DEVI);
    devinit ();

    /*
     * Install terminal based file system.
     */
    filefs_init(&termfs);

    /*
     * Create the standard i/o files the proper way
     */
    _file[0].valid = 1;
    _file[0].fs = &termfs;
    _file[1].valid = 1;
    _file[1].fs = &termfs;
    _file[2].valid = 1;
    _file[2].fs = &termfs;
    _file[3].valid = 1;
    _file[3].fs = &termfs;
    _file[4].valid = 1;
    _file[4].fs = &termfs;
    term_open(0, "/dev/tty0", 0, 0); /* stdin */
    term_open(1, "/dev/tty0", 0, 0); /* stdout */
    term_open(2, "/dev/tty0", 0, 0); /* stderr */
    term_open(3, "/dev/tty1", 0, 0); /* kbdin */
    term_open(4, "/dev/tty1", 0, 0); /* vgaout */
}

Bonito/Bonito/tgt_machdep.c
ConfigEntry ConfigTable[] =
{
     { (char *)COM3_BASE_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ },
/*   { (char *)COM1_BASE_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ },
     { (char *)COM2_BASE_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ }, */
#if NMOD_VGACON >0
    { (char *)1, 0, vgaterm, 256, CONS_BAUD, NS16550HZ },
#endif
    { 0 }
};
init_net>tgt_devconfig>kbd_initialize
kbd_available=1

pmon选择是键盘还是串口输入是依靠宏来实现的:
#define stdin   (kbd_available?(&_iob[3]):(&_iob[0]))
#define stdout  (vga_available?(&_iob[4]):(&_iob[1]))
#define stderr  (vga_available?(&_iob[4]):(&_iob[2]))
#define kbdin   (&_iob[3])
#define vgaout  (&_iob[4])

//----------------------------------------------------------------------------
串口Bonito/include/bonito.h
#define COM1_BASE_ADDR  0xbfd003f8
#define COM2_BASE_ADDR  0xbfd002f8
#define COM3_BASE_ADDR  0xbff003f8
//#define       NS16550HZ       1843200
#define NS16550HZ       3686400

用那个串口在汇编中取决于
LEAF(initserial)
#       la      v0, COM1_BASE_ADDR
        la      v0, COM3_BASE_ADD
...
END(initserial)

LEAF(tgt_putchar)
#       la      v0, COM1_BASE_ADDR
        la      v0, COM3_BASE_ADDR
...
END(tgt_putchar)

Bonito/Bonito/tgt_machdep.c
ConfigEntry ConfigTable[] =
{
     { (char *)COM3_BASE_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ },
/*   { (char *)COM1_BASE_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ },
     { (char *)COM2_BASE_ADDR, 0, ns16550, 256, CONS_BAUD, NS16550HZ }, */
#if NMOD_VGACON >0
    { (char *)1, 0, vgaterm, 256, CONS_BAUD, NS16550HZ },
#endif
    { 0 }
};


int
vgaterm (int op, struct DevEntry *dev, unsigned long param, int data)
{
    unsigned char code;
    switch (op) {
        case OP_INIT:
        case OP_XBAUD:
        case OP_BAUD:
            return 0;

        case OP_TXRDY:
            return 1;

        case OP_TX:
            if(vga_available)
                write_at_cursor(data&0xff);
            break;

        case OP_RXRDY:
            if(kbd_available)
                return kbd_code?1:0;
            else
                return 0;

        case OP_RX:
            if(kbd_available){
                code = kbd_code;
                kbd_code = 0;
                return code;
            }else{
                return 0;
            }

        case OP_RXSTOP:
            break;
    }
    return 0;
}

int write_at_cursor(char val)
{
//  int pos_row,pos_col;
    unsigned char hi,lo;
    unsigned short cursor;

    if(val == '/n') {
        vga_set_enter();
        return 0;
    }
    if(val == '/b') {
        backspace_cursor();
        return 0;
    }
    if(val == '/r') {
        return 0;
    }
    hi=get_crt_reg(index_cursor_pos_hi);
    lo=get_crt_reg(index_cursor_pos_lo);
    cursor=(hi<<8)|lo;
//  printf("cursor hi =0x%x,lo =0x%x,cursor=0x%x /n",hi,lo,cursor);
    *(unsigned char *)(vgabh+2*cursor)=val;
    *(unsigned char *)(vgabh+2*cursor+1)=0x07;
    if (cursor==rowcount*colcount-1)    {
        vga_roll();
        cursor-=colcount;
    }
    cursor=cursor+1;
    set_crt_reg(index_cursor_pos_lo,(cursor&0xff));
    set_crt_reg(index_cursor_pos_hi,(cursor>>8));
//  printf("write value=0x%x done! cursor=0x%x /n",val,cursor);
    return 0;
}

 

芯片应该只管指令集中每个指令的实现
不应管操作系统如何运行。

1、龙新至少32位,现在流行64位了。因为汉字站双字节:32位,便于处理汉字。
2、扩充启动程序,采取小字库方案,实现纯中文电脑。这个应该是主板的任务
3、加快速度,设计并行方案与并行指令,非时间戳方式。真正意义上的并行

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值