找回密码
 注册
关于网站域名变更的通知
查看: 327|回复: 1
打印 上一主题 下一主题

#技术风云榜#OR的汇编

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-11-10 13:49 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
#技术风云榜#OR的汇编# ]' c( t& c3 I! d: ?& A2 x
本小节,我们将通过一个简单的实验,对OR的汇编(指令集)做一个简单的梳理和测试。& v# S8 v5 X$ k. M4 P
8 z& V. d5 b( n6 ]0 {7 E2 m
1,基本思想
: _1 W. E1 S) q要想了解OR的指令集,其实只要查查OpenRISC architecture manual就可以了,但是不是最好的熟悉方式,也没有必要将其所有指令集记下来。我认为,通过一个实际的工程或者例子,从中了解OR的指令集是比较好的一种方式。+ {4 x: Q% l$ V7 d6 ~$ u/ J' Z

$ N* ~7 n* z- U+ P+ [( T那么,通过什么例子呢?7 x1 G" B0 T. S
0 M% _: `0 W2 i: O1 h
一般RISC的指令集包括,运算指令,分支指令,和访存指令,三类。所以我们这个实验最好能用到这三类指令,碰巧,我最近在测试DDR控制器,所以我们下面将通过一个读写内存的例子来熟悉OR的指令集。8 Y  i1 Q- g# \% ?  R% {, x* ^
8 o  E" f( Y& \5 @/ v% C
2,实验步骤
# E; ]; B. J, A. w2.1实验准备
1 \7 T; P  X; ]! x+ a9 D在开始编码之前,我们首先需要考虑如下几个问题:+ @8 C5 [& }9 d
8 ~9 j8 W; U5 t4 A1 z: ~! N1 j# t  U1 O
a,如何对汇编源程序(.S文件)进行编译,生成机器码。( y, m& O( X9 I0 N1 J; Z, D

$ S: P8 {: q. j0 X* nb,如何加载机器码使OR的指令总线能读到。- R5 Q) g- q# R. N, X  t

. ?! A; g) R1 n" Ac,如何查看机器码的执行过程和结果。
. e  \/ }: l' ]' J- L0 F
! M4 \7 E3 U3 O9 w! O; {. o8 T1 H
7 [  Q4 s' G; @: y$ G* Q
根据前面,我们积累下来的经验,可知,利用bootrom进行RTL仿真,可以很好的解决上面三个问题。并且都是自动化的。
4 c! m  T. [, C# n* z- h" F4 x: D& u8 @5 |( R
) M# X. e$ R" W9 {3 u# o

6 Z. d; ^* X! H: q2 U+ c- v$ X3 B/ i& D$ n3 ?
# ?% F8 B0 k" K- R* Z
2.2 实验步骤
7 n! D( Y3 z6 x在了解并解决了上面几个问题之后,剩下的就是具体的操作了。. |! o7 f$ S4 G  J1 ]

3 S0 E: |2 Z- b& r5 i8 @6 xa,修改soc-design/orpsocv2/sw/bootrom目录下的board.h+ s& P( y4 }- W& h) Q
: f& C5 |1 c7 E, O/ z' P

9 A1 ?: N8 @: q  U" Y
; {. ^$ i6 f& w1 F0 H6 r#ifndef _BOARD_H_7 o" T* N- x" {7 ?1 \: ]) }
#define _BOARD_H_" [1 d# c4 P0 w" ~; o7 Q
% r5 |( Y2 e2 k. W  {- S! h
//#define IN_CLK                50000000 // Hz
2 r/ |' ^. _$ {3 J#define IN_CLK                66666667 // Hz
' t5 b+ U6 e- |$ B4 Q0 e#define PRELOAD_RAM  
; q! G) _, v5 I% c3 y#define BOOTROM_MEM_TEST   ; T4 S) E/ ?! }
//  w8 w$ Z! N& w
// ROM bootloader/ V: z- v  O  N# ~# F" M
//& U! L$ j6 R& l% A
// Uncomment the appropriate bootloader define. This will effect the bootrom.S+ b7 t4 J4 ^7 K+ j- Q
// file, which is compiled and converted into Verilog for inclusion at ! G  u0 D4 Q3 O( e) E5 d( Y! K8 @
// synthesis time. See bootloader/bootloader.S for details on each option.' C; Y! H9 Y" E& o4 I* R
#ifndef PRELOAD_RAM
5 W& d7 V# s8 H2 G#define BOOTROM_SPI_FLASH. `0 n  u0 N! i8 a* h
//#define BOOTROM_GOTO_RESET5 G- ~( Q3 n1 f2 Z; F0 S4 R
//#define BOOTROM_LOOP_AT_ZERO. r: l$ ~( O8 t; [' k
//#define BOOTROM_LOOP_IN_ROM
5 O! @# o, m9 P+ Q; n6 W#else/ }9 ~9 Y. k0 c  U
        #ifdef BOOTROM_MEM_TEST4 G% M2 K- J" Q' B: A& a- E
                #define BOOTROM_MEM_TEST1
- f+ O5 I( B+ f, m        #else: s1 x& L, p1 m5 L, I) ?
                #define BOOTROM_GOTO_RESET
" Q9 ]- |# ?  J. e9 @        #endif
) O5 q+ d# ?0 ~#endif
2 f) k. ~( B. `( s6 e; ?- ?5 N8 T! A( z4 |
// Address bootloader should start from in FLASH% k: c& s) j" J  y
// Last 256KB of 2MB flash - offset 0x1c0000 (2MB-256KB)
3 U7 _1 i! S  K# R0 W- d+ M% B5 S#define BOOTROM_ADDR_BYTE2 0x1c+ Z! @/ s$ Q8 g$ U, l
#define BOOTROM_ADDR_BYTE1 0x00
. Z( m$ j$ n4 N5 n; W$ ]+ K* |6 O#define BOOTROM_ADDR_BYTE0 0x00
* ^, Z, \9 W) H7 W3 ~. j// Causes SPI bootloader to loop if SPI didn't give correct size of image
/ C& v1 [+ M0 f- N2 _/ I' c#define SPI_RETRY_IF_INSANE_SIZEWORD
/ M4 D4 k( L6 o- I# L, D0 ]  O
/ ~8 z1 `: }* @( v//% f9 K5 j9 V9 r: i7 v- f4 z
// Defines for each core (memory map base, OR1200 interrupt line number, etc.)
* d9 K# b( x" a/ R//; O9 Q+ E: c' c# X, v
#define SDRAM_BASE                 0x0$ b0 r3 n  z* C  S" G
0 V* i8 N$ o' N
#define GPIO_0_BASE         0x91000000& D7 c9 y  s0 }1 d
1 @3 q& g0 ~& u$ z# h& p6 I$ [  T
#define UART0_BASE              0x900000002 n( P" Y2 S# @( ~1 O4 _# z
#define UART0_IRQ                    26 }' u5 W2 ^/ k5 A6 U4 k2 d
#define UART0_BAUD_RATE         115200+ |- [, s+ T+ Y' c) R7 [

. z% [/ L' o% D& ^) Q
8 V& |) q+ @) |#define SPI0_BASE           0xb0000000% W8 g  Q4 c& u# o7 }
#define SPI0_IRQ                     6% \$ l' t3 p4 F5 `5 N, \+ w
7 {' ?3 \# `0 E
#define I2C_0_BASE          0xa0000000
7 E+ \& m0 b+ [! z% u#define I2C_0_IRQ                   101 N* Y% {. ?- p+ v$ ]
" E3 x# C# m. v; [
#define I2C_1_BASE          0xa1000000
0 ?) |) Y/ }  o, i/ h) L#define I2C_1_IRQ                   11
* W% z' r# b  ^: x. A8 @! O, m& R3 A) S# [& z/ e
#define ETH0_BASE            0x92000000
% H, n7 u- l) @6 S#define ETH0_IRQ                      4
' u$ q- v4 i4 x  u4 K$ V( g4 @' f5 M4 E1 i
#define ETH_MACADDR0                   0x00
, U6 [/ C0 a% ~% C. b+ w% K# c2 i#define ETH_MACADDR1                   0x12
' B) ]' P: o% D3 \0 o$ D% x$ a#define ETH_MACADDR2                     0x34
/ D4 w" I& e7 \2 V  y#define ETH_MACADDR3                   0x56
. y; S9 N5 g0 c0 x7 ?#define ETH_MACADDR4                     0x788 O' @; c. v3 a1 J( c1 o  p2 I
#define ETH_MACADDR5                   0x9a' x, d, F% p( R+ q/ ?1 D3 j
8 d) i6 F; p/ l2 X  K# d6 {
//( S! Q8 A+ j8 Z. M; [& l8 I! i
// OR1200 tick timer period define. |8 ?4 x4 H# f" H1 Y
//: G1 K9 a# d7 d+ {( x
#define TICKS_PER_SEC   100
% f6 k) e, }7 M& t) ^6 `% r
9 Z4 Z# h7 E& W4 U0 L' J//' j! K2 }) r* ]1 Y
// CFI flash controller base
: T! C" I9 f0 t: M9 o//; X5 Q6 p2 o) D* h
#define CFI_CTRL_BASE 0xf00000002 H0 W; b" I/ ^" b0 A1 R

9 ?# M  [4 J/ u# `# O//
0 B: s; r' r& j: M6 V  O4 L6 h3 N5 n* |// UART driver configuration
$ u8 m+ P- O" n+ W( H% K// ! j, b4 }6 x9 j. P2 o7 \+ n
#define UART_NUM_CORES 1
0 c( q' B3 D0 D+ x6 Q& }3 h#define UART_BASE_ADDRESSES_CSV        UART0_BASE
: V/ @: F! ^' n& f* v#define UART_BAUD_RATES_CSV UART0_BAUD_RATE
  I$ J; K9 l5 H1 `2 W0 _  p
& n! s) `8 @% @( R& ]8 Y  d9 N0 I6 f1 ~3 W+ Q1 ]) Q' D4 R
//
# g- |$ R9 K7 h3 n5 y1 K6 S2 D// i2c_master_slave core driver configuration
! P! f: K2 `& y/ Q: D//& z8 Z5 ~( H6 |% e: j& r
$ [1 @6 V2 a" ~  ?- }
#define I2C_MASTER_SLAVE_NUM_CORES 22 c; ^) R: [1 @' A
: _( b* U' ^  d2 Y
#define I2C_MASTER_SLAVE_BASE_ADDRESSES_CSV                \2 F& o( F$ q2 p+ R( O1 A- ]4 F# ]
        I2C_0_BASE, I2C_1_BASE% k# H2 q. u9 p

+ ~1 I8 d- b; f5 n6 U; Q3 d0 u( ]- ^! B  E. A- k
#endif- @$ ~. p. n7 l: f6 c$ A. a

+ v% i. d  ?) w. L* F! B6 D7 @2 H9 b% `' l5 }. f' P

