start.S 中的函数讲解

本文讲解那些在 "start.S 文件详解" 一文中没有讲到的各函数的内容,放在一边讲是为了方便读者与"start.S 文件详解" 一文比对着看,那篇文章实在太长了。

CPU_TLBClear

/*
 *  Clear the TLB. Normally called from start.S.
 */
#if __mips64
#define MTC0 dmtc0
#else 
#define MTC0 mtc0
#endif
LEAF(CPU_TLBClear)
    li    a3, 0            # First TLB index.

    li    a2, PG_SIZE_4K        // here it is 0x00000000
    MTC0   a2, COP_0_TLB_PG_MASK   // Pagemask's bits 24~13 are 0, then it represents 4K page

1:
    MTC0   zero, COP_0_TLB_HI    # Clear entry high.
    MTC0   zero, COP_0_TLB_LO0    # Clear entry low0.
    MTC0   zero, COP_0_TLB_LO1    # Clear entry low1.

    mtc0    a3, COP_0_TLB_INDEX    # Set the index.
    addiu    a3, 1
    li    a2, 64
    nop
    nop
    tlbwi                # Write the TLB at index

    bne    a3, a2, 1b        // do a repeat body, clear all TLB entries, that means it will execute 64 times
    nop

    jr    ra
    nop
END(CPU_TLBClear)

CPU_TLBInit

/*
 *  Set up the TLB. Normally called from start.S.
 *    All operation is due to the structure of EntryHi, EntryLo0, EntryLo1, so understand them first
 */
LEAF(CPU_TLBInit)
    li    a3, 0            # First TLB index.

    li    a2, PG_SIZE_16M                // here it is 0x01ffe000, its bits of 24~13 are all 1
    MTC0   a2, COP_0_TLB_PG_MASK   # All pages are 16Mb.

1:
    and    a2, a0, PG_SVPN                // PG_SVPN is 0xfffff000, a0's initial value is 0xc0000000
    MTC0   a2, COP_0_TLB_HI            // Set up entry high

    move    a2, a0
    srl    a2, a0, PG_SHIFT            // PG_SHIFT is 6. shift 6 bits right on a0
    and    a2, a2, PG_FRAME            // PG_FRAME is 0x3fffffc0, the most two bits are 0, because we only need 1G memory mapping
    ori    a2, PG_IOPAGE                // PG_IOPAGE is 0x00000017
    MTC0   a2, COP_0_TLB_LO0    # Set up entry low0.
    addu    a2, (0x01000000 >> PG_SHIFT) // 0x00020000, 128K interval??? 
    MTC0   a2, COP_0_TLB_LO1    # Set up entry low1.

    mtc0    a3, COP_0_TLB_INDEX    # Set the index.
    addiu    a3, 1
    li    a2, 0x02000000        // 32M
    subu    a1, a2                // a1's initial value is 0x40000000, that is 1G memory
    nop
    tlbwi                # Write the TLB

    bgtz    a1, 1b        // if a1>0 then goto 1b, totally it will execute 32 times
    addu    a0, a2        // Step address 32Mb.
                        // the first entry is EntryHi: 0xc0000000, EntryLo0: 0x03000017, EntryLo1: 0x03020017, maybe bug?

    jr    ra
    nop
END(CPU_TLBInit)

stringserial

LEAF(stringserial)
    move    a2, ra
    addu    a1, a0, s0    // a0 is the address of a string
    lbu    a0, 0(a1)        // load one byte by one byte
1:
    beqz    a0, 2f        // meet the char '\0', then go back 
    nop
    bal    tgt_putchar
    addiu    a1, 1        // a1 is the pointer to one char in the string
    b    1b
    lbu    a0, 0(a1)

2:
    j    a2
    nop
END(stringserial)

outstring

LEAF(outstring)
    move    a2, ra
    move    a1, a0
    lbu    a0, 0(a1)
1:
    beqz    a0, 2f
    nop
    bal    tgt_putchar
    addiu    a1, 1
    b    1b
    lbu    a0, 0(a1)

2:
    j    a2
    nop
END(outstring)

hexserial

LEAF(hexserial)
    move    a2, ra
    move    a1, a0
    li    a3, 7
