打印

memo移植RT-Thread到stm32f103zet6的方法

[复制链接]
8938|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
stm32boy|  楼主 | 2011-11-14 11:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 stm32boy 于 2011-11-23 14:31 编辑

RT-Thread0.4.0rc1出来了(已符合POSIX源码标准,可移植性更强,Pthread带来的多核并行线程库更加强大,带有浓厚的Linux味道),还带GUI,免费的,比uCOS+uCGUI收费的要划算啊,下了一套源码来,准备搞移植,初步看了看,多任务单线程的RTOS管理,调用上比0.3版本要优化很多了,给stm32f103zet6用正合适。已经移植过的砖家,请多多指教。我也会把移植过程中遇到的要点分享出来,大家共同发扬GUN开源精神。

欢迎砖家和高手围观,并使劲拍砖斧正,集思广益,指点迷津。先谢过了。

偶是用RealView MDK uVision4.22.22 pro来建立工程模板的,IAR也行,有6.21版的,还不太熟悉,就先用MDK for arm的来弄吧,等搞爽了再转IAR来优化。

RT-Thread 0.4.0RC1源码有带stm32f10xx的BSP模板,移植的工程基础已经完成了90%,余下的是要根据具体的STM32芯片型号和板载接口及外扩资源来DIY那10%,正在看,初步搞了搞,已经跑起来,里面很多具体变量要按具体使用的片子来重定义的,尤其是对FSMC和NVIC的具体设定和重载配置,都要根据板载原件的具体接脚来写驱动,而且还带GUI很多配置,TFT-LCD的驱动也要移植,参数很多,没有LCD就感觉象没有眼睛一样,不爽啊,手上的LCD是用ssd1289控制的,要调参数和FSMC的驱动总线,按部就班搞吧,急不来。

先动手把TFT-LCD3.2"的驱动搞了搞,结合开发板原来配的驱动源码作为参考,初步移植就点亮的,可以通过rtgui的初始化显示信息,不过还很简陋。(详见12-13楼源码)

在BSP的stm32f10x目录里,有几个关键的移植文件:
stm32f10x_conf.h
stm32f10x_it.h
stm32f10x_it.c
这三个是可以自行添加参数的,用于自定义所需的函数(库)以及所涉及中断触发条件/还原配置的条件声明与具体定义,当然了,还有libcpu的stm32目录里,
context_iar.S   /*用于IAR工程的上下文切换汇编码*/
context_rvds.S   /*用于RVDS工程的上下文切换汇编码,已经是完成初步的STM32移植了,有需要的话才再补充*/
cpuport.c /*stm32芯片的控制,这个也是现成的,不用再弄*/
以上都是需要在移植过程中配置参数的,我的理解是,把这几个码源参数设置成针对手上的片子和板子资源所需ISR调用,就可以完成初步的移植了,不知是否right了,望砖家拍砖提醒。

在3.5的STM32标准库里头,有个 startup_stm32f10x_hd.s /*调试了一下,发现0.4.0 rc1版已经不再需要0.3系列里面的start_rvds.S启动码了,还是直接用回标准库的码,RTT也不声明一下,真费劲*/
也是与MCU芯片非常密切的启动配置文件,还配套了
stm32f10x.h
system_stm32f10x.c
system_stm32f10x.h
core_cm3.c
core_cm3.h
上述5大官方的权威片子驱动源码,一般状况下无需再折腾,可以直接用,看了许久,发现通过startup_stm32f10x_hd.s以及与cpuport.ccontext_rvds.S进一步融合,初步建立好工程环境之后,RT-Thread0.4.0RC1就能顺利通过MDK的编译并让片子跑起来了……待续


沙发
stm32boy|  楼主 | 2011-11-14 14:39 | 只看该作者
本帖最后由 stm32boy 于 2011-11-17 21:24 编辑

先看了看rtconfig.h中OS的功能选项,真多选择,还是先从finSH和GUI下手,其它屏蔽掉,再慢慢搞。功能可以自选,用的话就打开#define选项,不用的话,就加//或者/*...*/屏蔽掉。
源码--
/* RT-Thread config file */
#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__