3 G5 d, O9 q4 l" @8 G, ?% i; o% U1 s8 }) d- G/ b% f* }
1 y. V. V/ N  z' I4 M) D
1 E4 R0 R1 y2 @5 K
b,修改soc-design/orpsocv2/sw/bootrom目录下的bootrom.S, w3 G; X) h4 n8 a

' k% m  `/ M. D3 K& S) U: a这个文件,是需要我们自己手动编写OR的汇编了。! o; Q5 O& r) `5 n4 P" c
% Y  H# n& H# N) z+ q
需要注意的有几点。
$ G; u3 k; V8 `9 s. O/ o8 q
7 P( S! k+ S2 T/ T( u首先,如何让仿真自动退出:使用“l.nop 1”这条指令,具体原因可参考or1200_monitor.v文件中的相关内容。- J1 H: u# _, J

/ q* A; ]  w9 I1 J其次,如何判断读写内存的成功与失败,分别使用“l.nop 4”和“l.nop 3”。
! Z9 n4 K% c" G% p8 p6 u4 ], U0 Y( i9 d  N2 U
最后,这些汇编,都很容易理解,唯一需要注意的是OR支持延迟槽。$ O8 D0 H, b! F5 k( s

; x6 W7 j( d0 W下面是具体代码清单:0 f+ G" e, m7 b7 v: `6 S+ |

