• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 60, 文章 - 0, 評論 - 197, 引用 - 0
            數據加載中……

            學習 ARM 系列 -- FS2410 開發板上通過串口實現 printf

            一、目的
               到目前為止我們所編寫的程序都是直接燒到裸板(FS2410)上運行,沒有借助操作系統,
            如果哪個環節出錯了,就只能揣測代碼的邏輯,無法借助 GDB 調試,這無形增加了編寫代
            碼的難度,如果任意時刻我們能把某個變量的值打印出來多好啊...呵呵, 你也許有同樣的
            困惑,上一個實驗我們對 UART 串口編程實現了對超級終端接收和發送數據,也許我們可以
            編寫一個類似 C 語言里的 printf,作用就是向上位機的超級終端發送我們指定的任何數據。
            懷著這樣美好的愿望,隨我一起踏上征程吧。


            二、代碼
               很多代碼是在前面幾個實驗的基礎上進行整理復用之,更多細節請參考前面隨筆,這里
            僅附簡略注解。
              
               @ 文件 head.s
               @ 作用:關閉看門狗、SDRAM 的初始化設置、搬移 Nand Flash 4K 以后
               @ 的代碼到 SDRAM 的指定位置、執行 SDRAM 中的代碼
               .text
               .global _start
               _start:
                ldr r0, =0x53000000 @ Close Watch Dog Timer
                mov r1, #0x0
                str r1, [r0]
              
                bl  memory_setup @ Initialize memory setting
                bl  flash_to_sdram @ Copy code to sdram
                
                    ldr sp, =0x34000000 @ Set stack pointer
                ldr pc, =main           @ execute the code in SDRAM


               @ 文件 mem.s
               @ 作用:SDRAM 的初始化設置
               @ 關于初始化的更多細節,請參考我前面的隨筆
               .global memory_setup
               memory_setup:
                mov  r1, #0x48000000
                adrl r2, mem_cfg_val
                add  r3, r1, #13*4
               1: 
                @ write initial values to registers
                ldr  r4, [r2], #4
                str  r4, [r1], #4
                cmp  r1, r3
                bne  1b
                mov  pc, lr
                
                .align 4
               mem_cfg_val:
                .long 0x22111110 @ BWSCON
                .long 0x00000700 @ BANKCON0
                .long 0x00000700 @ BANKCON1
                .long 0x00000700 @ BANKCON2
                .long 0x00000700 @ BANKCON3
                .long 0x00000700 @ BANKCON4
                .long 0x00000700 @ BANKCON5
                .long 0x00018005 @ BANKCON6
                .long 0x00018005 @ BANKCON7 9bit
                .long 0x008e07a3 @ REFRESH
                .long 0x000000b2 @ BANKSIZE
                .long 0x00000030 @ MRSRB6
                .long 0x00000030 @ MRSRB7


               @ 文件 flash.s
               @ 作用:設置 Nand Flash 的控制寄存器、讀取 Nand Flash
               @ 中的代碼到 SDRAM 的指定位置,更多細節請參考我前面的隨筆
               .equ NFCONF, 0x4e000000
               .equ NFCMD,  0x4e000004
               .equ NFADDR, 0x4e000008
               .equ NFDATA, 0x4e00000c
               .equ NFSTAT, 0x4e000010
               .equ NFECC,  0x4e000014
               .global flash_to_sdram
               flash_to_sdram:
                    @ Save return addr
                    mov r10,lr
                
                    @ Initialize Nand Flash
                    mov r0,#NFCONF
                    ldr r1,=0xf830
                    str r1,[r0]
               
                    @ First reset and enable Nand Flash
                    ldr r1,[r0]
                    bic r1, r1, #0x800
                    str r1,[r0]
               
                    ldr r2,=NFCMD
                    mov r3,#0xff
                    str r3,[r2]
                
                    @ for delay
                    mov r3, #0x0a
               1:
                    subs r3, r3, #1
                    bne 1b
              
               @ Wait until Nand Flash bit0 is 1
               wait_nfstat:
                    ldr r2,=NFSTAT
                    ldr r3,[r2]
                    tst r3,#0x01
                    beq wait_nfstat
                      
                @ Disable Nand Flash
                ldr r0,=NFCONF
                ldr r1,[r0]
                orr r1,r1,#0x8000
                str r1,[r0]
               
                @ Initialzie stack
                ldr sp,=4096
              
                @ Set arguments and call 
                @ function nand_read defined in nand_read.c
                ldr r0,=0x30000000
                mov r1,#0
                mov r2,#1024*40
                bl nand_read
               
                @ return
                mov pc,r10


               /* 文件 nand_read.c
                * 作用:從 Nand Flash 中讀取一塊數據到 SDRAM 中的指定位置
                */
               #define NFCONF (*(volatile unsigned long *)0x4e000000)
               #define NFCMD  (*(volatile unsigned long *)0x4e000004)
               #define NFADDR (*(volatile unsigned long *)0x4e000008)
               #define NFDATA (*(volatile unsigned long *)0x4e00000c)
               #define NFSTAT (*(volatile unsigned long *)0x4e000010)
               #define NFECC  (*(volatile unsigned long *)0x4e000014)
              
               #define NAND_SECTOR_SIZE 512
               #define NAND_BLOCK_MASK  0x1ff
              
               void wait_idle() {
                 int i;
                 for (i = 0; i < 50000; ++i) ;
               }
              
               int nand_read(unsigned char *buf, unsigned long start_addr, int size){
                 int i, j;
                 /*
                  * detect the argument
                  */ 
                 if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
                   return -1;    
                 }
               
                 /* chip Enable */
                 NFCONF &= ~0x800;
                 for (i=0; i<10; i++) {
                   ;
                 }
               
                 for (i=start_addr; i < (start_addr + size); i+=NAND_SECTOR_SIZE) {
                   NFCMD = 0;
               
                   /* Write Address */
                   NFADDR = i & 0xff;
                   NFADDR = (i >> 9)  & 0xff;
                   NFADDR = (i >> 17) & 0xff;
                   NFADDR = (i >> 25) & 0xff;
               
                   wait_idle();
               
                   for(j=0; j < NAND_SECTOR_SIZE; j++) {
                     *buf++ = (NFDATA & 0xff);
                   }
                 }
               
                 NFCONF |= 0x800;    /* chip disable */
                 return 0;
               }


               /* 頭文件 serl.h
                * 作用:定義相關寄存器、UART 初始化函數聲明、串口讀寫函數的聲明
                */  
               #ifndef __SERL_H__
               #define __SERL_H__
              
               #define GPHCON  (*(volatile unsigned long *)0x56000070)
              
               /* PORT PULL-UP REGISTER*/
               #define GPHUP   (*(volatile unsigned long *)0x56000078)
              
               /* UART FIFO control register 0*/
               #define UFCON0  (*(volatile unsigned long *)0x50000008)
              
               /* UART line control register 0*/
               #define ULCON0  (*(volatile unsigned long *)0x50000000)
              
               /* UART CONTROL REGISTER 0*/
               #define UCON0   (*(volatile unsigned long *)0x50000004)
              
               /* UART modem control register 0*/
               #define UMCON0  (*(volatile unsigned long *)0x5000000C)
              
               /* UART baud rate divisor register 0*/
               #define UBRDIV0 (*(volatile unsigned long *)0x50000028)
              
               /* UART TX/RX STATUS REGISTER 0*/
               #define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
              
              
               #define UTXH0 (*(volatile unsigned char *)0x50000020)
               #define URXH0 (*(volatile unsigned char *)0x50000024)
              
              
               #define TXD0_READY 0x2
               #define RXD0_READY 0x1
              
               void init_uart();
               unsigned char uart_getc();
               void uart_putc(unsigned char ch);
               void uart_puts(unsigned char* src);
              
               #endif


               /* 文件 serl.c*/
               #include "serl.h"
              
               void init_uart() {
                 GPHCON |= 0xa0; /* GPH2, GPH3 used as RXD0, TXD0*/
                 GPHUP = 0x0c;   /* GPH2, GPH3 poll-up */
              
                 ULCON0 = 0x03;  /* normal mode, no parity, one stop bit, 8-bit*/
                 UCON0 = 0x05;   /* Loopback mode*/
                 UFCON0 = 0x00;  /* not use FIFO*/
                 UMCON0 = 0x00;  /* disable flow control*/
                 UBRDIV0 = 12;   /* baud rate 57600*/
               }
              
               void uart_putc(unsigned char ch) {
                 while (!(UTRSTAT0 & TXD0_READY));
                 UTXH0 = ch;
               }
              
               unsigned char uart_getc(){
                 while (! (UTRSTAT0 & RXD0_READY));
                 return URXH0;
               }
              
               void uart_puts(unsigned char* src) {
                 unsigned char *p = src;
                 while (*p != '\0') {
                   if (*p == 0x0a)
                     uart_putc(0x0d);
                   uart_putc(*p);
                   p++;
                 }
               }
              

               /*
                * 頭文件 printf.h
                * 作用:對外提供調用接口 uart_printf
                */  
               #ifndef __PRINTF_HH__
               #define __PRINTF_HH__
              
               void uart_printf(char *fmt, ...);
              
               #endif

              
               /*
                * 文件 printf.c
                * 文件中大部分代碼來自 linux 0.11 內核的 vsprintf.c, 只是作了相應的刪減,
                * <<Linux 內核完全注釋>> 上有更詳細的解釋
                */
               #include <stdarg.h>
               #include <linux/types.h>
               #include <linux/ctype.h>
               #include "printf.h"
               #include "serl.h"
              
               #define ZEROPAD  1    /* pad with zero */
               #define SIGN           2    /* unsigned/signed long */
               #define PLUS           4    /* show plus */
               #define SPACE        8    /* space if plus */
               #define LEFT           16   /* left justified */
               #define SPECIAL     32  /* 0x */
               #define LARGE        64  /* use 'ABCDEF' instead of 'abcdef' */
              
               #define is_digit(c) ((c) >= '0' && (c) <= '9')

               #define do_div(n,base) ({    \
                     int __res;     \
                     __res = ((unsigned long) n) % (unsigned) base; \
                     n = ((unsigned long) n) / (unsigned) base; \
                     __res; })
              
               static unsigned char sprint_buf[1024];
              
               int strnlen(const char * s, int count)
               {
                 const char *sc;
              
                 for (sc = s; count-- && *sc != '\0'; ++sc)
                   /* nothing */;
                 return sc - s;
               }
              
               unsigned char _ctype[] = {
                 _C,_C,_C,_C,_C,_C,_C,_C,   /* 0-7 */
                 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
                 _C,_C,_C,_C,_C,_C,_C,_C,   /* 16-23 */
                 _C,_C,_C,_C,_C,_C,_C,_C,   /* 24-31 */
                 _S|_SP,_P,_P,_P,_P,_P,_P,_P,  /* 32-39 */
                 _P,_P,_P,_P,_P,_P,_P,_P,   /* 40-47 */
                 _D,_D,_D,_D,_D,_D,_D,_D,   /* 48-55 */
                 _D,_D,_P,_P,_P,_P,_P,_P,   /* 56-63 */
                 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
                 _U,_U,_U,_U,_U,_U,_U,_U,   /* 72-79 */
                 _U,_U,_U,_U,_U,_U,_U,_U,   /* 80-87 */
                 _U,_U,_U,_P,_P,_P,_P,_P,   /* 88-95 */
                 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
                 _L,_L,_L,_L,_L,_L,_L,_L,   /* 104-111 */
                 _L,_L,_L,_L,_L,_L,_L,_L,   /* 112-119 */
                 _L,_L,_L,_P,_P,_P,_P,_C,   /* 120-127 */
                 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 128-143 */
                 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 144-159 */
                 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
                 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
                 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
                 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
                 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
                 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */
              
               static int skip_atoi(const char **s)
               {
                 int i=0;
              
                 while (is_digit(**s))
                   i = i*10 + *((*s)++) - '0';
                 return i;
               }
              
               static char * number(char * str, long num, int base, int size, int precision
                      ,int type)
               {
                 char c,sign,tmp[66];
                 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
                 int i;
              
                 if (type & LARGE)
                   digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
                 if (type & LEFT)
                   type &= ~ZEROPAD;
                 if (base < 2 || base > 36)
                   return 0;
                 c = (type & ZEROPAD) ? '0' : ' ';
                 sign = 0;
                 if (type & SIGN) {
                   if (num < 0) {
                     sign = '-';
                     num = -num;
                     size--;
                   } else if (type & PLUS) {
                     sign = '+';
                     size--;
                   } else if (type & SPACE) {
                     sign = ' ';
                     size--;
                   }
                 }
                 if (type & SPECIAL) {
                   if (base == 16)
                     size -= 2;
                   else if (base == 8)
                     size--;
                 }
                 i = 0;
                 if (num == 0)
                   tmp[i++]='0';
                 else while (num != 0)
                 tmp[i++] = digits[do_div(num,base)];
                 if (i > precision)
                   precision = i;
                 size -= precision;
                 if (!(type&(ZEROPAD+LEFT)))
                   while(size-->0)
                     *str++ = ' ';
                 if (sign)
                   *str++ = sign;
                 if (type & SPECIAL) {
                   if (base==8)
                     *str++ = '0';
                   else if (base==16) {
                     *str++ = '0';
                     *str++ = digits[33];
                   }
                 }
                 if (!(type & LEFT))
                   while (size-- > 0)
                     *str++ = c;
                 while (i < precision--)
                   *str++ = '0';
                 while (i-- > 0)
                   *str++ = tmp[i];
                 while (size-- > 0)
                   *str++ = ' ';
                 return str;
               }
              
               int __vsprintf(char *buf, const char *fmt, va_list args)
               {
                 int len;
                 unsigned long num;
                 int i, base;
                 char * str;
                 const char *s;
              
                 int flags;  /* flags to number() */
              
                 int field_width; /* width of output field */
                 int precision;    /* min. # of digits for integers; max number of chars for from string */
                 int qualifier;      /* 'h', 'l', or 'L' for integer fields */
              
                 for (str=buf ; *fmt ; ++fmt) {
                   if (*fmt != '%') {
                     *str++ = *fmt;
                     continue;
                   }
                  
                   /* process flags */
                   flags = 0;
                 repeat:
                   ++fmt;  /* this also skips first '%' */
                   switch (*fmt) {
                     case '-': flags |= LEFT; goto repeat;
                     case '+': flags |= PLUS; goto repeat;
                     case ' ': flags |= SPACE; goto repeat;
                     case '#': flags |= SPECIAL; goto repeat;
                     case '0': flags |= ZEROPAD; goto repeat;
                   }
                 
                   /* get field width */
                   field_width = -1;
                   if (is_digit(*fmt))
                     field_width = skip_atoi(&fmt);
                   else if (*fmt == '*') {
                     ++fmt;
                     /* it's the next argument */
                     field_width = va_arg(args, int);
                     if (field_width < 0) {
                       field_width = -field_width;
                       flags |= LEFT;
                     }
                   }
              
                   /* get the precision */
                   precision = -1;
                   if (*fmt == '.') {
                     ++fmt; 
                     if (is_digit(*fmt))
                       precision = skip_atoi(&fmt);
                     else if (*fmt == '*') {
                       ++fmt;
                       /* it's the next argument */
                       precision = va_arg(args, int);
                     }
                     if (precision < 0)
                       precision = 0;
                   }
              
                   /* get the conversion qualifier */
                   qualifier = -1;
                   if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
                     qualifier = *fmt;
                     ++fmt;
                   }
              
                   /* default base */
                   base = 10;
              
                   switch (*fmt) {
                   case 'c':
                     if (!(flags & LEFT))
                       while (--field_width > 0)
                           *str++ = ' ';
                     *str++ = (unsigned char) va_arg(args, int);
                     while (--field_width > 0)
                       *str++ = ' ';
                     continue;
              
                   case 's':
                     s = va_arg(args, char *);
                     if (!s)
                       s = "<NULL>";
              
                     len = strnlen(s, precision);
              
                     if (!(flags & LEFT))
                       while (len < field_width--)
                         *str++ = ' ';
                     for (i = 0; i < len; ++i)
                      *str++ = *s++;
                     while (len < field_width--)
                       *str++ = ' ';
                     continue;
              
                   case 'p':
                     if (field_width == -1) {
                       field_width = 2*sizeof(void *);
                       flags |= ZEROPAD;
                     }
                     str = number(str,
                    (unsigned long) va_arg(args, void *), 16, field_width, precision, flags);
                     continue;
              
              
                   case 'n':
                     if (qualifier == 'l') {
                       long * ip = va_arg(args, long *);
                       *ip = (str - buf);
                     } else {
                         int * ip = va_arg(args, int *);
                         *ip = (str - buf);
                     }
                     continue;
              
                     /* integer number formats - set up the flags and "break" */
                   case 'o':
                     base = 8;
                     break;
              
                   case 'X':
                     flags |= LARGE;
                   case 'x':
                     base = 16;
                     break;
              
                   case 'd':
                   case 'i':
                     flags |= SIGN;
                   case 'u':
                     break;
              
                   default:
                     if (*fmt != '%')
                       *str++ = '%';
                     if (*fmt)
                       *str++ = *fmt;
                     else
                       --fmt;
                     continue;
                   }
                   if (qualifier == 'l')
                     num = va_arg(args, unsigned long);
                   else if (qualifier == 'h') {
                     num = (unsigned short) va_arg(args, int);
                     if (flags & SIGN)
                num = (short) num;
                   } else if (flags & SIGN)
                     num = va_arg(args, int);
                   else
                     num = va_arg(args, unsigned int);
                   str = number(str, num, base, field_width, precision, flags);
                 }
                 *str = '\0';
                 return str-buf;
               }
              
               /* 這就我們的 printf, 注意我們將參數輸出到串口 UART0,而非標準輸出*/
               void uart_printf(char *fmt, ...)
               {
                 va_list args;
              
                 va_start(args, fmt);
                 __vsprintf(sprint_buf, fmt,args);
                 va_end(args);
              
                 /* 將緩沖區的字符輸出到串口*/
                 uart_puts(sprint_buf);
               }
              

               /*
                * 文件 main.c
                * 作用:測試代碼
                */
               #include "serl.h"
               #include "printf.h"
              
               #define GPFCON (*(volatile unsigned long *)0x56000050)
               #define GPFDAT (*(volatile unsigned long *)0x56000054)
              
               int main()
               {
                 int a = 10;
                 init_uart();

                 /*
                  * 調用我們自己的 uart_printf,將數據輸出到串口,稍后你將
                  * 在超級終端上看到顯示結果。之所以不叫 printf 是為了不與
                  * arm-linux-gcc 的庫函數 printf 相沖突
                  */
                 uart_printf("Hello,Embeded!\n");
                 uart_printf("%d\n",a);

                 return 0;
               }
              

               最后要說的是 Makefile,這個Makefile 在前面 Makefile的基礎上作了很大的改進,
            它不需要你再指定源文件,而是在當前目錄下讀取擴展名為 .s 和 .c 的文件作為輸入文件,
            你只需指定最終要生成的可執行文件即可,只是它還是不太完美, 你還要指定它依賴的目標文
            件,因為 head.o mem.o flash.o nand_read.o 這些文件被連接生成可執行文件后它
            們的代碼必須位于前 4K, 這樣才能保證它們自動被 ARM 加載,從而設置堆棧、初始化內存、
            讀取 Nand Flash 的代碼完成自身到 SDRAM 的 self-copying。將來我們會用連接腳本
            來解決這個問題。

               # Makefile for compiling ARM program
               # Author: Jianbin Wang
              
               CC=arm-linux-gcc
               CFLAGS=-Wall -g -c
               LD=arm-linux-ld
               LDFLAGS:=$(LDFLAGS) -Ttext 0x30000000
              
               INCLUDES=-I./
               CFLAGS:=$(CFLAGS) $(INCLUDES)
               LIBS=-lgcc -L/usr/local/arm/3.3.2/lib/gcc-lib/arm-linux/3.3.2
              
               CONVERT=arm-linux-objcopy
               CVFLAGS=-O binary -S
               RM=rm -f
              
               SRCDIRS=.
               TARGET=main
               TMPOBJ=$(TARGET)_tmp.o
               SRCS=$(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.c $(dir)/*.s))
               OBJS=head.o mem.o flash.o nand_read.o main.o printf.o serl.o
              
               all:$(TARGET)
              
               $(TARGET):$(OBJS)
                $(LD) $(LDFLAGS) -o $(TMPOBJ) $(OBJS) $(LIBS)
                $(CONVERT) $(CVFLAGS) $(TMPOBJ) $(TARGET)
              
               $(OBJS):$(SRCS)
                $(CC) $(CFLAGS) $(SRCS)
              
               clean:
                $(RM) $(TARGET)
                $(RM) $(TMPOBJ)
                $(RM) $(OBJS)  


            三、編譯、燒寫、測試
               Make 一下就會生成我們要的文件 main, 將其通過 JTAG 燒入 Nand Flash。用超級終
            連接到開發板,注意波特率設為 57600,數據位 8,無奇偶校正,停止位1,無數據流控制。現
            在 Reset 一下的開發板,然后靜靜的等待吧,生成的二進制文件 main 有 39K 大呢,要等它
            完全復制到 SDRAM 至少要兩三分鐘...之后,在超級終端上是不是出現了字符串:

                 Hello,Embeded!
                 10

            呵呵,至此我們的愿望變現實,是不是很不可思議 :-)

            posted on 2008-01-17 15:53 Normandy 閱讀(3603) 評論(1)  編輯 收藏 引用 所屬分類: Embeded Area

            評論

            # re: 學習 ARM 系列 -- FS2410 開發板上通過串口實現 printf  回復  更多評論   

            樓主實在是太棒了!
            2008-01-17 16:01 | free
            亚洲伊人久久精品影院| 精品久久国产一区二区三区香蕉 | 一级女性全黄久久生活片免费 | 99久久er这里只有精品18| 久久se精品一区二区| 久久久久亚洲AV无码专区网站| 亚洲国产成人久久综合一区77| 久久午夜羞羞影院免费观看| 久久丝袜精品中文字幕| AAA级久久久精品无码片| 伊人色综合九久久天天蜜桃| 97久久超碰成人精品网站| 国产精品一区二区久久精品涩爱| 久久综合欧美成人| 亚洲国产精品无码久久久蜜芽 | 欧洲精品久久久av无码电影| 久久成人18免费网站| 91精品国产91久久综合| 婷婷久久久亚洲欧洲日产国码AV | 亚洲精品无码久久久久sm| 欧美无乱码久久久免费午夜一区二区三区中文字幕 | 99久久久精品| 亚洲va国产va天堂va久久| 亚洲国产成人久久一区久久| 久久精品国产亚洲AV不卡| 久久国产精品久久久| 久久精品亚洲一区二区三区浴池 | 久久天堂AV综合合色蜜桃网| 久久99这里只有精品国产| 色综合久久天天综线观看| 久久久久久国产精品美女 | 日韩精品无码久久久久久| 久久精品国产精品亚洲精品 | 国产精品综合久久第一页 | 色偷偷88888欧美精品久久久| 久久亚洲精品成人无码网站| 久久中文字幕人妻丝袜| 国产精品久久久久久久app| 亚洲国产精品无码久久一线| 久久国产热精品波多野结衣AV| 色诱久久久久综合网ywww|