/* RT_NAME_MAX*/
#define RT_NAME_MAX        8

/* RT_ALIGN_SIZE*/
#define RT_ALIGN_SIZE        4

/* PRIORITY_MAX */
#define RT_THREAD_PRIORITY_MAX        32

/* Tick per Second */
#define RT_TICK_PER_SECOND        100

/* SECTION: RT_DEBUG */
/* Thread Debug */
#define RT_DEBUG
#define RT_THREAD_DEBUG

#define RT_USING_OVERFLOW_CHECK

/* Using Hook */
#define RT_USING_HOOK

/* Using Software Timer */
/* #define RT_USING_TIMER_SOFT */
#define RT_TIMER_THREAD_PRIO                4
#define RT_TIMER_THREAD_STACK_SIZE        512
#define RT_TIMER_TICK_PER_SECOND        100

/* SECTION: IPC */
/* Using Semaphore*/
#define RT_USING_SEMAPHORE

/* Using Mutex */
#define RT_USING_MUTEX

/* Using Event */
#define RT_USING_EVENT

/* Using MailBox */
#define RT_USING_MAILBOX

/* Using Message Queue */
#define RT_USING_MESSAGEQUEUE

/* SECTION: Memory Management */
/* Using Memory Pool Management*/
#define RT_USING_MEMPOOL

/* Using Dynamic Heap Management */
#define RT_USING_HEAP

/* Using Small MM --是否使用小存储容量的片子的功能,用效率来换空间的意思*/
#define RT_USING_SMALL_MEM

/* SECTION: Device System --硬件接口的配置,按实际需要来具体自定义*/
/* Using Device System */
#define RT_USING_DEVICE
#define RT_USING_UART1

/* SECTION: Console options --很重要的总控,可以自定义所需的输入输出配置*/
#define RT_USING_CONSOLE
/* the buffer size of console*/
#define RT_CONSOLEBUF_SIZE        128

/* SECTION: finsh, a C-Express shell --系统界面,类似于一个DOS的交互界面,实时指令SHELL*/
#define RT_USING_FINSH
/* Using symbol table */
#define FINSH_USING_SYMTAB
#define FINSH_USING_DESCRIPTION

/* SECTION: device filesystem --储存方面的文件管理,如SD卡之类的使用,先不搞,就注释掉*/
/* #define RT_USING_DFS */

//#define RT_USING_DFS_ELMFAT
//#define RT_DFS_ELM_WORD_ACCESS
/* Reentrancy (thread safe) of the FatFs module.  */
//#define RT_DFS_ELM_REENTRANT
/* Number of volumes (logical drives) to be used. */
//#define RT_DFS_ELM_DRIVES                        2
/* #define RT_DFS_ELM_USE_LFN                        1 */
//#define RT_DFS_ELM_MAX_LFN                        255
/* Maximum sector size to be handled. */
//#define RT_DFS_ELM_MAX_SECTOR_SIZE  512

/* the max number of mounted filesystem */
//#define DFS_FILESYSTEMS_MAX                        2
/* the max number of opened files                 */
//#define DFS_FD_MAX                                        4

/* SECTION: lwip, a lighwight TCP/IP protocol stack --轻型的联网接口配置,先不搞,注释掉*/
/* #define RT_USING_LWIP */
/* LwIP uses RT-Thread Memory Management */
// #define RT_LWIP_USING_RT_MEM
/* Enable ICMP protocol*/
// #define RT_LWIP_ICMP
/* Enable UDP protocol*/
// #define RT_LWIP_UDP
/* Enable TCP protocol*/
// #define RT_LWIP_TCP
/* Enable DNS */
// #define RT_LWIP_DNS

/* the number of simulatenously active TCP connections*/
// #define RT_LWIP_TCP_PCB_NUM        5

/* Using DHCP */
/* #define RT_LWIP_DHCP */

/* ip address of target*/
// #define RT_LWIP_IPADDR0        192
// #define RT_LWIP_IPADDR1        168
// #define RT_LWIP_IPADDR2        1
// #define RT_LWIP_IPADDR3        30