- u( T8 v" A5 L5 n. A4 S( J% R2 V: @, a
1 l( J0 l; s4 P2 W+ m
5 B0 v4 S8 \+ h1 v* U//! _  C6 c1 _2 u& t' e% i
///                                                                8 V" o5 z  N( N8 p
/// bootrom      Rill 2014-04-28                                 
; J' `8 C, U2 H- ], S///                                                               . Y; z* ~+ s, l" [0 T5 g/ P
/// Assembly programs to be embedded inside system to aid boot    2 g$ \' }/ N+ _( M* T$ }  }
///                                                               + j& u  ~/ U/ _. [$ o. Z/ R
///                                                               
& N1 a$ R7 ]. G: x$ C2 H//0 Q: k8 u* n; n1 e! q

4 [7 \5 I4 j( _- x# S8 o1 E// Defines for which bootrom app to use are in board.h - TODO: use the
0 G" T: G* u% f/ }/ p! F5 @5 a, G// processed orspoc-defines.v file for this define. It makes more sense
) h# \+ C2 M+ G' t; D1 \// as this software ends up as gates.3 f6 K1 y, J# ^
        
" Z  B4 X  n4 j1 C  m7 M: v#include "board.h") m7 I% Y( i+ T' A  ?0 W  N9 M

  i9 }2 t% \! D+ m6 a4 K- G# R
; o; V9 v4 z$ U#ifdef BOOTROM_MEM_TEST1" e) p1 L& V8 e' l# C
        
5 g) a% l/ x. Q; n#define RAM_LOAD_BASE 0x1000004 Z" D' @$ I9 X: t! i8 y4 w" o
#define RESET_ADDR 0x100
: w; Z" h6 B$ ]% l#define RAM_LOAD_VALUE 0x5555
% F* \9 Z1 C4 x5 U0 m! p1 ?% D  I* W#define RAM_LOAD_SIZE 0xc
1 C' i, B9 S2 n  n
( r! \5 a9 u, j9 w+ \boot_init:        
; a/ l2 i/ L+ Z# ]; {, i        l.movhi r0, 0  /*0*/; ^. d* }6 p+ f9 r1 O# x* c8 \
        l.movhi r1, RAM_LOAD_BASE /*1*/
! j8 ^6 ~9 K8 d% r) |
9 Z# O) _4 G. C" a  fmem_write:! U# {! w% L0 _) n7 {9 m# w
        l.movhi r6, 0 /*2*/ /* counter*/