1:
    rol    a0, a1, 4
    move    a1, a0
    and    a0, 0xf
    la    v0, hexchar
    addu    v0, s0
    addu    v0, a0
    bal    tgt_putchar
    lbu    a0, 0(v0)

    bnez    a3, 1b
    addu    a3, -1

    j    a2
    nop
END(hexserial)

tgt_putchar

LEAF(tgt_putchar)
    la    v0, COM1_BASE_ADDR            // here it is 0xbfd003f8
1:
    lbu    v1, NSREG(NS16550_LSR)(v0)
    and    v1, LSR_TXRDY
    beqz    v1, 1b
    nop

    sb    a0, NSREG(NS16550_DATA)(v0)        // store byte, store the char wanted to print to the virtual address byte, then the serial device can process it correctly

#ifdef HAVE_NB_SERIAL
    move    v1, v0
    la    v0, COM3_BASE_ADDR
    bne    v0, v1, 1b
    nop
#endif

    j    ra
    nop    
END(tgt_putchar)

initserial

LEAF(initserial)
#ifdef HAVE_NB_SERIAL
    la    v0, COM3_BASE_ADDR
1:
    li    v1, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4
    sb    v1, NSREG(NS16550_FIFO)(v0)
    li    v1, CFCR_DLAB
    sb    v1, NSREG(NS16550_CFCR)(v0)
     li    v1, NS16550HZ/(16*CONS_BAUD)
    sb    v1, NSREG(NS16550_DATA)(v0)
    srl    v1, 8
    sb    v1, NSREG(NS16550_IER)(v0)
    li    v1, CFCR_8BITS
    sb    v1, NSREG(NS16550_CFCR)(v0)
    li    v1, MCR_DTR|MCR_RTS
    sb    v1, NSREG(NS16550_MCR)(v0)
    li    v1, 0x0
    sb    v1, NSREG(NS16550_IER)(v0)
#endif
    la    v0, COM1_BASE_ADDR
1:
    li    v1, FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_4
    sb    v1, NSREG(NS16550_FIFO)(v0)
    li    v1, CFCR_DLAB
    sb    v1, NSREG(NS16550_CFCR)(v0)
     li    v1, NS16550HZ/2/(16*CONS_BAUD)
    sb    v1, NSREG(NS16550_DATA)(v0)
    srl    v1, 8
    sb    v1, NSREG(NS16550_IER)(v0)
    li    v1, CFCR_8BITS
    sb    v1, NSREG(NS16550_CFCR)(v0)
    li    v1, MCR_DTR|MCR_RTS
    sb    v1, NSREG(NS16550_MCR)(v0)
    li    v1, 0x0
    sb    v1, NSREG(NS16550_IER)(v0)
    nop

    j    ra
    nop
END(initserial)

godson2_cache_init

LEAF(godson2_cache_init)
####part 2####
cache_detect_2way:
    mfc0    t4, CP0_CONFIG
    andi    t5, t4, 0x0e00
    srl    t5, t5, 9
    andi    t6, t4, 0x01c0
    srl    t6, t6, 6
    addiu    t6, t6, 11
    addiu    t5, t5, 11
    addiu    t4, $0, 1
    sllv    t6, t4, t6
    srl    t6,1
    sllv    t5, t4, t5
    srl    t5,1
    addiu    t7, $0, 2
####part 3####
    lui    a0, 0x8000
    addu    a1, $0, t5
    addu    a2, $0, t6
cache_init_d2way:
#a0=0x80000000, a1=icache_size, a2=dcache_size
#a3, v0 and v1 used as local registers
    mtc0    $0, CP0_TAGHI
    addu    v0, $0, a0
    addu    v1, a0, a2
1:    slt    a3, v0, v1
    beq    a3, $0, 1f
    nop
    mtc0    $0, CP0_TAGLO
    cache    Index_Store_Tag_D, 0x0(v0)
    mtc0    $0, CP0_TAGLO
    cache    Index_Store_Tag_D, 0x1(v0)
    mtc0    $0, CP0_TAGLO
    cache   Index_Store_Tag_D, 0x2(v0)
    mtc0    $0, CP0_TAGLO
    cache   Index_Store_Tag_D, 0x3(v0)
    beq    $0, $0, 1b
    addiu    v0, v0, 0x20