/* gateway address of target*/
// #define RT_LWIP_GWADDR0        192
// #define RT_LWIP_GWADDR1        168
// #define RT_LWIP_GWADDR2        1
// #define RT_LWIP_GWADDR3        1

/* mask address of target*/
// #define RT_LWIP_MSKADDR0        255
// #define RT_LWIP_MSKADDR1        255
// #define RT_LWIP_MSKADDR2        255
// #define RT_LWIP_MSKADDR3        0

/* tcp thread options */
// #define RT_LWIP_TCPTHREAD_PRIORITY                12
// #define RT_LWIP_TCPTHREAD_MBOX_SIZE                10
// #define RT_LWIP_TCPTHREAD_STACKSIZE                1024

/* ethernet if thread options */
// #define RT_LWIP_ETHTHREAD_PRIORITY                15
// #define RT_LWIP_ETHTHREAD_MBOX_SIZE                10
// #define RT_LWIP_ETHTHREAD_STACKSIZE                512

/* TCP sender buffer space */
// #define RT_LWIP_TCP_SND_BUF        8192
/* TCP receive window. */
// #define RT_LWIP_TCP_WND                8192

/* SECTION: RT-Thread/GUI --TFT/LCD的图形交互界面,很强大,比0.3版的有很大的飞跃,源于0.3超越0.3,要很费劲的,先搞一搞*/
#define RT_USING_RTGUI

/* name length of RTGUI object */
#define RTGUI_NAME_MAX                12
/* support 16 weight font */
#define RTGUI_USING_FONT16
/* support Chinese font */
#define RTGUI_USING_FONTHZ
/* use DFS as file interface */
//#define RTGUI_USING_DFS_FILERW
/* use font file as Chinese font --这个先注释掉,才能正常显示汉字,等搞好NAND-FLASH之后再弄大型的字库文件*/
// #define RTGUI_USING_HZ_FILE
/* use Chinese bitmap font */
#define RTGUI_USING_HZ_BMP
/* use small size in RTGUI */
#define RTGUI_USING_SMALL_SIZE
/* use mouse cursor */
/* #define RTGUI_USING_MOUSE_CURSOR */
/* default font size in RTGUI */
#define RTGUI_DEFAULT_FONT_SIZE        16

/* image support */
// #define RTGUI_IMAGE_XPM
// #define RTGUI_IMAGE_BMP

#endif

使用特权

评论回复
板凳
stm32boy|  楼主 | 2011-11-14 14:48 | 只看该作者
本帖最后由 stm32boy 于 2011-11-23 14:44 编辑

再看rtdef.h中OS的结构定义,哇,又一大坨,很有C++范儿,全预先打包封装了,厉害

细看了主芯片的接线以及各块IC/接口之间的PIN脚连接之后,对于FSMC的管理和调用就必须严格按照硬件之间的接法来定义。简单来说,FSMC最基本的功能实现是对4个储存模块的调度管理:
FSMC_NE1   基址 0x6000 0000
FSMC_NE2   基址 0x6400 0000
FSMC_NE3   基址 0x6800 0000
FSMC_NE4   基址 0x6C00 0000
--上述FSMC_NE[4:1]在芯片上直接对应4只脚(复用的),接什么IC外设就定义为什么,以硬件连接为准;
FSMC_NCE2
FSMC_NCE3

FSMC_NCE4_1
FSMC_NCE4_2

--正在啃读中……

使用特权

评论回复
地板
stm32boy|  楼主 | 2011-11-14 14:49 | 只看该作者
本帖最后由 stm32boy 于 2011-11-17 21:49 编辑

移植的重点还要弄RT-Thread中的application.c这个文件,里面是整个OS动态与静态线程的入口……待续

使用特权

评论回复
5
stm32boy|  楼主 | 2011-11-14 14:52 | 只看该作者
本帖最后由 stm32boy 于 2011-11-17 21:51 编辑

整个OS所需的变量/函数/结构对象声明全在rtthread.h里面了,又是超级一大坨,哇噻

对于驱动板载资源时将会十分有用。……待续

使用特权

评论回复
6
grissiom| | 2011-11-14 15:07 | 只看该作者
咱能不贴代码,直接说事么?……

使用特权