1 g9 i2 ~! ?3 \% Q1 J: `        l.ori r7, r0, RAM_LOAD_SIZE /*3*/
% X! M" I( S- ^8 P0 a; w! Q1 K        //l.movhi        r7, RAM_LOAD_SIZE
5 E: Z, J) M5 \, Q) G3 J        l.movhi r8, 0 /*4*/ /* load addr index*/' j, P! \. s8 j$ \( Q: {
write:        
% ]( |" X* f* r/ y: r" l        l.ori        r3,r0, RAM_LOAD_VALUE    /*5*/    /* Read a byte into r3 */: n9 L2 S" i, u" I: e, _
        l.add        r8, r1, r6    /*6*/   /* Calculate store address */
- J! r. P* |" U  k7 b# E) w- H        l.sw        0(r8), r3     /*7*/   /* Write byte to memory */& Y* D' _( B3 X7 t
        l.addi        r6, r6, 4     /*8*/   /* Increment counter */
8 P8 ?6 `1 g" S: _) O        l.sfeq         r6, r7                 /*9*/  /* Check if we've finished loading the words */$ u# V$ x, E# l
        l.bnf         write       /*10*/  /* Continue copying if not last word */
; S6 I, p3 B) [        l.nop                        /*11*// q9 \7 m, u& }2 n% ?. J; s