#if 1
1:
cache_init_l24way:
        mtc0    $0, CP0_TAGHI
        addu    v0, $0, a0
        addu    v1, a0, 128*1024
1:      slt     a3, v0, v1
        beq     a3, $0, 1f
        nop
        mtc0    $0, CP0_TAGLO
        cache   Index_Store_Tag_S, 0x0(v0)
        mtc0    $0, CP0_TAGLO
        cache   Index_Store_Tag_S, 0x1(v0)
        mtc0    $0, CP0_TAGLO
        cache   Index_Store_Tag_S, 0x2(v0)
        mtc0    $0, CP0_TAGLO
        cache   Index_Store_Tag_S, 0x3(v0)
        beq     $0, $0, 1b
        addiu   v0, v0, 0x20

1:
cache_flush_4way:
    addu    v0, $0, a0
    addu    v1, a0, 128*1024
1:    slt    a3, v0, v1
    beq    a3, $0, 1f
    nop
    cache    Index_Writeback_Inv_S, 0x0(v0)
    cache    Index_Writeback_Inv_S, 0x1(v0)
    cache    Index_Writeback_Inv_S, 0x2(v0)
    cache    Index_Writeback_Inv_S, 0x3(v0)
    beq    $0, $0, 1b
    addiu    v0, v0, 0x20
# endif

1:
cache_flush_i2way:
    addu    v0, $0, a0
    addu    v1, a0, a1
1:    slt    a3, v0, v1
    beq    a3, $0, 1f
    nop
    cache    Index_Invalidate_I, 0x0(v0)
#    cache    Index_Invalidate_I, 0x1(v0)
#    cache    Index_Invalidate_I, 0x2(v0)
#    cache    Index_Invalidate_I, 0x3(v0)
    beq    $0, $0, 1b
    addiu    v0, v0, 0x20
1:
cache_flush_d2way:
    addu    v0, $0, a0
    addu    v1, a0, a2
1:    slt    a3, v0, v1
    beq    a3, $0, 1f
    nop
    cache    Index_Writeback_Inv_D, 0x0(v0)
    cache    Index_Writeback_Inv_D, 0x1(v0)
    cache    Index_Writeback_Inv_D, 0x2(v0)
    cache    Index_Writeback_Inv_D, 0x3(v0)
    beq    $0, $0, 1b
    addiu    v0, v0, 0x20
1:
cache_init_finish:
    nop
    jr    ra
    nop

cache_init_panic:
    TTYDBG("cache init panic\r\n");
1:    b    1b
    nop
    .end    godson2_cache_init

superio_init

LEAF(superio_init)

    PCICONF_WRITEW(PCI_IDSEL_VIA686B,0,4,7);
    /*positive decode*/
    PCICONF_ORB(PCI_IDSEL_VIA686B,0,0x81,0x80);
    PCICONF_WRITEB(PCI_IDSEL_VIA686B,0,0x83,0x80|0x1| 0x8);
    PCICONF_WRITEB(PCI_IDSEL_VIA686B,0,0x85,3);
    /* enable RTC/PS2/KBC */
    PCICONF_WRITEB(PCI_IDSEL_VIA686B,0,0x5A,7);

    SUPERIO_WR(0xe2,E2_S2|E2_S1|E2_EPP|E2_FLOPPY) /*enable serial and floppy */
    SUPERIO_WR(0xe3,0x3f0>>2) /*floppy base address*/
    SUPERIO_WR(0xe6,0x378>>2) /*parallel port*/
    SUPERIO_WR(0xe7,0x3f8>>2) /*set serial port1 base addr 0x3f8*/
    SUPERIO_WR(0xe8,0x2f8>>2) /*set serial port2 base addr 0x2f8*/
    SUPERIO_WR(0xee,0xc0) /* both ports on high speed*/

    PCICONF_WRITEB(PCI_IDSEL_VIA686B,0,0x85,1)
    jr ra
    nop
END(superio_init)
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License