评论回复
7
ZigBee笔记| | 2011-11-14 15:13 | 只看该作者
???不是有移植好的BSP吗

使用特权

评论回复
8
47857872| | 2011-11-14 16:17 | 只看该作者
直接贴代码。。。囧 也不把改动的地方标红啥的

使用特权

评论回复
9
stm32boy|  楼主 | 2011-11-15 10:50 | 只看该作者
本帖最后由 stm32boy 于 2011-11-18 10:17 编辑

要移植,先要搞驱动stm32f103zet6片子的东西,context_rvds.S和cpuport.c这哥俩就是key啊,由于省掉了0.3系列的start_rvds.s文件,context_rvds.s就优化了中断调用的功能。

先尝尝context_rvds.S的源码--
;/*
; * File      : context_rvds.S
; * This file is part of RT-Thread RTOS
; * COPYRIGHT (C) 2009, RT-Thread Development Team
; *
; * The license and distribution terms for this file may be
; * found in the file LICENSE in this distribution or at
; * http://www.rt-thread.org/license/LICENSE
; *
; * Change Logs:
; * Date           Author       Notes
; * 2009-01-17     Bernard      first version
; */

;/**
; * @addtogroup STM32
; */
;/*@{*/

NVIC_INT_CTRL   EQU     0xE000ED04               ; interrupt control state register
NVIC_SYSPRI2    EQU     0xE000ED20               ; system priority register (2)
NVIC_PENDSV_PRI EQU     0x00FF0000               ; PendSV priority value (lowest)
NVIC_PENDSVSET  EQU     0x10000000               ; value to trigger PendSV exception

    AREA |.text|, CODE, READONLY, ALIGN=2
    THUMB
    REQUIRE8
    PRESERVE8

    IMPORT rt_thread_switch_interrupt_flag
    IMPORT rt_interrupt_from_thread
    IMPORT rt_interrupt_to_thread

;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
rt_hw_interrupt_disable    PROC
    EXPORT  rt_hw_interrupt_disable
    MRS     r0, PRIMASK
    CPSID   I
    BX      LR
    ENDP

;/*
; * void rt_hw_interrupt_enable(rt_base_t level);
; */
rt_hw_interrupt_enable    PROC
    EXPORT  rt_hw_interrupt_enable
    MSR     PRIMASK, r0
    BX      LR
    ENDP

;/*
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
; * r0 --> from
; * r1 --> to
; */
rt_hw_context_switch_interrupt
    EXPORT rt_hw_context_switch_interrupt
rt_hw_context_switch    PROC
    EXPORT rt_hw_context_switch

    ; set rt_thread_switch_interrupt_flag to 1
    LDR     r2, =rt_thread_switch_interrupt_flag
    LDR     r3, [r2]
    CMP     r3, #1
    BEQ     _reswitch
    MOV     r3, #1
    STR     r3, [r2]

    LDR     r2, =rt_interrupt_from_thread   ; set rt_interrupt_from_thread
    STR     r0, [r2]

_reswitch
    LDR     r2, =rt_interrupt_to_thread     ; set rt_interrupt_to_thread
    STR     r1, [r2]

    LDR     r0, =NVIC_INT_CTRL              ; trigger the PendSV exception (causes context switch)
    LDR     r1, =NVIC_PENDSVSET
    STR     r1, [r0]
    BX      LR
    ENDP

; r0 --> swith from thread stack
; r1 --> swith to thread stack
; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack
PendSV_Handler   PROC
    EXPORT PendSV_Handler

    ; disable interrupt to protect context switch
    MRS     r2, PRIMASK
    CPSID   I

    ; get rt_thread_switch_interrupt_flag
    LDR     r0, =rt_thread_switch_interrupt_flag
    LDR     r1, [r0]
    CBZ     r1, pendsv_exit         ; pendsv already handled

    ; clear rt_thread_switch_interrupt_flag to 0
    MOV     r1, #0x00
    STR     r1, [r0]

    LDR     r0, =rt_interrupt_from_thread
    LDR     r1, [r0]
    CBZ     r1, swtich_to_thread    ; skip register save at the first time

    MRS     r1, psp                 ; get from thread stack pointer
    STMFD   r1!, {r4 - r11}         ; push r4 - r11 register
    LDR     r0, [r0]
    STR     r1, [r0]                ; update from thread stack pointer