2 Y7 i! Q! ?. b. Lmem_read:
6 t$ n- p3 K4 `% U& f; t$ G5 C        l.movhi r6, 0
$ K  ^1 p2 R# N% o        l.ori r7, r0, RAM_LOAD_SIZE
" w2 ?) x, M1 m: a! @; k9 M        l.movhi r8, 0! n7 I2 [) ]8 C7 R
read:4 p% ?" ^+ K+ U+ A1 t
        l.add        r8, r1, r6: c4 a( Q3 q6 h( D" D. [
        l.lwz        r3, 0(r8)
- ]. i1 s$ E6 t/ @; f" h# U+ a        l.j        check
: F. c$ a1 W* w        l.nop3 g0 ^' c( n* B8 B& e- _7 M0 r
read2:4 Z5 r& ?3 p8 y9 t! z1 O
        l.addi        r6, r6, 42 c. p" X6 N0 C/ y
        l.sfeq         r6, r73 v& O5 {: `) ]/ W
        l.bnf         read1 _, V: L+ P) P- k' G3 F
        l.nop: S* T+ a4 }( M9 }! h
        l.j        success+ @. X0 c2 B6 J1 v& i; k; e
        l.nop3 y2 |1 n: h1 I; Q- D

" {( }6 B0 t9 Q6 Icheck:; O' S$ d& x  s( g( b; ~3 n1 {- t
        l.ori        r5,r0, RAM_LOAD_VALUE