swtich_to_thread
    LDR     r1, =rt_interrupt_to_thread
    LDR     r1, [r1]
    LDR     r1, [r1]                ; load thread stack pointer

    LDMFD   r1!, {r4 - r11}         ; pop r4 - r11 register
    MSR     psp, r1                 ; update stack pointer

pendsv_exit
    ; restore interrupt
    MSR     PRIMASK, r2

    ORR     lr, lr, #0x04
    BX      lr
    ENDP

;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; * this fucntion is used to perform the first thread switch
; */
rt_hw_context_switch_to    PROC
    EXPORT rt_hw_context_switch_to
    ; set to thread
    LDR     r1, =rt_interrupt_to_thread
    STR     r0, [r1]

    ; set from thread to 0
    LDR     r1, =rt_interrupt_from_thread
    MOV     r0, #0x0
    STR     r0, [r1]

    ; set interrupt flag to 1
    LDR     r1, =rt_thread_switch_interrupt_flag
    MOV     r0, #1
    STR     r0, [r1]

    ; set the PendSV exception priority
    LDR     r0, =NVIC_SYSPRI2
    LDR     r1, =NVIC_PENDSV_PRI
    LDR.W   r2, [r0,#0x00]       ; read
    ORR     r1,r1,r2             ; modify
    STR     r1, [r0]             ; write-back

    ; trigger the PendSV exception (causes context switch)
    LDR     r0, =NVIC_INT_CTRL
    LDR     r1, =NVIC_PENDSVSET
    STR     r1, [r0]

    ; enable interrupts at processor level
    CPSIE   I

    ; never reach here!
    ENDP

; compatible with old version
rt_hw_interrupt_thread_switch PROC
    EXPORT rt_hw_interrupt_thread_switch
    BX      lr
    NOP
    ENDP

    IMPORT rt_hw_hard_fault_exception
    EXPORT HardFault_Handler
HardFault_Handler    PROC

    ; get current context
    MRS     r0, psp                 ; get fault thread stack pointer
    PUSH    {lr}
    BL      rt_hw_hard_fault_exception
    POP     {lr}

    ORR     lr, lr, #0x04
    BX      lr
    ENDP

    END

使用特权

评论回复
10
stm32boy|  楼主 | 2011-11-15 10:51 | 只看该作者
本帖最后由 stm32boy 于 2011-11-17 21:55 编辑

不能少了cpuport.c呀,把原来0.3系列的几个分散文件集合起来了,更规范,好,还得啃下去--
/*
* File      : cpuport.c
* This file is part of RT-Thread RTOS
* COPYRIGHT (C) 2009 - 2011, RT-Thread Development Team
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rt-thread.org/license/LICENSE
*
* Change Logs:
* Date           Author       Notes
* 2006-08-23     Bernard      the first version
* 2011-06-03     Bernard      merge all of C source code into cpuport.c
*/
#include <rtthread.h>

/* exception and interrupt handler table */
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
rt_uint32_t rt_thread_switch_interrupt_flag;

struct stack_contex
{
        rt_uint32_t r0;
        rt_uint32_t r1;
        rt_uint32_t r2;
        rt_uint32_t r3;
        rt_uint32_t r12;
        rt_uint32_t lr;
        rt_uint32_t pc;
        rt_uint32_t psr;
};

rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter,
        rt_uint8_t *stack_addr, void *texit)
{
        unsigned long *stk;

        stk          = (unsigned long *)stack_addr;
        *(stk)   = 0x01000000L;                                        /* PSR */
        *(--stk) = (unsigned long)tentry;                /* entry point, pc */
        *(--stk) = (unsigned long)texit;                /* lr */
        *(--stk) = 0;                                                        /* r12 */
        *(--stk) = 0;                                                        /* r3 */
        *(--stk) = 0;                                                        /* r2 */
        *(--stk) = 0;                                                        /* r1 */
        *(--stk) = (unsigned long)parameter;        /* r0 : argument */

        *(--stk) = 0;                                                        /* r11 */
        *(--stk) = 0;                                                        /* r10 */
        *(--stk) = 0;                                                        /* r9 */
        *(--stk) = 0;                                                        /* r8 */
        *(--stk) = 0;                                                        /* r7 */
        *(--stk) = 0;                                                        /* r6 */
        *(--stk) = 0;                                                        /* r5 */
        *(--stk) = 0;                                                        /* r4 */

        /* return task's current stack address */
        return (rt_uint8_t *)stk;
}