3 I: U, O2 \; H7 Q        l.sfeq         r3, r5. I( p$ b  B( V. x/ D# d
        l.bnf         error
: F  H. e& _1 h. T* v* o        l.nop0 t: }( U& S; v$ N0 [- m8 P% ^
        l.j        read25 ?! A- ?9 Q( {8 s% u" a9 ]7 k; |; L& L1 @
        l.nop
1 c( M! A* Q3 D3 c$ S- u3 A# c5 g) r9 w' h, c" B$ @/ j1 Y
error:
. P! [  j; X! ^5 @) M5 s7 X; I        l.nop         3
4 C. m6 n7 p. |        l.j error        
" l# Y% n- ^1 c- S1 K, r        l.nop        10 D! X( n8 ]& N

# |" m& l  x) \4 tsuccess:8 ]! H: W- h1 h
        l.nop        40 ?& w! v4 W* W' x% {, e
        l.j        success        
$ ?: P& D. |* I2 Y8 d/ s' y        l.nop        1% ^' I1 C. M7 g* o3 ~7 C* o. r

* G, o( t" B& {( G, C. A#endif
  J* G) c3 e8 X/ F* P) U* v% N
1 c* s8 c" ?3 ~- f
# {! V' ^2 }4 d1 t1 L- |
7 K# G& L9 U# D# ~8 v! t! D& x4 x& r2 I5 A
! h- j. c' f$ o0 X! N, B9 g
  i- n1 _% M* g( e8 j
c,创建C语言裸机测试目录和程序' f& k7 z- E0 @" S9 d2 z" o. B' I0 d
% W# @7 ^8 |8 d* J2 @
由于我们想利用ORPSoC现成的测试环境,所以我们还需要编写一个假的,只是为了满足原有的测试环境的目录和文件。+ d8 \' p& \5 ]+ I0 O
" P8 o% R9 H: d* ~4 P4 `
在soc-design/orpsocv2/board/xilinx/ml501/sw/tests目录下创建目录和文件:
% B! U* T9 a8 z8 R* _, @" @) Z6 o3 ~$ Z0 i; d: c
" a2 {; b+ Z7 g: n/ T0 c( b* E
) P. m( ^* a5 ~3 M7 f3 y/ Y+ c
mkdir mem
) d; N8 {, k6 fcd mem+ G  T+ x' v( q5 ]- @+ ]7 P, X
touch mem.c  R0 Q4 y' q4 [3 w$ H) a7 U' V
cp ../../Makefile .0 _# H. @5 P; c
6 S# O1 K, m' k9 Y4 A; T4 f/ C

/ P3 Z& [- ^' b- [) v' M9 F; ~  |; n7 `- d8 C$ k

7 X: [$ \" J3 M5 s编辑mem.c:
. S1 W# h- b( y- Y5 K8 c* f% v- h, F4 k+ M

; `; {- M9 o$ O. e4 U
, w& m& _- V3 ?. w  c/*
+ ]' ^) R7 A% j$ E* e2 o* I. Y* Rill& T0 J8 B* l5 m0 ~7 L) ^5 L
* april/28/2014! w1 k, y7 M5 h* i0 B& U! x" E, |
*/; r) Y% R4 ~1 g- d* U. q! `2 f

5 z2 x, u& F# L. [6 V( h5 oint main()
' ]9 ~% _! \8 N$ \" J0 S6 d{3 w' q. p0 C( J; C; |1 ^
        while(1);//we run instructions in bootrom ONLY.+ d8 [$ b* l' A9 D# r+ Q
        return 0;
  M7 A1 }* v. o$ ^! I6 e% d}/ n' Z0 V7 k8 o; b, O
0 u: D- |' h9 @% k  @

' U8 u) x3 G% t9 W由于我们只运行bootrom.S中的指令,所以mem.c里面写什么语句不重要。
( [1 ?! o" P8 U8 |1 Z9 E, g& W5 U$ @) a

1 D+ C2 K& M$ O' B8 h' ~) m# T. o
" n* S, W$ w$ z6 ?$ Zd,测试与验证' D$ O5 m& R1 W- O  Q

( [- r; }; l% @完成编码之后,我们就可以运行我们刚才写的汇编程序了,方法我们之前已经介绍过多次了,这里重复如下:/ t/ g. n7 `4 Y/ y: l# O5 `' C; P
3 c. A( p: Z4 }2 h
在 soc-design/orpsocv2/board/xilinx/ml501/sim/run目录下执行如下:
- x  K2 O% |, W  t/ t# r% J
6 N; W: ]- T+ O. t5 `! A7 {
0 C, I5 y( \8 p) I: A6 M( e
/ I! x+ ?" i: J. P8 M8 Emake rtl-test TEST=mem VCD=11 o2 Z7 X* y* ?, z" m4 V/ Y" H& G
9 ^/ p$ A6 Z4 b9 ]  d

8 [1 i8 }; ~! \/ a) v- @6 G" l很快,我们就可以仿真结束,然后,我们就可以查看仿真日志文件和仿真波形。) X' H/ k1 I  C
0 \: B# O1 O: M
从中可以看出,对内存的读写都是正确的。
- b3 E7 `3 ^6 \( f5 C
( \3 K7 U/ b4 F8 nor1200_monitor输出的日志文件:mem-general.log
9 |# ?/ y( ^; k) R$ X0 e# m' r7 Q- Z$ `0 G: w% q' g7 L0 `8 {

+ {, W" l$ ?  x* \- I3 s# @. l0 `; N' `( \( m0 p4 M+ \2 s0 ~
58598000.0 ps: l.nop 4 putc (U), N9 A+ p8 B% V
58718000.0 ps: l.nop exit (00005555)
- l, G+ ?" I, G! |! c( @+ E6 G* ~: z" A' }$ h& Y. C/ u/ {
$ F5 l2 x9 X; }2 H) A6 C
$ K1 I$ G2 D- U/ g* a

! _( W3 g; `* s& \) ~/ Q( Z4 K9 t0 X

. P5 x! P3 x( C# `# }8 }vcd波形文件:% T( d0 b7 W5 j9 l& c7 J
2 w& s/ ^. ~+ g

, i1 a/ Q* f7 ~8 d* ]# A6 X; W5 \7 L4 u
* H* u: X* b  {$ @* E* F& `
: k% b1 H4 _3 F" M9 M3 S

1 K+ I% q( C6 \
; b& i1 ~; U4 N! V! g9 U8 P
: b9 n; q  n# r  f5 l
0 W8 x& m3 A/ v, B8 Z" T; h  s0 s3,小结- ]- i$ W; L9 S& n  V  Y8 n' y$ I
对于cpu来说,对所有外设(uart,i2c,vga......)的控制都可以通过load/store来完成,和读写内存的实质是完全相同的,所以,通过上面的汇编,我们只要改变一下读写地址修改成对应外设的地址,我们就可以实现对该设备的控制了。* q7 D+ U/ D7 P+ p
- u/ a: b. H! D! D' ]
当然,编写出优秀的汇编程序也不是一件太容易的事情,这就需要详细阅读OR的架构手册,掌握GPR和SPR的使用方法。甚至,我们还要查看or32-elf-asm来了解更准确的OR的指令集。
; V9 x9 D. y* X( l! ]

该用户从未签到

2#
发表于 2020-11-10 14:30 | 只看该作者
不知道回加#技术风云榜#的帖,有没有奖励
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-9-23 02:42 , Processed in 0.140625 second(s), 26 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表