extern void rt_hw_interrupt_thread_switch(void);
extern void list_thread(void);
extern rt_thread_t rt_current_thread;
void rt_hw_hard_fault_exception(struct stack_contex* contex)
{
        rt_kprintf("psr: 0x%08x\n", contex->psr);
        rt_kprintf(" pc: 0x%08x\n", contex->pc);
        rt_kprintf(" lr: 0x%08x\n", contex->lr);
        rt_kprintf("r12: 0x%08x\n", contex->r12);
        rt_kprintf("r03: 0x%08x\n", contex->r3);
        rt_kprintf("r02: 0x%08x\n", contex->r2);
        rt_kprintf("r01: 0x%08x\n", contex->r1);
        rt_kprintf("r00: 0x%08x\n", contex->r0);

        rt_kprintf("hard fault on thread: %s\n", rt_current_thread->name);
#ifdef RT_USING_FINSH
        list_thread();
#endif
        while (1);
}

void rt_hw_cpu_shutdown()
{
        rt_kprintf("shutdown...\n");

        RT_ASSERT(0);
}

使用特权

评论回复
11
stm32boy|  楼主 | 2011-11-15 17:14 | 只看该作者
本帖最后由 stm32boy 于 2011-11-17 21:44 编辑

很费劲的跑了一下0.4.0RC1,发现原来0.3中很重要的start_rvds.s已经不再重要了,RTT遵循国际惯例,还是归顺了stm32自带的startup_stm32f10x_hd.s,只是在context_rvds.S中改善了ISR的接口函数,RTT是不错的,就是配套有点山寨,呵呵

使用特权

评论回复
12
stm32boy|  楼主 | 2011-11-17 11:43 | 只看该作者
TFT-LCD3.2"的SSD1289驱动源码,先来ssd1289.h的--
#ifndef SSD1289_H_INCLUDED
#define SSD1289_H_INCLUDED

#include <rtthread.h>
#include <board.h>
#include <rtgui.h>
#include <rtgui_server.h>
#include <rtgui_system.h>
#include <driver.h>

// Compatible list:
// ssd1289
//输出重定向.当不进行重定向时.
#define printf               rt_kprintf //使用rt_kprintf来输出

/* LCD color */
#define White            0xFFFF
#define Black            0x0000
#define Grey             0xF7DE
#define Blue             0x001F
#define Blue2            0x051F
#define Red              0xF800
#define Magenta          0xF81F
#define Green            0x07E0
#define Cyan             0x7FFF
#define Yellow           0xFFE0

/*---------------------- Graphic LCD size definitions ------------------------*/
#define LCD_WIDTH       240                 /* Screen Width (in pixels)           */
#define LCD_HEIGHT      320                 /* Screen Hight (in pixels)           */
#define BPP             16                  /* Bits per pixel                     */
#define BYPP            ((BPP+7)/8)         /* Bytes per pixel                    */

void ssd1289_init(void);

//#define _ILI_REVERSE_DIRECTION_

rt_size_t lcd_ssd1289_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size);
rt_size_t lcd_ssd1289_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size);

#endif // SSD1289_H_INCLUDED

使用特权

评论回复
13
642142533| | 2012-8-3 23:38 | 只看该作者
楼主
   你移植好RT-Thread了吗
      用起来怎么样

使用特权

评论回复
14
houfire007| | 2012-10-26 17:52 | 只看该作者
貌似很猛啊!!!

使用特权

评论回复
15
aozima| | 2012-10-26 20:06 | 只看该作者
支持。

使用特权

评论回复
16
一般首席| | 2013-11-17 12:24 | 只看该作者
学习了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:for {;;}

0

主题

34

帖子

0

粉丝