From 30ba161180b60e5d5f0ee28d3f247c397529ef43 Mon Sep 17 00:00:00 2001 From: Bernard Xiong Date: Fri, 12 Oct 2018 12:11:07 +0800 Subject: [PATCH] import rt-thread code update rt-thread version to 33cb916ff7aa684d06769497bb5f5914e7ff95a2 --- .gitignore | 2 + rt-thread/.gitattributes | 42 + rt-thread/.gitignore | 28 + rt-thread/.travis.yml | 91 + rt-thread/AUTHORS | 45 + rt-thread/ChangeLog.md | 956 +++++++ rt-thread/Kconfig | 3 + rt-thread/LICENSE | 201 ++ rt-thread/README.md | 88 + rt-thread/README_zh.md | 97 + rt-thread/components/Kconfig | 28 + rt-thread/components/SConscript | 17 + rt-thread/components/drivers/Kconfig | 438 ++++ rt-thread/components/drivers/SConscript | 14 + .../drivers/include/drivers/alarm.h | 86 + .../drivers/include/drivers/audio.h | 230 ++ .../components/drivers/include/drivers/can.h | 301 +++ .../drivers/include/drivers/cputime.h | 42 + .../drivers/include/drivers/hwtimer.h | 78 + .../drivers/include/drivers/i2c-bit-ops.h | 53 + .../components/drivers/include/drivers/i2c.h | 105 + .../drivers/include/drivers/i2c_dev.h | 52 + .../components/drivers/include/drivers/mmc.h | 206 ++ .../drivers/include/drivers/mmcsd_card.h | 185 ++ .../drivers/include/drivers/mmcsd_cmd.h | 143 + .../drivers/include/drivers/mmcsd_core.h | 260 ++ .../drivers/include/drivers/mmcsd_host.h | 140 + .../components/drivers/include/drivers/mtd.h | 109 + .../drivers/include/drivers/mtd_nand.h | 131 + .../drivers/include/drivers/mtd_nor.h | 81 + .../drivers/include/drivers/mtdnand.h | 105 + .../drivers/include/drivers/mtdnor.h | 39 + .../components/drivers/include/drivers/pin.h | 107 + .../drivers/include/drivers/rt_drv_pwm.h | 61 + .../components/drivers/include/drivers/rtc.h | 34 + .../components/drivers/include/drivers/sd.h | 47 + .../components/drivers/include/drivers/sdio.h | 245 ++ .../drivers/include/drivers/sdio_func_ids.h | 53 + .../drivers/include/drivers/serial.h | 185 ++ .../components/drivers/include/drivers/spi.h | 276 ++ .../drivers/include/drivers/usb_common.h | 579 ++++ .../drivers/include/drivers/usb_device.h | 470 ++++ .../drivers/include/drivers/usb_host.h | 283 ++ .../drivers/include/drivers/watchdog.h | 56 + .../components/drivers/include/drivers/wlan.h | 21 + .../drivers/include/ipc/completion.h | 23 + .../drivers/include/ipc/dataqueue.h | 53 + .../components/drivers/include/ipc/pipe.h | 36 + .../components/drivers/include/ipc/poll.h | 53 + .../drivers/include/ipc/ringblk_buf.h | 115 + .../drivers/include/ipc/ringbuffer.h | 88 + .../drivers/include/ipc/waitqueue.h | 73 + .../drivers/include/ipc/workqueue.h | 44 + .../components/drivers/include/rtdevice.h | 121 + .../components/drivers/serial/SConscript | 8 + rt-thread/components/drivers/serial/serial.c | 1265 +++++++++ rt-thread/components/drivers/src/SConscript | 13 + rt-thread/components/drivers/src/ringbuffer.c | 375 +++ rt-thread/components/finsh/Kconfig | 81 + rt-thread/components/finsh/SConscript | 46 + rt-thread/components/finsh/cmd.c | 852 ++++++ rt-thread/components/finsh/finsh.h | 262 ++ rt-thread/components/finsh/finsh_api.h | 231 ++ rt-thread/components/finsh/finsh_compiler.c | 937 +++++++ rt-thread/components/finsh/finsh_error.c | 74 + rt-thread/components/finsh/finsh_error.h | 42 + rt-thread/components/finsh/finsh_heap.c | 298 +++ rt-thread/components/finsh/finsh_heap.h | 38 + rt-thread/components/finsh/finsh_init.c | 76 + rt-thread/components/finsh/finsh_node.c | 202 ++ rt-thread/components/finsh/finsh_node.h | 88 + rt-thread/components/finsh/finsh_ops.c | 622 +++++ rt-thread/components/finsh/finsh_ops.h | 135 + rt-thread/components/finsh/finsh_parser.c | 1005 +++++++ rt-thread/components/finsh/finsh_parser.h | 37 + rt-thread/components/finsh/finsh_token.c | 617 +++++ rt-thread/components/finsh/finsh_token.h | 82 + rt-thread/components/finsh/finsh_var.c | 161 ++ rt-thread/components/finsh/finsh_var.h | 60 + rt-thread/components/finsh/finsh_vm.c | 404 +++ rt-thread/components/finsh/finsh_vm.h | 54 + rt-thread/components/finsh/msh.c | 631 +++++ rt-thread/components/finsh/msh.h | 42 + rt-thread/components/finsh/msh_cmd.c | 441 ++++ rt-thread/components/finsh/msh_file.c | 159 ++ rt-thread/components/finsh/shell.c | 868 ++++++ rt-thread/components/finsh/shell.h | 129 + rt-thread/components/finsh/symbol.c | 84 + rt-thread/components/libc/Kconfig | 36 + rt-thread/components/libc/SConscript | 15 + .../components/libc/compilers/SConscript | 15 + .../libc/compilers/armlibc/SConscript | 21 + .../libc/compilers/armlibc/dirent.h | 54 + .../components/libc/compilers/armlibc/fcntl.h | 8 + .../components/libc/compilers/armlibc/libc.c | 59 + .../components/libc/compilers/armlibc/libc.h | 38 + .../libc/compilers/armlibc/libc_syms.c | 41 + .../libc/compilers/armlibc/mem_std.c | 48 + .../components/libc/compilers/armlibc/stdio.c | 91 + .../components/libc/compilers/armlibc/stubs.c | 334 +++ .../libc/compilers/armlibc/sys/README.md | 1 + .../libc/compilers/armlibc/sys/errno.h | 6 + .../libc/compilers/armlibc/sys/mman.h | 72 + .../libc/compilers/armlibc/sys/stat.h | 0 .../libc/compilers/armlibc/sys/time.h | 45 + .../libc/compilers/armlibc/sys/types.h | 12 + .../libc/compilers/armlibc/sys/unistd.h | 41 + .../libc/compilers/armlibc/termios.h | 7 + .../components/libc/compilers/armlibc/time.c | 77 + .../libc/compilers/armlibc/unistd.h | 1 + .../components/libc/compilers/dlib/README.md | 4 + .../components/libc/compilers/dlib/SConscript | 26 + .../components/libc/compilers/dlib/dirent.h | 54 + .../components/libc/compilers/dlib/environ.c | 25 + .../components/libc/compilers/dlib/fcntl.h | 0 .../components/libc/compilers/dlib/libc.c | 60 + .../components/libc/compilers/dlib/libc.h | 39 + .../components/libc/compilers/dlib/rmtx.c | 74 + .../components/libc/compilers/dlib/stdio.c | 74 + .../libc/compilers/dlib/sys/README.md | 1 + .../libc/compilers/dlib/sys/errno.h | 7 + .../components/libc/compilers/dlib/sys/mman.h | 72 + .../components/libc/compilers/dlib/sys/stat.h | 0 .../components/libc/compilers/dlib/sys/time.h | 52 + .../libc/compilers/dlib/sys/types.h | 12 + .../libc/compilers/dlib/sys/unistd.h | 39 + .../libc/compilers/dlib/syscall_close.c | 43 + .../libc/compilers/dlib/syscall_lseek.c | 43 + .../libc/compilers/dlib/syscall_mem.c | 46 + .../libc/compilers/dlib/syscall_open.c | 88 + .../libc/compilers/dlib/syscall_read.c | 57 + .../libc/compilers/dlib/syscall_remove.c | 38 + .../libc/compilers/dlib/syscall_write.c | 68 + .../components/libc/compilers/dlib/syscalls.h | 23 + .../components/libc/compilers/dlib/termios.h | 7 + .../components/libc/compilers/dlib/time.c | 76 + .../components/libc/compilers/dlib/unistd.h | 6 + .../libc/compilers/minilibc/SConscript | 15 + .../libc/compilers/minilibc/ctype.c | 53 + .../libc/compilers/minilibc/ctype.h | 22 + .../libc/compilers/minilibc/errno.h | 8 + .../libc/compilers/minilibc/inttypes.h | 6 + .../components/libc/compilers/minilibc/math.c | 168 ++ .../components/libc/compilers/minilibc/math.h | 9 + .../libc/compilers/minilibc/qsort.c | 44 + .../components/libc/compilers/minilibc/rand.c | 35 + .../libc/compilers/minilibc/stddef.h | 7 + .../libc/compilers/minilibc/stdint.h | 258 ++ .../libc/compilers/minilibc/stdio.h | 18 + .../libc/compilers/minilibc/stdlib.c | 79 + .../libc/compilers/minilibc/stdlib.h | 37 + .../libc/compilers/minilibc/string.c | 634 +++++ .../libc/compilers/minilibc/string.h | 73 + .../libc/compilers/minilibc/sys/mman.h | 72 + .../libc/compilers/minilibc/sys/stat.h | 36 + .../libc/compilers/minilibc/sys/time.h | 46 + .../libc/compilers/minilibc/sys/types.h | 37 + .../components/libc/compilers/minilibc/time.c | 282 ++ .../components/libc/compilers/minilibc/time.h | 16 + .../libc/compilers/newlib/SConscript | 21 + .../components/libc/compilers/newlib/libc.c | 66 + .../components/libc/compilers/newlib/libc.h | 55 + .../libc/compilers/newlib/libc_syms.c | 72 + .../components/libc/compilers/newlib/stdio.c | 96 + .../libc/compilers/newlib/sys/dirent.h | 57 + .../libc/compilers/newlib/sys/mman.h | 72 + .../libc/compilers/newlib/sys/statfs.h | 13 + .../libc/compilers/newlib/sys/termios.h | 0 .../libc/compilers/newlib/syscalls.c | 426 +++ .../libc/compilers/newlib/termios.h | 7 + .../components/libc/compilers/newlib/time.c | 77 + rt-thread/include/libc/libc_dirent.h | 14 + rt-thread/include/libc/libc_errno.h | 161 ++ rt-thread/include/libc/libc_fcntl.h | 102 + rt-thread/include/libc/libc_fdset.h | 64 + rt-thread/include/libc/libc_ioctl.h | 234 ++ rt-thread/include/libc/libc_signal.h | 192 ++ rt-thread/include/libc/libc_stat.h | 107 + rt-thread/include/rtdbg.h | 174 ++ rt-thread/include/rtdebug.h | 146 ++ rt-thread/include/rtdef.h | 1038 ++++++++ rt-thread/include/rthw.h | 128 + rt-thread/include/rtlibc.h | 39 + rt-thread/include/rtm.h | 47 + rt-thread/include/rtservice.h | 319 +++ rt-thread/include/rtthread.h | 535 ++++ rt-thread/libcpu/Kconfig | 90 + rt-thread/libcpu/SConscript | 31 + rt-thread/libcpu/arm/AT91SAM7S/AT91SAM7S.h | 297 +++ rt-thread/libcpu/arm/AT91SAM7S/context_gcc.S | 94 + rt-thread/libcpu/arm/AT91SAM7S/context_rvds.S | 107 + rt-thread/libcpu/arm/AT91SAM7S/cpu.c | 42 + rt-thread/libcpu/arm/AT91SAM7S/interrupt.c | 91 + rt-thread/libcpu/arm/AT91SAM7S/serial.c | 387 +++ rt-thread/libcpu/arm/AT91SAM7S/serial.h | 56 + rt-thread/libcpu/arm/AT91SAM7S/stack.c | 63 + rt-thread/libcpu/arm/AT91SAM7S/start_gcc.S | 237 ++ rt-thread/libcpu/arm/AT91SAM7S/start_rvds.S | 499 ++++ rt-thread/libcpu/arm/AT91SAM7S/trap.c | 40 + rt-thread/libcpu/arm/AT91SAM7X/context_gcc.S | 99 + rt-thread/libcpu/arm/AT91SAM7X/context_rvds.S | 107 + rt-thread/libcpu/arm/AT91SAM7X/cpu.c | 42 + rt-thread/libcpu/arm/AT91SAM7X/interrupt.c | 114 + rt-thread/libcpu/arm/AT91SAM7X/stack.c | 63 + rt-thread/libcpu/arm/AT91SAM7X/start_gcc.S | 279 ++ rt-thread/libcpu/arm/AT91SAM7X/start_rvds.S | 517 ++++ rt-thread/libcpu/arm/AT91SAM7X/trap.c | 53 + rt-thread/libcpu/arm/am335x/am33xx.h | 341 +++ rt-thread/libcpu/arm/am335x/context_gcc.S | 102 + rt-thread/libcpu/arm/am335x/context_iar.S | 96 + rt-thread/libcpu/arm/am335x/cp15_gcc.S | 145 + rt-thread/libcpu/arm/am335x/cp15_iar.s | 154 ++ rt-thread/libcpu/arm/am335x/cpu.c | 168 ++ rt-thread/libcpu/arm/am335x/interrupt.c | 217 ++ rt-thread/libcpu/arm/am335x/interrupt.h | 50 + rt-thread/libcpu/arm/am335x/mmu.c | 193 ++ rt-thread/libcpu/arm/am335x/mmu.h | 51 + rt-thread/libcpu/arm/am335x/stack.c | 68 + rt-thread/libcpu/arm/am335x/start_gcc.S | 265 ++ rt-thread/libcpu/arm/am335x/start_iar.s | 292 +++ rt-thread/libcpu/arm/am335x/trap.c | 200 ++ rt-thread/libcpu/arm/am335x/vector_gcc.S | 65 + rt-thread/libcpu/arm/arm926/context_gcc.S | 92 + rt-thread/libcpu/arm/arm926/context_iar.S | 96 + rt-thread/libcpu/arm/arm926/context_rvds.S | 105 + rt-thread/libcpu/arm/arm926/cpuport.c | 244 ++ rt-thread/libcpu/arm/arm926/mmu.c | 457 ++++ rt-thread/libcpu/arm/arm926/mmu.h | 63 + rt-thread/libcpu/arm/arm926/stack.c | 80 + rt-thread/libcpu/arm/arm926/start_gcc.S | 319 +++ rt-thread/libcpu/arm/arm926/start_iar.S | 292 +++ rt-thread/libcpu/arm/arm926/start_rvds.S | 327 +++ rt-thread/libcpu/arm/arm926/trap.c | 221 ++ rt-thread/libcpu/arm/armv6/arm_entry_gcc.S | 140 + rt-thread/libcpu/arm/armv6/armv6.h | 107 + rt-thread/libcpu/arm/armv6/context_gcc.S | 110 + rt-thread/libcpu/arm/armv6/cpuport.c | 248 ++ rt-thread/libcpu/arm/armv6/mmu.c | 562 ++++ rt-thread/libcpu/arm/armv6/mmu.h | 208 ++ rt-thread/libcpu/arm/armv6/stack.c | 82 + rt-thread/libcpu/arm/armv6/vfp.c | 52 + rt-thread/libcpu/arm/armv6/vfp.h | 110 + rt-thread/libcpu/arm/common/backtrace.c | 67 + rt-thread/libcpu/arm/common/div0.c | 4 + rt-thread/libcpu/arm/common/divsi3.S | 393 +++ rt-thread/libcpu/arm/common/showmem.c | 42 + rt-thread/libcpu/arm/cortex-a/armv7.h | 64 + rt-thread/libcpu/arm/cortex-a/context_gcc.S | 105 + rt-thread/libcpu/arm/cortex-a/cp15.h | 12 + rt-thread/libcpu/arm/cortex-a/cp15_gcc.S | 140 + rt-thread/libcpu/arm/cortex-a/cpu.c | 37 + rt-thread/libcpu/arm/cortex-a/interrupt.c | 152 ++ rt-thread/libcpu/arm/cortex-a/mmu.c | 207 ++ rt-thread/libcpu/arm/cortex-a/pmu.c | 12 + rt-thread/libcpu/arm/cortex-a/pmu.h | 151 ++ rt-thread/libcpu/arm/cortex-a/stack.c | 68 + rt-thread/libcpu/arm/cortex-a/start_gcc.S | 249 ++ rt-thread/libcpu/arm/cortex-a/trap.c | 181 ++ rt-thread/libcpu/arm/cortex-a/vector_gcc.S | 65 + rt-thread/libcpu/arm/cortex-m0/context_gcc.S | 214 ++ rt-thread/libcpu/arm/cortex-m0/context_iar.S | 210 ++ rt-thread/libcpu/arm/cortex-m0/context_rvds.S | 219 ++ rt-thread/libcpu/arm/cortex-m0/cpuport.c | 120 + rt-thread/libcpu/arm/cortex-m3/context_gcc.S | 214 ++ rt-thread/libcpu/arm/cortex-m3/context_iar.S | 206 ++ rt-thread/libcpu/arm/cortex-m3/context_rvds.S | 211 ++ rt-thread/libcpu/arm/cortex-m3/cpuport.c | 407 +++ rt-thread/libcpu/arm/cortex-m4/context_gcc.S | 249 ++ rt-thread/libcpu/arm/cortex-m4/context_iar.S | 257 ++ rt-thread/libcpu/arm/cortex-m4/context_rvds.S | 251 ++ rt-thread/libcpu/arm/cortex-m4/cpuport.c | 487 ++++ rt-thread/libcpu/arm/cortex-m7/context_gcc.S | 249 ++ rt-thread/libcpu/arm/cortex-m7/context_iar.S | 257 ++ rt-thread/libcpu/arm/cortex-m7/context_rvds.S | 257 ++ rt-thread/libcpu/arm/cortex-m7/cpuport.c | 487 ++++ rt-thread/libcpu/arm/cortex-r4/armv7.h | 48 + .../libcpu/arm/cortex-r4/context_ccs.asm | 264 ++ rt-thread/libcpu/arm/cortex-r4/context_gcc.S | 255 ++ rt-thread/libcpu/arm/cortex-r4/cpu.c | 99 + rt-thread/libcpu/arm/cortex-r4/interrupt.c | 110 + rt-thread/libcpu/arm/cortex-r4/stack.c | 87 + rt-thread/libcpu/arm/cortex-r4/start_ccs.asm | 552 ++++ rt-thread/libcpu/arm/cortex-r4/start_gcc.S | 478 ++++ rt-thread/libcpu/arm/cortex-r4/trap.c | 152 ++ rt-thread/libcpu/arm/cortex-r4/vector_ccs.asm | 34 + rt-thread/libcpu/arm/cortex-r4/vector_gcc.S | 31 + rt-thread/libcpu/arm/dm36x/context_gcc.S | 109 + rt-thread/libcpu/arm/dm36x/context_rvds.S | 117 + rt-thread/libcpu/arm/dm36x/cpuport.c | 246 ++ rt-thread/libcpu/arm/dm36x/mmu.c | 560 ++++ rt-thread/libcpu/arm/dm36x/mmu.h | 164 ++ rt-thread/libcpu/arm/dm36x/stack.c | 81 + rt-thread/libcpu/arm/lpc214x/context_gcc.S | 102 + rt-thread/libcpu/arm/lpc214x/context_rvds.S | 164 ++ rt-thread/libcpu/arm/lpc214x/cpuport.c | 206 ++ rt-thread/libcpu/arm/lpc214x/lpc214x.h | 393 +++ rt-thread/libcpu/arm/lpc214x/start_rvds.S | 464 ++++ rt-thread/libcpu/arm/lpc214x/startup_gcc.S | 312 +++ rt-thread/libcpu/arm/lpc24xx/LPC24xx.h | 1201 +++++++++ rt-thread/libcpu/arm/lpc24xx/context_gcc.S | 99 + rt-thread/libcpu/arm/lpc24xx/context_rvds.S | 111 + rt-thread/libcpu/arm/lpc24xx/cpu.c | 42 + rt-thread/libcpu/arm/lpc24xx/interrupt.c | 107 + rt-thread/libcpu/arm/lpc24xx/stack.c | 67 + rt-thread/libcpu/arm/lpc24xx/start_gcc.S | 286 ++ rt-thread/libcpu/arm/lpc24xx/start_rvds.S | 1632 ++++++++++++ rt-thread/libcpu/arm/lpc24xx/trap.c | 147 ++ .../libcpu/arm/realview-a8-vmm/SConscript | 17 + rt-thread/libcpu/arm/realview-a8-vmm/armv7.h | 64 + .../libcpu/arm/realview-a8-vmm/context_gcc.S | 172 ++ rt-thread/libcpu/arm/realview-a8-vmm/cp15.h | 12 + .../libcpu/arm/realview-a8-vmm/cp15_gcc.S | 140 + rt-thread/libcpu/arm/realview-a8-vmm/cpu.c | 37 + rt-thread/libcpu/arm/realview-a8-vmm/gic.c | 316 +++ rt-thread/libcpu/arm/realview-a8-vmm/gic.h | 35 + .../libcpu/arm/realview-a8-vmm/interrupt.c | 144 + .../libcpu/arm/realview-a8-vmm/interrupt.h | 50 + rt-thread/libcpu/arm/realview-a8-vmm/mmu.c | 207 ++ rt-thread/libcpu/arm/realview-a8-vmm/pmu.c | 12 + rt-thread/libcpu/arm/realview-a8-vmm/pmu.h | 151 ++ rt-thread/libcpu/arm/realview-a8-vmm/stack.c | 67 + .../libcpu/arm/realview-a8-vmm/start_gcc.S | 366 +++ rt-thread/libcpu/arm/realview-a8-vmm/trap.c | 204 ++ .../libcpu/arm/realview-a8-vmm/vector_gcc.S | 66 + rt-thread/libcpu/arm/s3c24x0/context_gcc.S | 99 + rt-thread/libcpu/arm/s3c24x0/context_rvds.S | 107 + rt-thread/libcpu/arm/s3c24x0/cpu.c | 190 ++ rt-thread/libcpu/arm/s3c24x0/interrupt.c | 132 + rt-thread/libcpu/arm/s3c24x0/mmu.c | 394 +++ rt-thread/libcpu/arm/s3c24x0/rtc.c | 189 ++ rt-thread/libcpu/arm/s3c24x0/rtc.h | 21 + rt-thread/libcpu/arm/s3c24x0/s3c24x0.h | 611 +++++ rt-thread/libcpu/arm/s3c24x0/serial.c | 295 +++ rt-thread/libcpu/arm/s3c24x0/serial.h | 58 + rt-thread/libcpu/arm/s3c24x0/stack.c | 63 + rt-thread/libcpu/arm/s3c24x0/start_gcc.S | 390 +++ rt-thread/libcpu/arm/s3c24x0/start_rvds.S | 1190 +++++++++ rt-thread/libcpu/arm/s3c24x0/system_clock.c | 108 + rt-thread/libcpu/arm/s3c24x0/trap.c | 177 ++ rt-thread/libcpu/arm/s3c44b0/context_gcc.S | 99 + rt-thread/libcpu/arm/s3c44b0/context_rvds.S | 107 + rt-thread/libcpu/arm/s3c44b0/cpu.c | 122 + rt-thread/libcpu/arm/s3c44b0/interrupt.c | 148 ++ rt-thread/libcpu/arm/s3c44b0/s3c44b0.h | 346 +++ rt-thread/libcpu/arm/s3c44b0/serial.c | 118 + rt-thread/libcpu/arm/s3c44b0/stack.c | 62 + rt-thread/libcpu/arm/s3c44b0/start_gcc.S | 257 ++ rt-thread/libcpu/arm/s3c44b0/start_rvds.S | 1072 ++++++++ rt-thread/libcpu/arm/s3c44b0/trap.c | 181 ++ rt-thread/libcpu/arm/sep4020/clk.c | 112 + rt-thread/libcpu/arm/sep4020/context_rvds.S | 107 + rt-thread/libcpu/arm/sep4020/cpu.c | 190 ++ rt-thread/libcpu/arm/sep4020/interrupt.c | 135 + rt-thread/libcpu/arm/sep4020/sep4020.h | 867 ++++++ rt-thread/libcpu/arm/sep4020/serial.c | 282 ++ rt-thread/libcpu/arm/sep4020/serial.h | 90 + rt-thread/libcpu/arm/sep4020/stack.c | 61 + rt-thread/libcpu/arm/sep4020/start_rvds.S | 385 +++ rt-thread/libcpu/arm/sep4020/trap.c | 171 ++ rt-thread/libcpu/arm/zynq7000/SConscript | 17 + rt-thread/libcpu/arm/zynq7000/armv7.h | 65 + rt-thread/libcpu/arm/zynq7000/context_gcc.S | 102 + rt-thread/libcpu/arm/zynq7000/cp15.h | 31 + rt-thread/libcpu/arm/zynq7000/cp15_gcc.S | 140 + rt-thread/libcpu/arm/zynq7000/cpu.c | 45 + rt-thread/libcpu/arm/zynq7000/gic.c | 239 ++ rt-thread/libcpu/arm/zynq7000/gic.h | 41 + rt-thread/libcpu/arm/zynq7000/interrupt.c | 143 + rt-thread/libcpu/arm/zynq7000/interrupt.h | 26 + rt-thread/libcpu/arm/zynq7000/mmu.c | 182 ++ rt-thread/libcpu/arm/zynq7000/stack.c | 62 + rt-thread/libcpu/arm/zynq7000/start_gcc.S | 254 ++ rt-thread/libcpu/arm/zynq7000/trap.c | 185 ++ rt-thread/libcpu/arm/zynq7000/vector_gcc.S | 65 + rt-thread/libcpu/risc-v/e310/SConscript | 13 + rt-thread/libcpu/risc-v/e310/context_gcc.S | 227 ++ rt-thread/libcpu/risc-v/e310/entry_gcc.S | 145 + rt-thread/libcpu/risc-v/e310/stack.c | 104 + rt-thread/src/Kconfig | 298 +++ rt-thread/src/SConscript | 43 + rt-thread/src/clock.c | 118 + rt-thread/src/components.c | 253 ++ rt-thread/src/device.c | 480 ++++ rt-thread/src/idle.c | 277 ++ rt-thread/src/ipc.c | 2326 +++++++++++++++++ rt-thread/src/irq.c | 113 + rt-thread/src/kservice.c | 1358 ++++++++++ rt-thread/src/mem.c | 699 +++++ rt-thread/src/memheap.c | 717 +++++ rt-thread/src/mempool.c | 454 ++++ rt-thread/src/object.c | 502 ++++ rt-thread/src/scheduler.c | 420 +++ rt-thread/src/signal.c | 486 ++++ rt-thread/src/slab.c | 937 +++++++ rt-thread/src/thread.c | 797 ++++++ rt-thread/src/timer.c | 707 +++++ 396 files changed, 74772 insertions(+) create mode 100644 rt-thread/.gitattributes create mode 100644 rt-thread/.gitignore create mode 100644 rt-thread/.travis.yml create mode 100644 rt-thread/AUTHORS create mode 100644 rt-thread/ChangeLog.md create mode 100644 rt-thread/Kconfig create mode 100644 rt-thread/LICENSE create mode 100644 rt-thread/README.md create mode 100644 rt-thread/README_zh.md create mode 100644 rt-thread/components/Kconfig create mode 100644 rt-thread/components/SConscript create mode 100644 rt-thread/components/drivers/Kconfig create mode 100644 rt-thread/components/drivers/SConscript create mode 100644 rt-thread/components/drivers/include/drivers/alarm.h create mode 100644 rt-thread/components/drivers/include/drivers/audio.h create mode 100644 rt-thread/components/drivers/include/drivers/can.h create mode 100644 rt-thread/components/drivers/include/drivers/cputime.h create mode 100644 rt-thread/components/drivers/include/drivers/hwtimer.h create mode 100644 rt-thread/components/drivers/include/drivers/i2c-bit-ops.h create mode 100644 rt-thread/components/drivers/include/drivers/i2c.h create mode 100644 rt-thread/components/drivers/include/drivers/i2c_dev.h create mode 100644 rt-thread/components/drivers/include/drivers/mmc.h create mode 100644 rt-thread/components/drivers/include/drivers/mmcsd_card.h create mode 100644 rt-thread/components/drivers/include/drivers/mmcsd_cmd.h create mode 100644 rt-thread/components/drivers/include/drivers/mmcsd_core.h create mode 100644 rt-thread/components/drivers/include/drivers/mmcsd_host.h create mode 100644 rt-thread/components/drivers/include/drivers/mtd.h create mode 100644 rt-thread/components/drivers/include/drivers/mtd_nand.h create mode 100644 rt-thread/components/drivers/include/drivers/mtd_nor.h create mode 100644 rt-thread/components/drivers/include/drivers/mtdnand.h create mode 100644 rt-thread/components/drivers/include/drivers/mtdnor.h create mode 100644 rt-thread/components/drivers/include/drivers/pin.h create mode 100644 rt-thread/components/drivers/include/drivers/rt_drv_pwm.h create mode 100644 rt-thread/components/drivers/include/drivers/rtc.h create mode 100644 rt-thread/components/drivers/include/drivers/sd.h create mode 100644 rt-thread/components/drivers/include/drivers/sdio.h create mode 100644 rt-thread/components/drivers/include/drivers/sdio_func_ids.h create mode 100644 rt-thread/components/drivers/include/drivers/serial.h create mode 100644 rt-thread/components/drivers/include/drivers/spi.h create mode 100644 rt-thread/components/drivers/include/drivers/usb_common.h create mode 100644 rt-thread/components/drivers/include/drivers/usb_device.h create mode 100644 rt-thread/components/drivers/include/drivers/usb_host.h create mode 100644 rt-thread/components/drivers/include/drivers/watchdog.h create mode 100644 rt-thread/components/drivers/include/drivers/wlan.h create mode 100644 rt-thread/components/drivers/include/ipc/completion.h create mode 100644 rt-thread/components/drivers/include/ipc/dataqueue.h create mode 100644 rt-thread/components/drivers/include/ipc/pipe.h create mode 100644 rt-thread/components/drivers/include/ipc/poll.h create mode 100644 rt-thread/components/drivers/include/ipc/ringblk_buf.h create mode 100644 rt-thread/components/drivers/include/ipc/ringbuffer.h create mode 100644 rt-thread/components/drivers/include/ipc/waitqueue.h create mode 100644 rt-thread/components/drivers/include/ipc/workqueue.h create mode 100644 rt-thread/components/drivers/include/rtdevice.h create mode 100644 rt-thread/components/drivers/serial/SConscript create mode 100644 rt-thread/components/drivers/serial/serial.c create mode 100644 rt-thread/components/drivers/src/SConscript create mode 100644 rt-thread/components/drivers/src/ringbuffer.c create mode 100644 rt-thread/components/finsh/Kconfig create mode 100644 rt-thread/components/finsh/SConscript create mode 100644 rt-thread/components/finsh/cmd.c create mode 100644 rt-thread/components/finsh/finsh.h create mode 100644 rt-thread/components/finsh/finsh_api.h create mode 100644 rt-thread/components/finsh/finsh_compiler.c create mode 100644 rt-thread/components/finsh/finsh_error.c create mode 100644 rt-thread/components/finsh/finsh_error.h create mode 100644 rt-thread/components/finsh/finsh_heap.c create mode 100644 rt-thread/components/finsh/finsh_heap.h create mode 100644 rt-thread/components/finsh/finsh_init.c create mode 100644 rt-thread/components/finsh/finsh_node.c create mode 100644 rt-thread/components/finsh/finsh_node.h create mode 100644 rt-thread/components/finsh/finsh_ops.c create mode 100644 rt-thread/components/finsh/finsh_ops.h create mode 100644 rt-thread/components/finsh/finsh_parser.c create mode 100644 rt-thread/components/finsh/finsh_parser.h create mode 100644 rt-thread/components/finsh/finsh_token.c create mode 100644 rt-thread/components/finsh/finsh_token.h create mode 100644 rt-thread/components/finsh/finsh_var.c create mode 100644 rt-thread/components/finsh/finsh_var.h create mode 100644 rt-thread/components/finsh/finsh_vm.c create mode 100644 rt-thread/components/finsh/finsh_vm.h create mode 100644 rt-thread/components/finsh/msh.c create mode 100644 rt-thread/components/finsh/msh.h create mode 100644 rt-thread/components/finsh/msh_cmd.c create mode 100644 rt-thread/components/finsh/msh_file.c create mode 100644 rt-thread/components/finsh/shell.c create mode 100644 rt-thread/components/finsh/shell.h create mode 100644 rt-thread/components/finsh/symbol.c create mode 100644 rt-thread/components/libc/Kconfig create mode 100644 rt-thread/components/libc/SConscript create mode 100644 rt-thread/components/libc/compilers/SConscript create mode 100644 rt-thread/components/libc/compilers/armlibc/SConscript create mode 100644 rt-thread/components/libc/compilers/armlibc/dirent.h create mode 100644 rt-thread/components/libc/compilers/armlibc/fcntl.h create mode 100644 rt-thread/components/libc/compilers/armlibc/libc.c create mode 100644 rt-thread/components/libc/compilers/armlibc/libc.h create mode 100644 rt-thread/components/libc/compilers/armlibc/libc_syms.c create mode 100644 rt-thread/components/libc/compilers/armlibc/mem_std.c create mode 100644 rt-thread/components/libc/compilers/armlibc/stdio.c create mode 100644 rt-thread/components/libc/compilers/armlibc/stubs.c create mode 100644 rt-thread/components/libc/compilers/armlibc/sys/README.md create mode 100644 rt-thread/components/libc/compilers/armlibc/sys/errno.h create mode 100644 rt-thread/components/libc/compilers/armlibc/sys/mman.h create mode 100644 rt-thread/components/libc/compilers/armlibc/sys/stat.h create mode 100644 rt-thread/components/libc/compilers/armlibc/sys/time.h create mode 100644 rt-thread/components/libc/compilers/armlibc/sys/types.h create mode 100644 rt-thread/components/libc/compilers/armlibc/sys/unistd.h create mode 100644 rt-thread/components/libc/compilers/armlibc/termios.h create mode 100644 rt-thread/components/libc/compilers/armlibc/time.c create mode 100644 rt-thread/components/libc/compilers/armlibc/unistd.h create mode 100644 rt-thread/components/libc/compilers/dlib/README.md create mode 100644 rt-thread/components/libc/compilers/dlib/SConscript create mode 100644 rt-thread/components/libc/compilers/dlib/dirent.h create mode 100644 rt-thread/components/libc/compilers/dlib/environ.c create mode 100644 rt-thread/components/libc/compilers/dlib/fcntl.h create mode 100644 rt-thread/components/libc/compilers/dlib/libc.c create mode 100644 rt-thread/components/libc/compilers/dlib/libc.h create mode 100644 rt-thread/components/libc/compilers/dlib/rmtx.c create mode 100644 rt-thread/components/libc/compilers/dlib/stdio.c create mode 100644 rt-thread/components/libc/compilers/dlib/sys/README.md create mode 100644 rt-thread/components/libc/compilers/dlib/sys/errno.h create mode 100644 rt-thread/components/libc/compilers/dlib/sys/mman.h create mode 100644 rt-thread/components/libc/compilers/dlib/sys/stat.h create mode 100644 rt-thread/components/libc/compilers/dlib/sys/time.h create mode 100644 rt-thread/components/libc/compilers/dlib/sys/types.h create mode 100644 rt-thread/components/libc/compilers/dlib/sys/unistd.h create mode 100644 rt-thread/components/libc/compilers/dlib/syscall_close.c create mode 100644 rt-thread/components/libc/compilers/dlib/syscall_lseek.c create mode 100644 rt-thread/components/libc/compilers/dlib/syscall_mem.c create mode 100644 rt-thread/components/libc/compilers/dlib/syscall_open.c create mode 100644 rt-thread/components/libc/compilers/dlib/syscall_read.c create mode 100644 rt-thread/components/libc/compilers/dlib/syscall_remove.c create mode 100644 rt-thread/components/libc/compilers/dlib/syscall_write.c create mode 100644 rt-thread/components/libc/compilers/dlib/syscalls.h create mode 100644 rt-thread/components/libc/compilers/dlib/termios.h create mode 100644 rt-thread/components/libc/compilers/dlib/time.c create mode 100644 rt-thread/components/libc/compilers/dlib/unistd.h create mode 100644 rt-thread/components/libc/compilers/minilibc/SConscript create mode 100644 rt-thread/components/libc/compilers/minilibc/ctype.c create mode 100644 rt-thread/components/libc/compilers/minilibc/ctype.h create mode 100644 rt-thread/components/libc/compilers/minilibc/errno.h create mode 100644 rt-thread/components/libc/compilers/minilibc/inttypes.h create mode 100644 rt-thread/components/libc/compilers/minilibc/math.c create mode 100644 rt-thread/components/libc/compilers/minilibc/math.h create mode 100644 rt-thread/components/libc/compilers/minilibc/qsort.c create mode 100644 rt-thread/components/libc/compilers/minilibc/rand.c create mode 100644 rt-thread/components/libc/compilers/minilibc/stddef.h create mode 100644 rt-thread/components/libc/compilers/minilibc/stdint.h create mode 100644 rt-thread/components/libc/compilers/minilibc/stdio.h create mode 100644 rt-thread/components/libc/compilers/minilibc/stdlib.c create mode 100644 rt-thread/components/libc/compilers/minilibc/stdlib.h create mode 100644 rt-thread/components/libc/compilers/minilibc/string.c create mode 100644 rt-thread/components/libc/compilers/minilibc/string.h create mode 100644 rt-thread/components/libc/compilers/minilibc/sys/mman.h create mode 100644 rt-thread/components/libc/compilers/minilibc/sys/stat.h create mode 100644 rt-thread/components/libc/compilers/minilibc/sys/time.h create mode 100644 rt-thread/components/libc/compilers/minilibc/sys/types.h create mode 100644 rt-thread/components/libc/compilers/minilibc/time.c create mode 100644 rt-thread/components/libc/compilers/minilibc/time.h create mode 100644 rt-thread/components/libc/compilers/newlib/SConscript create mode 100644 rt-thread/components/libc/compilers/newlib/libc.c create mode 100644 rt-thread/components/libc/compilers/newlib/libc.h create mode 100644 rt-thread/components/libc/compilers/newlib/libc_syms.c create mode 100644 rt-thread/components/libc/compilers/newlib/stdio.c create mode 100644 rt-thread/components/libc/compilers/newlib/sys/dirent.h create mode 100644 rt-thread/components/libc/compilers/newlib/sys/mman.h create mode 100644 rt-thread/components/libc/compilers/newlib/sys/statfs.h create mode 100644 rt-thread/components/libc/compilers/newlib/sys/termios.h create mode 100644 rt-thread/components/libc/compilers/newlib/syscalls.c create mode 100644 rt-thread/components/libc/compilers/newlib/termios.h create mode 100644 rt-thread/components/libc/compilers/newlib/time.c create mode 100644 rt-thread/include/libc/libc_dirent.h create mode 100644 rt-thread/include/libc/libc_errno.h create mode 100644 rt-thread/include/libc/libc_fcntl.h create mode 100644 rt-thread/include/libc/libc_fdset.h create mode 100644 rt-thread/include/libc/libc_ioctl.h create mode 100644 rt-thread/include/libc/libc_signal.h create mode 100644 rt-thread/include/libc/libc_stat.h create mode 100644 rt-thread/include/rtdbg.h create mode 100644 rt-thread/include/rtdebug.h create mode 100644 rt-thread/include/rtdef.h create mode 100644 rt-thread/include/rthw.h create mode 100644 rt-thread/include/rtlibc.h create mode 100644 rt-thread/include/rtm.h create mode 100644 rt-thread/include/rtservice.h create mode 100644 rt-thread/include/rtthread.h create mode 100644 rt-thread/libcpu/Kconfig create mode 100644 rt-thread/libcpu/SConscript create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/AT91SAM7S.h create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/context_gcc.S create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/context_rvds.S create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/cpu.c create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/interrupt.c create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/serial.c create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/serial.h create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/stack.c create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/start_gcc.S create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/start_rvds.S create mode 100644 rt-thread/libcpu/arm/AT91SAM7S/trap.c create mode 100644 rt-thread/libcpu/arm/AT91SAM7X/context_gcc.S create mode 100644 rt-thread/libcpu/arm/AT91SAM7X/context_rvds.S create mode 100644 rt-thread/libcpu/arm/AT91SAM7X/cpu.c create mode 100644 rt-thread/libcpu/arm/AT91SAM7X/interrupt.c create mode 100644 rt-thread/libcpu/arm/AT91SAM7X/stack.c create mode 100644 rt-thread/libcpu/arm/AT91SAM7X/start_gcc.S create mode 100644 rt-thread/libcpu/arm/AT91SAM7X/start_rvds.S create mode 100644 rt-thread/libcpu/arm/AT91SAM7X/trap.c create mode 100644 rt-thread/libcpu/arm/am335x/am33xx.h create mode 100644 rt-thread/libcpu/arm/am335x/context_gcc.S create mode 100644 rt-thread/libcpu/arm/am335x/context_iar.S create mode 100644 rt-thread/libcpu/arm/am335x/cp15_gcc.S create mode 100644 rt-thread/libcpu/arm/am335x/cp15_iar.s create mode 100644 rt-thread/libcpu/arm/am335x/cpu.c create mode 100644 rt-thread/libcpu/arm/am335x/interrupt.c create mode 100644 rt-thread/libcpu/arm/am335x/interrupt.h create mode 100644 rt-thread/libcpu/arm/am335x/mmu.c create mode 100644 rt-thread/libcpu/arm/am335x/mmu.h create mode 100644 rt-thread/libcpu/arm/am335x/stack.c create mode 100644 rt-thread/libcpu/arm/am335x/start_gcc.S create mode 100644 rt-thread/libcpu/arm/am335x/start_iar.s create mode 100644 rt-thread/libcpu/arm/am335x/trap.c create mode 100644 rt-thread/libcpu/arm/am335x/vector_gcc.S create mode 100644 rt-thread/libcpu/arm/arm926/context_gcc.S create mode 100644 rt-thread/libcpu/arm/arm926/context_iar.S create mode 100644 rt-thread/libcpu/arm/arm926/context_rvds.S create mode 100644 rt-thread/libcpu/arm/arm926/cpuport.c create mode 100644 rt-thread/libcpu/arm/arm926/mmu.c create mode 100644 rt-thread/libcpu/arm/arm926/mmu.h create mode 100644 rt-thread/libcpu/arm/arm926/stack.c create mode 100644 rt-thread/libcpu/arm/arm926/start_gcc.S create mode 100644 rt-thread/libcpu/arm/arm926/start_iar.S create mode 100644 rt-thread/libcpu/arm/arm926/start_rvds.S create mode 100644 rt-thread/libcpu/arm/arm926/trap.c create mode 100644 rt-thread/libcpu/arm/armv6/arm_entry_gcc.S create mode 100644 rt-thread/libcpu/arm/armv6/armv6.h create mode 100644 rt-thread/libcpu/arm/armv6/context_gcc.S create mode 100644 rt-thread/libcpu/arm/armv6/cpuport.c create mode 100644 rt-thread/libcpu/arm/armv6/mmu.c create mode 100644 rt-thread/libcpu/arm/armv6/mmu.h create mode 100644 rt-thread/libcpu/arm/armv6/stack.c create mode 100644 rt-thread/libcpu/arm/armv6/vfp.c create mode 100644 rt-thread/libcpu/arm/armv6/vfp.h create mode 100644 rt-thread/libcpu/arm/common/backtrace.c create mode 100644 rt-thread/libcpu/arm/common/div0.c create mode 100644 rt-thread/libcpu/arm/common/divsi3.S create mode 100644 rt-thread/libcpu/arm/common/showmem.c create mode 100644 rt-thread/libcpu/arm/cortex-a/armv7.h create mode 100644 rt-thread/libcpu/arm/cortex-a/context_gcc.S create mode 100644 rt-thread/libcpu/arm/cortex-a/cp15.h create mode 100644 rt-thread/libcpu/arm/cortex-a/cp15_gcc.S create mode 100644 rt-thread/libcpu/arm/cortex-a/cpu.c create mode 100644 rt-thread/libcpu/arm/cortex-a/interrupt.c create mode 100644 rt-thread/libcpu/arm/cortex-a/mmu.c create mode 100644 rt-thread/libcpu/arm/cortex-a/pmu.c create mode 100644 rt-thread/libcpu/arm/cortex-a/pmu.h create mode 100644 rt-thread/libcpu/arm/cortex-a/stack.c create mode 100644 rt-thread/libcpu/arm/cortex-a/start_gcc.S create mode 100644 rt-thread/libcpu/arm/cortex-a/trap.c create mode 100644 rt-thread/libcpu/arm/cortex-a/vector_gcc.S create mode 100644 rt-thread/libcpu/arm/cortex-m0/context_gcc.S create mode 100644 rt-thread/libcpu/arm/cortex-m0/context_iar.S create mode 100644 rt-thread/libcpu/arm/cortex-m0/context_rvds.S create mode 100644 rt-thread/libcpu/arm/cortex-m0/cpuport.c create mode 100644 rt-thread/libcpu/arm/cortex-m3/context_gcc.S create mode 100644 rt-thread/libcpu/arm/cortex-m3/context_iar.S create mode 100644 rt-thread/libcpu/arm/cortex-m3/context_rvds.S create mode 100644 rt-thread/libcpu/arm/cortex-m3/cpuport.c create mode 100644 rt-thread/libcpu/arm/cortex-m4/context_gcc.S create mode 100644 rt-thread/libcpu/arm/cortex-m4/context_iar.S create mode 100644 rt-thread/libcpu/arm/cortex-m4/context_rvds.S create mode 100644 rt-thread/libcpu/arm/cortex-m4/cpuport.c create mode 100644 rt-thread/libcpu/arm/cortex-m7/context_gcc.S create mode 100644 rt-thread/libcpu/arm/cortex-m7/context_iar.S create mode 100644 rt-thread/libcpu/arm/cortex-m7/context_rvds.S create mode 100644 rt-thread/libcpu/arm/cortex-m7/cpuport.c create mode 100644 rt-thread/libcpu/arm/cortex-r4/armv7.h create mode 100644 rt-thread/libcpu/arm/cortex-r4/context_ccs.asm create mode 100644 rt-thread/libcpu/arm/cortex-r4/context_gcc.S create mode 100644 rt-thread/libcpu/arm/cortex-r4/cpu.c create mode 100644 rt-thread/libcpu/arm/cortex-r4/interrupt.c create mode 100644 rt-thread/libcpu/arm/cortex-r4/stack.c create mode 100644 rt-thread/libcpu/arm/cortex-r4/start_ccs.asm create mode 100644 rt-thread/libcpu/arm/cortex-r4/start_gcc.S create mode 100644 rt-thread/libcpu/arm/cortex-r4/trap.c create mode 100644 rt-thread/libcpu/arm/cortex-r4/vector_ccs.asm create mode 100644 rt-thread/libcpu/arm/cortex-r4/vector_gcc.S create mode 100644 rt-thread/libcpu/arm/dm36x/context_gcc.S create mode 100644 rt-thread/libcpu/arm/dm36x/context_rvds.S create mode 100644 rt-thread/libcpu/arm/dm36x/cpuport.c create mode 100644 rt-thread/libcpu/arm/dm36x/mmu.c create mode 100644 rt-thread/libcpu/arm/dm36x/mmu.h create mode 100644 rt-thread/libcpu/arm/dm36x/stack.c create mode 100644 rt-thread/libcpu/arm/lpc214x/context_gcc.S create mode 100644 rt-thread/libcpu/arm/lpc214x/context_rvds.S create mode 100644 rt-thread/libcpu/arm/lpc214x/cpuport.c create mode 100644 rt-thread/libcpu/arm/lpc214x/lpc214x.h create mode 100644 rt-thread/libcpu/arm/lpc214x/start_rvds.S create mode 100644 rt-thread/libcpu/arm/lpc214x/startup_gcc.S create mode 100644 rt-thread/libcpu/arm/lpc24xx/LPC24xx.h create mode 100644 rt-thread/libcpu/arm/lpc24xx/context_gcc.S create mode 100644 rt-thread/libcpu/arm/lpc24xx/context_rvds.S create mode 100644 rt-thread/libcpu/arm/lpc24xx/cpu.c create mode 100644 rt-thread/libcpu/arm/lpc24xx/interrupt.c create mode 100644 rt-thread/libcpu/arm/lpc24xx/stack.c create mode 100644 rt-thread/libcpu/arm/lpc24xx/start_gcc.S create mode 100644 rt-thread/libcpu/arm/lpc24xx/start_rvds.S create mode 100644 rt-thread/libcpu/arm/lpc24xx/trap.c create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/SConscript create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/armv7.h create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/context_gcc.S create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/cp15.h create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/cp15_gcc.S create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/cpu.c create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/gic.c create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/gic.h create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/interrupt.c create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/interrupt.h create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/mmu.c create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/pmu.c create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/pmu.h create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/stack.c create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/start_gcc.S create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/trap.c create mode 100644 rt-thread/libcpu/arm/realview-a8-vmm/vector_gcc.S create mode 100644 rt-thread/libcpu/arm/s3c24x0/context_gcc.S create mode 100644 rt-thread/libcpu/arm/s3c24x0/context_rvds.S create mode 100644 rt-thread/libcpu/arm/s3c24x0/cpu.c create mode 100644 rt-thread/libcpu/arm/s3c24x0/interrupt.c create mode 100644 rt-thread/libcpu/arm/s3c24x0/mmu.c create mode 100644 rt-thread/libcpu/arm/s3c24x0/rtc.c create mode 100644 rt-thread/libcpu/arm/s3c24x0/rtc.h create mode 100644 rt-thread/libcpu/arm/s3c24x0/s3c24x0.h create mode 100644 rt-thread/libcpu/arm/s3c24x0/serial.c create mode 100644 rt-thread/libcpu/arm/s3c24x0/serial.h create mode 100644 rt-thread/libcpu/arm/s3c24x0/stack.c create mode 100644 rt-thread/libcpu/arm/s3c24x0/start_gcc.S create mode 100644 rt-thread/libcpu/arm/s3c24x0/start_rvds.S create mode 100644 rt-thread/libcpu/arm/s3c24x0/system_clock.c create mode 100644 rt-thread/libcpu/arm/s3c24x0/trap.c create mode 100644 rt-thread/libcpu/arm/s3c44b0/context_gcc.S create mode 100644 rt-thread/libcpu/arm/s3c44b0/context_rvds.S create mode 100644 rt-thread/libcpu/arm/s3c44b0/cpu.c create mode 100644 rt-thread/libcpu/arm/s3c44b0/interrupt.c create mode 100644 rt-thread/libcpu/arm/s3c44b0/s3c44b0.h create mode 100644 rt-thread/libcpu/arm/s3c44b0/serial.c create mode 100644 rt-thread/libcpu/arm/s3c44b0/stack.c create mode 100644 rt-thread/libcpu/arm/s3c44b0/start_gcc.S create mode 100644 rt-thread/libcpu/arm/s3c44b0/start_rvds.S create mode 100644 rt-thread/libcpu/arm/s3c44b0/trap.c create mode 100644 rt-thread/libcpu/arm/sep4020/clk.c create mode 100644 rt-thread/libcpu/arm/sep4020/context_rvds.S create mode 100644 rt-thread/libcpu/arm/sep4020/cpu.c create mode 100644 rt-thread/libcpu/arm/sep4020/interrupt.c create mode 100644 rt-thread/libcpu/arm/sep4020/sep4020.h create mode 100644 rt-thread/libcpu/arm/sep4020/serial.c create mode 100644 rt-thread/libcpu/arm/sep4020/serial.h create mode 100644 rt-thread/libcpu/arm/sep4020/stack.c create mode 100644 rt-thread/libcpu/arm/sep4020/start_rvds.S create mode 100644 rt-thread/libcpu/arm/sep4020/trap.c create mode 100644 rt-thread/libcpu/arm/zynq7000/SConscript create mode 100644 rt-thread/libcpu/arm/zynq7000/armv7.h create mode 100644 rt-thread/libcpu/arm/zynq7000/context_gcc.S create mode 100644 rt-thread/libcpu/arm/zynq7000/cp15.h create mode 100644 rt-thread/libcpu/arm/zynq7000/cp15_gcc.S create mode 100644 rt-thread/libcpu/arm/zynq7000/cpu.c create mode 100644 rt-thread/libcpu/arm/zynq7000/gic.c create mode 100644 rt-thread/libcpu/arm/zynq7000/gic.h create mode 100644 rt-thread/libcpu/arm/zynq7000/interrupt.c create mode 100644 rt-thread/libcpu/arm/zynq7000/interrupt.h create mode 100644 rt-thread/libcpu/arm/zynq7000/mmu.c create mode 100644 rt-thread/libcpu/arm/zynq7000/stack.c create mode 100644 rt-thread/libcpu/arm/zynq7000/start_gcc.S create mode 100644 rt-thread/libcpu/arm/zynq7000/trap.c create mode 100644 rt-thread/libcpu/arm/zynq7000/vector_gcc.S create mode 100644 rt-thread/libcpu/risc-v/e310/SConscript create mode 100644 rt-thread/libcpu/risc-v/e310/context_gcc.S create mode 100644 rt-thread/libcpu/risc-v/e310/entry_gcc.S create mode 100644 rt-thread/libcpu/risc-v/e310/stack.c create mode 100644 rt-thread/src/Kconfig create mode 100644 rt-thread/src/SConscript create mode 100644 rt-thread/src/clock.c create mode 100644 rt-thread/src/components.c create mode 100644 rt-thread/src/device.c create mode 100644 rt-thread/src/idle.c create mode 100644 rt-thread/src/ipc.c create mode 100644 rt-thread/src/irq.c create mode 100644 rt-thread/src/kservice.c create mode 100644 rt-thread/src/mem.c create mode 100644 rt-thread/src/memheap.c create mode 100644 rt-thread/src/mempool.c create mode 100644 rt-thread/src/object.c create mode 100644 rt-thread/src/scheduler.c create mode 100644 rt-thread/src/signal.c create mode 100644 rt-thread/src/slab.c create mode 100644 rt-thread/src/thread.c create mode 100644 rt-thread/src/timer.c diff --git a/.gitignore b/.gitignore index c6127b3..01d7a41 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ modules.order Module.symvers Mkfile.old dkms.conf + +sample diff --git a/rt-thread/.gitattributes b/rt-thread/.gitattributes new file mode 100644 index 0000000..4821411 --- /dev/null +++ b/rt-thread/.gitattributes @@ -0,0 +1,42 @@ +* text=auto + +*.S text +*.asm text +*.c text +*.cc text +*.cpp text +*.cxx text +*.h text +*.htm text +*.html text +*.in text +*.ld text +*.m4 text +*.mak text +*.mk text +*.py text +*.rb text +*.s text +*.sct text +*.sh text +*.txt text +*.xml text +SConscript text +Makefile text +AUTHORS text +COPYING text + +*.LZO -text +*.Opt -text +*.Uv2 -text +*.ewp -text +*.eww -text +*.vcproj -text +*.bat -text +*.dos -text +*.icf -text +*.inf -text +*.ini -text +*.sct -text +*.xsd -text +Jamfile -text diff --git a/rt-thread/.gitignore b/rt-thread/.gitignore new file mode 100644 index 0000000..e9d1143 --- /dev/null +++ b/rt-thread/.gitignore @@ -0,0 +1,28 @@ +*.pyc +*.map +*.dblite +*.elf +*.bin +*.hex +*.axf +*.exe +*.pdb +*.idb +*.ilk +*.old +build +Debug +documentation/html +*~ +*.o +*.obj +*.bak +*.dep +*.lib +*.a +*.i +*.d +tools/kconfig-frontends/kconfig-mconf +packages +cconfig.h +GPUCache diff --git a/rt-thread/.travis.yml b/rt-thread/.travis.yml new file mode 100644 index 0000000..fce9c19 --- /dev/null +++ b/rt-thread/.travis.yml @@ -0,0 +1,91 @@ +language: c + +notifications: + email: false + +before_script: +# travis has changed to 64-bit and we require 32-bit compatibility libraries + - sudo apt-get update + # clang + - "sudo apt-get -qq install gcc-multilib libc6:i386 libgcc1:i386 gcc-4.6-base:i386 libstdc++5:i386 libstdc++6:i386 libsdl-dev || true" + # - sudo apt-get -qq install gcc-arm-none-eabi + # - "[ $RTT_TOOL_CHAIN = 'sourcery-arm' ] && export RTT_EXEC_PATH=/usr/bin && arm-none-eabi-gcc --version || true" + # - "[ $RTT_TOOL_CHAIN = 'sourcery-arm' ] && curl -s https://sourcery.mentor.com/public/gnu_toolchain/arm-none-eabi/arm-2014.05-28-arm-none-eabi-i686-pc-linux-gnu.tar.bz2 | sudo tar xjf - -C /opt && export RTT_EXEC_PATH=/opt/arm-2014.05/bin && /opt/arm-2014.05/bin/arm-none-eabi-gcc --version || true" + - "[ $RTT_TOOL_CHAIN = 'sourcery-arm' ] && wget -q https://github.com/RT-Thread/toolchains-ci/releases/download/arm-2017q2-v6/gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2 && sudo tar xjf gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2 -C /opt && export RTT_EXEC_PATH=/opt/gcc-arm-none-eabi-6-2017-q2-update/bin && /opt/gcc-arm-none-eabi-6-2017-q2-update/bin/arm-none-eabi-gcc --version || true" + - "[ $RTT_TOOL_CHAIN = 'sourcery-mips' ] && curl -s https://sourcery.mentor.com/public/gnu_toolchain/mips-sde-elf/mips-2012.09-98-mips-sde-elf-i686-pc-linux-gnu.tar.bz2 | sudo tar xjf - -C /opt && export RTT_EXEC_PATH=/opt/mips-2012.09/bin && /opt/mips-2012.09/bin/mips-sde-elf-gcc --version || true" + # - "[ $RTT_TOOL_CHAIN = 'sourcery-ppc' ] && curl -s https://sourcery.mentor.com/public/gnu_toolchain/powerpc-eabi/freescale-2011.03-39-powerpc-eabi-i686-pc-linux-gnu.tar.bz2 | sudo tar xjf - -C /opt && export RTT_EXEC_PATH=/opt/freescale-2011.03/bin && /opt/freescale-2011.03/bin/powerpc-eabi-gcc --version || true" + # - "[ $RTT_TOOL_CHAIN = 'atmel-avr32' ] && curl -s http://www.atmel.com/images/avr32-gnu-toolchain-3.4.1.348-linux.any.x86.tar.gz | sudo tar xzf - -C /opt && export RTT_EXEC_PATH=/opt/avr32-gnu-toolchain-linux_x86/bin && /opt/avr32-gnu-toolchain-linux_x86/bin/avr32-gcc --version && curl -sO http://www.atmel.com/images/avr-headers-3.2.3.970.zip && unzip -qq avr-headers-3.2.3.970.zip -d bsp/$RTT_BSP || true" + - export RTT_ROOT=`pwd` + - "[ x$RTT_CC == x ] && export RTT_CC='gcc' || true" + +script: + - scons -C bsp/$RTT_BSP + +env: +# - RTT_BSP='simulator' RTT_CC='clang-analyze' RTT_EXEC_PATH=/usr/share/clang/scan-build + - RTT_BSP='CME_M7' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='apollo2' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='asm9260t' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='at91sam9260' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='allwinner_tina' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='imxrt1052-evk' RTT_TOOL_CHAIN='sourcery-arm' +# - RTT_BSP='avr32uc3b0' RTT_TOOL_CHAIN='atmel-avr32' +# - RTT_BSP='bf533' # no scons + - RTT_BSP='efm32' RTT_TOOL_CHAIN='sourcery-arm' +# - RTT_BSP='gd32450z-eval' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='gkipc' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='lm3s8962' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='lm3s9b9x' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='lm4f232' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='tm4c129x' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='lpc176x' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='lpc178x' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='lpc2148' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='lpc2478' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='xplorer4330/M4' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='lpc43xx/M4' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='lpc408x' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='lpc5410x' RTT_TOOL_CHAIN='sourcery-arm' +# - RTT_BSP='lpc54608-LPCXpresso' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='ls1bdev' RTT_TOOL_CHAIN='sourcery-mips' + - RTT_BSP='ls1cdev' RTT_TOOL_CHAIN='sourcery-mips' + - RTT_BSP='imx6sx/cortex-a9' RTT_TOOL_CHAIN='sourcery-arm' +# - RTT_BSP='m16c62p' # m32c + - RTT_BSP='mb9bf500r' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='mb9bf506r' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='mb9bf618s' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='mb9bf568r' RTT_TOOL_CHAIN='sourcery-arm' +# - RTT_BSP='microblaze' # no scons + - RTT_BSP='mini2440' RTT_TOOL_CHAIN='sourcery-arm' +# - RTT_BSP='mini4020' # no scons +# - RTT_BSP='nios_ii' # no scons + - RTT_BSP='nuvoton_nuc472' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='nuvoton_m05x' RTT_TOOL_CHAIN='sourcery-arm' +# - RTT_BSP='pic32ethernet' # no scons + - RTT_BSP='qemu-vexpress-a9' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='qemu-vexpress-gemini' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='sam7x' RTT_TOOL_CHAIN='sourcery-arm' +# - RTT_BSP='simulator' # x86 + - RTT_BSP='stm32f0x' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32l072' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32f107' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32f10x' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32f10x-HAL' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32f20x' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32f40x' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32f4xx-HAL' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32f411-nucleo' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32f429-apollo' RTT_TOOL_CHAIN='sourcery-arm' +# - RTT_BSP='stm32f429-armfly' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32f429-disco' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32l475-iot-disco' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32l476-nucleo' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='stm32h743-nucleo' RTT_TOOL_CHAIN='sourcery-arm' +# - RTT_BSP='taihu' RTT_TOOL_CHAIN='sourcery-ppc' +# - RTT_BSP='upd70f3454' # iar +# - RTT_BSP='x86' # x86 + - RTT_BSP='beaglebone' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='zynq7000' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='frdm-k64f' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='fh8620' RTT_TOOL_CHAIN='sourcery-arm' + - RTT_BSP='x1000' RTT_TOOL_CHAIN='sourcery-mips' diff --git a/rt-thread/AUTHORS b/rt-thread/AUTHORS new file mode 100644 index 0000000..54bd4ad --- /dev/null +++ b/rt-thread/AUTHORS @@ -0,0 +1,45 @@ +Kernel Design & Implementation +- Bernard Xiong + +LwIP 1.3.0/1.3.1/1.3.2/1.4.0 +- Porting + Qiu Yi + Mbbill +- Testing + Bernard Xiong + +Filesystem +- Porting and Add Virtual Filesystem +- Testing + Qiu Yi + prife + +RTGUI +- Design and Implemenation + Bernard Xiong + Grissiom + +BSP +Bernard Xiong +- ATMEL AT91SAM7S64 & AT91SAM7X256 Porting +- STM32 Porting +- S3C4510 Porting + +Mbbill +- ATMEL AT91SAM7X256 + +Xulong Cao +- QEMU/x86 + +Aozima +- LPC 2148 Porting +- STM32 Porting + +Jing Lee +- LPC 2478 Porting + +Qiu Yi +- S3C2410 & S3C2440 Porting +- TI LM3S + +others... diff --git a/rt-thread/ChangeLog.md b/rt-thread/ChangeLog.md new file mode 100644 index 0000000..6fce51e --- /dev/null +++ b/rt-thread/ChangeLog.md @@ -0,0 +1,956 @@ +# RT-Thread 3.1.0 Change Log + +## Kernel + +* The main thread priority can be configured by Kconfig; +* Add the checking of kernel object type, which can effectively avoid the problem of continuing to use kernel objects after they are destroyed. +* Add the idle hook list to mount multiple idle hook, and can be configured by Kconfig. +* Add the device_ops operation set to reduce the footprint of device object. +* Remove the special memory operation in application module when using SLAB memory management algorithm. +* Move application module from the kernel to `libc/libdl`. +* Enhance the debug information output of `rtdbg.h` file. +* In Keil/IAR tool chain, the `RT_USED` is used to keep symbols and avoid to add more argument or section in link phrase. + +## Components + +* Remove all of external codes, which will be moved to packages in the future. +* Add initialization flag for shell, file system, network protocol stack etc to prevent repeated initialization; +* Enable the long file name feature of ELM FatFs in default. +* Change DFS FD to dynamic allocation mode. The maximum number of allocation is still DFS_FD_MAX. +* Add dfs_fdtable_get() function to get different fdtable; +* Add more DFS error messages, and provide easy to understand log when abnormal. +* Fix the disk format issue of FatFs file system when multiple FatFs file systems are mounted. +* Remove the folder enter feature in msh when input a folder name; +* Add `int finsh_set_prompt (const char * prompt);` routine for setting a custom prompt for msh; +* Add the VBUS configuration in Kconfig. +* Move the application module from kernel to `libc/libdl` component; +* Rewrite most of the management code for application module: replace the original object container with the object list; split the symbol resolution code into different processor architecture etc. +* Update the application module chapter in the programming guide, and change it into dynamic module chapter. +* Overwrite the exit() function of newlib to take over the processing of exit for a dlmodule. +* Add SAL (Socket Abstraction Layer) component for adapting different protocol stacks and network implementations, and update the relevant sections of the programming guide; +* Add AT component, including AT client, AT server and AT Socket function; +* Remove the poll/select API of DFS_NET and move them to SAL component. +* Remove the strong dependence of lwIP component for DFS_NET and replace it with Kconfig configuration in SAL. +* Add the DHCP server function with lwIP raw API; +* Fix the wait queue none-initialization issue in socket allocation of lwIP. +* When a thread is about to block on a wait queue, fix the wake up issue for `rt_wqueue_wakeup' is executed to wake up that thread; +* Add the PWM driver framework; +* Fix the sdio_irq_wakeup release issue in the MMC/SD framework. +* Fix the problem of DMA handling in the serial driver framework. +* Update SFUD to v1.0.6 version; + +## BSP + +* Fix the SP issue when hard fault occurs for ARM Cortex-M arch; +* Add C-Sky CK802 architecture porting; +* Add Realtek amebaz WiFi SOC (rtl8710bn) BSP; +* Update imxrt1052-evk firmware SDK to support B model chip. +* Fix the copying packets issue in the Godson 1C BSP when sending message. +* The Nuvoton m05x/m451 BSP are changed into the main() entry mode, and supports GCC compilation; +* Fix the inconsistency issue between touch range and LCD resolution in qemu-vexpress-a9. +* Add qemu-vexpress-gemini BSP for dual core A9 (RT-Thread + Linux) arch; +* Add the basic porting for Raspberry Pi 2B ; +* Add CAN and PWM drivers in stm32f4xx-HAL BSP; +* Optimize the GPIO driver in stm32f4xx-HAL BSP; +* Add UART3 driver in stm32f4xx-HAL BSP; +* Fix the I2C1 driver clock in stm32f10x BSP and WDG control interface. +* Add rt_hw_us_delay interface in stm32f10x-HAL BSP; +* Optimize the GPIO driver in stm32f10x-HAL BSP; +* Add GPIO driver and RTC driver in stm32f107 BSP; + +## Tool + +* ENV update to v1.0.0 final version. +* ENV added the China mirror for software package, which can speed up the software package download, update etc. +* Fix the ENV known bugs and enhance the interaction with users. +* Add building script to detect the version of GCC & newlib; +* Add building script to detect the version of armcc; +* Add `scons --dist` function to make distribution for a BSP. +* Add `scons - dist - strip' function to make a minimal files of distribution for a BSP. +* Add `ASFLAGS/LOCAL_ASFLAGS' parameters for defined a group and pass them to assembler; +* Fix some errors in building script under the Linux environment. +* Add the C-Sky CDK IDE project generation. +* Add `scons --target=vsc -s` to generate friendly configuration files for VSCode; + +# RT-Thread 3.0.4 Change Log + +## Kernel + +* Change the location of hook invoking in rt_event_send, which can better reflect the event value to the system view. +* Fix the rt_realloc() issue in memheap; +* Fix the vstart_addr issue in the dynamic library. +* Ensure that signal is more standardized and remove si_errno members from siginfo_t; +* Add rt_thread_mdelay() API for millisecond delay in thread. + +## Components + +* Fix the DFS mkfs issue of FatFs (which is a merge issue introduced in RT-Thread V3.0 upgrade). +* Fix dfs_net poll issue, if there is already received data, the upper layer can not wake up and deal with data. +* Fix the socket issue in dfs_net if lwip_socket failed(Bluebear233); +* If the dfs_net/socket feature is used within lwIP 1.x version, a compiler error will be returned. +* Fix the DFS df() information issue; +* Fix the audio device write issue while the interrupt is not properly recovered. +* Fix the one-shot timeout issue in the hardware timer driver framework. +* In ENC28J60 driver, the "link change interrupt" is enable in initialization. +* Fix the data issue in put data into ringbuffer. +* Add UDP information display in netstat command; +* Fix the USB HS issue when sending 1 bytes of data will cause two times of transmission. +* Change the registration mechanism of USB Class Driver and Class Driver can be registered in package. +* Add USB Device driver framework for HS USB. +* Enhance the compatibility of time() function for different compilers; +* Add more configuration items for DHCPD in menuconfig. + +## BSP + +* Temporarily remove the Andes AE210P transplant because of the mistakenly use SVC for context switching. +* Add SD/MMC drive in Allwinner ARM9 BSP; +* Add SPI and SPI Flash drivers to Allwinner ARM9 BSP. +* Add GD32's gd32303e-eval development board support; +* gd32450z-eval supports GNU GCC compilation; +* Rewriting the hifive1 board level support package for the risc-v architecture; +* About i.MX RT1052, we have completed various development board support: ATK, Fire, seeed studio; +* On i.MX RT1052, add the cache-ops functions; +* On i.MX RT1052, add I2S driver and WM8960 codec driver support; +* Improve ETH driver support (including support for Fire development board) on i.MX RT1052. +* Add Hardware Timer driver support on i.MX RT1052. +* On i.MX RT1052, add GPIO driver; +* On i.MX RT1052, add RTC driver; +* On i.MX RT1052, improve SD/MMC driver; +* On i.MX RT1052, add SPI driver and SPI Flash driver (connect to SFUD component); +* Add USB Device driver on i.MX RT1052. +* Add README files and KConfig files in LPC408x BSP; +* Add README documents in LPC5460x-LPCXpresso BSP; +* Add the display controller driver (Sundm75) in Godson 1C BSP. +* Add CAN driver in Loongson 1C BSP(Sundm75); +* In GPIO driver of Loongson 1C BSP, add (external) interrupt feature (Zhuangwei); +* Use SPI automatic initialization in Loongson 1C BSP. +* Add I2C driver in Loongson1C BSP(Sundm75); +* Add resistive touch screen driver in Loongson 1C BSP(Sundm75); +* In Loongson 1C BSP, the components initiliazation and main function is enable(Zhuangwei). +* Add self bootup in Loongson1C BSP (Zhuangwei); +* Add README files and KConfig files to Loongson 1C BSP(Zhuangwei). +* Fix the rx descriptor issue in init_rx_desc function in NUC472 BSP (Bluebear233); +* Add AC97 Audio driver in QEMU-VExpress-A9 BSP; +* Add README description file in QEMU-VExpress-A9; +* Add I2C driver in stm32f4xx-HAL BSP, and README description file; +* Add cache-ops in stm32f7-disco BSP, and README description file; +* Add README description file in stm32f10x/stm32f10x-HAL; +* Add README specification files and KConfig configuration files in stm32f40x BSP; +* Add KConfig configuration file in stm32f20x BSP; +* Add README description file to stm32f411-nucleo BSP and enable GNU GCC tool chain support; +* Add GPIO driver and README description file in stm32f429-apollo BSP; +* Add KConfig configuration files in stm32f429-armfly BSP; +* Add README description file in stm32l476-nucleo BSP; +* Because V2M-MPS2 does not support in 32-bit machine simulation operation, temporarily remove this BSP. +* Add README description file and some firmware file, such as u-boot.bin, wifi firmware etc, in X1000 BSP; +Tools +* Add detection feature for the version of GNU GCC tool chain and libc function feature. +* Add the function of VSCode editor assistance, and support scons --target=vsc -s under BSP folder to generate configuration files for VSCode. +* Add the detection of verson of IAR; +* Add the ProjectInfo (Env) function to get information about target: all source files should be compiled, all header files, all macro definitions, the search paths for header file etc. + +# RT-Thread 3.0.3 Change Log + +## Kernel + +* Add scheduler protection when do cleanup for a detached thread; +* Fix the object_find issue when enable module feature; +* Improve POSIX signal support and add rt_signal_wait function and POSIX sigwait interface; +* When enable finsh shell, rtthread.h header file includes the API file of finsh. Therefore, the application code can use command export feature without finsh.h file; +* Improve the comments of rtdbg.h file. In RT-Thread, just use following code to add debug log feature: + +```c + #define DBG_ENABLE + + #define DBG_SECTION_NAME "[ MOD]" + #define DBG_LEVEL DBG_INFO + #define DBG_COLOR + #include +``` + +When close the DBG_ENABLE definition, the debug log will be closed. Otherwise, the `dbg_log(level, fmt, ...)` can be used to print debug information. + +DBG_SECTION_NAME - The prefix information for each log line; +DBG_LEVEL - The debug log level; +DBG_COLOR - Whether use color log in console. + +## Components + +* Fix the flag issue of fopen in GNU GCC; +* Fix the pthread_detach issue when used for a detached pthread; +* Fix the _TIMESPEC_DEFINED issue in IAR 8; +* Add libc_stdio_get_console() interface for returns the fd of console; +* Move UI engine component as a standalone package; +* Add a unify TF/SD card driver on SPI device bus; +* Add soft-RTC device, therefore device can synchronize with network time and maintains the time with OS tick later; +* Change the open/fcntl/ioctl API to POSIX standard interface; +* Fix ramfs issue when update with RTT 3.0.x; +* Fix the elm fatfs umount issue; (liu2guang) +* ignore the O_CREAT flag when open a device file; +* Improve VCOM class driver in USB stack; (ChunfengMu, Aubr.Cool) + +## BSP + +* Fix the potential issue when enable Cortex-M hardware FPU; +* Add v2m-mps2 bsp, which is used in Keil MDK5 for Cortex-M4/M7/M23/M33 simulation; +* Add sdcard driver for stm32f10x-HAL;(liu2guang) +* Improve GNU GCC support for stm32f10x-HAL;(Xeon Xu) +* simulator bsp can be used in Windows/Visual C++ and update SDL to v2.0.7; +* Add gk7102 bsp by gokemicro;(gokemicro) +* Add allwinner F1C100s ARM9 bsp;(uestczyh222) +* Fix some issues in peripherals drive library of NXP LPC54608/i.MX RT; (Valeriy Van) + +## Tools + +* scons building script will automatically add `_REENT_SMALL` macro when enable newlib nanao; +* Modify building script for Python 3.x and scons 3.0 + +# RT-Thread v3.0.2 Change log + +## Platform + +* Make sure the Object_Class to a fixed value +* Add `rt_device_create/destroy` API +* Add memory trace for small memory management algorithm for memory leak and overwritten. +* Add a first version of asynchronous I/O API +* Add cputime for high resolution counter +* Add pipe device functions in DeviceDrivers +* USB Host available in stm32f4 with mass storage class +* Add 'df' command in msh +* Update UI engine and add an example +* Split `clock_time` from pthreads and add a new clock id: `CLOCK_CPUTIME_ID` +* Enable IPv6 in lwIP 2.0.2 version +* Add memlog in logtrace +* Fix closesocket issue in dfs_net +* Fix IPv6 issue in NFS +* Update JFFS2 file system with new DFS API +* Fix the issue of stat "/.." of lwext4 (parai) +* Fix the fs type search issue in mkfs +* Fix the select issue in dfs_net + +## Tools + +* scons: add '--useconfig' command to use an exist config file +* scons: force to use g++ for link when enable `RT_USING_CPLUSPLUS` in GNU GCC configuration +* Enable package feature in Linux/MacOS host + +## BSP + +* Add NUC472 bsp (bluebear) +* Update SD/MMC driver for qemu-vexpress-A9 +* Add keyboard/mouse driver for qemu-vexpress-a9 +* Add ADC/I2C/Flash/PWM/RTC/smbus/SPI driver for apollo2 (Haleyl) +* Add I2C/LCD/Touch driver for i.MXRT1052-EVK +* Update SD/MMC driver for mini2440 (kuangdazzidd) +* Update simulator to adapt VC++ compiler +* Add USB host driver in stm32f4xx-HAL (uestczyh222) +* Update EMAC driver for IPv6 in stm32f40x/stm32f107 +* Add stm32h743-nucleo bsp (polariss) + +# RT-Thread v3.0.1 Change log + +## Platform: + +* Add mmap()/munmap() API for POSIX compatibility. +* Fix the filesystem_operation_table issue. +* Enhance USB stack for USB slave (HID/ECM/RNDIS/WINUSB or composite device); +* Enhance USB stack for USB host (HID/MSC etc); +* Fix memory leak issue when close a pipe. +* Fix the romfs open issue; +* Add SoftAP device in Wi-Fi framework; +* Re-order the lwIP/ETH initialization; +* Add IPv6 options in Kconfig; +* Fix the module_id issue in _rt_thread_init; + +## Tools: + +* Add menuconfig for Linux/Mac platform: use `scons --memuconfig` to enable it; +* Add LIBS feature for IAR project; + +## BSP: + +* Enhance LPC54608 BSP for kinds of compiler; +* Add GPIO/I2C/SPI driver for Loongson 1C; +* Add csd cmd in sdcard driver of mini2440; +* Add SDIO/EMAC driver for qemu-vexpress-a9 bsp; +* Enable VC++ to compile simulator bsp; +* Add stm32f4xx-HAL bsp for kinds of STM32F4 series ; +* Fix the PHY reset in stm32f429-apollo bsp; +* Add Audio/MMC/SLCD/Touch/USB slave/RTC/SPI/SFC Flash driver in Ingenic X1000 bsp; + +# RT-Thread v3.0.0 Change log +## Platform: + +* Add more POSIX features, for example poll/select, signal, termios etc. +* Add waitqueue for poll feature. +* Use fops for file operation. There are two ways to visit device object: rt_device_* API, the file API(open/read/write/close etc). +* Change the type of cmd from uint8_t to int in control interface. +* Add more C++ object for RT-Thread Kernel Object. +* Add wlan driver framework for wlan device operation. +* Integrate SFUD into RT-Thread to unify the operations of spi flash. +* Update lwIP to v2.0.2 version. + +## Tools: + +* Enable packages, with ENV tool. +* menuconfig & Kconfig. +* Add scons --dist for make a distribution for specified BSP. + +## BSP: + +* more MCU porting. + +## IoT: + +* put more IoT components as packages, for example, MQTT, CoAP, HTTP, TLS etc. + +# RT-Thread v2.1.0 Change log + +This release is the final release for RT-Thread v2.1.0 branch. This release has been delayed many time. After committed fh8620 and x1000 bsp, we are proud to announce this branch release of the official version. + +The change log since last stable version: + +## Kernel: + +* Move the init component to the kernel. +* Fix the device open flag issue. +* Add assertion hook. +* Better application module support. +* Does not lock scheduler when invoking soft-timer timeout function. + +## Board Support Package: + +* fh8620, which is provided by Shanghai Fullhan Microelectronics Co., Ltd. It's a IP camera chip with ARM1176, 300MHz, 16KB I-Cache and 16kB D-Cache. +* x1000 bsp. The CPU is a XBurst CPU 1.0GHz, MIPS-based, from Ingenic Semiconductor Co.,Ltd. +* imx6sx bsp, only the Cortex-A9 core porting in the NXP i.MX6 solox. BTW, another full Kinetis series porting was created in rt-thread_fsl, which is maintained by NXP employee. +* lpc5410x bsp, only the Cortex-M4 core porting. +* ls1cdev bsp for Loogson1C board. +* dm365 bsp. +* nRF51822/nRF52832 bsp. +* stm32f7-disco bsp, the first ARM Cortex-M7 porting in RT-Thread. +* stm32f411-nucleo bsp. +* Add IAR compiler support in beaglebone bsp. + +## Components: + +* Add more socket fd operators in DFS with a virtual lwIP file system ops. +* Add CAN/Hardware Timer device drivers. +* Fix the SDIO issue to support sdio wifi device. +* Add eMMC support in SD/MMC device drivers; +* Fix the NAT configured enter reset issue in lwIP NAT. +* RTGUI come back, but as a UI engine for blend point/line/rect and bitmap etc. +* Add nanopb porting, a small code-size Protocol Buffers implementation; +* Add paho-mqtt porting, the Eclipse Paho MQTT C/C++ client for Embedded platforms; +* Update freetype to 2.5.4 version. +* Enhance msh for file operations. +* Split the exported commands of finsh shell to a standalone section: ".rodata.name" + +# RT-Thread v2.1.0 beta版本更改说明 + +## BSP部分 + +* BeagleBone加入GPIO驱动; +* 京微雅格M7,更新驱动库并改进EMAC驱动程åºï¼› +* 新加入dm365ç§»æ¤ï¼ˆåŒ…括EMACã€GPIOã€I2Cã€MMC/SDã€SPI等驱动); +* LPC4088加入EMCã€ç¡¬ä»¶å®šæ—¶å™¨ã€CAN驱动; +* 新加入龙芯1C,智龙v2开呿¿ç§»æ¤ï¼ˆåŒ…括多串å£é©±åŠ¨ï¼‰ï¼› +* 更改mini2440ç§»æ¤ä¸ºapplications/drivers等的目录方å¼ï¼› +* æ›´æ–°simulator在MS VC++上的移æ¤ï¼Œå¤„ç†å¥½åˆå§‹åŒ–代ç å·¥ä½œï¼Œå®Œå–„UART控制å°é©±åŠ¨ï¼› +* 新加入stm32f7-discoç§»æ¤ï¼› +* 在stm32f10x中新加入CAN驱动åŠåº”用代ç ç¤ºä¾‹ï¼› +* 在stm32f40x中加入硬件定时器驱动,RTC驱动; +* 调整stm32f107为新的串å£é©±åŠ¨æ¡†æž¶ï¼› + +## 组件 + +* DFSçš„struct stat定义中移除st_blksizeæˆå‘˜ï¼ˆå¯ä»¥å…¼å®¹äºŽVC++中的stat定义); +* 修正DFS中select实现的问题; +* 修正DFS中文件æ“作出错ã€å…³é—­æ—¶çš„fd处ç†é—®é¢˜ï¼› +* 修正DFS中mkdirå’Œlseek出错时的fd处ç†é—®é¢˜ï¼› +* 修正lwIP中SYS_ARCH_PROTECT/SYS_ARCH_UNPROTECTä¿æŠ¤çš„é—®é¢˜ï¼› +* 增加CAN驱动框架; +* 增加硬件定时器驱动框架; +* SD/MMC驱动框架中增加eMMC支æŒï¼› +* 修正注册SDIO驱动时驱动关è”的问题; +* 修正串å£é©±åŠ¨æ¡†æž¶DMAå‘逿—¶æ¿€æ´»æ ‡å¿—的问题; +* SPI Flash驱动中加入对GD25Q spi flash芯片支æŒï¼› +* 增加paho-mqtt组件移æ¤ï¼› +* 增加msh的脚本执行能力,å¯ä»¥åœ¨msh下执行*.sh脚本; +* 增加msh下的mkfs命令; +* 修正在Linux Telnet下使用finsh shell回车符处ç†çš„问题; +* 增加应用模å—在使用armccã€gnu gcc编译器时的libc符å·å¯¼å‡ºï¼› +* 在以太网网å¡é©±åŠ¨æ¡†æž¶ä¸­å¢žåŠ ETHIF_LINK_AUTOUP/PHYUP傿•°ç”¨äºŽæŒ‡å®šåˆå§‹æ—¶çš„链路Up/Down状æ€ï¼› +* 在组件åˆå§‹åŒ–中导出log_trace组件; + +## 内核 + +* 更改UNUSED/USED等更改æˆRT_UNUSED/RT_USEDï¼› +* 链接时增加.rodata.name section,当空间资æºå—陿—¶å¯ä»¥æŠŠå®ƒæ”¾åˆ°æ€§èƒ½ä½Žçš„内存区域; +* 完善IAR编译器下的组件自动åˆå§‹åŒ–ï¼› +* 增加rt_assert_hookï¼Œåœ¨è§¦å‘æ–­è¨€æ—¶å¯ä»¥æ‰§è¡Œè¿™ä¸ªé’©å­å‡½æ•°ï¼› +* 修正应用模å—分散加载情况下的问题; + +## 工具 + +* scons中定义Group时加入了本Groupå†…çš„ç¼–è¯‘å‚æ•°å®šä¹‰ï¼› +* 修正了如果Group中å³åŒ…å«ä»£ç ï¼Œä¹ŸåŒ…å«äºŒè¿›åˆ¶åº“时,生æˆçš„Keil MDK工程文件有两个é‡åGroup的问题; + +版本: RT-Threadv2.0.1åŠv2.1.0 alpha + +RT-Thread v2.0.1是2.0这个系列的bug修正版,而v2.1.0 alpha则是当å‰å¼€å‘主干的一个技术预览版本,它给出了v2.1.0这个版本系列的技术预览情况,ä¸å»ºè®®ç”¨äºŽå®žé™…产å“中,因为它å¯èƒ½å­˜åœ¨å¤§é‡çš„一些bug。 + +# RT-Thread v2.0.1更改说明 + +* IAR用的dlib,加入THREAD_SUPPORT å’Œ FILE_DESCRIPTOR的支æŒï¼› +* 修正finsh中echo回显模å¼çš„问题; +* 修正USB host代ç çš„编译错误; +* 修正sensor框架回调函数的问题; +* 修正pin设备注册时的设备å称问题; + +而v2.1.0 alphaè¿™ä¸ªæŠ€æœ¯é¢„è§ˆç‰ˆåˆ™æ²¿ç€æœ€åˆè®¾å®šçš„roadmap技术路线进行,这其中主è¦åŒ…括: + +* lwip更深度的集æˆï¼šæŠŠå®ƒé›†æˆåˆ°RT-Thread的文件系统接å£ä¸­ï¼Œè¿™æ ·Linux/Unix下的一些socket网络应用能够更顺利的移æ¤åˆ°RT-Thread上,也为以åŽå¯ä»¥åº”用到更多地方的select接å£é“ºè·¯ã€‚ + +* 这部分是和RT-Threadå‘布本身无关,但也是这个版本系列设定的目标之一:开å¯ä¸€ä¸ªäº‘端集æˆå¼€å‘环境的时代ï¼äº‘端会是什么样的,请用现代化的æµè§ˆå™¨æ‰“å¼€[CloudIDE](http://lab.rt-thread.org/cloudide/simulator/index.html) + +# RT-Thread 2.0.0æ­£å¼ç‰ˆæ›´æ”¹è¯´æ˜Ž + +ç»åŽ†äº†å¤§çº¦1年的时间,RT-Thread v2.0.0的最终版本终于å‘布出æ¥äº†ã€‚自这个版本开å‘以æ¥ï¼Œå¼•入了多项功能ã€ä¿®æ”¹ã€å¢žå¼ºç­‰ã€‚感谢å‚与的诸ä½å¼€å‘äººå‘˜ï¼ +以下是自v2.0.0 RC版本以æ¥çš„详细更改记录。åŽç»­æˆ‘还会给出v2.0.0版本自v1.2.x版本的主è¦ä¸åŒã€çœ‹ç‚¹ï¼Œä»¥åŠç»™å‡ºä¸‹ä¸€ä¸ªç‰ˆæœ¬çš„roadmap规划。 + +## 内核 + +* console以RT_DEVICE_FLAG_STREAM傿•°æ‰“开字符设备; +* 在rt_memheap_free中加入更多的断言检查; + +## 组件 + +* æ›´æ–°RW009驱动以支æŒWi-Fi SoftAP模å¼ï¼ˆaozima); +* 修正sensor框架的一些问题,并加入C API接å£ï¼ˆç¿èµ›å¾·æœåŠ¡å…¬å¸æä¾›ï¼‰ï¼› +* 加入MPU6050 sensor的代ç ï¼ˆbernard, Coing); +* 加入BMI055 sensor的代ç ï¼ˆCoing); +* 当未使能heap时,修正finsh/msh中list_memheap的问题; +* 修正LIBC编译的警告; +* 加入IAR dlib相关的移æ¤ï¼Œä½¿å¾—应用能够使用标准的API接å£ï¼› +* 修正YModeæ¡æ‰‹æ—¶å¯èƒ½å¼•起的竞争问题(grissiom); +* æ›´æ–°FreeType版本到2.5.4 +* å•独把C++的全局对象åˆå§‹åŒ–放到cplusplus_system_init函数中,并在åˆå§‹åŒ–线程中调用; +* finsh中以RT_DEVICE_FLAG_STREAM傿•°æ‰“开字符设备; +* 添加VBUS组件用于Linux与RT-Thread系统之间,RT-Thread与RT-Thread系统之间通信(ç¿èµ›å¾·æœåŠ¡å…¬å¸æèµ ï¼‰ï¼› +* 增加lwIP/NAT组件,å¯ä»¥åšå¤šä¸ªç½‘å£é—´çš„地å€è½¬æ¢ï¼ˆHicard); +* 增加lwIP/DHCPæœåŠ¡ç«¯ï¼Œç”¨äºŽå‘客户端分é…IP地å€ï¼ˆç¿èµ›å¾·æœåŠ¡å…¬å¸æä¾›ï¼‰ï¼› + +## BSP + +* 修正LPC4357串å£é©±åЍåˆå§‹åŒ–时过早打开中断的问题(nongxiaoming); +* é‡å†™LPC4357串å£é©±åŠ¨ï¼Œå¹¶è®©èŠ¯ç‰‡ä¸ŠM4/M0核心分别都执行RT-Thread系统,两核心之间以VBUS组件进行系统间通信(ç¿èµ›å¾·æœåŠ¡å…¬å¸æèµ ï¼‰ï¼› +* 新增RXç§»æ¤ï¼ˆlimxuzheng); +* 新增NuMicro M051 Seriesç§»æ¤ï¼Œæ”¯æŒGCCã€Keil MDK编译器(bright-pan); +* 新增LPC54102ç§»æ¤ï¼ˆCoing); +* 移除STM32F4 BSP中ä¸éœ€è¦çš„RT_TIMER_TICK_PER_SECONDé…置(pangweishen); +* 在Linux Clang编译分æžä¸­ï¼Œå¼ºåˆ¶ä»¥32使¨¡å¼è¿›è¡Œç¼–译(grissiom); +* 修正STM32F103中串å£é©±åŠ¨ä¸­æ–­è¿‡æ—©æ‰“å¼€çš„é—®é¢˜ï¼ˆarmink); + +## 工具 + +* 增加scons中的MD5支æŒï¼ˆbright-pan); + +# RT-Thread 2.0.0 RC 更改说明 + +å‘布时间:2014/11/4 + +éšç€RT-Thread功能越æ¥è¶Šå¤šï¼Œå¦‚何å‘布版本也æˆä¸ºä¸€ä»¶å¤´ç–¼çš„事情,因为需è¦ä»”细对比最近三个月æ¥çš„修改记录。这次的å‘布è·ç¦»ä¸Šä¸€æ¬¡beta版本ä¾ç„¶æ˜¯ä¸‰ä¸ªæœˆçš„æ—¶é—´ï¼Œä½†æŒ‰ç…§å‘布计划已然推迟了一个月进行å‘布。 + +在这三个月中,开æºç¤¾åŒºä¸Šä¹Ÿå‘生了很多有趣的事情: + +阿嘉的使用RT-Thread的四轴飞行器毕业设计惊艳亮相,采用了1个STM32F4 + 8个STM32F1进行飞行控制,总计9个MCUçš„å¦ç±»å®žçŽ°æ–¹å¼ï¼›æ²¿å¾ªå››è½´é£žè¡Œå™¨çš„路线,与国内匿å团队åˆä½œï¼Œé‡‡ç”¨RW009 Wi-Fi控制的迷你四轴飞行器也在稳步推进过程中。 + +RT-Threadåšä¸ºä¸€ä¸ªå¼€æºç»„织å‚与的CSDNå¼€æºå¤ä»¤è¥ç»“出了丰硕的果实: +ç”±hduffddybzå‚与的IPv6å议栈移æ¤ï¼ˆæœ€æ–°ç‰ˆæœ¬çš„lwIP-head版本移æ¤ï¼‰åœ¨è¿™æ¬¡å‘布中已ç»åŒ…括进æ¥ï¼Œä»Žè€Œèƒ½å¤Ÿåœ¨ä½¿ç”¨RT-Threadçš„å°åž‹è®¾å¤‡ä¸Šå®žçްTCP/IP v4/v6åŒæ ˆçš„æ”¯æŒï¼› +ç”±wzyy2å‚与的GDB stub实现,也完美的支æŒBeagleBoneBlack开呿¿å’ŒSTM32F4å¹³å°ï¼› +CSDNå¼€æºå¤ä»¤è¥å…¶ä»–çš„æˆæžœï¼Œä¾‹å¦‚bluedroidç§»æ¤ä¹Ÿæœ‰äº†åˆæ­¥çš„æˆæžœï¼Œå¸Œæœ›èƒ½å¤Ÿåœ¨åŽç»­çš„版本(å¯èƒ½ä¼šæ˜¯2.1.0系列版本?)包å«è¿›æ¥ã€‚CSDNå¼€æºå¤ä»¤è¥æ˜¯ä¸€æ¬¡éžå¸¸æ£’的活动,能够让学生æå‰è¿›å…¥å®žæˆ˜ï¼Œäº†è§£è½¯ä»¶å¼€å‘çš„åˆæ­¥çŸ¥è¯†ã€‚对开æºç¤¾åŒºæ¥è¯´ï¼Œä¹Ÿæ˜¯ä¸€æ¬¡éžå¸¸æœ‰ç›Šçš„社区互动活动。希望明年这个活动å¯ä»¥ç»§ç»­ï¼Œå…³æ³¨RT-Threadã€åµŒå…¥å¼å¼€å‘çš„åŒå­¦å¯ä»¥å…³æ³¨æ˜Žå¹´çš„动å‘。 + +当剿™ºèƒ½åŒ–设备是一个备å—关注的领域,针对这一领域的特点,RT-Thread也相应的åšå‡ºäº†ç§¯æžçš„å“应,所以这个版本开始加入sensor的应用框架(APP/算法 <--> sensor framework <--> RT-Thread device driver <--> 硬件外设)。希望在å°åž‹åŒ–çš„RT-Threadæ“作系统基础上èžåˆæ™ºèƒ½åŒ–相关的技术,让RT-Threadæˆä¸ºè¿™æ–¹é¢å¯é€‰çš„OS系统之一。RT-Threadæ“作系统的sensor框架也å°è¯•新的实现方å¼ï¼Œå³é‡‡ç”¨C++çš„æ–¹å¼æ¥å®žçŽ°ï¼ˆå½“ç„¶ä¹Ÿä¼šè€ƒè™‘Cæ–¹é¢çš„兼容,无疑C++çš„é¢å‘对象特性会更好,所以最终选择了C++),在这个基础上也å¯èƒ½èžåˆå…¶ä»–çš„ä¸€äº›ç”Ÿæ€æŠ€æœ¯ï¼Œä¾‹å¦‚ARM mbedå¹³å°ä¸Šçš„一些社区组件技术。所以这个å‘布版本中既包括sensor框架,也包括了C++底层的一些基础支撑。 + +这个版本是RT-Thread 2.0.0系列正å¼ç‰ˆæœ¬çš„候选版本,正å¼ç‰ˆæœ¬é¢„计会在年底正å¼å‘布,è·ç¦»æ­£å¼ç‰ˆæœ¬è¿˜ä¼šåŠ å…¥æ›´å®Œå–„çš„ä¸€äº›æ”¯æ’‘ï¼ˆä¾‹å¦‚å„ç§ä¼ æ„Ÿå™¨é©±åŠ¨ï¼‰ã€‚ä¹Ÿè®¡åˆ’2014å¹´11月22日,在上海浦东举行RT-Thread嵌入å¼ç³»ç»Ÿæ²™é¾™æ´»åŠ¨ï¼Œæ¬¢è¿Žå¤§å®¶å…³æ³¨å¹¶å‚与进行RT-Thread方方é¢é¢çš„æŠ€æœ¯äº¤æµã€‚ + +以下是这个版本的更改记录: + +## 内核 + +* 修正当采用高级别优化编译时,idleä»»åŠ¡ä¸­æŸ¥è¯¢æ˜¯å¦æœ‰åƒµå°¸çº¿ç¨‹çš„æ½œåœ¨bugï¼› + +* 修正memory pool中的竞争问题; + +* 在consoleä¸­æ‰“å¼€è®¾å¤‡æ—¶ï¼ŒåŠ å…¥æµæ ‡å¿—进行打开; + +## 组件 + +* 加入C++基础支撑组件。C++组件ä¾èµ–于RT_USING_LIBC库,当使用GCCç¼–è¯‘å™¨æ—¶è¯·æ³¨æ„æŸ¥çœ‹å…¶ä¸­çš„说明文档并更改ld scriptï¼› +* 修正DFS中NFS打开目录的bugï¼› +* 更改DFS ROMFS默认romfs_root为弱化符å·ï¼› +* 添加DFS中dfs_file_lseek接å£ä¸­å…³äºŽfs的检查; +* 移除I2C core中无用的core locké”ï¼› +* 添加sensor framework(采用C++çš„æ–¹å¼æ”¯æŒå„ç§sensor); +* 修正serial框架中DMAå‘é€çš„bug(heyuanjie87); +* 移除SPI框架中ä¸å¿…è¦çš„deviceåˆå§‹åŒ–代ç ï¼› +* 完善SPI Wi-Fi网å¡RW009驱动并æä¾›RSSI相关的命令; +* 修正MSH中未定义DFS_USING_WORKDIR时更改当å‰ç›®å½•çš„bugï¼› +* 修正MSH中未定义RT_LWIP_TCPæ—¶ä¾ç„¶å®šä¹‰äº†netstat命令的bugï¼› +* 修正MSH中未定义RT_USING_HEAPæ—¶ä¾ç„¶å®šä¹‰äº†free命令的bugï¼› +* 修正finsh中FINSH_USING_HISTORY相关的è£å‰ªï¼› +* 加入gdb stubç»„ä»¶ï¼Œå½“å‰æ”¯æŒARM Cortex-A8å’ŒCortex-M3/4(wzyy2); +* 统一ä¸åŒç¼–译器下使用LIBCçš„å®ä¸ºRT_USING_LIBC,原有的å®å®šä¹‰RT_USING_NEWLIB/RT_USING_ARM_LIBC需è¦ä»Žrtconfig.hä¸­ç§»é™¤ï¼Œå¹¶æ›¿æ¢æˆRT_USING_LIBCï¼› +* 加入最新的lwIP分支:lwip-head,以æä¾›IPv4/v6åŒæ ˆçš„功能(hduffddybz); +* YMode中打开串å£è®¾å¤‡æ—¶ï¼Œæ·»åŠ open flag(armink); + +## bsp + +* 加入北京京微雅格的M7(åŽå±±ï¼‰ä½ŽåŠŸè€—FPGAçš„ARM Cortex-M3ç§»æ¤ï¼ˆaozima); +* 加入北京京微雅格的M7 EMAC以太网驱动(aozima); +* AT91SAM9260分支中更改RT_USING_NEWLIB为RT_USING_LIBCï¼› +* BeagleBoneBlack分支中加入gdb stub支æŒï¼ˆwzyy2); +* LPC176x分支中加入C++支æŒï¼› +* LPC176x分支中修正SDå¡é©±åŠ¨è¿”å›žå¡ä¿¡æ¯çš„bugï¼› +* 修正LPC408x分支中GCC编译时的问题; +* LPC408x分支中加入C++支æŒï¼› +* 龙芯1B分支中加入UART3驱动; +* 加入飞索åŠå¯¼ä½“çš„MB9BF568 FM4分支移æ¤ï¼ˆyangfasheng); +* mini2440分支中更改RT_USING_NEWLIB为 RT_USING_LIBCï¼› +* stm32f0x分支中移除ä¸åŒç¼–译器下的LIBC定义,统一更改为RT_USING_LIBCï¼› +* stm32f0xåˆ†æ”¯ä¸­åŠ å…¥ä¸²å£æŽ¥æ”¶æº¢å‡ºä¸­æ–­å¤„ç†ï¼ˆarmink); +* stm32f40x分支中加入gdb stub支æŒå¹¶æ·»åŠ UART6驱动(wzzy2); +* zynq7000分支中更改RT_USING_NEWLIB为RT_USING_LIBCï¼› +* 加入ARM Cortex-M4芯片指令级的ffs实现; +* 修正MB0BF618S分支中缺少timeråˆå§‹åŒ–çš„bug(mike mao); + +## 工具 + +* 移除Python 2.6中未支æŒçš„语法(xfguo); +* 移除Windowså¹³å°ä¸­çš„startupinfoä¿¡æ¯ï¼ˆå¯¹Python版本兼容性更好); +* 修正CPPPATH被打乱的bugï¼› + +# RT-Thread 2.0.0 Beta更改说明 + +å‘布时间:2014/8/1 + +v2.0.0这个版本系列是RT-Thread当å‰çš„å¼€å‘分支,如果è¦ä¸Šæ–°é¡¹ç›®ï¼Œå»ºè®®ä½¿ç”¨è¿™ä¸ªç‰ˆæœ¬æ¥è¿›è¡Œï¼Œé¢„计这个版本的正å¼ç‰ˆä¼šåœ¨å¹´åº•å‘布。欢迎对这个版本进行测试ã€å¹¶å馈问题,能够早日进入到稳定版。 + +v2.0.0版本的开å‘相对活跃些,开æºç¤¾åŒºæä¾›äº†å¼ºæœ‰åŠ›çš„æ”¯æŒï¼šå¦‚Arda贡献的TM4C129xç§»æ¤ï¼ŒRomeo贡献的frdm-k64fç§»æ¤ï¼Œxiaonongçš„LPC4300ç§»æ¤ç­‰ï¼Œä»¥åŠç¿èµ›å¾·æœåŠ¡å…¬å¸æèµ çš„Zynq7000ç§»æ¤ï¼ŒMB9BF618Sç§»æ¤ï¼Œä»¥åŠSPI WiFi网å¡çš„驱动代ç ç­‰ã€‚ + +更改记录 + +## 内核 + +* 移除rt_device_init_all()函数:在系统å¯åŠ¨æ—¶ä¸éœ€è¦å†è°ƒç”¨è¿™ä¸ªå‡½æ•°æ¥åˆå§‹åŒ–驱动,而是由上层应用执行rt_device_open时自动进行设备åˆå§‹åŒ–ï¼› +* 修正设备对象引用计数在打开设备失败ä¾ç„¶é€’增的问题; +* 增加WEAKå®ç”¨äºŽå®šä¹‰/声明弱符å·ï¼› +* åœ¨æ‰§è¡Œé™æ€å†…å­˜å—分é…å‰ï¼Œé‡ç½®çº¿ç¨‹çš„errnoï¼› +* 修正timeræœªæ‰“å¼€è°ƒè¯•é€‰é¡¹æ—¶ï¼Œæ— ç”¨çš„é™æ€å‡½æ•°å®šä¹‰ï¼ˆå¯¼è‡´ç¼–译警告); +* å¯åЍtimerå‰ï¼Œå¯¹timer进行强制移除; +* 在执行soft timer超时函数时,打开调度器é”ï¼› +* 新增å—è®¾å¤‡çš„è‡ªåŠ¨åˆ·æ–°å‚æ•°ï¼ŒRT_DEVICE_CTRL_BLK_AUTOREFRESHï¼› + +## 工具 + +* 修正scons命令编译时,选择keil mdk (armcc)编译器时,命令行太长编译失败的问题; + +## ç§»æ¤ + +* 移除rt_device_init_all()相关的调用; +* æ ¹æ®ä¸²å£æ¡†æž¶è°ƒæ•´ç›¸å…³çš„驱动代ç ï¼› +* 新增frdm-k64fç§»æ¤ï¼ˆFreeScale K64芯片); +* 移除K60Fxxxxç§»æ¤ï¼› +* 新增LPC43xxç§»æ¤ï¼ˆNXP LPC4357芯片); +* 移除LPC176x中的组件åˆå§‹åŒ–é…置; +* 修正龙芯1Bç§»æ¤ï¼ˆls1bdev)中链接脚本关于组件åˆå§‹åŒ–部分的é…置; +* 修正STM32F40x中UART3çš„é…置; +* 修正STM32F40x中GNU GCC连接脚本中ROM/RAM大å°çš„é…置; +* 移除STM32F107中的组件åˆå§‹åŒ–é…置; +* 增强STM32F107 EMACé©±åŠ¨æ€§èƒ½ï¼ŒåŒæ—¶åŠ å…¥è‡ªåŠ¨æŸ¥æ‰¾PHY芯片地å€åŠŸèƒ½ï¼› +* é‡å†™xplorer4330(NXP LPC4330芯片)移æ¤ï¼ˆxiaonong完æˆï¼‰ï¼› +* 新增Zynq7000 ARM Dual Cortex-A9ç§»æ¤ï¼› +* 新增MB9BF618Sç§»æ¤ï¼› +* 新增tm4c129xç§»æ¤ï¼Œå¹¶åŠ å…¥ç›¸åº”çš„EMAC以太网驱动; + +## 组件 + +* DFS: 新增根æ®è®¾å¤‡å¯¹è±¡èŽ·å¾—å…¶ä¸Šè£…è½½æ–‡ä»¶ç³»ç»Ÿè·¯å¾„çš„å‡½æ•°ï¼šdfs_filesystem_get_mounted_path(struct rt_device* device); +* DFS: 修正readdir在GNU GCC下的编译警告; +* DeviceDrivers:新增workqueue实现; +* DeviceDrivers: 修正USB Device栈中的一些拼写错误; +* DeviceDrivers: é‡å†™serial框架,能够让串å£è®¾å¤‡é©±åŠ¨åŒæ—¶æ”¯æŒä¸‰ç§æ¨¡å¼ï¼špollã€interruptã€DMA。模å¼é€‰æ‹©éœ€è¦åœ¨æ‰§è¡Œrt_device_open时,由open flags指定; +* DeviceDrivers: 加入更多的SPI设备驱动,例如RW009çš„SPI WiFi网å£é©±åŠ¨ï¼ˆ2.4G 802.11 b/g/n,WEP/WPA/WPA2,SoftAP/Station),SPI NorFlashå—设备驱动,ENC28J60以太网网å¡é©±åŠ¨ï¼› +* Finsh: list_device()命令中增加refcount的信æ¯ï¼› +* Finsh: 修正'0'零叏釿— æ³•识别的错误; +* Finsh: mv命令,实现把一个文件移动到一个目录中; +* Finsh: ifconfig命令支æŒå¯¹ä¸€ä¸ªç½‘络接å£çš„基本é…置; +* Finsh: 新增netstat命令,用于显示当å‰ç³»ç»Ÿä¸­TCP连接的状æ€ï¼› +* Finsh: 修正当命令行太长导致的缓冲区移除的问题; +* libc: 修正arm libc中未使用DFS时的编译警告; +* libc: 修正newlib中使用DFS时的系统调用编译警告(GNU GCC下); +* lwIP 1.4.1: 默认打开LWIP_SO_SNDTIMEO以支æŒè¿žæŽ¥å‘é€è¶…æ—¶ï¼› +* lwIP 1.4.1: 修正MEMP_NUM_TCP_SEG定义错误的问题; +* lwIP 1.4.1: 加入RT_LWIP_REASSEMBLY_FRAG选项定义以支æŒIP分组åŠåˆå¹¶ï¼› +* lwIP 1.4.1: ethnetç½‘ç»œæŽ¥å£æ”¯æŒå®šä¹‰LWIP_NO_TX_THREAD/LWIP_NO_RX_THREAD,以关闭etx/erx线程; +* lwIP 1.4.1: 用户å¯ä»¥é‡æ–°å®šä¹‰RT_LWIP_ETH_MTU,以修改网络中的MTU值; +* lwIP 1.4.1: 修正LWIP_NETIF_LINK_CALLBACKæ¡ä»¶ç¼–译的问题; +* lwIP 1.4.1: 完善移æ¤ç›¸å…³çš„æ³¨é‡Šï¼› +* log trace: 增加log_session_lvl接å£ï¼› +* log trace: log trace中的session引用更改æˆå¸¸é‡å½¢å¼ï¼› +* ymodem: å¢žå¼ºæ•°æ®æŽ¥æ”¶çš„ç¨³å®šæ€§ï¼› + +# RT-Thread 2.0.0 Alpha更改说明 + +å‘布时间:2014/4/8 + +RT-Thread 2.0.0分支的第一个技术预览版本,仅用于展示2.0.0å‘展分支的演化动å‘(按照roadmap,2.0.0这个分支会有一部分RT-Threadå’ŒLinux互补性的技术,为Linux增加更好的实时性,为RT-Thread增加更多的功能性,这份技术预览版正是æœç€è¿™ä¸ªç›®æ ‡è€ŒåŠªåŠ›),欢迎å馈建议和问题。 + +## 组件 + +* msh: bugfix 和功能性增强。新的 msh åœ¨è°ƒç”¨å¤–éƒ¨æ¨¡å—æ–¹é¢æ›´åŠ æ–¹ä¾¿ã€‚ +* DFS: nfs çš„ bugfix 和内置命令的增强。ELM FatFS加入对扇区ä¸åŒ¹é…情况下的信æ¯è¾“å‡ºï¼Œè¿™æ ·èƒ½å¤ŸåŠæ—¶å®šä½é—®é¢˜ã€‚ +* JS:新添了轻é‡çº§Javascript引擎,å¯ä»¥åœ¨RT-Thread中直接è¿è¡Œjavascript脚本。 +* VMM:å¯ä»¥åœ¨qemu中è¿è¡Œçš„ Virtual Machine Module ç»„ä»¶ã€‚æš‚æ—¶åªæ”¯æŒ realview-pb-a8 çš„ bsp。 +* CMSIS:版本更新至 3.20 +* drivers:USB åè®®æ ˆçš„é‡æž„。新的框架中编写驱动å˜å¾—更加容易了。 + +## BSP + +* beaglebone:串å£é©±åŠ¨æ›´æ–° +* realview-a8:添加了 VMM 组件 + +## 工具 + +* 固件加入scons --target=ua -s,用于准备用户应用环境; + +[å‘布åŽè®°] + +RT-Thread 2.0.0. Alpha版本相比于RT-Thread 1.2.1ï¼Œæ–°çš„ç‰¹æ€§ä¸»è¦æœ‰ä¸¤éƒ¨åˆ†ï¼š +- RT-Thread + LinuxåŒç³»ç»Ÿï¼Œè¿™éƒ¨åˆ†ä»¥RealView-A8处ç†å™¨(ARM Cortex-A8啿 ¸)ä¸ºè“æœ¬ï¼Œç»™å‡ºä¸€ä¸ªç®€å•çš„åŒç³»ç»Ÿå¹¶è¡Œè¿è¡Œçš„demo;在没有硬件的环境下,å¯ä»¥ä½¿ç”¨QEMU软件虚拟方å¼çš„æ‰§è¡Œã€‚这个链接中包å«ä¸€ä¸ªç¼–译好的LinuxåŠRT-Thread二进制包,å¯ä»¥ç›´æŽ¥ä¸‹è½½è¿›è¡Œä½“验。 + +目录中有 Linux çš„å†…æ ¸é•œåƒ zImage,ramdisk rootfs.cpio.gz。å¯ä»¥ç”¨ +qemu-system-arm -M realview-pb-a8 -kernel zImage -initrd rootfs.cpio.gz -serial vc -serial vc +æ¥å¯åŠ¨ã€‚å¯åŠ¨ä¹‹åŽ Linux 的控制å°åœ¨ç¬¬ä¸€ä¸ªä¸²å£ä¸Š(Atl + Ctrl + 3),å¯ä»¥ç›´æŽ¥æ— å¯†ç ä»¥ root 用户登录。登录之åŽåŠ è½½å†…æ ¸æ¨¡å—: +insmod rtvmm.ko +æ¥å¯åЍ RT-Thread。RT-Thread å¯åŠ¨ä¹‹åŽæŽ§åˆ¶å°åœ¨ç¬¬äºŒä¸ªä¸²å£ä¸Š(Atl + Ctrl + 4)。第一个串å£Linux shellä¾ç„¶å¯ä»¥ä½¿ç”¨ï¼Œç¬¬äºŒä¸ªä¸²å£åˆ™æ˜¯RT-Threadçš„shell。 +- JavaScriptè§£æžå™¨ï¼Œè¿™ä¸ªæ˜¯ç”±ç‰›å¤´å“¥ç§»æ¤çš„,å¯ä»¥åœ¨ä¸€ä¸ªéžå¸¸å°èµ„料的MCU上以JavaScript脚本方å¼è¿›è¡Œç¼–程ã€å¼€å‘。根æ®è¿™ç§æ–¹å¼ï¼Œä¹Ÿæä¾›äº†RN001JS的以太网硬件模å—:以JavaScript脚本语言作为二次开å‘,æä¾›åœ¨çº¿web(å³WebIDE)进行编程并è¿è¡ŒJavaScript程åºã€‚JavaScript作为一门轻é‡çº§ã€è§£é‡Šåž‹çš„语言,更容易上手,é…åˆWebIDEã€åŠæä¾›çš„ä¸€äº›exampleå¯ä»¥ä½¿å¾—å¼€å‘å˜å¾—éžå¸¸çš„è½»æ¾ï¼Œä¹ŸåŒ…括一些传感器的JavaScript例å­ï¼Œè®©åšç½‘页的人也å¯ä»¥çŽ©ç¡¬ä»¶äº†ï¼ + +# RT-Thread 1.2.1更改说明 + +å‘布时间: 2014/4/8 + +在原有的1.2.0版本的bug修正版本,也是1.2.0ç³»åˆ—çš„ç¬¬ä¸€ä¸ªä¿®æ­£ç‰ˆæœ¬ï¼ŒåŽŸåˆ™ä¸Šä¸æ·»åŠ ä»»ä½•çš„æ–°åŠŸèƒ½ï¼Œæˆ‘ä»¬å°½é‡ä¼šæŒ‰ç…§æ¯ä¸ªå­£åº¦ä¸€ä¸ªä¿®è®¢ç‰ˆæœ¬çš„æ–¹å¼æŽ¨è¿›ã€‚大家在使用的过程中有什么问题还请å馈给我们,这些问题很å¯èƒ½ä¼šåœ¨ä¸‹ä¸ªç‰ˆæœ¬ä¸­ä¿®æ­£ï¼ + +以下是更改记录: + +## 内核 + +* ç”¨æˆ·åº”ç”¨ï¼Œå¢žåŠ ç”¨æˆ·åº”ç”¨å‘½ä»¤è¡Œå‚æ•°æ”¯æŒï¼› +* 在挂起一个任务时,把相应的定时器也关闭; + +## BSP + +* BeagleBone,加入更多串å£é©±åŠ¨æ”¯æŒï¼› +* 移除BSP中rt_device_init_allå‡½æ•°è°ƒç”¨ï¼Œæ”¹æˆæ‰“开设备时自动进行åˆå§‹åŒ–ï¼› +* LPC176x,移除componentsåˆå§‹åŒ–管ç†å™¨ï¼› +* LPC4088,修正LED驱动的问题; +* STM32F107,移除componentsåˆå§‹åŒ–管ç†å™¨ï¼› + +## 组件 + +* 文件系统,ELM FatFS加入对扇区ä¸åŒ¹é…情况下的信æ¯è¾“å‡ºï¼Œè¿™æ ·èƒ½å¤ŸåŠæ—¶å®šä½é—®é¢˜ï¼› +* 文件系统,NFS网络文件系统修正相关的一些编译警告信æ¯ï¼› +* 文件系统,copy命令加入文件夹方å¼å¤åˆ¶åŠŸèƒ½ï¼› +* 文件系统,RAMFS,加入到componentsåˆå§‹åŒ–管ç†å™¨ä¸­ï¼› +* 文件系统,ROMFSï¼Œç”¨äºŽè½¬æ¢æ–‡ä»¶çš„工具mkromfs.py,增加Linux主机的支æŒï¼› +* CMSIS更新到3.2.0版本; +* 串å£é©±åŠ¨æ¡†æž¶åŠ å…¥serial->ops->control的调用; +* 命令行系统,优化msh,支æŒç”¨æˆ·åº”ç”¨çš„å‘½ä»¤è¡Œå‚æ•°ï¼› +* 命令行系统,当使用msh时,默认使用msh >的命令行æç¤ºç¬¦ï¼› +* TCP/IPå议栈,导出更多的lwIP接å£ç»™ç”¨æˆ·åº”用; +* POSIX threadï¼Œä¿®æ­£äº†åŒæ—¶ä½¿ç”¨lwIP组件时的编译警告; +* 第三方组件,加入TJPGD的移æ¤ï¼ŒåŠ å…¥libpng的移æ¤ï¼› + +## 工具 + +* 固件加入scons --target=ua -s,用于准备用户应用环境; + +[å‘布åŽè®°] +* RT-Threadæºå¸¦äº†ä¼—多的BSP,ä¸ä¸€å®šèƒ½å¤Ÿä¸€ä¸€ä¿è¯æ¯ä¸ªåˆ†æ”¯ä¸ŠæŠŠRT-Thread上相应的功能使用起æ¥ã€‚æ‰€ä»¥é’ˆå¯¹è¿™ç§æƒ…å†µï¼Œæˆ‘ä»¬æœ‰ä¸€æ¬¾è¯„ä¼°ç”¨çš„ç¡¬ä»¶å¼€å‘æ¿ï¼šRealBoard 4088,在上é¢åŠ›æ±‚æŠŠä¸€äº›ç›¸å…³ä¾‹ç¨‹éƒ½æ·»åŠ ä¸Šï¼Œè¿™æ ·åœ¨ä¸€ä¸ªåŸºæœ¬çš„BSP基础上,å¯ä»¥å¯¹ç…§ç€æŠŠå…¶ä»–的组件ã€åŠŸèƒ½æ·»åŠ è¿›åŽ»ï¼› +* RealBoard 4088使用的RT-Thread版本主è¦ä»¥RT-Thread 1.2.1版本为主。 + +# RT-Thread 1.2.0æ­£å¼ç‰ˆæœ¬æ›´æ”¹è¯´æ˜Ž + +å‘布时间: 2014/1/6 + +实现roadmap中æåˆ°çš„大部分内容 + +1,文档方é¢å·²å®Œæˆã€ŠRT-Threadç¼–ç¨‹æ‰‹å†Œã€‹ï¼ŒåŒæ—¶è¿˜æœ‰è®ºå›ä¸Šjiezhi童鞋的《一起æ¥å­¦RT-Thread系列连载教程》 +2,BSPåˆ†æ”¯æ–¹é¢æ–°å¢žcortext-A8(beaglebone),cortext-R4(rm48x50),UNITY-2(SEP6200),lpc408xçš„ç§»æ¤ +3,组件方é¢ï¼š +- 加入msh(类似linux shell的风格)ï¼Œèƒ½å¤Ÿç›´æŽ¥æ‰§è¡Œåº”ç”¨ç¨‹åº +- 新增freemodbus 1.6.0çš„ç§»æ¤ +- 新增开æºçš„嵌入å¼å…³ç³»æ•°æ®åº“SQLite 3.8.1çš„ç§»æ¤ +- 新增Ymodemåè®® +- 默认使用lwIP 1.4.1 + +䏋颿˜¯è‡ªRT-Thread 1.2.0 RC版本å‘布以æ¥å…·ä½“çš„å˜æ›´å±¥åŽ†ï¼š + +## 内核 + +* timer.c - 使用跳跃表(skip list)实现系统定时器链表,并在bsp中的startup.c䏭釿–°åŠ å…¥å®šæ—¶å™¨åˆå§‹åŒ–函数rt_system_timer_init() +* rtdebug.h - 新增å®å®šä¹‰RT_DEBUG_IN_THREAD_CONTEXT +* idle.c - 在函数rt_thread_idle_excute()中一次清除所有的死线程 +* scheduler.c - 新增API rt_critical_level()è¿”å›žè°ƒåº¦å™¨ä¸Šé”æ¬¡æ•° + +## ç§»æ¤ + +* cortex-m0 - 修正 cortex-m0 GCCç§»æ¤ä¸­hardfault的问题点 +* cortex-r4 - 在startupåŽé‡Šæ”¾IRQ堆栈空间 +* cortex-r4 - 按字节长度分é…堆栈空间 + +## BSP分支 + +* 新增lpc408xç§»æ¤ +* bsp/stm32f0x - 增加USART1,USART2驱动,支æŒfinsh,支æŒç»„ä»¶åˆå§‹åŒ– +* bsp/simulator - 当RTGUIé…置无效时打å°é”™è¯¯ä¿¡æ¯ +* bsp/simulator - 默认情况下关闭RTGUI选项 +* bsp/simulator - 增加createdef.py文件æ¥ç”ŸæˆVSçš„def文件 +* bsp/simulator - 当使用VC++编译时去除_TIME_T_DEFINED的定义 +* bsp/xplorer4330 - é‡å‘½å文件Retarget.c为retarget.c,å¦åˆ™linux系统中编译会报错 +* bsp/xplorer4330 - 修正GCC编译链接时关于ENTRY的警告 +* bsp/rm48x50 - 新增GCCçš„ç§»æ¤ +* bsp/K60Fxxxx - 修正一个编译错误 + +## 组件 + +* dfs - 正确处ç†mkfs未实现的情况 +* dfs - 使用指针代替indexå˜é‡ +* dfs - 在函数dfs_filesystem_lookup()å°†å«ä¹‰æ¨¡ç³Šçš„æŒ‡é’ˆå˜é‡åç§°emptyé‡å‘½å为fs +* dfs - 修正dfs_unmount问题点 +* dfs - 在设备打开错误时令挂载失败 +* dfs/elmfat - 令elmfatfsæ¯æ¬¡éƒ½æ£€æŸ¥æ‰‡åŒºå¤§å° +* net - 新增freemodbus 1.6.0çš„ç§»æ¤ +* finsh - 新增FINSH_USING_MSH_ONLY选项 +* finsh - åªæœ‰å½“shell设备为空时调用rt_console_get_device() +* finsh - 修正FINSH_USING_SYMTAB未定义的错误 +* finsh - 釿ž„controlæŒ‰é”®çš„å¤„ç† +* msh - 增加文件和路径å称自动补全的功能 +* msh - msh内增加执行module的功能 +* msh - msh内增加更多的命令 +* libc - 修正 _sys_read()/_sys_write()问题点 +* external - 增加开æºçš„嵌入å¼å…³ç³»æ•°æ®åº“SQLite 3.8.1çš„ç§»æ¤ +* pthreads - é¿å…ESHUTDOWNé‡å¤å®šä¹‰ +* mtd_nand - 在MTD nand中增加更多的调试措施 +* mtd_nand - 修正æ“作MTD nandæ—¶èµ·å§‹å—错误的问题 +* lwip-1.4.1 - 在lwIP内加入更多的RT-Thread选项设置 +* log_trace - 修正函数memmove()傿•°ä½¿ç”¨é”™è¯¯çš„问题 +* drivers/pipe - 增加一个control命令æ¥èŽ·å¾—pipe剩余的空间 +* drivers/serial - 如果读写长度为0,则立å³è¿”回 + +## 例程 + +* examples - 用rt_sem_control()中的RT_IPC_CMD_RESET命令rt_sem_trytake()æ¥æ¸…除信å·é‡ +* examples - 始终打å°è¾“出测试结果 +* examples - 在所有的测试结æŸåŽæ‰“å°è¾“出简报 +* examples - 在TC线程中清除å˜é‡_tc_statçš„TC_STAT_RUNNINGçŠ¶æ€ +* examples - 釿–°å®žçްloop功能,并新增finsh命令tc_loop +* examples - 在tc_stop中增加延时,由原æ¥çš„å»¶æ—¶RT_TICK_PER_SECOND/2调整为10 * RT_TICK_PER_SECOND +* examples - 在SConscript中判断TC如果被使能,在CPPPATH中增加TC路径 +* examples - 新增一个in-mem-logçš„ä¾‹å­ +* semaphore_priority.c - 在cleanup时释放信å·é‡ +* heap_realloc.c - 检查调用realloc(ptr, 0)æ˜¯å¦æˆåŠŸ +* thread_delete.c - tc线程的延时应该比tid2的延时长,ä¿è¯å…¶æµ‹è¯•过程中正常è¿è¡Œ +* thread_delay.c - 放宽超时判断æ¡ä»¶ï¼Œå› ä¸ºå½“RT_TICK_PER_SECOND为1000时,容易产生1个tick的误差 +* semaphore_static.c - 放宽超时判断æ¡ä»¶ï¼Œå› ä¸ºå½“RT_TICK_PER_SECOND为1000时,容易产生1个tick的误差 +* semaphore_dynamic.c - 放宽超时判断æ¡ä»¶ï¼Œå› ä¸ºå½“RT_TICK_PER_SECOND为1000时,容易产生1个tick的误差 + +其他: +* æ›´æ–°README.md + +# RT-Thread 1.2.0RC更改说明 + +å‘布时间: 2013/10/10/ 10:19 + +主è¦è¯´æ˜Ž: 该版本新增ARM Cortex-A8的支æŒ(BeagleBone),新增UNITY-2内核的支æŒ(SEP6200),新增Ymodemå议。 + +å˜æ›´å±¥åކ +======== + +[内核] + +* 修正rtdef.h中的拼写错误(_MSC_VER_ -> _MSC_VER) +* 修正scheduler.c中的调试打å°è¾“出错误 +* ipc - 在函数rt_event_recv()ä¸­å¢žåŠ å¯¹å‚æ•°option有效性的检查 +* device - 增加统计设备引用次数的å˜é‡ref_count +* memheap - 修正内存å—分割问题点 +* memheap - 优化函数rt_memheap_realloc() +* kservice - 函数声明使用rt_vsnprintf代替vsnprintf + + +[组件] + +* dfs - 修正dfs_file.c中一处å˜é‡å‚数类型错误的问题 +* dfs - 增加mount table +* dfs - 在building脚本中加入ramfsçš„æ”¯æŒ +* dfs - 修正ramfs中O_APPEND write的问题 +* dfs/elm - 在mkfs中加入device_open/close +* dfs/jffs2 - 修正jffs2_opn/opendir中的f_flagåˆå§‹åŒ–问题 +* dfs/jffs2 - 修正jffs2å¸è½½é—®é¢˜ +* pthread - 修正一处编译警告 +* drivers/pipe - 增加rt_pipe_init/rt_pipe_detach +* drivers/pipe - 增加éžé˜»å¡žè¯»å†™å’Œå¼ºåˆ¶å†™æ¨¡å¼ +* drivers/pipe - 当æ¢å¤è¯»çš„æ—¶å€™è°ƒç”¨å‡½æ•°rx_indicate() +* drivers/pipe - 增加一个设备类型(pipe类型) +* drivers/portal - 实现portal设备类型 +* drivers/ringbuffer - ä¿®æ”¹ä¸€äº›æ¨¡ç³Šä¸æ¸…的函数åç§° +* drivers/ringbuffer - 新增put_forceå’Œputchar_force接å£å‡½æ•° +* finsh - 当set_device时增加设备检查 +* finsh - 在rx_ind中增加对shell设备的自动设置 +* finsh - 增加pipeå’Œportal设备的æè¿° +* finsh - 在å˜é‡å®šä¹‰æ—¶ä½¿ç”¨åˆ«å +* finsh - 当关闭设备时注销rx_indicate +* finsh - 修正命令行太长的问题 +* finsh/msh - åªæœ‰å½“DFS_USING_WORKDIR使能时æ‰å£°æ˜Žcd/pwd +* init - 为新的组件åˆå§‹åŒ–机制更新连接脚本 +* init - 增加组件åˆå§‹åŒ–è°ƒè¯•ä»£ç  +* logtrace - æ•´ç†ä»£ç ï¼ŒåŽ»é™¤ç¼–è¯‘è­¦å‘Š +* logtrace - 增加LOG_TRACE_VERBOSE +* logtrace - 调整log values +* logtrace - åªæœ‰å½“finsh使能的时候æ‰å£°æ˜Žcmd +* libc/minilibc - 在sys/time.h中增加gettimeofday的声明 +* utilities - 新增ymodem + +工具: + +* building.py - 增加clang陿€ç¼éš™å™¨çš„æ”¯æŒ +* building.py - 为Keil MDK增加buildlib功能 +* building.py - 在clang-analyze中执行'clang -Wall -fsyntas-only' +* clang-analyze.py - 增加一个定制工具实现clang陿€åˆ†æž + +分支: + +* 新增BeagleBoneçš„ç§»æ¤ +* 新增SEP6200çš„ç§»æ¤ +* 新增K60Fxxxxçš„ç§»æ¤ +* 修正Linux中的编译错误(lm4f232, stm32f40x, xplorer4330) +* cortex-m3 - 加强hard fault的异常处ç†å‡½æ•° +* at91sam9260 - 更新串å£é©±åŠ¨ï¼Œä½¿ç”¨ç»„ä»¶ä¸­çš„é€šç”¨ä¸²å£é©±åЍ +* at91sam9260 - 更新工程目录结构 +* at91sam9260 - 修正编译错误 +* at91sam9260 - 内嵌GPLv2è®¸å¯ +* stm32f10x - 删除无用的文件 +* stm32f10x - 更新工程目录结构 +* stm32f10x - 更新工程文件 +* stm32f10x - 为使用新的组件åˆå§‹åŒ–更新连接脚本 +* stm32f10x - 为使用新的组件åˆå§‹åŒ–æ›´æ–°SD card驱动 +* stm32f10x - 为使用新的组件åˆå§‹åŒ–æ›´æ–°DM9000驱动 +* stm32f10x - 更新串å£é©±åŠ¨ï¼Œä½¿ç”¨ç»„ä»¶ä¸­çš„é€šç”¨ä¸²å£é©±åЍ +* stm32f10x - 修正rtguiåˆå§‹åŒ–问题 +* simulator - 为使用新的组件åˆå§‹åŒ–更新代ç ï¼Œä»¥ä¾¿æ”¯æŒmingw +* simulator - 支æŒLinux系统 +* simulator - 修正Linux系统中的SDLåˆå§‹åŒ–问题 +* simulator - 在rt_components_init之åŽåˆå§‹åŒ–SDL +* simulator - 将对SDL设置的内容移入drivers/SConstruct +* simulator - 在env中获得CORSS_TOOLå’ŒEXEC_PATH的值 +* simulator - 支æŒclang-analyze +* simulator - 增加tap netif driver + +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- + + +版本: RT-Thread 1.2.0 Beta 版本 + +å‘布时间: 2013/6/30 + +进过开å‘人员三个月的努力,RT-Thread 1.2.0 Beta 版本如期å‘布。 +该版本默认采用lwIP 1.4.1å议栈,USB device stack也进一步完善。加入 log_trace å­ç³»ç»Ÿï¼ŒåŠ å…¥ç»„ä»¶åˆå§‹åŒ–å‡çº§ç‰ˆæœ¬ï¼ŒåŠ å…¥ ARM Cortex-R 的移æ¤ã€‚ + +主è¦å˜åŒ–: + +* 1,新增组件åˆå§‹åŒ–功能 +- 详情请看论å›å¸–å­[新功能] 组件åˆå§‹åŒ– +* 2,支æŒARM Cortex-R系列处ç†å™¨ +- Grissiom å®Œæˆ ARM Cortex-R 的移æ¤ï¼Œç›®å‰BSP中已有TI RM48x50分支(仅支æŒTI CCSå¼€å‘环境) +* 3,文件系统中新增 RAMFS +* 4,加入 log_trace å­ç³»ç»Ÿ +* 5,优化Cortex-M4线程上下文切æ¢ï¼Œä½¿ç”¨äº†æµ®ç‚¹è¿ç®—的线程æ‰ä¿å­˜åŠæ¢å¤FPU寄存器 +- 详情请看论å›å¸–å­[优化]cortex-m4f线程切æ¢ï¼Œä¼˜åŒ–FPU寄存器 +* 6,新增API rt_memheap_realloc() +* 7ï¼Œé‡æ–°å®žçްringbuffer,采用镜åƒçš„æ–¹æ³•区分“满â€å’Œâ€œç©ºâ€ï¼ŒåŒæ—¶æ”¯æŒä»»æ„大å°çš„buffer +* 8,内核中加入RT_KERNEL_MALLOC/RT_KERNEL_FREE/RT_KERNEL_REALLOCå®ã€‚ +如果用户未定义这些å®ï¼Œå°†é»˜è®¤æŒ‡å‘rt_malloc/rt_free/rt_realloc。 +åŒæ—¶å†…核仅局é™äºŽä½¿ç”¨è¿™äº›å®æ¥ä½¿ç”¨åЍæ€å†…å­˜ +* 9,在 building.py ä¸­æ–°å¢žç”Ÿæˆ cscope database 的选项 +* 10,USB组件新增reset函数,支æŒçƒ­æ’æ‹” +* 11,scons编译系统支æŒCCSå¼€å‘环境 +* 12,USB组件新增状æ€ä¿¡æ¯ï¼ˆUSB_STATE_NOTATTACHED,USB_STATE_ATTACHED,USB_STATE_POWERED...) + +ä¿®å¤é—®é¢˜ç‚¹ï¼š + +* 1,USB组件HOSTå¯ä»¥æŒ‚èµ·endpoints +* 2,simulatoråˆ†æ”¯ï¼Œä¿®å¤ serial_write 问题 +* 3,udiskå¯ä»¥è¢«å¼¹å‡º +* 4,iar.py中修å¤ç»å¯¹è·¯å¾„的问题 +* 5,dfs_fs.h内增加dfs_mkfs()函数的申明 +* 6,生æˆMDK工程文件的时候加入library文件 +* 7,当PCä¸å†æŽ¥å—æ•°æ®çš„æ—¶å€™ï¼Œé‡ç½®VCOMç›¸åº”çš„çŠ¶æ€ +* 8,USB组件:返回正确的LangID字符串长度给HOST +* 9,Cortex-M0,Cortex-M3,Cortex-M4ä¸Šä¸‹æ–‡åˆ‡æ¢æ—¶ï¼Œå›žæ”¶ç³»ç»Ÿåˆå§‹åŒ–时用到的栈空间 + +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- + + + +版本: RT-Thread 1.2.0 Alpha版本 + +å‘布时间: 2013/4/10 + +éµå¾ª2013å¹´RT-Thread roadmap,RT-Thread 1.2.0 Alpha版本å‘布,Alphaæ„å‘³ç€æ­¤ç‰ˆæœ¬ä¸ºæŠ€æœ¯é¢„览版,仅用于展示RT-Thread 1.2.0未æ¥çš„å‘展方å‘,并ä¸é€‚åˆäºŽå¼€å‘æ­£å¼äº§å“。RT-Thread 1.2.0版本是1.1.x系列的下一个分支,这个分支主è¦ä½“现的是RT-Thread 1.x系列的文档情况。当然也有一些功能ã€ä»£ç æ–¹é¢çš„增强。 + +ä¼´éšç€æ–°ç‰ˆæœ¬çš„到æ¥ï¼ŒRT-Thread有几个é‡å¤§çš„转å˜ï¼š +1ï¼Œä»£ç æ‰˜ç®¡ä»Žgoogle code(SVN)è¿ç§»åˆ°github(GIT) +2,RT-Thread与RTGUI区分开æ¥ï¼Œå¹¶æˆä¸ºä¸¤ä¸ªç‹¬ç«‹çš„å¼€å‘分支 +3,é‡è§†æ–‡æ¡£ï¼Œå°†æ–‡æ¡£å»ºè®¾ä½œä¸º1.2.0版本的首è¦ä»»åŠ¡æ¥æŠ“ + +内核主è¦å˜åŒ–: +1,加入__rt_ffs函数用于实现32使•´æ•°ä¸­èŽ·å–第一个置1çš„ä½ï¼›åŒæ—¶è°ƒåº¦å™¨ä¸­ä½å›¾ç›¸å…³ç®—法直接使用__rt_ffs函数;CPUç§»æ¤æ—¶ï¼Œå¯å®šä¹‰RT_USING_CPU_FFS,使用芯片指令完æˆã€‚ + +2,新的中断注册机制 +weety加入interrupt description功能,用于为interrupt增加更多的信æ¯ï¼ŒåŒæ—¶ä¸­æ–­æœåŠ¡ä¾‹ç¨‹ä¹Ÿå¯ä»¥æºå¸¦ç”¨æˆ·è‡ªå®šä¹‰çš„傿•°ç±»åž‹ã€‚ +* 这部分对ARM7ã€ARM9ã€MIPS等影å“很大,需è¦å¯¹CPUç§»æ¤åšç›¸åº”的一些修改。 +* 这部分对ARM Cortex-M系列芯片没有影å“。 + +3,调整定时器æ’å…¥ä½ç½®ï¼Œä¸ºç›¸åŒè¶…时定时的åŽé¢ã€‚ + +组件主è¦å˜åŒ–: +1,添加lwIP 1.4.1。 +2,在finsh shell中加入module shell功能。finsh shell本身是一个C语言表达å¼çš„shell命令行,而module shellæ›´ç±»ä¼¼äºŽä¸€ä¸ªä¼ ç»Ÿçš„å‘½ä»¤è¡Œï¼Œç”±å‘½ä»¤ï¼Œå‚æ•°ç­‰æ–¹å¼æž„æˆã€‚ + +分支主è¦å˜åŒ–: +1,完善simulator分支,支æŒRTGUI,支æŒåº”用模å—。 +2,完善at91sam9260分支的移æ¤åŠé©±åŠ¨æ›´æ–°ã€‚ + +编译系统主è¦å˜åŒ–: +1,开å¯çœç•¥ç¼–è¯‘æ—¶é•¿å‘½ä»¤ç‰¹æ€§ï¼Œå¦‚æžœéœ€è¦æŸ¥çœ‹ç¼–译时命令行,å¯ä»¥ä½¿ç”¨scons --verbose查看。 +2,加入生æˆCodeBlocks工程特性。 +3,修正当系统安装使用Keil MDK 4.6+版本的问题。 + +githubä¸»è¦æäº¤å±¥åŽ†: +5646189b29: elm fatfs支æŒmkfs,并且无需æå‰æ‰§è¡Œdfs_mount; mount/umount/mkfsæ“作也ä¸ä¼šå¼•èµ·reset +22786f8817: å…许用户自定义PIDå’ŒVID +0001344105: 更明确的定时器è¿è¡Œæœºåˆ¶ï¼Œå¦‚果两个定时器在åŒä¸€ä¸ªæ—¶åˆ»å‘ç”Ÿè¶…æ—¶ï¼Œé‚£ä¹ˆå…ˆå¼€å§‹çš„å®šæ—¶å™¨å…ˆå¤„ç† +5d68ef8ec1: 修正使用64ä½GCC时编译finsh过程中å‘生错误的问题 +a4d661dcf1: 修正dfs_elm.c中一处内存泄露,并且在mount fatfs失败时执行 umount fatfsæ“作 +43228aeb9c: 修正list_tcps问题:ipaddr_ntoa䏿˜¯å¯é‡å…¥çš„函数。 +3de4b92a68: 修正AT91SAM9260分支中PHY link状æ€é”™è¯¯çš„问题。 +1abaa0492d diff --git a/rt-thread/Kconfig b/rt-thread/Kconfig new file mode 100644 index 0000000..b32f7da --- /dev/null +++ b/rt-thread/Kconfig @@ -0,0 +1,3 @@ +source "$RTT_DIR/src/Kconfig" +source "$RTT_DIR/libcpu/Kconfig" +source "$RTT_DIR/components/Kconfig" diff --git a/rt-thread/LICENSE b/rt-thread/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/rt-thread/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/rt-thread/README.md b/rt-thread/README.md new file mode 100644 index 0000000..c835908 --- /dev/null +++ b/rt-thread/README.md @@ -0,0 +1,88 @@ +# RT-Thread # + +[中文页](README_zh.md) | + +[![GitHub](https://img.shields.io/github/license/RT-Thread/rt-thread.svg)](https://github.com/RT-Thread/rt-thread/blob/master/LICENSE) +[![GitHub release](https://img.shields.io/github/release/RT-Thread/rt-thread.svg)](https://github.com/RT-Thread/rt-thread/releases) +[![Build Status](https://travis-ci.org/RT-Thread/rt-thread.svg)](https://travis-ci.org/RT-Thread/rt-thread) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/RT-Thread/rt-thread?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![GitHub pull-requests](https://img.shields.io/github/issues-pr/RT-Thread/rt-thread.svg)](https://github.com/RT-Thread/rt-thread/pulls) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](https://github.com/RT-Thread/rt-thread/pulls) + +RT-Thread is an open source IoT operating system from China, which has strong scalability: from a tiny kernel running on a tiny core, for example ARM Cortex-M0, or Cortex-M3/4/7, to a rich feature system running on MIPS32, ARM Cortex-A8, ARM Cortex-A9 DualCore etc. + +## Overview ## + +RT-Thread RTOS like a traditional real-time operating system. The kernel has real-time multi-task scheduling, semaphore, mutex, mail box, message queue, signal etc. However, it has three different things: + +* Device Driver; +* Component; +* Dyanmic Module + +The device driver is more like a driver framework, UART, IIC, SPI, SDIO, USB device/host, EMAC, MTD NAND etc. The developer can easily add low level driver and board configuration, then combined with the upper framework, he/she can use lots of features. + +The Component is a software concept upon RT-Thread kernel, for example a shell (finsh/msh shell), virtual file system (FAT, YAFFS, UFFS, ROM/RAM file system etc), TCP/IP protocol stack (lwIP), POSIX (thread) interface etc. One component must be a directory under RT-Thread/Components and one component can be descripted by a SConscript file (then be compiled and linked into the system). + +The Dyanmic Module, formerly named as User Applicaion (UA) is a dyanmic loaded module or library, it can be compiled standalone without Kernel. Each Dyanmic Module has its own object list to manage thread/semaphore/kernel object which was created or initialized inside this UA. More information about UA, please visit another [git repo](https://github.com/RT-Thread/rtthread-apps). + +## Board Support Package ## + +RT-Thread RTOS can support many architectures: + +* ARM Cortex-M0 +* ARM Cortex-M3/M4/7 +* ARM Cortex-R4 +* ARM Cortex-A8/A9 +* ARM920T/ARM926 etc +* MIPS32 +* x86 +* Andes +* C-Sky +* RISC-V +* PowerPC + +## License ## + +RT-Thread is Open Source software under the Apache License 2.0 since RT-Thread v3.1.1. License and copyright information can be found within the code. + + /* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +Since 9th of September 2018, PRs submitted by the community may be merged into the main line only after signing the Contributor License Agreement(CLA). + +NOTE: + +RT-Thread using the Apache license v2.0 is only launched after the release of v3.1.1, and is still in preparation right now. + +## Usage ## + +RT-Thread RTOS uses [scons](http://www.scons.org) as building system. Therefore, please install scons and Python 2.7 firstly. +So far, the RT-Thread scons building system support the command line compile or generate some IDE's project. There are some option varaibles in the scons building script (rtconfig.py): + +* ```CROSS_TOOL``` the compiler which you want to use, gcc/keil/iar. +* ```EXEC_PATH``` the path of compiler. + +In SConstruct file: + +```RTT_ROOT``` This variable is the root directory of RT-Thread RTOS. If you build the porting in the bsp directory, you can use the default setting. Also, you can set the root directory in ```RTT_ROOT``` environment variable and not modify SConstruct files. + +When you set these variables correctly, you can use command: + + scons + +under BSP directory to simplely compile RT-Thread RTOS. + +If you want to generate the IDE's project file, you can use command: + + scons --target=mdk/mdk4/mdk5/iar/cb -s + +to generate the project file. + +NOTE: RT-Thread scons building system will tailor the system according to your rtconfig.h configuration header file. For example, if you disable the lwIP in the rtconfig.h by commenting the ```#define RT_USING_LWIP```, the generated project file should have no lwIP related files. + +## Contribution ## + +Please refer the contributors in the github. Thank all of RT-Thread Developers. diff --git a/rt-thread/README_zh.md b/rt-thread/README_zh.md new file mode 100644 index 0000000..56fe096 --- /dev/null +++ b/rt-thread/README_zh.md @@ -0,0 +1,97 @@ +# RT-Thread # + +[![GitHub release](https://img.shields.io/github/release/RT-Thread/rt-thread.svg)](https://github.com/RT-Thread/rt-thread/releases) +[![Build Status](https://travis-ci.org/RT-Thread/rt-thread.svg)](https://travis-ci.org/RT-Thread/rt-thread) +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/RT-Thread/rt-thread?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![GitHub pull-requests](https://img.shields.io/github/issues-pr/RT-Thread/rt-thread.svg)](https://github.com/RT-Thread/rt-thread/pulls) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](https://github.com/RT-Thread/rt-thread/pulls) + +RT-Thread是一个æ¥è‡ªä¸­å›½çš„å¼€æºç‰©è”网æ“作系统,它æä¾›äº†éžå¸¸å¼ºçš„å¯ä¼¸ç¼©èƒ½åŠ›ï¼šä»Žä¸€ä¸ªå¯ä»¥è¿è¡Œåœ¨ARM Cortex-M0芯片上的æžå°å†…核,到中等的ARM Cortex-M3/4/7系统,甚至是è¿è¡ŒäºŽMIPS32ã€ARM Cortex-A系列处ç†å™¨ä¸ŠåŠŸèƒ½ä¸°å¯Œç³»ç»Ÿã€‚ + +## 简介 ## + +RT-Thread包å«äº†ä¸€ä¸ªè‡ªæœ‰çš„ã€ä¼ ç»Ÿçš„ç¡¬å®žæ—¶å†…æ ¸ï¼šå¯æŠ¢å çš„多任务实时调度器,信å·é‡ï¼Œäº’æ–¥é‡ï¼Œé‚®ç®±ï¼Œæ¶ˆæ¯é˜Ÿåˆ—,信å·ç­‰ã€‚当然,它和传统的实时æ“作系统还存在ç€ä¸‰ç§ä¸åŒï¼š + +* 设备驱动框架; +* 软件组件; +* åº”ç”¨æ¨¡å— + +设备驱动框架更类似一套驱动框架,涉åŠåˆ°UART,IIC,SPI,SDIO,USB从设备/主设备,EMAC,NAND闪存设备等。它会把这些设备驱动中的共性抽象/抽å–出æ¥ï¼Œè€Œé©±åŠ¨å·¥ç¨‹å¸ˆåªéœ€è¦æŒ‰ç…§å›ºå®šçš„æ¨¡å¼å®žçް少é‡çš„底层硬件æ“ä½œåŠæ¿çº§é…置。通过这样的方å¼ï¼Œè®©ä¸€ä¸ªç¡¬ä»¶å¤–设更容易地对接到RT-Thread系统中,并获得RT-Threadå¹³å°ä¸Šçš„完整软件栈功能。 + +软件组件是ä½äºŽRT-Thread内核上的软件å•元,例如命令行(finsh/msh shell),虚拟文件系统(FAT,YAFFS,UFFS,ROM/RAM文件系统等),TCP/IP网络å议栈(lwIP),Libc/POSIX标准层等。一般的,一个软件组件放置于一个目录下,例如RT-Thread/components目录下的文件夹,并且æ¯ä¸ªè½¯ä»¶ç»„件通过一个 SConscriptæ–‡ä»¶æ¥æè¿°å¹¶è¢«æ·»åŠ åˆ°RT-Thread的构建系统中。当系统é…置中开å¯äº†è¿™ä¸€è½¯ä»¶ç»„件时,这个组件将被编译并链接到最终的RT-Thread固件中。 + +注:éšç€RT-Thread 3.0中的包管ç†å™¨å¼€å¯ï¼Œè¶Šæ¥è¶Šå¤šçš„软件组件将以packageæ–¹å¼å‡ºçŽ°åœ¨RT-Threadå¹³å°ä¸­ã€‚而RT-Thread平尿›´å¤šçš„æ˜¯æŒ‡ï¼š + +* RT-Thread内核; +* shell命令行; +* 虚拟文件系统; +* TCP/IP网络å议栈; +* 设备驱动框架; +* Libc/POSIX标准层。 + +更多的IoT软件包则以packageæ–¹å¼è¢«æ·»åŠ åˆ°RT-Thread系统中。 + +应用模å—,或者说用户应用(User Application,UA)是一个å¯åЍæ€åŠ è½½çš„æ¨¡å—:它å¯ä»¥ç‹¬ç«‹äºŽRT-Thread固件而å•独编译。一般的,æ¯ä¸ªUA都包å«ä¸€ä¸ªmain函数入å£ï¼›ä¸€ä¸ªå®ƒè‡ªå·±çš„对象链表,用于管ç†è¿™ä¸ªåº”用的任务/ä¿¡å·é‡/消æ¯é˜Ÿåˆ—等内核对象,创建ã€åˆå§‹åŒ–ã€é”€æ¯ç­‰ã€‚更多关于UA的信æ¯ï¼Œè¯·è®¿é—®å¦å¤–一个 [git 仓库](https://github.com/RT-Thread/rtthread-apps) 了解。 + +## 支æŒçš„芯片架构 ## + +RT-Threadæ”¯æŒæ•°ç§èŠ¯ç‰‡ä½“ç³»æž¶æž„ï¼Œå·²ç»è¦†ç›–当å‰åº”用中的主æµä½“系架构: + +* ARM Cortex-M0 +* ARM Cortex-M3/M4/7 +* ARM Cortex-R4 +* ARM Cortex-A8/A9 +* ARM920T/ARM926 etc +* MIPS32 +* x86 +* Andes +* C-Sky +* RISC-V +* PowerPC + +## 许å¯è¯ ## + +RT-Thread从v3.1.1版本开始,是一个以Apache许å¯è¯2.0版本授æƒçš„å¼€æºè½¯ä»¶ï¼Œè®¸å¯è¯ä¿¡æ¯ä»¥åŠç‰ˆæƒä¿¡æ¯ä¸€èˆ¬çš„å¯ä»¥åœ¨ä»£ç é¦–部看到: + + /* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +从2018/09/09开始,开å‘者æäº¤PR需è¦ç­¾ç½²è´¡çŒ®è€…许å¯å议(CLA)。 + +注æ„: + +以Apache许å¯åè®®v2.0版本授æƒä»…在RT-Thread v3.1.1æ­£å¼ç‰ˆå‘å¸ƒä¹‹åŽæ‰æ­£å¼å®žæ–½ï¼Œå½“å‰ä¾ç„¶åœ¨å‡†å¤‡é˜¶æ®µï¼ˆå‡†å¤‡æ‰€æœ‰åŽŸæœ‰å¼€å‘者签署CLAå议)。 + +## 编译 ## + +RT-Thread使用了[scons](http://www.scons.org)åšä¸ºè‡ªèº«çš„编译构建系统,并进行一定的定制以满足自身的需求(å¯ä»¥é€šè¿‡scons --help查看RT-Thread中é¢å¤–添加的命令)。在编译RT-Threadå‰ï¼Œè¯·å…ˆå®‰è£…Python 2.7.xåŠscons。 + +截至目å‰ï¼ŒRT-Thread scons构建系统å¯ä»¥ä½¿ç”¨å‘½ä»¤è¡Œæ–¹å¼ç¼–译代ç ï¼Œæˆ–者使用sconsæ¥ç”Ÿæˆä¸åŒIDE的工程文件。在使用scons时,需è¦å¯¹æž„建é…置文件(rtconfig.py)中如下的å˜é‡è¿›è¡Œé…置: + +* ```CROSS_TOOL``` 指定希望使用的工具链,例如gcc/keil/iar. +* ```EXEC_PATH``` 工具链的路径. + +注:在SConstruct文件中: + +```RTT_ROOT``` 这个å˜é‡æŒ‡å‘了RT-Threadçš„å‘布æºä»£ç æ ¹ç›®å½•。如果你仅计划编译bsp目录下的target,这个`RTT_ROOT`å¯ä»¥ä½¿ç”¨é»˜è®¤é…置。å¦å¤–,你也å¯ä»¥è®¾ç½®åŒå的环境å˜é‡æ¥æŒ‡å‘ä¸åŒçš„RT-Threadæºä»£ç æ ¹ç›®å½•。 + +当你把相关的é…置都é…置正确åŽï¼Œä½ å¯ä»¥åœ¨å…·æœ‰ç›®æ ‡ç›®å½•下(这个目录应包括rtconfig.pyã€SContruct文件)执行以下命令: + + scons + +从而简å•地就编译好RT-Thread。 + +如果你希望使用IDEæ¥ç¼–译RT-Thread,你也å¯ä»¥ä½¿ç”¨å‘½ä»¤è¡Œï¼š + + scons --target=mdk/mdk4/mdk5/iar/cb -s + +æ¥ç”Ÿæˆmdk/iar等的工程文件。而åŽåœ¨IDE中打开projectå‰ç¼€çš„工程文件æ¥ç¼–译RT-Thread。 + +注æ„:RT-Threadçš„scons构建系统会根æ®é…置头文件rtconfig.hæ¥è£å‰ªç³»ç»Ÿã€‚例如,如果你关闭了rtconfig.h中的lwIP定义(通过注释掉```#define RT_USING_LWIP```的方å¼ï¼‰ï¼Œåˆ™scons生æˆçš„IDE工程文件中将自动ä¸åŒ…括lwIP相关的文件。而在RT-Thread 3.0版本中,å¯ä»¥é€šè¿‡menuconfigçš„æ–¹å¼æ¥é…置整个系统,而ä¸éœ€è¦å†æ‰‹å·¥æ›´æ”¹rtconfig.hé…置头文件。 + +## 贡献者 ## + +请访问github上RT-Thread项目上的contributors了解已ç»ä¸ºRT-Threadæäº¤è¿‡ä»£ç ï¼ŒPR的贡献者。感谢所有为RT-Thread付出的开å‘è€…ä»¬ï¼ diff --git a/rt-thread/components/Kconfig b/rt-thread/components/Kconfig new file mode 100644 index 0000000..227f6ef --- /dev/null +++ b/rt-thread/components/Kconfig @@ -0,0 +1,28 @@ +menu "RT-Thread Components" + +config RT_USING_COMPONENTS_INIT + bool "Use components automatically initialization" + default y + +if RT_USING_COMPONENTS_INIT + config RT_USING_USER_MAIN + bool "The main() function as user entry function" + default y + + if RT_USING_USER_MAIN + config RT_MAIN_THREAD_STACK_SIZE + int "Set main thread stack size" + default 2048 + config RT_MAIN_THREAD_PRIORITY + int "Set main thread priority" + default 4 if RT_THREAD_PRIORITY_8 + default 10 if RT_THREAD_PRIORITY_32 + default 85 if RT_THREAD_PRIORITY_256 + endif +endif + +source "$RTT_DIR/components/finsh/Kconfig" +source "$RTT_DIR/components/drivers/Kconfig" +source "$RTT_DIR/components/libc/Kconfig" + +endmenu diff --git a/rt-thread/components/SConscript b/rt-thread/components/SConscript new file mode 100644 index 0000000..82efd7b --- /dev/null +++ b/rt-thread/components/SConscript @@ -0,0 +1,17 @@ +# for module compiling +import os +Import('remove_components') +from building import * + +objs = [] +cwd = GetCurrentDir() +list = os.listdir(cwd) + +for item in list: + if item in remove_components: + continue + + if os.path.isfile(os.path.join(cwd, item, 'SConscript')): + objs = objs + SConscript(os.path.join(item, 'SConscript')) + +Return('objs') diff --git a/rt-thread/components/drivers/Kconfig b/rt-thread/components/drivers/Kconfig new file mode 100644 index 0000000..f70ed49 --- /dev/null +++ b/rt-thread/components/drivers/Kconfig @@ -0,0 +1,438 @@ +menu "Device Drivers" + +config RT_USING_DEVICE_IPC + bool "Using device drivers IPC" + default y + +if RT_USING_DEVICE_IPC + config RT_PIPE_BUFSZ + int "Set pipe buffer size" + default 512 +endif + +config RT_USING_SERIAL + bool "Using serial device drivers" + select RT_USING_DEVICE_IPC + select RT_USING_DEVICE + default y + +config RT_USING_CAN + bool "Using CAN device drivers" + default n + +if RT_USING_CAN + config RT_CAN_USING_HDR + bool "Enable CAN hardware filter" + default y +endif + +config RT_USING_HWTIMER + bool "Using hardware timer device drivers" + default n + +config RT_USING_CPUTIME + bool "Enable CPU time for high resolution clock counter" + default n + help + When enable this option, the BSP should provide a rt_clock_cputime_ops + for CPU time by: + const static struct rt_clock_cputime_ops _ops = {...}; + clock_cpu_setops(&_ops); + + Then user can use high resolution clock counter with: + + ts1 = clock_cpu_gettime(); + ts2 = clock_cpu_gettime(); + + /* and get the ms of delta tick with API: */ + ms_tick = clock_cpu_millisecond(t2 - t1); + us_tick = clock_cpu_microsecond(t2 - t1); + +if RT_USING_CPUTIME + config RT_USING_CPUTIME_CORTEXM + bool "Use DWT for CPU time" + default y + depends on ARCH_ARM_CORTEX_M3 || ARCH_ARM_CORTEX_M4 || ARCH_ARM_CORTEX_M7 + help + Some Cortex-M3/4/7 MCU has Data Watchpoint and Trace Register, use + the cycle counter in DWT for CPU time. +endif + +config RT_USING_I2C + bool "Using I2C device drivers" + default n + +if RT_USING_I2C + config RT_USING_I2C_BITOPS + bool "Use GPIO to simulate I2C" + default y +endif + +config RT_USING_PIN + bool "Using generic GPIO device drivers" + default y + +config RT_USING_PWM + bool "Using PWM device drivers" + default n + +config RT_USING_MTD_NOR + bool "Using MTD Nor Flash device drivers" + default n + +config RT_USING_MTD_NAND + bool "Using MTD Nand Flash device drivers" + default n + + if RT_USING_MTD_NAND + config RT_MTD_NAND_DEBUG + bool "Enable MTD Nand operations debug information" + default n + endif + +config RT_USING_MTD + bool "Using Memory Technology Device (MTD)" + default n + + if RT_USING_MTD + config MTD_USING_NOR + bool "Using MTD Nor Flash device" + default n + + config MTD_USING_NAND + bool "Using MTD Nand Flash device" + default n + endif + +config RT_USING_RTC + bool "Using RTC device drivers" + default n + + if RT_USING_RTC + config RT_USING_SOFT_RTC + bool "Using software simulation RTC device" + default n + config RTC_SYNC_USING_NTP + bool "Using NTP auto sync RTC time" + select PKG_USING_NETUTILS + select PKG_NETUTILS_NTP + default n + + if RTC_SYNC_USING_NTP + config RTC_NTP_FIRST_SYNC_DELAY + int "NTP first sync delay time(second) for network connect" + default 30 + config RTC_NTP_SYNC_PERIOD + int "NTP auto sync period(second)" + default 3600 + endif + endif + +config RT_USING_SDIO + bool "Using SD/MMC device drivers" + default n + + if RT_USING_SDIO + config RT_SDIO_STACK_SIZE + int "The stack size for sdio irq thread" + default 512 + + config RT_SDIO_THREAD_PRIORITY + int "The priority level value of sdio irq thread" + default 15 + + config RT_MMCSD_STACK_SIZE + int "The stack size for mmcsd thread" + default 1024 + + config RT_MMCSD_THREAD_PREORITY + int "The priority level value of mmcsd thread" + default 22 + + config RT_MMCSD_MAX_PARTITION + int "mmcsd max partition" + default 16 + config RT_SDIO_DEBUG + bool "Enable SDIO debug log output" + default n + endif + +config RT_USING_SPI + bool "Using SPI Bus/Device device drivers" + default n + + if RT_USING_SPI + config RT_USING_SPI_MSD + bool "Using SD/TF card driver with spi" + select RT_USING_DFS + default n + + config RT_USING_SFUD + bool "Using Serial Flash Universal Driver" + default n + if RT_USING_SFUD + config RT_SFUD_USING_SFDP + bool "Using auto probe flash JEDEC SFDP parameter" + default y + + config RT_SFUD_USING_FLASH_INFO_TABLE + bool "Using defined supported flash chip information table" + default y + + config RT_DEBUG_SFUD + bool "Show more SFUD debug information" + default n + endif + + config RT_USING_W25QXX + bool "Using W25QXX SPI NorFlash" + default n + + config RT_USING_GD + bool "Using GD SPI NorFlash" + default n + + config RT_USING_ENC28J60 + bool "Using ENC28J60 SPI Ethernet network interface" + select RT_USING_LWIP + default n + + config RT_USING_SPI_WIFI + bool "Using RW009/007 SPI Wi-Fi wireless interface" + select RT_USING_LWIP + default n + endif + +config RT_USING_WDT + bool "Using Watch Dog device drivers" + default n + +config RT_USING_AUDIO + bool "Using Audio device drivers" + default n + +menu "Using WiFi" + config RT_USING_WIFI + bool "Using Wi-Fi framework" + default n + + if RT_USING_WIFI + config RT_WLAN_DEVICE_STA_NAME + string "The WiFi device name for station" + default "wlan0" + + config RT_WLAN_DEVICE_AP_NAME + string "The WiFi device name for ap" + default "wlan1" + + config RT_WLAN_DEFAULT_PROT + string "Default transport protocol" + default "lwip" + + config RT_WLAN_SCAN_WAIT_MS + int "Set scan timeout time(ms)" + default 10000 + + config RT_WLAN_CONNECT_WAIT_MS + int "Set connect timeout time(ms)" + default 10000 + + config RT_WLAN_SSID_MAX_LENGTH + int "SSID name maximum length" + default 32 + + config RT_WLAN_PASSWORD_MAX_LENGTH + int "Maximum password length" + default 32 + + config RT_WLAN_SCAN_SORT + bool "Automatic sorting of scan results" + default y + + config RT_WLAN_CFG_INFO_MAX + int "Maximum number of WiFi information automatically saved" + default 3 + + config RT_WLAN_WORKQUEUE_THREAD_NAME + string "WiFi work queue thread name" + default "wlan_job" + + config RT_WLAN_WORKQUEUE_THREAD_SIZE + int "wifi work queue thread size" + default 2048 + + config RT_WLAN_WORKQUEUE_THREAD_PRIO + int "WiFi work queue thread priority" + default 22 + + config RT_WLAN_DEV_EVENT_NUM + int "Maximum number of driver events" + default 2 + + config RT_WLAN_PROT_LWIP_PBUF_FORCE + bool "Forced use of PBUF transmission" + default n + + menuconfig RT_WLAN_DEBUG + bool "Enable WLAN Debugging Options" + default n + + if RT_WLAN_DEBUG + config RT_WLAN_CMD_DEBUG + bool "Enable Debugging of wlan_cmd.c" + default n + + config RT_WLAN_MGNT_DEBUG + bool "Enable Debugging of wlan_mgnt.c" + default n + + config RT_WLAN_DEV_DEBUG + bool "Enable Debugging of wlan_dev.c" + default n + + config RT_WLAN_PROT_DEBUG + bool "Enable Debugging of wlan_prot.c" + default n + + config RT_WLAN_CFG_DEBUG + bool "Enable Debugging of wlan_cfg.c" + default n + + config RT_WLAN_LWIP_DEBUG + bool "Enable Debugging of wlan_lwip.c" + default n + endif + endif +endmenu + +menu "Using USB" + config RT_USING_USB_HOST + bool "Using USB host" + default n + + if RT_USING_USB_HOST + config RT_USBH_MSTORAGE + bool "Enable Udisk Drivers" + default n + if RT_USBH_MSTORAGE + config UDISK_MOUNTPOINT + string "Udisk mount dir" + default "/" + endif + endif + config RT_USING_USB_DEVICE + bool "Using USB device" + default n + if RT_USING_USB_DEVICE || RT_USING_USB_HOST + config RT_USBD_THREAD_STACK_SZ + int "usb thread stack size" + default 4096 + endif + if RT_USING_USB_DEVICE + config USB_VENDOR_ID + hex "USB Vendor ID" + default 0x0FFE + config USB_PRODUCT_ID + hex "USB Product ID" + default 0x0001 + + config RT_USB_DEVICE_COMPOSITE + bool "Enable composite device" + default n + choice + prompt "Device type" + default _RT_USB_DEVICE_NONE + depends on !RT_USB_DEVICE_COMPOSITE + config _RT_USB_DEVICE_NONE + bool "Using custom class by register interface" + select RT_USB_DEVICE_NONE + config _RT_USB_DEVICE_CDC + bool "Enable to use device as CDC device" + select RT_USB_DEVICE_CDC + config _RT_USB_DEVICE_MSTORAGE + bool "Enable to use device as Mass Storage device" + select RT_USB_DEVICE_MSTORAGE + config _RT_USB_DEVICE_HID + bool "Enable to use device as HID device" + select RT_USB_DEVICE_HID + config _RT_USB_DEVICE_RNDIS + bool "Enable to use device as rndis device" + select RT_USB_DEVICE_RNDIS + depends on RT_USING_LWIP + config _RT_USB_DEVICE_ECM + bool "Enable to use device as ecm device" + select RT_USB_DEVICE_ECM + depends on RT_USING_LWIP + config _RT_USB_DEVICE_WINUSB + bool "Enable to use device as winusb device" + select RT_USB_DEVICE_WINUSB + endchoice + if RT_USB_DEVICE_COMPOSITE + config RT_USB_DEVICE_CDC + bool "Enable to use device as CDC device" + default n + config RT_USB_DEVICE_NONE + bool + default y + config RT_USB_DEVICE_MSTORAGE + bool "Enable to use device as Mass Storage device" + default n + config RT_USB_DEVICE_HID + bool "Enable to use device as HID device" + default n + config RT_USB_DEVICE_RNDIS + bool "Enable to use device as rndis device" + default n + depends on RT_USING_LWIP + config RT_USB_DEVICE_ECM + bool "Enable to use device as ecm device" + default n + depends on RT_USING_LWIP + config RT_USB_DEVICE_WINUSB + bool "Enable to use device as winusb device" + default n + endif + if RT_USB_DEVICE_WINUSB + config RT_WINUSB_GUID + string "Guid for winusb" + default "{6860DC3C-C05F-4807-8807-1CA861CC1D66}" + endif + if RT_USB_DEVICE_MSTORAGE + config RT_USB_MSTORAGE_DISK_NAME + string "msc class disk name" + default "flash0" + endif + if RT_USB_DEVICE_HID + config RT_USB_DEVICE_HID_KEYBOARD + bool "Use to HID device as Keyboard" + default n + if RT_USB_DEVICE_HID_KEYBOARD + config RT_USB_DEVICE_HID_KEYBOARD_NUMBER + int "Number of Keyboard(max 3)" + default 1 + range 1 3 + endif + config RT_USB_DEVICE_HID_MOUSE + bool "Use to HID device as Mouse" + default n + config RT_USB_DEVICE_HID_GENERAL + bool "Use to HID device as General HID device" + default y + if RT_USB_DEVICE_HID_GENERAL + config RT_USB_DEVICE_HID_GENERAL_OUT_REPORT_LENGTH + int "General HID device out report length" + default 63 + range 0 63 + + config RT_USB_DEVICE_HID_GENERAL_IN_REPORT_LENGTH + int "General HID device in report length" + default 63 + range 0 63 + endif + config RT_USB_DEVICE_HID_MEDIA + bool "Use to HID device as media keyboard" + default y + endif + endif + endmenu +endmenu diff --git a/rt-thread/components/drivers/SConscript b/rt-thread/components/drivers/SConscript new file mode 100644 index 0000000..744d8d7 --- /dev/null +++ b/rt-thread/components/drivers/SConscript @@ -0,0 +1,14 @@ +# for module compiling +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/rt-thread/components/drivers/include/drivers/alarm.h b/rt-thread/components/drivers/include/drivers/alarm.h new file mode 100644 index 0000000..99dd8ef --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/alarm.h @@ -0,0 +1,86 @@ +/* + * File : alarm.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-10-27 heyuanjie87 first version. + */ + +#ifndef __ALARM_H__ +#define __ALARM_H__ + +#include + +#define RT_ALARM_TM_NOW -1 /* set the alarm tm_day,tm_mon,tm_sec,etc. + to now.we also call it "don't care" value */ + +/* alarm flags */ +#define RT_ALARM_ONESHOT 0x000 /* only alarm onece */ +#define RT_ALARM_DAILY 0x100 /* alarm everyday */ +#define RT_ALARM_WEEKLY 0x200 /* alarm weekly at Monday or Friday etc. */ +#define RT_ALARM_MONTHLY 0x400 /* alarm monthly at someday */ +#define RT_ALARM_YAERLY 0x800 /* alarm yearly at a certain date */ + +/* alarm control cmd */ +#define RT_ALARM_CTRL_MODIFY 1 /* modify alarm time or alarm flag */ + +typedef struct rt_alarm *rt_alarm_t; +typedef void (*rt_alarm_callback_t)(rt_alarm_t alarm, time_t timestamp); + +/* used for low level RTC driver */ +struct rt_rtc_wkalarm +{ + rt_bool_t enable; /* 0 = alarm disabled, 1 = alarm enabled */ + rt_int32_t tm_sec; /* alarm at tm_sec */ + rt_int32_t tm_min; /* alarm at tm_min */ + rt_int32_t tm_hour; /* alarm at tm_hour */ +}; + +struct rt_alarm +{ + rt_list_t list; + rt_uint32_t flag; + rt_alarm_callback_t callback; + struct tm wktime; +}; + +struct rt_alarm_setup +{ + rt_uint32_t flag; /* alarm flag */ + struct tm wktime; /* when will the alarm wake up user */ +}; + +struct rt_alarm_container +{ + rt_list_t head; + struct rt_mutex mutex; + struct rt_event event; + struct rt_alarm *current; +}; + +rt_alarm_t rt_alarm_create(rt_alarm_callback_t callback, + struct rt_alarm_setup *setup); +rt_err_t rt_alarm_control(rt_alarm_t alarm, int cmd, void *arg); +void rt_alarm_update(rt_device_t dev, rt_uint32_t event); +rt_err_t rt_alarm_delete(rt_alarm_t alarm); +rt_err_t rt_alarm_start(rt_alarm_t alarm); +rt_err_t rt_alarm_stop(rt_alarm_t alarm); +void rt_alarm_system_init(void); + +#endif /* __ALARM_H__ */ diff --git a/rt-thread/components/drivers/include/drivers/audio.h b/rt-thread/components/drivers/include/drivers/audio.h new file mode 100644 index 0000000..04821c2 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/audio.h @@ -0,0 +1,230 @@ +/* + * File : audio.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-05-09 Urey first version + */ + +#ifndef __AUDIO_H__ +#define __AUDIO_H__ + +/* AUDIO command */ +#define _AUDIO_CTL(a) (0x10 + a) + +#define AUDIO_CTL_GETCAPS _AUDIO_CTL(1) +#define AUDIO_CTL_CONFIGURE _AUDIO_CTL(2) +#define AUDIO_CTL_SHUTDOWN _AUDIO_CTL(3) +#define AUDIO_CTL_START _AUDIO_CTL(4) +#define AUDIO_CTL_STOP _AUDIO_CTL(5) +#define AUDIO_CTL_PAUSE _AUDIO_CTL(6) +#define AUDIO_CTL_RESUME _AUDIO_CTL(7) +#define AUDIO_CTL_GETBUFFERINFO _AUDIO_CTL(8) +#define AUDIO_CTL_ALLOCBUFFER _AUDIO_CTL(9) +#define AUDIO_CTL_FREEBUFFER _AUDIO_CTL(10) +#define AUDIO_CTL_HWRESET _AUDIO_CTL(11) + + +/* Audio Device Types */ +#define AUDIO_TYPE_QUERY 0x00 +#define AUDIO_TYPE_INPUT 0x01 +#define AUDIO_TYPE_OUTPUT 0x02 +#define AUDIO_TYPE_MIXER 0x04 +#define AUDIO_TYPE_SELECTOR 0x08 +#define AUDIO_TYPE_EFFECT 0x10 + +/* Audio Format Types */ +#define AUDIO_FMT_PCM_U8 0x0001 +#define AUDIO_FMT_PCM_S8 0x0002 + +#define AUDIO_FMT_PCM_U16_LE 0x0010 +#define AUDIO_FMT_PCM_S16_BE 0x0020 +#define AUDIO_FMT_PCM_S16_LE 0x0040 +#define AUDIO_FMT_PCM_U16_BE 0x0080 +#define AUDIO_FMT_PCM_U24_LE 0x0100 +#define AUDIO_FMT_PCM_S24_BE 0x0200 +#define AUDIO_FMT_PCM_S24_LE 0x0400 +#define AUDIO_FMT_PCM_U24_BE 0x0800 +#define AUDIO_FMT_PCM_U32_LE 0x1000 +#define AUDIO_FMT_PCM_S32_BE 0x2000 +#define AUDIO_FMT_PCM_S32_LE 0x4000 +#define AUDIO_FMT_PCM_U32_BE 0x8000 + +/* Supported Sampling Rates */ +#define AUDIO_SAMP_RATE_8K 0x0001 +#define AUDIO_SAMP_RATE_11K 0x0002 +#define AUDIO_SAMP_RATE_16K 0x0004 +#define AUDIO_SAMP_RATE_22K 0x0008 +#define AUDIO_SAMP_RATE_32K 0x0010 +#define AUDIO_SAMP_RATE_44K 0x0020 +#define AUDIO_SAMP_RATE_48K 0x0040 +#define AUDIO_SAMP_RATE_96K 0x0080 +#define AUDIO_SAMP_RATE_128K 0x0100 +#define AUDIO_SAMP_RATE_160K 0x0200 +#define AUDIO_SAMP_RATE_172K 0x0400 +#define AUDIO_SAMP_RATE_192K 0x0800 + +/* Supported Bit Rates */ +#define AUDIO_BIT_RATE_22K 0x01 +#define AUDIO_BIT_RATE_44K 0x02 +#define AUDIO_BIT_RATE_48K 0x04 +#define AUDIO_BIT_RATE_96K 0x08 +#define AUDIO_BIT_RATE_128K 0x10 +#define AUDIO_BIT_RATE_160K 0x20 +#define AUDIO_BIT_RATE_172K 0x40 +#define AUDIO_BIT_RATE_192K 0x80 + + + +/* Support Dsp(input/output) Units controls */ +#define AUDIO_DSP_PARAM 0 /* get/set all params */ +#define AUDIO_DSP_SAMPLERATE 1 /* ²ÉÑùƵÂÊ */ +#define AUDIO_DSP_FMT 2 +#define AUDIO_DSP_CHANNELS 3 + +/* Supported Mixer Units controls */ +#define AUDIO_MIXER_QUERY 0x0000 +#define AUDIO_MIXER_MUTE 0x0001 +#define AUDIO_MIXER_VOLUME 0x0002 +#define AUDIO_MIXER_BASS 0x0004 +#define AUDIO_MIXER_MID 0x0008 +#define AUDIO_MIXER_TREBLE 0x0010 +#define AUDIO_MIXER_EQUALIZER 0x0020 +#define AUDIO_MIXER_LINE 0x0040 +#define AUDIO_MIXER_DIGITAL 0x0080 +#define AUDIO_MIXER_MIC 0x0100 + +#define AUDIO_MIXER_EXTEND 0x8000 //extend mixer command + +#define CFG_AUDIO_REPLAY_QUEUE_COUNT 4 +#define CFG_AUDIO_RECORD_PIPE_SIZE (8 * 1024) +#define AUDIO_DEVICE_MP_CNT (4) +#define AUDIO_DEVICE_DECODE_MP_BLOCK_SZ (4352 * 4) +#define AUDIO_DEVICE_DECODE_MP_SZ ((AUDIO_DEVICE_DECODE_MP_BLOCK_SZ*2 + 4)*AUDIO_DEVICE_MP_CNT) + + +enum +{ + AUDIO_STREAM_REPLAY = 0, + AUDIO_STREAM_RECORD, + AUDIO_STREAM_LAST = AUDIO_STREAM_RECORD, +}; + +/* the preferred number and size of audio pipeline buffer for the audio device */ +struct rt_audio_buf_info +{ + rt_uint32_t buffer_size; /* Preferred qty of buffers */ + rt_uint32_t buffer_count; /* Preferred size of the buffers */ +}; +struct rt_audio_buf_desc +{ + rt_uint8_t *data_ptr; + rt_size_t data_size; +}; + +struct rt_audio_frame +{ + const void *data_ptr; + rt_size_t data_size; +}; + +struct rt_audio_device; +struct rt_audio_caps; +struct rt_audio_configure; +struct rt_audio_ops +{ + rt_err_t (*getcaps) (struct rt_audio_device *audio,struct rt_audio_caps *caps); + rt_err_t (*configure) (struct rt_audio_device *audio,struct rt_audio_caps *caps); + + rt_err_t (*init) (struct rt_audio_device *audio); + rt_err_t (*shutdown) (struct rt_audio_device *audio); + rt_err_t (*start) (struct rt_audio_device *audio,int stream); + rt_err_t (*stop) (struct rt_audio_device *audio,int stream); + rt_err_t (*suspend) (struct rt_audio_device *audio,int stream); + rt_err_t (*resume) (struct rt_audio_device *audio,int stream); + + rt_err_t (*control) (struct rt_audio_device *audio, int cmd, void *arg); + rt_size_t (*transmit) (struct rt_audio_device *audio, const void *writeBuf,void *readBuf, rt_size_t size); + + //get page size of codec or private buffer's info + void (*buffer_info) (struct rt_audio_device *audio,struct rt_audio_buf_info *info ); +}; + + +struct rt_audio_configure +{ + rt_uint32_t channels; + + rt_uint32_t samplefmt; + rt_uint32_t samplerate; + rt_uint32_t samplefmts; +}; + +struct rt_audio_caps +{ + int main_type; + int sub_type; + + union + { + rt_uint32_t mask; + int value; + struct rt_audio_configure config; + }udata; +}; + +struct rt_audio_replay +{ + rt_bool_t activated; + struct rt_data_queue queue; +}; + +struct rt_audio_record +{ + rt_bool_t activated; +}; + +struct rt_audio_device +{ + struct rt_device parent; + struct rt_audio_ops *ops; + + struct rt_mempool mp; + + struct rt_audio_replay *replay; + struct rt_audio_record *record; +}; + +rt_err_t rt_audio_register (struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data); +void rt_audio_tx_complete (struct rt_audio_device *audio,rt_uint8_t *pbuf); +void rt_audio_rx_done (struct rt_audio_device *audio,rt_uint8_t *pbuf,rt_size_t len); +rt_uint32_t rt_audio_format_to_bits (rt_uint32_t format); + + +/* Device Control Commands */ +#define CODEC_CMD_RESET 0 +#define CODEC_CMD_SET_VOLUME 1 +#define CODEC_CMD_GET_VOLUME 2 +#define CODEC_CMD_SAMPLERATE 3 +#define CODEC_CMD_EQ 4 +#define CODEC_CMD_3D 5 + +#define CODEC_VOLUME_MAX (63) + +#endif /* __AUDIO_H__ */ diff --git a/rt-thread/components/drivers/include/drivers/can.h b/rt-thread/components/drivers/include/drivers/can.h new file mode 100644 index 0000000..ecf3b5f --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/can.h @@ -0,0 +1,301 @@ +/* + * File : can.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-05-14 aubrcool@qq.com first version + * 2015-07-06 Bernard remove RT_CAN_USING_LED. + */ + +#ifndef CAN_H_ +#define CAN_H_ + +#include + +#ifndef RT_CANMSG_BOX_SZ +#define RT_CANMSG_BOX_SZ 16 +#endif +#ifndef RT_CANSND_BOX_NUM +#define RT_CANSND_BOX_NUM 1 +#endif + +enum CANBAUD +{ + CAN1MBaud = 1000UL * 1000,/* 1 MBit/sec */ + CAN800kBaud = 1000UL * 800, /* 800 kBit/sec */ + CAN500kBaud = 1000UL * 500, /* 500 kBit/sec */ + CAN250kBaud = 1000UL * 250, /* 250 kBit/sec */ + CAN125kBaud = 1000UL * 125, /* 125 kBit/sec */ + CAN100kBaud = 1000UL * 100, /* 100 kBit/sec */ + CAN50kBaud = 1000UL * 50, /* 50 kBit/sec */ + CAN20kBaud = 1000UL * 20, /* 20 kBit/sec */ + CAN10kBaud = 1000UL * 10 /* 10 kBit/sec */ +}; + +#define RT_CAN_MODE_NORMAL 0 +#define RT_CAN_MODE_LISEN 1 +#define RT_CAN_MODE_LOOPBACK 2 +#define RT_CAN_MODE_LOOPBACKANLISEN 3 + +#define RT_CAN_MODE_PRIV 0x01 +#define RT_CAN_MODE_NOPRIV 0x00 + +struct rt_can_filter_item +{ + rt_uint32_t id : 29; + rt_uint32_t ide : 1; + rt_uint32_t rtr : 1; + rt_uint32_t mode : 1; + rt_uint32_t mask; + rt_int32_t hdr; +#ifdef RT_CAN_USING_HDR + rt_err_t (*ind)(rt_device_t dev, void *args , rt_int32_t hdr, rt_size_t size); + void *args; +#endif /*RT_CAN_USING_HDR*/ +}; + +#ifdef RT_CAN_USING_HDR +#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,ind,args) \ + {(id), (ide), (rtr), (mode), (mask), -1, (ind), (args)} +#define RT_CAN_FILTER_STD_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,ind,args) +#define RT_CAN_FILTER_EXT_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF,ind,args) +#define RT_CAN_STD_RMT_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF,ind,args) +#define RT_CAN_EXT_RMT_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF,ind,args) +#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF,ind,args) +#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,ind,args) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,ind,args) +#else + +#define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask) \ + {(id), (ide), (rtr), (mode), (mask), -1, } +#define RT_CAN_FILTER_STD_INIT(id) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF) +#define RT_CAN_FILTER_EXT_INIT(id) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,0,0xFFFFFFFF) +#define RT_CAN_STD_RMT_FILTER_INIT(id) \ + RT_CAN_FILTER_ITEM_INIT(id,0,1,0,0xFFFFFFFF) +#define RT_CAN_EXT_RMT_FILTER_INIT(id) \ + RT_CAN_FILTER_ITEM_INIT(id,1,1,0,0xFFFFFFFF) +#define RT_CAN_STD_RMT_DATA_FILTER_INIT(id) \ + RT_CAN_FILTER_ITEM_INIT(id,0,0,1,0xFFFFFFFF) +#define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id) \ + RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF) +#endif + +struct rt_can_filter_config +{ + rt_uint32_t count; + rt_uint32_t actived; + struct rt_can_filter_item *items; +}; + +struct can_configure +{ + rt_uint32_t baud_rate; + rt_uint32_t msgboxsz; + rt_uint32_t sndboxnumber; + rt_uint32_t mode : 8; + rt_uint32_t privmode : 8; + rt_uint32_t reserved : 16; + rt_uint32_t ticks; +#ifdef RT_CAN_USING_HDR + rt_uint32_t maxhdr; +#endif +}; + +#define CANDEFAULTCONFIG \ +{\ + CAN1MBaud,\ + RT_CANMSG_BOX_SZ,\ + RT_CANSND_BOX_NUM,\ + RT_CAN_MODE_NORMAL,\ +}; + +struct rt_can_ops; +#define RT_CAN_CMD_SET_FILTER 0x13 +#define RT_CAN_CMD_SET_BAUD 0x14 +#define RT_CAN_CMD_SET_MODE 0x15 +#define RT_CAN_CMD_SET_PRIV 0x16 +#define RT_CAN_CMD_GET_STATUS 0x17 +#define RT_CAN_CMD_SET_STATUS_IND 0x18 +#define RT_CAN_CMD_SET_BUS_HOOK 0x19 + +#define RT_DEVICE_CAN_INT_ERR 0x1000 + +enum RT_CAN_STATUS_MODE +{ + NORMAL = 0, + ERRWARNING = 1, + ERRPASSIVE = 2, + BUSOFF = 4, +}; +enum RT_CAN_BUS_ERR +{ + RT_CAN_BUS_NO_ERR = 0, + RT_CAN_BUS_BIT_PAD_ERR = 1, + RT_CAN_BUS_FORMAT_ERR = 2, + RT_CAN_BUS_ACK_ERR = 3, + RT_CAN_BUS_IMPLICIT_BIT_ERR = 4, + RT_CAN_BUS_EXPLICIT_BIT_ERR = 5, + RT_CAN_BUS_CRC_ERR = 6, +}; + +struct rt_can_status +{ + rt_uint32_t rcverrcnt; + rt_uint32_t snderrcnt; + rt_uint32_t errcode; + rt_uint32_t rcvpkg; + rt_uint32_t dropedrcvpkg; + rt_uint32_t sndpkg; + rt_uint32_t dropedsndpkg; + rt_uint32_t bitpaderrcnt; + rt_uint32_t formaterrcnt; + rt_uint32_t ackerrcnt; + rt_uint32_t biterrcnt; + rt_uint32_t crcerrcnt; + rt_uint32_t rcvchange; + rt_uint32_t sndchange; + rt_uint32_t lasterrtype; +}; + +#ifdef RT_CAN_USING_HDR +struct rt_can_hdr +{ + rt_uint32_t connected; + rt_uint32_t msgs; + struct rt_can_filter_item filter; + struct rt_list_node list; +}; +#endif +struct rt_can_device; +typedef rt_err_t (*rt_canstatus_ind)(struct rt_can_device *, void *); +typedef struct rt_can_status_ind_type +{ + rt_canstatus_ind ind; + void *args; +} *rt_can_status_ind_type_t; +typedef void (*rt_can_bus_hook)(struct rt_can_device *); +struct rt_can_device +{ + struct rt_device parent; + + const struct rt_can_ops *ops; + struct can_configure config; + struct rt_can_status status; + + rt_uint32_t timerinitflag; + struct rt_timer timer; + + struct rt_can_status_ind_type status_indicate; +#ifdef RT_CAN_USING_HDR + struct rt_can_hdr *hdr; +#endif +#ifdef RT_CAN_USING_BUS_HOOK + rt_can_bus_hook bus_hook; +#endif /*RT_CAN_USING_BUS_HOOK*/ + struct rt_mutex lock; + void *can_rx; + void *can_tx; +}; +typedef struct rt_can_device *rt_can_t; + +#define RT_CAN_STDID 0 +#define RT_CAN_EXTID 1 +#define RT_CAN_DTR 0 +#define RT_CAN_RTR 1 + +typedef struct rt_can_status *rt_can_status_t; +struct rt_can_msg +{ + rt_uint32_t id : 29; + rt_uint32_t ide : 1; + rt_uint32_t rtr : 1; + rt_uint32_t rsv : 1; + rt_uint32_t len : 8; + rt_uint32_t priv : 8; + rt_uint32_t hdr : 8; + rt_uint32_t reserved : 8; + rt_uint8_t data[8]; +}; +typedef struct rt_can_msg *rt_can_msg_t; + +struct rt_can_msg_list +{ + struct rt_list_node list; +#ifdef RT_CAN_USING_HDR + struct rt_list_node hdrlist; + struct rt_can_hdr *owner; +#endif + struct rt_can_msg data; +}; + +struct rt_can_rx_fifo +{ + /* software fifo */ + struct rt_can_msg_list *buffer; + rt_uint32_t freenumbers; + struct rt_list_node freelist; + struct rt_list_node uselist; +}; + +#define RT_CAN_SND_RESULT_OK 0 +#define RT_CAN_SND_RESULT_ERR 1 +#define RT_CAN_SND_RESULT_WAIT 2 + +#define RT_CAN_EVENT_RX_IND 0x01 /* Rx indication */ +#define RT_CAN_EVENT_TX_DONE 0x02 /* Tx complete */ +#define RT_CAN_EVENT_TX_FAIL 0x03 /* Tx complete */ +#define RT_CAN_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */ +#define RT_CAN_EVENT_RXOF_IND 0x06 /* Rx overflow */ + +struct rt_can_sndbxinx_list +{ + struct rt_list_node list; + struct rt_completion completion; + rt_uint32_t result; +}; + +struct rt_can_tx_fifo +{ + struct rt_can_sndbxinx_list *buffer; + struct rt_semaphore sem; + struct rt_list_node freelist; +}; + +struct rt_can_ops +{ + rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg); + rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg); + int (*sendmsg)(struct rt_can_device *can, const void *buf, rt_uint32_t boxno); + int (*recvmsg)(struct rt_can_device *can, void *buf, rt_uint32_t boxno); +}; + +rt_err_t rt_hw_can_register(struct rt_can_device *can, + const char *name, + const struct rt_can_ops *ops, + void *data); +void rt_hw_can_isr(struct rt_can_device *can, int event); +#endif /*_CAN_H*/ + diff --git a/rt-thread/components/drivers/include/drivers/cputime.h b/rt-thread/components/drivers/include/drivers/cputime.h new file mode 100644 index 0000000..c3dd243 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/cputime.h @@ -0,0 +1,42 @@ +/* + * File : cputime.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-12-23 Bernard first version + */ + +#ifndef CPUTIME_H__ +#define CPUTIME_H__ + +struct rt_clock_cputime_ops +{ + float (*cputime_getres) (void); + uint32_t (*cputime_gettime)(void); +}; + +float clock_cpu_getres(void); +uint32_t clock_cpu_gettime(void); + +uint32_t clock_cpu_microsecond(uint32_t cpu_tick); +uint32_t clock_cpu_millisecond(uint32_t cpu_tick); + +int clock_cpu_setops(const struct rt_clock_cputime_ops *ops); + +#endif diff --git a/rt-thread/components/drivers/include/drivers/hwtimer.h b/rt-thread/components/drivers/include/drivers/hwtimer.h new file mode 100644 index 0000000..24cec74 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/hwtimer.h @@ -0,0 +1,78 @@ +#ifndef __HWTIMER_H__ +#define __HWTIMER_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Timer Control Command */ +typedef enum +{ + HWTIMER_CTRL_FREQ_SET = 0x01, /* set the count frequency */ + HWTIMER_CTRL_STOP, /* stop timer */ + HWTIMER_CTRL_INFO_GET, /* get a timer feature information */ + HWTIMER_CTRL_MODE_SET /* Setting the timing mode(oneshot/period) */ +} rt_hwtimer_ctrl_t; + +/* Timing Mode */ +typedef enum +{ + HWTIMER_MODE_ONESHOT = 0x01, + HWTIMER_MODE_PERIOD +} rt_hwtimer_mode_t; + +/* Time Value */ +typedef struct rt_hwtimerval +{ + rt_int32_t sec; /* second */ + rt_int32_t usec; /* microsecond */ +} rt_hwtimerval_t; + +#define HWTIMER_CNTMODE_UP 0x01 /* increment count mode */ +#define HWTIMER_CNTMODE_DW 0x02 /* decreasing count mode */ + +struct rt_hwtimer_device; + +struct rt_hwtimer_ops +{ + void (*init)(struct rt_hwtimer_device *timer, rt_uint32_t state); + rt_err_t (*start)(struct rt_hwtimer_device *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode); + void (*stop)(struct rt_hwtimer_device *timer); + rt_uint32_t (*count_get)(struct rt_hwtimer_device *timer); + rt_err_t (*control)(struct rt_hwtimer_device *timer, rt_uint32_t cmd, void *args); +}; + +/* Timer Feature Information */ +struct rt_hwtimer_info +{ + rt_int32_t maxfreq; /* the maximum count frequency timer support */ + rt_int32_t minfreq; /* the minimum count frequency timer support */ + rt_uint32_t maxcnt; /* counter maximum value */ + rt_uint8_t cntmode; /* count mode (inc/dec) */ +}; + +typedef struct rt_hwtimer_device +{ + struct rt_device parent; + const struct rt_hwtimer_ops *ops; + const struct rt_hwtimer_info *info; + + rt_int32_t freq; /* counting frequency set by the user */ + rt_int32_t overflow; /* timer overflows */ + float period_sec; + rt_int32_t cycles; /* how many times will generate a timeout event after overflow */ + rt_int32_t reload; /* reload cycles(using in period mode) */ + rt_hwtimer_mode_t mode; /* timing mode(oneshot/period) */ +} rt_hwtimer_t; + +rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data); +void rt_device_hwtimer_isr(rt_hwtimer_t *timer); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/i2c-bit-ops.h b/rt-thread/components/drivers/include/drivers/i2c-bit-ops.h new file mode 100644 index 0000000..6360b99 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/i2c-bit-ops.h @@ -0,0 +1,53 @@ +/* + * File : i2c-bit-ops.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-04-25 weety first version + */ + +#ifndef __I2C_BIT_OPS_H__ +#define __I2C_BIT_OPS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct rt_i2c_bit_ops +{ + void *data; /* private data for lowlevel routines */ + void (*set_sda)(void *data, rt_int32_t state); + void (*set_scl)(void *data, rt_int32_t state); + rt_int32_t (*get_sda)(void *data); + rt_int32_t (*get_scl)(void *data); + + void (*udelay)(rt_uint32_t us); + + rt_uint32_t delay_us; /* scl and sda line delay */ + rt_uint32_t timeout; /* in tick */ +}; + +rt_err_t rt_i2c_bit_add_bus(struct rt_i2c_bus_device *bus, + const char *bus_name); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/i2c.h b/rt-thread/components/drivers/include/drivers/i2c.h new file mode 100644 index 0000000..b6f5273 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/i2c.h @@ -0,0 +1,105 @@ +/* + * File : i2c.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-04-25 weety first version + */ + +#ifndef __I2C_H__ +#define __I2C_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define RT_I2C_WR 0x0000 +#define RT_I2C_RD (1u << 0) +#define RT_I2C_ADDR_10BIT (1u << 2) /* this is a ten bit chip address */ +#define RT_I2C_NO_START (1u << 4) +#define RT_I2C_IGNORE_NACK (1u << 5) +#define RT_I2C_NO_READ_ACK (1u << 6) /* when I2C reading, we do not ACK */ + +struct rt_i2c_msg +{ + rt_uint16_t addr; + rt_uint16_t flags; + rt_uint16_t len; + rt_uint8_t *buf; +}; + +struct rt_i2c_bus_device; + +struct rt_i2c_bus_device_ops +{ + rt_size_t (*master_xfer)(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], + rt_uint32_t num); + rt_size_t (*slave_xfer)(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], + rt_uint32_t num); + rt_err_t (*i2c_bus_control)(struct rt_i2c_bus_device *bus, + rt_uint32_t, + rt_uint32_t); +}; + +/*for i2c bus driver*/ +struct rt_i2c_bus_device +{ + struct rt_device parent; + const struct rt_i2c_bus_device_ops *ops; + rt_uint16_t flags; + rt_uint16_t addr; + struct rt_mutex lock; + rt_uint32_t timeout; + rt_uint32_t retries; + void *priv; +}; + +#ifdef RT_I2C_DEBUG +#define i2c_dbg(fmt, ...) rt_kprintf(fmt, ##__VA_ARGS__) +#else +#define i2c_dbg(fmt, ...) +#endif + +rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus, + const char *bus_name); +struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name); +rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus, + struct rt_i2c_msg msgs[], + rt_uint32_t num); +rt_size_t rt_i2c_master_send(struct rt_i2c_bus_device *bus, + rt_uint16_t addr, + rt_uint16_t flags, + const rt_uint8_t *buf, + rt_uint32_t count); +rt_size_t rt_i2c_master_recv(struct rt_i2c_bus_device *bus, + rt_uint16_t addr, + rt_uint16_t flags, + rt_uint8_t *buf, + rt_uint32_t count); +int rt_i2c_core_init(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/i2c_dev.h b/rt-thread/components/drivers/include/drivers/i2c_dev.h new file mode 100644 index 0000000..81e9896 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/i2c_dev.h @@ -0,0 +1,52 @@ +/* + * File : i2c_dev.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-04-25 weety first version + */ + +#ifndef __I2C_DEV_H__ +#define __I2C_DEV_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define RT_I2C_DEV_CTRL_10BIT 0x20 +#define RT_I2C_DEV_CTRL_ADDR 0x21 +#define RT_I2C_DEV_CTRL_TIMEOUT 0x22 +#define RT_I2C_DEV_CTRL_RW 0x23 + +struct rt_i2c_priv_data +{ + struct rt_i2c_msg *msgs; + rt_size_t number; +}; + +rt_err_t rt_i2c_bus_device_device_init(struct rt_i2c_bus_device *bus, + const char *name); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/mmc.h b/rt-thread/components/drivers/include/drivers/mmc.h new file mode 100644 index 0000000..6800c2a --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/mmc.h @@ -0,0 +1,206 @@ +/* + * File : mmc.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-06-15 hichard first version + */ + +#ifndef __MMC_H__ +#define __MMC_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * EXT_CSD fields + */ + +#define EXT_CSD_FLUSH_CACHE 32 /* W */ +#define EXT_CSD_CACHE_CTRL 33 /* R/W */ +#define EXT_CSD_POWER_OFF_NOTIFICATION 34 /* R/W */ +#define EXT_CSD_PACKED_FAILURE_INDEX 35 /* RO */ +#define EXT_CSD_PACKED_CMD_STATUS 36 /* RO */ +#define EXT_CSD_EXP_EVENTS_STATUS 54 /* RO, 2 bytes */ +#define EXT_CSD_EXP_EVENTS_CTRL 56 /* R/W, 2 bytes */ +#define EXT_CSD_DATA_SECTOR_SIZE 61 /* R */ +#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ +#define EXT_CSD_PARTITION_ATTRIBUTE 156 /* R/W */ +#define EXT_CSD_PARTITION_SUPPORT 160 /* RO */ +#define EXT_CSD_HPI_MGMT 161 /* R/W */ +#define EXT_CSD_RST_N_FUNCTION 162 /* R/W */ +#define EXT_CSD_BKOPS_EN 163 /* R/W */ +#define EXT_CSD_BKOPS_START 164 /* W */ +#define EXT_CSD_SANITIZE_START 165 /* W */ +#define EXT_CSD_WR_REL_PARAM 166 /* RO */ +#define EXT_CSD_RPMB_MULT 168 /* RO */ +#define EXT_CSD_BOOT_WP 173 /* R/W */ +#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ +#define EXT_CSD_PART_CONFIG 179 /* R/W */ +#define EXT_CSD_ERASED_MEM_CONT 181 /* RO */ +#define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_HS_TIMING 185 /* R/W */ +#define EXT_CSD_POWER_CLASS 187 /* R/W */ +#define EXT_CSD_REV 192 /* RO */ +#define EXT_CSD_STRUCTURE 194 /* RO */ +#define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_OUT_OF_INTERRUPT_TIME 198 /* RO */ +#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */ +#define EXT_CSD_PWR_CL_52_195 200 /* RO */ +#define EXT_CSD_PWR_CL_26_195 201 /* RO */ +#define EXT_CSD_PWR_CL_52_360 202 /* RO */ +#define EXT_CSD_PWR_CL_26_360 203 /* RO */ +#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define EXT_CSD_S_A_TIMEOUT 217 /* RO */ +#define EXT_CSD_REL_WR_SEC_C 222 /* RO */ +#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ +#define EXT_CSD_ERASE_TIMEOUT_MULT 223 /* RO */ +#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ +#define EXT_CSD_BOOT_MULT 226 /* RO */ +#define EXT_CSD_SEC_TRIM_MULT 229 /* RO */ +#define EXT_CSD_SEC_ERASE_MULT 230 /* RO */ +#define EXT_CSD_SEC_FEATURE_SUPPORT 231 /* RO */ +#define EXT_CSD_TRIM_MULT 232 /* RO */ +#define EXT_CSD_PWR_CL_200_195 236 /* RO */ +#define EXT_CSD_PWR_CL_200_360 237 /* RO */ +#define EXT_CSD_PWR_CL_DDR_52_195 238 /* RO */ +#define EXT_CSD_PWR_CL_DDR_52_360 239 /* RO */ +#define EXT_CSD_BKOPS_STATUS 246 /* RO */ +#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ +#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ +#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ +#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */ +#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ +#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ +#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */ +#define EXT_CSD_MAX_PACKED_READS 501 /* RO */ +#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ +#define EXT_CSD_HPI_FEATURES 503 /* RO */ + +/* + * EXT_CSD field definitions + */ + +#define EXT_CSD_WR_REL_PARAM_EN (1<<2) + +#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40) +#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10) +#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04) +#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01) + +#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) +#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1) +#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3) +#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4) + +#define EXT_CSD_PART_SUPPORT_PART_EN (0x1) + +#define EXT_CSD_CMD_SET_NORMAL (1<<0) +#define EXT_CSD_CMD_SET_SECURE (1<<1) +#define EXT_CSD_CMD_SET_CPSECURE (1<<2) + +#define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */ +#define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */ +#define EXT_CSD_CARD_TYPE_HS (EXT_CSD_CARD_TYPE_HS_26 | \ + EXT_CSD_CARD_TYPE_HS_52) +#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */ + /* DDR mode @1.8V or 3V I/O */ +#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */ + /* DDR mode @1.2V I/O */ +#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \ + | EXT_CSD_CARD_TYPE_DDR_1_2V) +#define EXT_CSD_CARD_TYPE_HS200_1_8V (1<<4) /* Card can run at 200MHz */ +#define EXT_CSD_CARD_TYPE_HS200_1_2V (1<<5) /* Card can run at 200MHz */ + /* SDR mode @1.2V I/O */ +#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \ + EXT_CSD_CARD_TYPE_HS200_1_2V) +#define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz DDR, 1.8V */ +#define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */ +#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \ + EXT_CSD_CARD_TYPE_HS400_1_2V) + +#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ +#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ +#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */ +#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */ +#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */ + +#define EXT_CSD_TIMING_BC 0 /* Backwards compatility */ +#define EXT_CSD_TIMING_HS 1 /* High speed */ +#define EXT_CSD_TIMING_HS200 2 /* HS200 */ +#define EXT_CSD_TIMING_HS400 3 /* HS400 */ + +#define EXT_CSD_SEC_ER_EN BIT(0) +#define EXT_CSD_SEC_BD_BLK_EN BIT(2) +#define EXT_CSD_SEC_GB_CL_EN BIT(4) +#define EXT_CSD_SEC_SANITIZE BIT(6) /* v4.5 only */ + +#define EXT_CSD_RST_N_EN_MASK 0x3 +#define EXT_CSD_RST_N_ENABLED 1 /* RST_n is enabled on card */ + +#define EXT_CSD_NO_POWER_NOTIFICATION 0 +#define EXT_CSD_POWER_ON 1 +#define EXT_CSD_POWER_OFF_SHORT 2 +#define EXT_CSD_POWER_OFF_LONG 3 + +#define EXT_CSD_PWR_CL_8BIT_MASK 0xF0 /* 8 bit PWR CLS */ +#define EXT_CSD_PWR_CL_4BIT_MASK 0x0F /* 8 bit PWR CLS */ +#define EXT_CSD_PWR_CL_8BIT_SHIFT 4 +#define EXT_CSD_PWR_CL_4BIT_SHIFT 0 + +#define EXT_CSD_PACKED_EVENT_EN BIT(3) + +/* + * EXCEPTION_EVENT_STATUS field + */ +#define EXT_CSD_URGENT_BKOPS BIT(0) +#define EXT_CSD_DYNCAP_NEEDED BIT(1) +#define EXT_CSD_SYSPOOL_EXHAUSTED BIT(2) +#define EXT_CSD_PACKED_FAILURE BIT(3) + +#define EXT_CSD_PACKED_GENERIC_ERROR BIT(0) +#define EXT_CSD_PACKED_INDEXED_ERROR BIT(1) + +/* + * BKOPS status level + */ +#define EXT_CSD_BKOPS_LEVEL_2 0x2 +/* + * MMC_SWITCH access modes + */ +#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */ +#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */ +#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ + +/* + * extern function + */ +rt_err_t mmc_send_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t *rocr); +rt_int32_t init_mmc(struct rt_mmcsd_host *host, rt_uint32_t ocr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/mmcsd_card.h b/rt-thread/components/drivers/include/drivers/mmcsd_card.h new file mode 100644 index 0000000..18470a5 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/mmcsd_card.h @@ -0,0 +1,185 @@ +/* + * File : mmcsd_card.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-07-25 weety first version + */ + +#ifndef __MMCSD_CARD_H__ +#define __MMCSD_CARD_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SD_SCR_BUS_WIDTH_1 (1 << 0) +#define SD_SCR_BUS_WIDTH_4 (1 << 2) + +struct rt_mmcsd_cid { + rt_uint8_t mid; /* ManufacturerID */ + rt_uint8_t prv; /* Product Revision */ + rt_uint16_t oid; /* OEM/Application ID */ + rt_uint32_t psn; /* Product Serial Number */ + rt_uint8_t pnm[5]; /* Product Name */ + rt_uint8_t reserved1;/* reserved */ + rt_uint16_t mdt; /* Manufacturing Date */ + rt_uint8_t crc; /* CID CRC */ + rt_uint8_t reserved2;/* not used, always 1 */ +}; + +struct rt_mmcsd_csd { + rt_uint8_t csd_structure; /* CSD register version */ + rt_uint8_t taac; + rt_uint8_t nsac; + rt_uint8_t tran_speed; /* max data transfer rate */ + rt_uint16_t card_cmd_class; /* card command classes */ + rt_uint8_t rd_blk_len; /* max read data block length */ + rt_uint8_t rd_blk_part; + rt_uint8_t wr_blk_misalign; + rt_uint8_t rd_blk_misalign; + rt_uint8_t dsr_imp; /* DSR implemented */ + rt_uint8_t c_size_mult; /* CSD 1.0 , device size multiplier */ + rt_uint32_t c_size; /* device size */ + rt_uint8_t r2w_factor; + rt_uint8_t wr_blk_len; /* max wtire data block length */ + rt_uint8_t wr_blk_partial; + rt_uint8_t csd_crc; + +}; + +struct rt_sd_scr { + rt_uint8_t sd_version; + rt_uint8_t sd_bus_widths; +}; + +struct rt_sdio_cccr { + rt_uint8_t sdio_version; + rt_uint8_t sd_version; + rt_uint8_t direct_cmd:1, /* Card Supports Direct Commands during data transfer + only SD mode, not used for SPI mode */ + multi_block:1, /* Card Supports Multi-Block */ + read_wait:1, /* Card Supports Read Wait + only SD mode, not used for SPI mode */ + suspend_resume:1, /* Card supports Suspend/Resume + only SD mode, not used for SPI mode */ + s4mi:1, /* generate interrupts during a 4-bit + multi-block data transfer */ + e4mi:1, /* Enable the multi-block IRQ during + 4-bit transfer for the SDIO card */ + low_speed:1, /* Card is a Low-Speed card */ + low_speed_4:1; /* 4-bit support for Low-Speed cards */ + + rt_uint8_t bus_width:1, /* Support SDIO bus width, 1:4bit, 0:1bit */ + cd_disable:1, /* Connect[0]/Disconnect[1] the 10K-90K ohm pull-up + resistor on CD/DAT[3] (pin 1) of the card */ + power_ctrl:1, /* Support Master Power Control */ + high_speed:1; /* Support High-Speed */ + + +}; + +struct rt_sdio_cis { + rt_uint16_t manufacturer; + rt_uint16_t product; + rt_uint16_t func0_blk_size; + rt_uint32_t max_tran_speed; +}; + +/* + * SDIO function CIS tuple (unknown to the core) + */ +struct rt_sdio_function_tuple { + struct rt_sdio_function_tuple *next; + rt_uint8_t code; + rt_uint8_t size; + rt_uint8_t *data; +}; + +struct rt_sdio_function; +typedef void (rt_sdio_irq_handler_t)(struct rt_sdio_function *); + +/* + * SDIO function devices + */ +struct rt_sdio_function { + struct rt_mmcsd_card *card; /* the card this device belongs to */ + rt_sdio_irq_handler_t *irq_handler; /* IRQ callback */ + rt_uint8_t num; /* function number */ + + rt_uint8_t func_code; /* Standard SDIO Function interface code */ + rt_uint16_t manufacturer; /* manufacturer id */ + rt_uint16_t product; /* product id */ + + rt_uint32_t max_blk_size; /* maximum block size */ + rt_uint32_t cur_blk_size; /* current block size */ + + rt_uint32_t enable_timeout_val; /* max enable timeout in msec */ + + struct rt_sdio_function_tuple *tuples; + + void *priv; +}; + +#define SDIO_MAX_FUNCTIONS 7 + + + +struct rt_mmcsd_card { + struct rt_mmcsd_host *host; + rt_uint32_t rca; /* card addr */ + rt_uint32_t resp_cid[4]; /* card CID register */ + rt_uint32_t resp_csd[4]; /* card CSD register */ + rt_uint32_t resp_scr[2]; /* card SCR register */ + + rt_uint16_t tacc_clks; /* data access time by ns */ + rt_uint32_t tacc_ns; /* data access time by clk cycles */ + rt_uint32_t max_data_rate; /* max data transfer rate */ + rt_uint32_t card_capacity; /* card capacity, unit:KB */ + rt_uint32_t card_blksize; /* card block size */ + rt_uint32_t erase_size; /* erase size in sectors */ + rt_uint16_t card_type; +#define CARD_TYPE_MMC 0 /* MMC card */ +#define CARD_TYPE_SD 1 /* SD card */ +#define CARD_TYPE_SDIO 2 /* SDIO card */ +#define CARD_TYPE_SDIO_COMBO 3 /* SD combo (IO+mem) card */ + + rt_uint16_t flags; +#define CARD_FLAG_HIGHSPEED (1 << 0) /* SDIO bus speed 50MHz */ +#define CARD_FLAG_SDHC (1 << 1) /* SDHC card */ +#define CARD_FLAG_SDXC (1 << 2) /* SDXC card */ + + struct rt_sd_scr scr; + struct rt_mmcsd_csd csd; + rt_uint32_t hs_max_data_rate; /* max data transfer rate in high speed mode */ + + rt_uint8_t sdio_function_num; /* totol number of SDIO functions */ + struct rt_sdio_cccr cccr; /* common card info */ + struct rt_sdio_cis cis; /* common tuple info */ + struct rt_sdio_function *sdio_function[SDIO_MAX_FUNCTIONS + 1]; /* SDIO functions (devices) */ + +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/mmcsd_cmd.h b/rt-thread/components/drivers/include/drivers/mmcsd_cmd.h new file mode 100644 index 0000000..2700771 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/mmcsd_cmd.h @@ -0,0 +1,143 @@ +/* + * File : mmcsd_cmd.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-07-25 weety first version + */ + +#ifndef __CMD_H__ +#define __CMD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + /* class 1 */ +#define GO_IDLE_STATE 0 /* bc */ +#define SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ +#define ALL_SEND_CID 2 /* bcr R2 */ +#define SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define SET_DSR 4 /* bc [31:16] RCA */ +#define SWITCH 6 /* ac [31:0] See below R1b */ +#define SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define SEND_EXT_CSD 8 /* adtc R1 */ +#define SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define SEND_CID 10 /* ac [31:16] RCA R2 */ +#define READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ +#define STOP_TRANSMISSION 12 /* ac R1b */ +#define SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ +#define SPI_READ_OCR 58 /* spi spi_R3 */ +#define SPI_CRC_ON_OFF 59 /* spi [0:0] flag spi_R1 */ + + /* class 2 */ +#define SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ + + /* class 3 */ +#define WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ + + /* class 4 */ +#define SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ +#define WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ +#define PROGRAM_CID 26 /* adtc R1 */ +#define PROGRAM_CSD 27 /* adtc R1 */ + + /* class 6 */ +#define SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + + /* class 5 */ +#define ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ +#define ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ +#define ERASE 38 /* ac R1b */ + + /* class 9 */ +#define FAST_IO 39 /* ac R4 */ +#define GO_IRQ_STATE 40 /* bcr R5 */ + + /* class 7 */ +#define LOCK_UNLOCK 42 /* adtc R1b */ + + /* class 8 */ +#define APP_CMD 55 /* ac [31:16] RCA R1 */ +#define GEN_CMD 56 /* adtc [0] RD/WR R1 */ + + +/* SD commands type argument response */ + /* class 0 */ +/* This is basically the same command as for MMC with some quirks. */ +#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */ +#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */ + + /* class 10 */ +#define SD_SWITCH 6 /* adtc [31:0] See below R1 */ + + /* Application commands */ +#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */ +#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */ +#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */ +#define SD_APP_SEND_SCR 51 /* adtc R1 */ + +#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */ +#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */ +#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */ + + +/* SDIO commands type argument response */ +#define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */ +#define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */ +#define SD_IO_RW_EXTENDED 53 /* adtc [31:0] See below R5 */ + + +/* CMD52 arguments */ +#define SDIO_ARG_CMD52_READ (0<<31) +#define SDIO_ARG_CMD52_WRITE (1u<<31) +#define SDIO_ARG_CMD52_FUNC_SHIFT 28 +#define SDIO_ARG_CMD52_FUNC_MASK 0x7 +#define SDIO_ARG_CMD52_RAW_FLAG (1u<<27) +#define SDIO_ARG_CMD52_REG_SHIFT 9 +#define SDIO_ARG_CMD52_REG_MASK 0x1ffff +#define SDIO_ARG_CMD52_DATA_SHIFT 0 +#define SDIO_ARG_CMD52_DATA_MASK 0xff +#define SDIO_R5_DATA(resp) ((resp)[0] & 0xff) + +/* CMD53 arguments */ +#define SDIO_ARG_CMD53_READ (0<<31) +#define SDIO_ARG_CMD53_WRITE (1u<<31) +#define SDIO_ARG_CMD53_FUNC_SHIFT 28 +#define SDIO_ARG_CMD53_FUNC_MASK 0x7 +#define SDIO_ARG_CMD53_BLOCK_MODE (1u<<27) +#define SDIO_ARG_CMD53_INCREMENT (1u<<26) +#define SDIO_ARG_CMD53_REG_SHIFT 9 +#define SDIO_ARG_CMD53_REG_MASK 0x1ffff +#define SDIO_ARG_CMD53_LENGTH_SHIFT 0 +#define SDIO_ARG_CMD53_LENGTH_MASK 0x1ff +#define SDIO_ARG_CMD53_LENGTH_MAX 511 + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/mmcsd_core.h b/rt-thread/components/drivers/include/drivers/mmcsd_core.h new file mode 100644 index 0000000..2be758b --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/mmcsd_core.h @@ -0,0 +1,260 @@ +/* + * File : mmcsd_core.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-07-25 weety first version + */ + +#ifndef __CORE_H__ +#define __CORE_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef RT_MMCSD_DBG +#define mmcsd_dbg(fmt, ...) rt_kprintf(fmt, ##__VA_ARGS__) +#else +#define mmcsd_dbg(fmt, ...) +#endif + +struct rt_mmcsd_data { + rt_uint32_t blksize; + rt_uint32_t blks; + rt_uint32_t *buf; + rt_int32_t err; + rt_uint32_t flags; +#define DATA_DIR_WRITE (1 << 0) +#define DATA_DIR_READ (1 << 1) +#define DATA_STREAM (1 << 2) + + unsigned int bytes_xfered; + + struct rt_mmcsd_cmd *stop; /* stop command */ + struct rt_mmcsd_req *mrq; /* associated request */ + + rt_uint32_t timeout_ns; + rt_uint32_t timeout_clks; +}; + +struct rt_mmcsd_cmd { + rt_uint32_t cmd_code; + rt_uint32_t arg; + rt_uint32_t resp[4]; + rt_uint32_t flags; +/*rsponse types + *bits:0~3 + */ +#define RESP_MASK (0xF) +#define RESP_NONE (0) +#define RESP_R1 (1 << 0) +#define RESP_R1B (2 << 0) +#define RESP_R2 (3 << 0) +#define RESP_R3 (4 << 0) +#define RESP_R4 (5 << 0) +#define RESP_R6 (6 << 0) +#define RESP_R7 (7 << 0) +#define RESP_R5 (8 << 0) /*SDIO command response type*/ +/*command types + *bits:4~5 + */ +#define CMD_MASK (3 << 4) /* command type */ +#define CMD_AC (0 << 4) +#define CMD_ADTC (1 << 4) +#define CMD_BC (2 << 4) +#define CMD_BCR (3 << 4) + +#define resp_type(cmd) ((cmd)->flags & RESP_MASK) + +/*spi rsponse types + *bits:6~8 + */ +#define RESP_SPI_MASK (0x7 << 6) +#define RESP_SPI_R1 (1 << 6) +#define RESP_SPI_R1B (2 << 6) +#define RESP_SPI_R2 (3 << 6) +#define RESP_SPI_R3 (4 << 6) +#define RESP_SPI_R4 (5 << 6) +#define RESP_SPI_R5 (6 << 6) +#define RESP_SPI_R7 (7 << 6) + +#define spi_resp_type(cmd) ((cmd)->flags & RESP_SPI_MASK) +/* + * These are the command types. + */ +#define cmd_type(cmd) ((cmd)->flags & CMD_MASK) + + rt_int32_t retries; /* max number of retries */ + rt_int32_t err; + + struct rt_mmcsd_data *data; + struct rt_mmcsd_req *mrq; /* associated request */ +}; + +struct rt_mmcsd_req { + struct rt_mmcsd_data *data; + struct rt_mmcsd_cmd *cmd; + struct rt_mmcsd_cmd *stop; +}; + +/*the following is response bit*/ +#define R1_OUT_OF_RANGE (1 << 31) /* er, c */ +#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ +#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ +#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ +#define R1_ERASE_PARAM (1 << 27) /* ex, c */ +#define R1_WP_VIOLATION (1 << 26) /* erx, c */ +#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ +#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ +#define R1_COM_CRC_ERROR (1 << 23) /* er, b */ +#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ +#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ +#define R1_CC_ERROR (1 << 20) /* erx, c */ +#define R1_ERROR (1 << 19) /* erx, c */ +#define R1_UNDERRUN (1 << 18) /* ex, c */ +#define R1_OVERRUN (1 << 17) /* ex, c */ +#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ +#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ +#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ +#define R1_ERASE_RESET (1 << 13) /* sr, c */ +#define R1_STATUS(x) (x & 0xFFFFE000) +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R1_APP_CMD (1 << 5) /* sr, c */ + + +#define R1_SPI_IDLE (1 << 0) +#define R1_SPI_ERASE_RESET (1 << 1) +#define R1_SPI_ILLEGAL_COMMAND (1 << 2) +#define R1_SPI_COM_CRC (1 << 3) +#define R1_SPI_ERASE_SEQ (1 << 4) +#define R1_SPI_ADDRESS (1 << 5) +#define R1_SPI_PARAMETER (1 << 6) +/* R1 bit 7 is always zero */ +#define R2_SPI_CARD_LOCKED (1 << 8) +#define R2_SPI_WP_ERASE_SKIP (1 << 9) /* or lock/unlock fail */ +#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP +#define R2_SPI_ERROR (1 << 10) +#define R2_SPI_CC_ERROR (1 << 11) +#define R2_SPI_CARD_ECC_ERROR (1 << 12) +#define R2_SPI_WP_VIOLATION (1 << 13) +#define R2_SPI_ERASE_PARAM (1 << 14) +#define R2_SPI_OUT_OF_RANGE (1 << 15) /* or CSD overwrite */ +#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE + +#define CARD_BUSY 0x80000000 /* Card Power up status bit */ + +/* R5 response bits */ +#define R5_COM_CRC_ERROR (1 << 15) +#define R5_ILLEGAL_COMMAND (1 << 14) +#define R5_ERROR (1 << 11) +#define R5_FUNCTION_NUMBER (1 << 9) +#define R5_OUT_OF_RANGE (1 << 8) +#define R5_STATUS(x) (x & 0xCB00) +#define R5_IO_CURRENT_STATE(x) ((x & 0x3000) >> 12) + + + +/** + * fls - find last (most-significant) bit set + * @x: the word to search + * + * This is defined the same way as ffs. + * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. + */ + +rt_inline rt_uint32_t __rt_fls(rt_uint32_t val) +{ + rt_uint32_t bit = 32; + + if (!val) + return 0; + if (!(val & 0xffff0000u)) + { + val <<= 16; + bit -= 16; + } + if (!(val & 0xff000000u)) + { + val <<= 8; + bit -= 8; + } + if (!(val & 0xf0000000u)) + { + val <<= 4; + bit -= 4; + } + if (!(val & 0xc0000000u)) + { + val <<= 2; + bit -= 2; + } + if (!(val & 0x80000000u)) + { + bit -= 1; + } + + return bit; +} + +#define MMCSD_HOST_PLUGED 0 +#define MMCSD_HOST_UNPLUGED 1 + +int mmcsd_wait_cd_changed(rt_int32_t timeout); +void mmcsd_host_lock(struct rt_mmcsd_host *host); +void mmcsd_host_unlock(struct rt_mmcsd_host *host); +void mmcsd_req_complete(struct rt_mmcsd_host *host); +void mmcsd_send_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req); +rt_int32_t mmcsd_send_cmd(struct rt_mmcsd_host *host, struct rt_mmcsd_cmd *cmd, int retries); +rt_int32_t mmcsd_go_idle(struct rt_mmcsd_host *host); +rt_int32_t mmcsd_spi_read_ocr(struct rt_mmcsd_host *host, rt_int32_t high_capacity, rt_uint32_t *ocr); +rt_int32_t mmcsd_all_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid); +rt_int32_t mmcsd_get_cid(struct rt_mmcsd_host *host, rt_uint32_t *cid); +rt_int32_t mmcsd_get_csd(struct rt_mmcsd_card *card, rt_uint32_t *csd); +rt_int32_t mmcsd_select_card(struct rt_mmcsd_card *card); +rt_int32_t mmcsd_deselect_cards(struct rt_mmcsd_card *host); +rt_int32_t mmcsd_spi_use_crc(struct rt_mmcsd_host *host, rt_int32_t use_crc); +void mmcsd_set_chip_select(struct rt_mmcsd_host *host, rt_int32_t mode); +void mmcsd_set_clock(struct rt_mmcsd_host *host, rt_uint32_t clk); +void mmcsd_set_bus_mode(struct rt_mmcsd_host *host, rt_uint32_t mode); +void mmcsd_set_bus_width(struct rt_mmcsd_host *host, rt_uint32_t width); +void mmcsd_set_data_timeout(struct rt_mmcsd_data *data, const struct rt_mmcsd_card *card); +rt_uint32_t mmcsd_select_voltage(struct rt_mmcsd_host *host, rt_uint32_t ocr); +void mmcsd_change(struct rt_mmcsd_host *host); +void mmcsd_detect(void *param); +struct rt_mmcsd_host *mmcsd_alloc_host(void); +void mmcsd_free_host(struct rt_mmcsd_host *host); +int rt_mmcsd_core_init(void); + +int rt_mmcsd_blk_init(void); +rt_int32_t rt_mmcsd_blk_probe(struct rt_mmcsd_card *card); +void rt_mmcsd_blk_remove(struct rt_mmcsd_card *card); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/mmcsd_host.h b/rt-thread/components/drivers/include/drivers/mmcsd_host.h new file mode 100644 index 0000000..877a04d --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/mmcsd_host.h @@ -0,0 +1,140 @@ +/* + * File : mmcsd_host.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-07-25 weety first version + */ + +#ifndef __HOST_H__ +#define __HOST_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct rt_mmcsd_io_cfg { + rt_uint32_t clock; /* clock rate */ + rt_uint16_t vdd; + +/* vdd stores the bit number of the selected voltage range from below. */ + + rt_uint8_t bus_mode; /* command output mode */ + +#define MMCSD_BUSMODE_OPENDRAIN 1 +#define MMCSD_BUSMODE_PUSHPULL 2 + + rt_uint8_t chip_select; /* SPI chip select */ + +#define MMCSD_CS_IGNORE 0 +#define MMCSD_CS_HIGH 1 +#define MMCSD_CS_LOW 2 + + rt_uint8_t power_mode; /* power supply mode */ + +#define MMCSD_POWER_OFF 0 +#define MMCSD_POWER_UP 1 +#define MMCSD_POWER_ON 2 + + rt_uint8_t bus_width; /* data bus width */ + +#define MMCSD_BUS_WIDTH_1 0 +#define MMCSD_BUS_WIDTH_4 2 +#define MMCSD_BUS_WIDTH_8 3 + +}; + +struct rt_mmcsd_host; +struct rt_mmcsd_req; + +struct rt_mmcsd_host_ops { + void (*request)(struct rt_mmcsd_host *host, struct rt_mmcsd_req *req); + void (*set_iocfg)(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg); + rt_int32_t (*get_card_status)(struct rt_mmcsd_host *host); + void (*enable_sdio_irq)(struct rt_mmcsd_host *host, rt_int32_t en); +}; + +struct rt_mmcsd_host { + struct rt_mmcsd_card *card; + const struct rt_mmcsd_host_ops *ops; + rt_uint32_t freq_min; + rt_uint32_t freq_max; + struct rt_mmcsd_io_cfg io_cfg; + rt_uint32_t valid_ocr; /* current valid OCR */ +#define VDD_165_195 (1 << 7) /* VDD voltage 1.65 - 1.95 */ +#define VDD_20_21 (1 << 8) /* VDD voltage 2.0 ~ 2.1 */ +#define VDD_21_22 (1 << 9) /* VDD voltage 2.1 ~ 2.2 */ +#define VDD_22_23 (1 << 10) /* VDD voltage 2.2 ~ 2.3 */ +#define VDD_23_24 (1 << 11) /* VDD voltage 2.3 ~ 2.4 */ +#define VDD_24_25 (1 << 12) /* VDD voltage 2.4 ~ 2.5 */ +#define VDD_25_26 (1 << 13) /* VDD voltage 2.5 ~ 2.6 */ +#define VDD_26_27 (1 << 14) /* VDD voltage 2.6 ~ 2.7 */ +#define VDD_27_28 (1 << 15) /* VDD voltage 2.7 ~ 2.8 */ +#define VDD_28_29 (1 << 16) /* VDD voltage 2.8 ~ 2.9 */ +#define VDD_29_30 (1 << 17) /* VDD voltage 2.9 ~ 3.0 */ +#define VDD_30_31 (1 << 18) /* VDD voltage 3.0 ~ 3.1 */ +#define VDD_31_32 (1 << 19) /* VDD voltage 3.1 ~ 3.2 */ +#define VDD_32_33 (1 << 20) /* VDD voltage 3.2 ~ 3.3 */ +#define VDD_33_34 (1 << 21) /* VDD voltage 3.3 ~ 3.4 */ +#define VDD_34_35 (1 << 22) /* VDD voltage 3.4 ~ 3.5 */ +#define VDD_35_36 (1 << 23) /* VDD voltage 3.5 ~ 3.6 */ + rt_uint32_t flags; /* define device capabilities */ +#define MMCSD_BUSWIDTH_4 (1 << 0) +#define MMCSD_BUSWIDTH_8 (1 << 1) +#define MMCSD_MUTBLKWRITE (1 << 2) +#define MMCSD_HOST_IS_SPI (1 << 3) +#define controller_is_spi(host) (host->flags & MMCSD_HOST_IS_SPI) +#define MMCSD_SUP_SDIO_IRQ (1 << 4) /* support signal pending SDIO IRQs */ +#define MMCSD_SUP_HIGHSPEED (1 << 5) /* support high speed */ + + rt_uint32_t max_seg_size; /* maximum size of one dma segment */ + rt_uint32_t max_dma_segs; /* maximum number of dma segments in one request */ + rt_uint32_t max_blk_size; /* maximum block size */ + rt_uint32_t max_blk_count; /* maximum block count */ + + rt_uint32_t spi_use_crc; + struct rt_mutex bus_lock; + struct rt_semaphore sem_ack; + + rt_uint32_t sdio_irq_num; + struct rt_semaphore *sdio_irq_sem; + struct rt_thread *sdio_irq_thread; + + void *private_data; +}; + +rt_inline void mmcsd_delay_ms(rt_uint32_t ms) +{ + if (ms < 1000 / RT_TICK_PER_SECOND) + { + rt_thread_delay(1); + } + else + { + rt_thread_delay(ms/(1000 / RT_TICK_PER_SECOND)); + } +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/mtd.h b/rt-thread/components/drivers/include/drivers/mtd.h new file mode 100644 index 0000000..9cc7c47 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/mtd.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : mtd.h + * + * Change Logs: + * Date Author Notes + 2018-09-10 heyuanjie87 first version + + */ + +#ifndef __MTD_H__ +#define __MTD_H__ + +#include +#include +#include + +#define MTD_TYPE_NOR 1 +#define MTD_TYPE_NAND 2 + + /** + * MTD operation modes + * + * @MTD_OPM_PLACE_OOB: OOB data are placed at the given offset (default) + * @MTD_OPM_AUTO_OOB: OOB data are automatically placed at the free areas + * @MTD_OPM_RAW: data are transferred as-is, with no error correction; + */ +enum mtd_opm +{ + MTD_OPM_PLACE_OOB = 0, + MTD_OPM_AUTO_OOB = 1, + MTD_OPM_RAW = 2, +}; + +#ifndef loff_t +typedef long loff_t; +#endif + +struct mtd_oob_region +{ + uint8_t offset; + uint8_t length; +}; + +typedef struct mtd_info +{ + struct rt_device parent; + + const struct mtd_ops *ops; + + uint16_t oob_size; + uint16_t sector_size; /* Minimal writable flash unit size */ + uint32_t block_size:28; /* Erase size for the device */ + uint32_t type:4; + + size_t size; /* Total size of the MTD */ + loff_t offset; /* At which this MTD starts, from the beginning of the MEMORY */ + struct mtd_info *master; + + void *priv; +}rt_mtd_t; + +struct mtd_io_desc +{ + uint8_t mode; /* operation mode(enum mtd_opm) */ + uint8_t ooblen; /* number of oob bytes to write/read */ + uint8_t oobretlen; /* number of oob bytes written/read */ + uint8_t ooboffs; /* offset in the oob area */ + uint8_t *oobbuf; + + size_t datlen; /* number of data bytes to write/read */ + size_t datretlen; /* number of data bytes written/read */ + uint8_t *datbuf; /* if NULL only oob are read/written */ +}; + +struct mtd_ops +{ + int(*erase)(rt_mtd_t *mtd, loff_t addr, size_t len); /* return 0 if success */ + int(*read) (rt_mtd_t *mtd, loff_t from, struct mtd_io_desc *ops); /* return 0 if success */ + int(*write) (rt_mtd_t *mtd, loff_t to, struct mtd_io_desc *ops); /* return 0 if success */ + int(*isbad) (rt_mtd_t *mtd, uint32_t block); /* return 1 if bad, 0 not bad */ + int(*markbad) (rt_mtd_t *mtd, uint32_t block); /* return 0 if success */ +}; + +struct mtd_part +{ + const char *name; /* name of the MTD partion */ + loff_t offset; /* start addr of partion */ + size_t size; /* size of partion */ +}; + +int rt_mtd_erase(rt_mtd_t *mtd, loff_t addr, size_t size); +int rt_mtd_block_erase(rt_mtd_t *mtd, uint32_t block); +int rt_mtd_read_oob(rt_mtd_t *mtd, loff_t from, struct mtd_io_desc *desc); +int rt_mtd_write_oob(rt_mtd_t *mtd, loff_t to, struct mtd_io_desc *desc); +int rt_mtd_read(rt_mtd_t *mtd, loff_t from, uint8_t *buf, size_t len); +int rt_mtd_write(rt_mtd_t *mtd, loff_t to, const uint8_t *buf, size_t len); +int rt_mtd_block_markbad(rt_mtd_t *mtd, uint32_t block); +int rt_mtd_block_isbad(rt_mtd_t *mtd, uint32_t block); + +rt_mtd_t* rt_mtd_get(const char *name); +int rt_mtd_register(rt_mtd_t *master, const struct mtd_part *parts, int np); + +#endif diff --git a/rt-thread/components/drivers/include/drivers/mtd_nand.h b/rt-thread/components/drivers/include/drivers/mtd_nand.h new file mode 100644 index 0000000..fb14eb0 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/mtd_nand.h @@ -0,0 +1,131 @@ +/* + * File : mtd_nand.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-12-05 Bernard the first version + * 2011-04-02 prife add mark_badblock and check_block + */ + +/* + * COPYRIGHT (C) 2012, Shanghai Real Thread + */ + +#ifndef __MTD_NAND_H__ +#define __MTD_NAND_H__ + +#include + +struct rt_mtd_nand_driver_ops; +#define RT_MTD_NAND_DEVICE(device) ((struct rt_mtd_nand_device*)(device)) + +#define RT_MTD_EOK 0 /* NO error */ +#define RT_MTD_EECC 1 /* ECC error */ +#define RT_MTD_EBUSY 2 /* hardware busy */ +#define RT_MTD_EIO 3 /* generic IO issue */ +#define RT_MTD_ENOMEM 4 /* out of memory */ +#define RT_MTD_ESRC 5 /* source issue */ +#define RT_MTD_EECC_CORRECT 6 /* ECC error but correct */ + +struct rt_mtd_nand_device +{ + struct rt_device parent; + + rt_uint16_t page_size; /* The Page size in the flash */ + rt_uint16_t oob_size; /* Out of bank size */ + rt_uint16_t oob_free; /* the free area in oob that flash driver not use */ + rt_uint16_t plane_num; /* the number of plane in the NAND Flash */ + + rt_uint32_t pages_per_block; /* The number of page a block */ + rt_uint16_t block_total; + + rt_uint32_t block_start; /* The start of available block*/ + rt_uint32_t block_end; /* The end of available block */ + + /* operations interface */ + const struct rt_mtd_nand_driver_ops* ops; +}; + +struct rt_mtd_nand_driver_ops +{ + rt_err_t (*read_id) (struct rt_mtd_nand_device* device); + + rt_err_t (*read_page)(struct rt_mtd_nand_device* device, + rt_off_t page, + rt_uint8_t* data, rt_uint32_t data_len, + rt_uint8_t * spare, rt_uint32_t spare_len); + + rt_err_t (*write_page)(struct rt_mtd_nand_device * device, + rt_off_t page, + const rt_uint8_t * data, rt_uint32_t data_len, + const rt_uint8_t * spare, rt_uint32_t spare_len); + rt_err_t (*move_page) (struct rt_mtd_nand_device *device, rt_off_t src_page, rt_off_t dst_page); + + rt_err_t (*erase_block)(struct rt_mtd_nand_device* device, rt_uint32_t block); + rt_err_t (*check_block)(struct rt_mtd_nand_device* device, rt_uint32_t block); + rt_err_t (*mark_badblock)(struct rt_mtd_nand_device* device, rt_uint32_t block); +}; + +rt_err_t rt_mtd_nand_register_device(const char* name, struct rt_mtd_nand_device* device); + +rt_inline rt_uint32_t rt_mtd_nand_read_id(struct rt_mtd_nand_device* device) +{ + return device->ops->read_id(device); +} + +rt_inline rt_err_t rt_mtd_nand_read( + struct rt_mtd_nand_device* device, + rt_off_t page, + rt_uint8_t* data, rt_uint32_t data_len, + rt_uint8_t * spare, rt_uint32_t spare_len) +{ + return device->ops->read_page(device, page, data, data_len, spare, spare_len); +} + +rt_inline rt_err_t rt_mtd_nand_write( + struct rt_mtd_nand_device* device, + rt_off_t page, + const rt_uint8_t* data, rt_uint32_t data_len, + const rt_uint8_t * spare, rt_uint32_t spare_len) +{ + return device->ops->write_page(device, page, data, data_len, spare, spare_len); +} + +rt_inline rt_err_t rt_mtd_nand_move_page(struct rt_mtd_nand_device* device, + rt_off_t src_page, rt_off_t dst_page) +{ + return device->ops->move_page(device, src_page, dst_page); +} + +rt_inline rt_err_t rt_mtd_nand_erase_block(struct rt_mtd_nand_device* device, rt_uint32_t block) +{ + return device->ops->erase_block(device, block); +} + +rt_inline rt_err_t rt_mtd_nand_check_block(struct rt_mtd_nand_device* device, rt_uint32_t block) +{ + return device->ops->check_block(device, block); +} + +rt_inline rt_err_t rt_mtd_nand_mark_badblock(struct rt_mtd_nand_device* device, rt_uint32_t block) +{ + return device->ops->mark_badblock(device, block); +} + +#endif /* MTD_NAND_H_ */ diff --git a/rt-thread/components/drivers/include/drivers/mtd_nor.h b/rt-thread/components/drivers/include/drivers/mtd_nor.h new file mode 100644 index 0000000..c51ce87 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/mtd_nor.h @@ -0,0 +1,81 @@ +/* + * File : mtd_nor.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, Shanghai Real-Thread Technology Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-5-30 Bernard the first version + */ + +#ifndef __MTD_NOR_H__ +#define __MTD_NOR_H__ + +#include + +struct rt_mtd_nor_driver_ops; +#define RT_MTD_NOR_DEVICE(device) ((struct rt_mtd_nor_device*)(device)) + +struct rt_mtd_nor_device +{ + struct rt_device parent; + + rt_uint32_t block_size; /* The Block size in the flash */ + rt_uint32_t block_start; /* The start of available block*/ + rt_uint32_t block_end; /* The end of available block */ + + /* operations interface */ + const struct rt_mtd_nor_driver_ops* ops; +}; + +struct rt_mtd_nor_driver_ops +{ + rt_err_t (*read_id) (struct rt_mtd_nor_device* device); + + rt_size_t (*read) (struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint8_t* data, rt_uint32_t length); + rt_size_t (*write) (struct rt_mtd_nor_device* device, rt_off_t offset, const rt_uint8_t* data, rt_uint32_t length); + + rt_err_t (*erase_block)(struct rt_mtd_nor_device* device, rt_off_t offset, rt_uint32_t length); +}; + +rt_err_t rt_mtd_nor_register_device(const char* name, struct rt_mtd_nor_device* device); + +rt_inline rt_uint32_t rt_mtd_nor_read_id(struct rt_mtd_nor_device* device) +{ + return device->ops->read_id(device); +} + +rt_inline rt_size_t rt_mtd_nor_read( + struct rt_mtd_nor_device* device, + rt_off_t offset, rt_uint8_t* data, rt_uint32_t length) +{ + return device->ops->read(device, offset, data, length); +} + +rt_inline rt_size_t rt_mtd_nor_write( + struct rt_mtd_nor_device* device, + rt_off_t offset, const rt_uint8_t* data, rt_uint32_t length) +{ + return device->ops->write(device, offset, data, length); +} + +rt_inline rt_err_t rt_mtd_nor_erase_block(struct rt_mtd_nor_device* device, rt_off_t offset, rt_size_t length) +{ + return device->ops->erase_block(device, offset, length); +} + +#endif diff --git a/rt-thread/components/drivers/include/drivers/mtdnand.h b/rt-thread/components/drivers/include/drivers/mtdnand.h new file mode 100644 index 0000000..c767e4a --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/mtdnand.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : mtdnand.h + * + * Change Logs: + * Date Author Notes + 2018-09-10 heyuanjie87 first version + + */ + +#ifndef _MTDNAND_H_ +#define _MTDNAND_H_ + +#include "mtd.h" + + /* Status bits */ +#define NAND_STATUS_FAIL 0x01 +#define NAND_STATUS_FAIL_N1 0x02 +#define NAND_STATUS_WP 0x80 + +typedef enum +{ + NAND_CMD_PAGE_RD, /* read data to chip's page buffer,do WaitBusy after this cmd in low driver */ + NAND_CMD_PAGE_WR0, /* write data to chip's page buffer */ + NAND_CMD_PAGE_WR1, /* do flash programe */ + NAND_CMD_BLK_ERASE, /* erase block */ + NAND_CMD_ECC_EN, /* enable gen HWECC */ + NAND_CMD_ECC_DIS /* disable gen HWECC */ +} nand_cmd_t; + +typedef enum +{ + NAND_ECCM_NONE, + NAND_ECCM_HW, +} nand_eccmode_t; + +struct nand_chip; +struct nand_ops; + +/** +* struct nand_buffers - buffer structure for read/write +* @ecccalc: buffer pointer for calculated ECC, size is oobsize. +* @ecccode: buffer pointer for ECC read from flash, size is oobsize. +* +*/ +struct nand_buffers +{ + uint8_t *ecccalc; + uint8_t *ecccode; +}; + +struct nand_ecc +{ + uint8_t mode; /* nand_eccmode_t */ + uint8_t bytes; /* gen ecc bytes per ecc step(usually 3) */ + uint16_t stepsize:12; /* min 256 */ + uint16_t _step:4; /* */ + + /* driver must set the two interface if HWECC */ + void (*calculate)(struct nand_chip *chip, const uint8_t *dat, uint8_t *ecc_code); + /* return max bit flips if can't correct,return -1 ECC is error(0 success) */ + int(*correct)(struct nand_chip *chip, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc); + /* ignore if NONECC */ + const struct mtd_oob_region *layout; +}; + +typedef struct nand_chip +{ + rt_mtd_t parent; + + /* driver must init these */ + const struct nand_ops *ops; + struct nand_ecc ecc; + const struct mtd_oob_region *freelayout; + + /* driver do not touch */ + struct nand_buffers buffers; + uint8_t *oob_poi; + uint8_t *pagebuf; + uint32_t size; + uint16_t oobsize; + uint8_t pages_pb; + uint16_t page_size; + int(*read_page)(struct nand_chip *chip, uint8_t *buf, int oob_required, int page); + int(*write_page)(struct nand_chip *chip, const uint8_t *buf, int oob_required, int page); +}rt_nand_t; + +struct nand_ops +{ + int(*cmdfunc)(rt_nand_t *nand, int cmd, int page, int offset); /* send nand operation cmd, return Status bits(0 success), + if nand is busy please wait in low driver */ + int(*read_buf)(rt_nand_t *nand, uint8_t *buf, int len); /* read data from nand chip's page buffer */ + int(*write_buf)(rt_nand_t *nand, const uint8_t *buf, int len);/* write data to nand chip's page buffer */ + int(*isbad)(rt_nand_t *nand, uint32_t blk); /* if NULL OOB[0] used as bad mark(not 0xff is bad) */ + int(*markbad)(rt_nand_t *nand, uint32_t blk); /* if NULL OOB[0] used as bad mark(set to 0x00) */ +}; + +int rt_mtd_nand_init(rt_nand_t *nand, int blk_size, int page_size, int oob_size); + +#endif /* MTD_NAND_H_ */ diff --git a/rt-thread/components/drivers/include/drivers/mtdnor.h b/rt-thread/components/drivers/include/drivers/mtdnor.h new file mode 100644 index 0000000..709efe2 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/mtdnor.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : mtdnor.h + * + * Change Logs: + * Date Author Notes + 2018-09-10 heyuanjie87 first version + + */ + +#ifndef __MTDNOR_H__ +#define __MTDNOR_H__ + +#include + +struct nor_ops; + +typedef struct +{ + rt_mtd_t parent; + + const struct nor_ops *ops; /* operations interface */ +}rt_nor_t; + +struct nor_ops +{ + int (*erase)(rt_nor_t *nor, loff_t addr, size_t len); /* return success erased len or error code */ + int (*read)(rt_nor_t *nor, loff_t addr, uint8_t *buf, size_t len); /* return success data size or error code */ + int (*write)(rt_nor_t *nor, loff_t addr, const uint8_t *buf, size_t len); /* return success data size or error code */ +}; + +int rt_mtd_nor_init(rt_nor_t *nor, int blksize); + +#endif diff --git a/rt-thread/components/drivers/include/drivers/pin.h b/rt-thread/components/drivers/include/drivers/pin.h new file mode 100644 index 0000000..de8fd21 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/pin.h @@ -0,0 +1,107 @@ +/* + * File : pin.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-20 Bernard the first version + * 2017-10-20 ZYH add mode open drain and input pull down + */ + +#ifndef PIN_H__ +#define PIN_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* pin device and operations for RT-Thread */ +struct rt_device_pin +{ + struct rt_device parent; + const struct rt_pin_ops *ops; +}; + +#define PIN_LOW 0x00 +#define PIN_HIGH 0x01 + +#define PIN_MODE_OUTPUT 0x00 +#define PIN_MODE_INPUT 0x01 +#define PIN_MODE_INPUT_PULLUP 0x02 +#define PIN_MODE_INPUT_PULLDOWN 0x03 +#define PIN_MODE_OUTPUT_OD 0x04 + +#define PIN_IRQ_MODE_RISING 0x00 +#define PIN_IRQ_MODE_FALLING 0x01 +#define PIN_IRQ_MODE_RISING_FALLING 0x02 +#define PIN_IRQ_MODE_HIGH_LEVEL 0x03 +#define PIN_IRQ_MODE_LOW_LEVEL 0x04 + +#define PIN_IRQ_DISABLE 0x00 +#define PIN_IRQ_ENABLE 0x01 + +#define PIN_IRQ_PIN_NONE -1 + +struct rt_device_pin_mode +{ + rt_uint16_t pin; + rt_uint16_t mode; +}; +struct rt_device_pin_status +{ + rt_uint16_t pin; + rt_uint16_t status; +}; +struct rt_pin_irq_hdr +{ + rt_int16_t pin; + rt_uint16_t mode; + void (*hdr)(void *args); + void *args; +}; +struct rt_pin_ops +{ + void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_base_t mode); + void (*pin_write)(struct rt_device *device, rt_base_t pin, rt_base_t value); + int (*pin_read)(struct rt_device *device, rt_base_t pin); + + /* TODO: add GPIO interrupt */ + rt_err_t (*pin_attach_irq)(struct rt_device *device, rt_int32_t pin, + rt_uint32_t mode, void (*hdr)(void *args), void *args); + rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_int32_t pin); + rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint32_t enabled); +}; + +int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data); + +void rt_pin_mode(rt_base_t pin, rt_base_t mode); +void rt_pin_write(rt_base_t pin, rt_base_t value); +int rt_pin_read(rt_base_t pin); +rt_err_t rt_pin_attach_irq(rt_int32_t pin, rt_uint32_t mode, + void (*hdr)(void *args), void *args); +rt_err_t rt_pin_detach_irq(rt_int32_t pin); +rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint32_t enabled); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/rt_drv_pwm.h b/rt-thread/components/drivers/include/drivers/rt_drv_pwm.h new file mode 100644 index 0000000..0aa2f56 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/rt_drv_pwm.h @@ -0,0 +1,61 @@ +/* + * File : rt_drv_pwm.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2018-05-07 aozima the first version + */ + +#ifndef __DRV_PWM_H_INCLUDE__ +#define __DRV_PWM_H_INCLUDE__ + +#include +#include + +#define PWM_CMD_ENABLE (128 + 0) +#define PWM_CMD_DISABLE (128 + 1) +#define PWM_CMD_SET (128 + 2) +#define PWM_CMD_GET (128 + 3) + +struct rt_pwm_configuration +{ + rt_uint32_t channel; /* 0-n */ + rt_uint32_t period; /* unit:ns 1ns~4.29s:1Ghz~0.23hz */ + rt_uint32_t pulse; /* unit:ns (pulse<=period) */ +}; + +struct rt_device_pwm; +struct rt_pwm_ops +{ + rt_err_t (*control)(struct rt_device_pwm *device, int cmd, void *arg); +}; + +struct rt_device_pwm +{ + struct rt_device parent; + const struct rt_pwm_ops *ops; +}; + +rt_err_t rt_device_pwm_register(struct rt_device_pwm *device, const char *name, const struct rt_pwm_ops *ops, const void *user_data); + +rt_err_t rt_pwm_enable(struct rt_device_pwm *device, int channel); +rt_err_t rt_pwm_disable(struct rt_device_pwm *device, int channel); +rt_err_t rt_pwm_set(struct rt_device_pwm *device, int channel, rt_uint32_t period, rt_uint32_t pulse); + +#endif /* __DRV_PWM_H_INCLUDE__ */ diff --git a/rt-thread/components/drivers/include/drivers/rtc.h b/rt-thread/components/drivers/include/drivers/rtc.h new file mode 100644 index 0000000..7e89bd3 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/rtc.h @@ -0,0 +1,34 @@ +/* + * File : rtc.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-10-10 aozima first version. + */ + +#ifndef __RTC_H__ +#define __RTC_H__ + +rt_err_t set_date(rt_uint32_t year, rt_uint32_t month, rt_uint32_t day); +rt_err_t set_time(rt_uint32_t hour, rt_uint32_t minute, rt_uint32_t second); + +int rt_soft_rtc_init(void); +int rt_rtc_ntp_sync_init(void); + +#endif /* __RTC_H__ */ diff --git a/rt-thread/components/drivers/include/drivers/sd.h b/rt-thread/components/drivers/include/drivers/sd.h new file mode 100644 index 0000000..7d5fcac --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/sd.h @@ -0,0 +1,47 @@ +/* + * File : sd.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-07-25 weety first version + */ + +#ifndef __SD_H__ +#define __SD_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +rt_err_t mmcsd_send_if_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr); +rt_err_t mmcsd_send_app_op_cond(struct rt_mmcsd_host *host, rt_uint32_t ocr, rt_uint32_t *rocr); + +rt_err_t mmcsd_get_card_addr(struct rt_mmcsd_host *host, rt_uint32_t *rca); +rt_int32_t mmcsd_get_scr(struct rt_mmcsd_card *card, rt_uint32_t *scr); + +rt_int32_t init_sd(struct rt_mmcsd_host *host, rt_uint32_t ocr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/sdio.h b/rt-thread/components/drivers/include/drivers/sdio.h new file mode 100644 index 0000000..2cd1c7d --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/sdio.h @@ -0,0 +1,245 @@ +/* + * File : sdio.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-01-15 weety first version + */ + +#ifndef __SDIO_H__ +#define __SDIO_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Card Common Control Registers (CCCR) + */ + +#define SDIO_REG_CCCR_CCCR_REV 0x00 + +#define SDIO_CCCR_REV_1_00 0 /* CCCR/FBR Version 1.00 */ +#define SDIO_CCCR_REV_1_10 1 /* CCCR/FBR Version 1.10 */ +#define SDIO_CCCR_REV_1_20 2 /* CCCR/FBR Version 1.20 */ +#define SDIO_CCCR_REV_3_00 3 /* CCCR/FBR Version 2.00 */ + +#define SDIO_SDIO_REV_1_00 0 /* SDIO Spec Version 1.00 */ +#define SDIO_SDIO_REV_1_10 1 /* SDIO Spec Version 1.10 */ +#define SDIO_SDIO_REV_1_20 2 /* SDIO Spec Version 1.20 */ +#define SDIO_SDIO_REV_2_00 3 /* SDIO Spec Version 2.00 */ + +#define SDIO_REG_CCCR_SD_REV 0x01 + +#define SDIO_SD_REV_1_01 0 /* SD Physical Spec Version 1.01 */ +#define SDIO_SD_REV_1_10 1 /* SD Physical Spec Version 1.10 */ +#define SDIO_SD_REV_2_00 2 /* SD Physical Spec Version 2.00 */ + +#define SDIO_REG_CCCR_IO_EN 0x02 +#define SDIO_REG_CCCR_IO_RDY 0x03 + +#define SDIO_REG_CCCR_INT_EN 0x04 /* Function/Master Interrupt Enable */ +#define SDIO_REG_CCCR_INT_PEND 0x05 /* Function Interrupt Pending */ + +#define SDIO_REG_CCCR_IO_ABORT 0x06 /* function abort/card reset */ + +#define SDIO_REG_CCCR_BUS_IF 0x07 /* bus interface controls */ + +#define SDIO_BUS_WIDTH_1BIT 0x00 +#define SDIO_BUS_WIDTH_4BIT 0x02 +#define SDIO_BUS_ECSI 0x20 /* Enable continuous SPI interrupt */ +#define SDIO_BUS_SCSI 0x40 /* Support continuous SPI interrupt */ + +#define SDIO_BUS_ASYNC_INT 0x20 + +#define SDIO_BUS_CD_DISABLE 0x80 /* disable pull-up on DAT3 (pin 1) */ + +#define SDIO_REG_CCCR_CARD_CAPS 0x08 + +#define SDIO_CCCR_CAP_SDC 0x01 /* can do CMD52 while data transfer */ +#define SDIO_CCCR_CAP_SMB 0x02 /* can do multi-block xfers (CMD53) */ +#define SDIO_CCCR_CAP_SRW 0x04 /* supports read-wait protocol */ +#define SDIO_CCCR_CAP_SBS 0x08 /* supports suspend/resume */ +#define SDIO_CCCR_CAP_S4MI 0x10 /* interrupt during 4-bit CMD53 */ +#define SDIO_CCCR_CAP_E4MI 0x20 /* enable ints during 4-bit CMD53 */ +#define SDIO_CCCR_CAP_LSC 0x40 /* low speed card */ +#define SDIO_CCCR_CAP_4BLS 0x80 /* 4 bit low speed card */ + +#define SDIO_REG_CCCR_CIS_PTR 0x09 /* common CIS pointer (3 bytes) */ + +/* Following 4 regs are valid only if SBS is set */ +#define SDIO_REG_CCCR_BUS_SUSPEND 0x0c +#define SDIO_REG_CCCR_FUNC_SEL 0x0d +#define SDIO_REG_CCCR_EXEC_FLAG 0x0e +#define SDIO_REG_CCCR_READY_FLAG 0x0f + +#define SDIO_REG_CCCR_FN0_BLKSIZE 0x10 /* 2bytes, 0x10~0x11 */ + +#define SDIO_REG_CCCR_POWER_CTRL 0x12 + +#define SDIO_POWER_SMPC 0x01 /* Supports Master Power Control */ +#define SDIO_POWER_EMPC 0x02 /* Enable Master Power Control */ + +#define SDIO_REG_CCCR_SPEED 0x13 + +#define SDIO_SPEED_SHS 0x01 /* Supports High-Speed mode */ +#define SDIO_SPEED_EHS 0x02 /* Enable High-Speed mode */ + +/* + * Function Basic Registers (FBR) + */ + +#define SDIO_REG_FBR_BASE(f) ((f) * 0x100) /* base of function f's FBRs */ + +#define SDIO_REG_FBR_STD_FUNC_IF 0x00 + +#define SDIO_FBR_SUPPORTS_CSA 0x40 /* supports Code Storage Area */ +#define SDIO_FBR_ENABLE_CSA 0x80 /* enable Code Storage Area */ + +#define SDIO_REG_FBR_STD_IF_EXT 0x01 + +#define SDIO_REG_FBR_POWER 0x02 + +#define SDIO_FBR_POWER_SPS 0x01 /* Supports Power Selection */ +#define SDIO_FBR_POWER_EPS 0x02 /* Enable (low) Power Selection */ + +#define SDIO_REG_FBR_CIS 0x09 /* CIS pointer (3 bytes) */ + + +#define SDIO_REG_FBR_CSA 0x0C /* CSA pointer (3 bytes) */ + +#define SDIO_REG_FBR_CSA_DATA 0x0F + +#define SDIO_REG_FBR_BLKSIZE 0x10 /* block size (2 bytes) */ + +/* SDIO CIS Tuple code */ +#define CISTPL_NULL 0x00 +#define CISTPL_CHECKSUM 0x10 +#define CISTPL_VERS_1 0x15 +#define CISTPL_ALTSTR 0x16 +#define CISTPL_MANFID 0x20 +#define CISTPL_FUNCID 0x21 +#define CISTPL_FUNCE 0x22 +#define CISTPL_SDIO_STD 0x91 +#define CISTPL_SDIO_EXT 0x92 +#define CISTPL_END 0xff + +/* SDIO device id */ +#define SDIO_ANY_FUNC_ID 0xff +#define SDIO_ANY_MAN_ID 0xffff +#define SDIO_ANY_PROD_ID 0xffff + +struct rt_sdio_device_id +{ + rt_uint8_t func_code; + rt_uint16_t manufacturer; + rt_uint16_t product; +}; + +struct rt_sdio_driver +{ + char *name; + rt_int32_t (*probe)(struct rt_mmcsd_card *card); + rt_int32_t (*remove)(struct rt_mmcsd_card *card); + struct rt_sdio_device_id *id; +}; + +rt_int32_t sdio_io_send_op_cond(struct rt_mmcsd_host *host, + rt_uint32_t ocr, + rt_uint32_t *cmd5_resp); +rt_int32_t sdio_io_rw_direct(struct rt_mmcsd_card *card, + rt_int32_t rw, + rt_uint32_t fn, + rt_uint32_t reg_addr, + rt_uint8_t *pdata, + rt_uint8_t raw); +rt_int32_t sdio_io_rw_extended(struct rt_mmcsd_card *card, + rt_int32_t rw, + rt_uint32_t fn, + rt_uint32_t addr, + rt_int32_t op_code, + rt_uint8_t *buf, + rt_uint32_t blocks, + rt_uint32_t blksize); +rt_int32_t sdio_io_rw_extended_block(struct rt_sdio_function *func, + rt_int32_t rw, + rt_uint32_t addr, + rt_int32_t op_code, + rt_uint8_t *buf, + rt_uint32_t len); +rt_uint8_t sdio_io_readb(struct rt_sdio_function *func, + rt_uint32_t reg, + rt_int32_t *err); +rt_int32_t sdio_io_writeb(struct rt_sdio_function *func, + rt_uint32_t reg, + rt_uint8_t data); +rt_uint16_t sdio_io_readw(struct rt_sdio_function *func, + rt_uint32_t addr, + rt_int32_t *err); +rt_int32_t sdio_io_writew(struct rt_sdio_function *func, + rt_uint16_t data, + rt_uint32_t addr); +rt_uint32_t sdio_io_readl(struct rt_sdio_function *func, + rt_uint32_t addr, + rt_int32_t *err); +rt_int32_t sdio_io_writel(struct rt_sdio_function *func, + rt_uint32_t data, + rt_uint32_t addr); +rt_int32_t sdio_io_read_multi_fifo_b(struct rt_sdio_function *func, + rt_uint32_t addr, + rt_uint8_t *buf, + rt_uint32_t len); +rt_int32_t sdio_io_write_multi_fifo_b(struct rt_sdio_function *func, + rt_uint32_t addr, + rt_uint8_t *buf, + rt_uint32_t len); +rt_int32_t sdio_io_read_multi_incr_b(struct rt_sdio_function *func, + rt_uint32_t addr, + rt_uint8_t *buf, + rt_uint32_t len); +rt_int32_t sdio_io_write_multi_incr_b(struct rt_sdio_function *func, + rt_uint32_t addr, + rt_uint8_t *buf, + rt_uint32_t len); +rt_int32_t init_sdio(struct rt_mmcsd_host *host, rt_uint32_t ocr); +rt_int32_t sdio_attach_irq(struct rt_sdio_function *func, + rt_sdio_irq_handler_t *handler); +rt_int32_t sdio_detach_irq(struct rt_sdio_function *func); +void sdio_irq_wakeup(struct rt_mmcsd_host *host); +rt_int32_t sdio_enable_func(struct rt_sdio_function *func); +rt_int32_t sdio_disable_func(struct rt_sdio_function *func); +void sdio_set_drvdata(struct rt_sdio_function *func, void *data); +void* sdio_get_drvdata(struct rt_sdio_function *func); +rt_int32_t sdio_set_block_size(struct rt_sdio_function *func, + rt_uint32_t blksize); +rt_int32_t sdio_register_driver(struct rt_sdio_driver *driver); +rt_int32_t sdio_unregister_driver(struct rt_sdio_driver *driver); +void rt_sdio_init(void); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/rt-thread/components/drivers/include/drivers/sdio_func_ids.h b/rt-thread/components/drivers/include/drivers/sdio_func_ids.h new file mode 100644 index 0000000..9fee7c2 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/sdio_func_ids.h @@ -0,0 +1,53 @@ +/* + * File : sdio_func_ids.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-02-26 weety first version + */ + +#ifndef __SDIO_FUNC_IDS_H__ +#define __SDIO_FUNC_IDS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Standard SDIO Function Interfaces */ + +#define SDIO_FUNC_CODE_NONE 0x00 /* Not a SDIO standard interface */ +#define SDIO_FUNC_CODE_UART 0x01 /* SDIO Standard UART */ +#define SDIO_FUNC_CODE_BT_A 0x02 /* SDIO Type-A for Bluetooth standard interface */ +#define SDIO_FUNC_CODE_BT_B 0x03 /* SDIO Type-B for Bluetooth standard interface */ +#define SDIO_FUNC_CODE_GPS 0x04 /* SDIO GPS standard interface */ +#define SDIO_FUNC_CODE_CAMERA 0x05 /* SDIO Camera standard interface */ +#define SDIO_FUNC_CODE_PHS 0x06 /* SDIO PHS standard interface */ +#define SDIO_FUNC_CODE_WLAN 0x07 /* SDIO WLAN interface */ +#define SDIO_FUNC_CODE_ATA 0x08 /* Embedded SDIO-ATA standard interface */ + +/* manufacturer id, product io */ + +#define SDIO_MANUFACTURER_ID_MARVELL 0x02df +#define SDIO_PRODUCT_ID_MARVELL_88W8686 0x9103 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/serial.h b/rt-thread/components/drivers/include/drivers/serial.h new file mode 100644 index 0000000..2abf925 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/serial.h @@ -0,0 +1,185 @@ +/* + * File : serial.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-05-15 lgnq first version. + * 2012-05-28 bernard change interfaces + * 2013-02-20 bernard use RT_SERIAL_RB_BUFSZ to define + * the size of ring buffer. + */ + +#ifndef __SERIAL_H__ +#define __SERIAL_H__ + +#include + +#define BAUD_RATE_2400 2400 +#define BAUD_RATE_4800 4800 +#define BAUD_RATE_9600 9600 +#define BAUD_RATE_19200 19200 +#define BAUD_RATE_38400 38400 +#define BAUD_RATE_57600 57600 +#define BAUD_RATE_115200 115200 +#define BAUD_RATE_230400 230400 +#define BAUD_RATE_460800 460800 +#define BAUD_RATE_921600 921600 +#define BAUD_RATE_2000000 2000000 +#define BAUD_RATE_3000000 3000000 + +#define DATA_BITS_5 5 +#define DATA_BITS_6 6 +#define DATA_BITS_7 7 +#define DATA_BITS_8 8 +#define DATA_BITS_9 9 + +#define STOP_BITS_1 0 +#define STOP_BITS_2 1 +#define STOP_BITS_3 2 +#define STOP_BITS_4 3 + +#ifdef _WIN32 +#include +#else +#define PARITY_NONE 0 +#define PARITY_ODD 1 +#define PARITY_EVEN 2 +#endif + +#define BIT_ORDER_LSB 0 +#define BIT_ORDER_MSB 1 + +#define NRZ_NORMAL 0 /* Non Return to Zero : normal mode */ +#define NRZ_INVERTED 1 /* Non Return to Zero : inverted mode */ + +#ifndef RT_SERIAL_RB_BUFSZ +#define RT_SERIAL_RB_BUFSZ 64 +#endif + +#define RT_SERIAL_EVENT_RX_IND 0x01 /* Rx indication */ +#define RT_SERIAL_EVENT_TX_DONE 0x02 /* Tx complete */ +#define RT_SERIAL_EVENT_RX_DMADONE 0x03 /* Rx DMA transfer done */ +#define RT_SERIAL_EVENT_TX_DMADONE 0x04 /* Tx DMA transfer done */ +#define RT_SERIAL_EVENT_RX_TIMEOUT 0x05 /* Rx timeout */ + +#define RT_SERIAL_DMA_RX 0x01 +#define RT_SERIAL_DMA_TX 0x02 + +#define RT_SERIAL_RX_INT 0x01 +#define RT_SERIAL_TX_INT 0x02 + +#define RT_SERIAL_ERR_OVERRUN 0x01 +#define RT_SERIAL_ERR_FRAMING 0x02 +#define RT_SERIAL_ERR_PARITY 0x03 + +#define RT_SERIAL_TX_DATAQUEUE_SIZE 2048 +#define RT_SERIAL_TX_DATAQUEUE_LWM 30 + +/* Default config for serial_configure structure */ +#define RT_SERIAL_CONFIG_DEFAULT \ +{ \ + BAUD_RATE_115200, /* 115200 bits/s */ \ + DATA_BITS_8, /* 8 databits */ \ + STOP_BITS_1, /* 1 stopbit */ \ + PARITY_NONE, /* No parity */ \ + BIT_ORDER_LSB, /* LSB first sent */ \ + NRZ_NORMAL, /* Normal mode */ \ + RT_SERIAL_RB_BUFSZ, /* Buffer size */ \ + 0 \ +} + +struct serial_configure +{ + rt_uint32_t baud_rate; + + rt_uint32_t data_bits :4; + rt_uint32_t stop_bits :2; + rt_uint32_t parity :2; + rt_uint32_t bit_order :1; + rt_uint32_t invert :1; + rt_uint32_t bufsz :16; + rt_uint32_t reserved :4; +}; + +/* + * Serial FIFO mode + */ +struct rt_serial_rx_fifo +{ + /* software fifo */ + rt_uint8_t *buffer; + + rt_uint16_t put_index, get_index; + + rt_bool_t is_full; +}; + +struct rt_serial_tx_fifo +{ + struct rt_completion completion; +}; + +/* + * Serial DMA mode + */ +struct rt_serial_rx_dma +{ + rt_bool_t activated; +}; + +struct rt_serial_tx_dma +{ + rt_bool_t activated; + struct rt_data_queue data_queue; +}; + +struct rt_serial_device +{ + struct rt_device parent; + + const struct rt_uart_ops *ops; + struct serial_configure config; + + void *serial_rx; + void *serial_tx; +}; +typedef struct rt_serial_device rt_serial_t; + +/** + * uart operators + */ +struct rt_uart_ops +{ + rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg); + rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg); + + int (*putc)(struct rt_serial_device *serial, char c); + int (*getc)(struct rt_serial_device *serial); + + rt_size_t (*dma_transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction); +}; + +void rt_hw_serial_isr(struct rt_serial_device *serial, int event); + +rt_err_t rt_hw_serial_register(struct rt_serial_device *serial, + const char *name, + rt_uint32_t flag, + void *data); + +#endif diff --git a/rt-thread/components/drivers/include/drivers/spi.h b/rt-thread/components/drivers/include/drivers/spi.h new file mode 100644 index 0000000..0fbaabe --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/spi.h @@ -0,0 +1,276 @@ +/* + * File : spi.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-11-23 Bernard Add extern "C" + */ + +#ifndef __SPI_H__ +#define __SPI_H__ + +#include +#include + +#ifdef __cplusplus +extern "C"{ +#endif + +#define RT_SPI_CPHA (1<<0) /* bit[0]:CPHA, clock phase */ +#define RT_SPI_CPOL (1<<1) /* bit[1]:CPOL, clock polarity */ +/** + * At CPOL=0 the base value of the clock is zero + * - For CPHA=0, data are captured on the clock's rising edge (low->high transition) + * and data are propagated on a falling edge (high->low clock transition). + * - For CPHA=1, data are captured on the clock's falling edge and data are + * propagated on a rising edge. + * At CPOL=1 the base value of the clock is one (inversion of CPOL=0) + * - For CPHA=0, data are captured on clock's falling edge and data are propagated + * on a rising edge. + * - For CPHA=1, data are captured on clock's rising edge and data are propagated + * on a falling edge. + */ +#define RT_SPI_LSB (0<<2) /* bit[2]: 0-LSB */ +#define RT_SPI_MSB (1<<2) /* bit[2]: 1-MSB */ + +#define RT_SPI_MASTER (0<<3) /* SPI master device */ +#define RT_SPI_SLAVE (1<<3) /* SPI slave device */ + +#define RT_SPI_MODE_0 (0 | 0) /* CPOL = 0, CPHA = 0 */ +#define RT_SPI_MODE_1 (0 | RT_SPI_CPHA) /* CPOL = 0, CPHA = 1 */ +#define RT_SPI_MODE_2 (RT_SPI_CPOL | 0) /* CPOL = 1, CPHA = 0 */ +#define RT_SPI_MODE_3 (RT_SPI_CPOL | RT_SPI_CPHA) /* CPOL = 1, CPHA = 1 */ + +#define RT_SPI_MODE_MASK (RT_SPI_CPHA | RT_SPI_CPOL | RT_SPI_MSB) + +#define RT_SPI_CS_HIGH (1<<4) /* Chipselect active high */ +#define RT_SPI_NO_CS (1<<5) /* No chipselect */ +#define RT_SPI_3WIRE (1<<6) /* SI/SO pin shared */ +#define RT_SPI_READY (1<<7) /* Slave pulls low to pause */ + +/** + * SPI message structure + */ +struct rt_spi_message +{ + const void *send_buf; + void *recv_buf; + rt_size_t length; + struct rt_spi_message *next; + + unsigned cs_take : 1; + unsigned cs_release : 1; +}; + +/** + * SPI configuration structure + */ +struct rt_spi_configuration +{ + rt_uint8_t mode; + rt_uint8_t data_width; + rt_uint16_t reserved; + + rt_uint32_t max_hz; +}; + +struct rt_spi_ops; +struct rt_spi_bus +{ + struct rt_device parent; + const struct rt_spi_ops *ops; + + struct rt_mutex lock; + struct rt_spi_device *owner; +}; + +/** + * SPI operators + */ +struct rt_spi_ops +{ + rt_err_t (*configure)(struct rt_spi_device *device, struct rt_spi_configuration *configuration); + rt_uint32_t (*xfer)(struct rt_spi_device *device, struct rt_spi_message *message); +}; + +/** + * SPI Virtual BUS, one device must connected to a virtual BUS + */ +struct rt_spi_device +{ + struct rt_device parent; + struct rt_spi_bus *bus; + + struct rt_spi_configuration config; + void *user_data; +}; +#define SPI_DEVICE(dev) ((struct rt_spi_device *)(dev)) + +/* register a SPI bus */ +rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus, + const char *name, + const struct rt_spi_ops *ops); + +/* attach a device on SPI bus */ +rt_err_t rt_spi_bus_attach_device(struct rt_spi_device *device, + const char *name, + const char *bus_name, + void *user_data); + +/** + * This function takes SPI bus. + * + * @param device the SPI device attached to SPI bus + * + * @return RT_EOK on taken SPI bus successfully. others on taken SPI bus failed. + */ +rt_err_t rt_spi_take_bus(struct rt_spi_device *device); + +/** + * This function releases SPI bus. + * + * @param device the SPI device attached to SPI bus + * + * @return RT_EOK on release SPI bus successfully. + */ +rt_err_t rt_spi_release_bus(struct rt_spi_device *device); + +/** + * This function take SPI device (takes CS of SPI device). + * + * @param device the SPI device attached to SPI bus + * + * @return RT_EOK on release SPI bus successfully. others on taken SPI bus failed. + */ +rt_err_t rt_spi_take(struct rt_spi_device *device); + +/** + * This function releases SPI device (releases CS of SPI device). + * + * @param device the SPI device attached to SPI bus + * + * @return RT_EOK on release SPI device successfully. + */ +rt_err_t rt_spi_release(struct rt_spi_device *device); + +/* set configuration on SPI device */ +rt_err_t rt_spi_configure(struct rt_spi_device *device, + struct rt_spi_configuration *cfg); + +/* send data then receive data from SPI device */ +rt_err_t rt_spi_send_then_recv(struct rt_spi_device *device, + const void *send_buf, + rt_size_t send_length, + void *recv_buf, + rt_size_t recv_length); + +rt_err_t rt_spi_send_then_send(struct rt_spi_device *device, + const void *send_buf1, + rt_size_t send_length1, + const void *send_buf2, + rt_size_t send_length2); + +/** + * This function transmits data to SPI device. + * + * @param device the SPI device attached to SPI bus + * @param send_buf the buffer to be transmitted to SPI device. + * @param recv_buf the buffer to save received data from SPI device. + * @param length the length of transmitted data. + * + * @return the actual length of transmitted. + */ +rt_size_t rt_spi_transfer(struct rt_spi_device *device, + const void *send_buf, + void *recv_buf, + rt_size_t length); + +/** + * This function transfers a message list to the SPI device. + * + * @param device the SPI device attached to SPI bus + * @param message the message list to be transmitted to SPI device + * + * @return RT_NULL if transmits message list successfully, + * SPI message which be transmitted failed. + */ +struct rt_spi_message *rt_spi_transfer_message(struct rt_spi_device *device, + struct rt_spi_message *message); + +rt_inline rt_size_t rt_spi_recv(struct rt_spi_device *device, + void *recv_buf, + rt_size_t length) +{ + return rt_spi_transfer(device, RT_NULL, recv_buf, length); +} + +rt_inline rt_size_t rt_spi_send(struct rt_spi_device *device, + const void *send_buf, + rt_size_t length) +{ + return rt_spi_transfer(device, send_buf, RT_NULL, length); +} + +rt_inline rt_uint8_t rt_spi_sendrecv8(struct rt_spi_device *device, + rt_uint8_t data) +{ + rt_uint8_t value; + + rt_spi_send_then_recv(device, &data, 1, &value, 1); + + return value; +} + +rt_inline rt_uint16_t rt_spi_sendrecv16(struct rt_spi_device *device, + rt_uint16_t data) +{ + rt_uint16_t value; + + rt_spi_send_then_recv(device, &data, 2, &value, 2); + + return value; +} + +/** + * This function appends a message to the SPI message list. + * + * @param list the SPI message list header. + * @param message the message pointer to be appended to the message list. + */ +rt_inline void rt_spi_message_append(struct rt_spi_message *list, + struct rt_spi_message *message) +{ + RT_ASSERT(list != RT_NULL); + if (message == RT_NULL) + return; /* not append */ + + while (list->next != RT_NULL) + { + list = list->next; + } + + list->next = message; + message->next = RT_NULL; +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/usb_common.h b/rt-thread/components/drivers/include/drivers/usb_common.h new file mode 100644 index 0000000..922682b --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/usb_common.h @@ -0,0 +1,579 @@ +/* + * File : usb_common.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-10-01 Yi Qiu first version + * 2013-04-26 aozima add DEVICEQUALIFIER support. + * 2017-11-15 ZYH fix ep0 transform error + */ + +#ifndef __USB_COMMON_H__ +#define __USB_COMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define RT_DEBUG_USB 0x00 +#define USB_DYNAMIC 0x00 + +#define USB_CLASS_DEVICE 0x00 +#define USB_CLASS_AUDIO 0x01 +#define USB_CLASS_CDC 0x02 +#define USB_CLASS_HID 0x03 +#define USB_CLASS_PHYSICAL 0x05 +#define USB_CLASS_IMAGE 0x06 +#define USB_CLASS_PRINTER 0x07 +#define USB_CLASS_MASS_STORAGE 0x08 +#define USB_CLASS_HUB 0x09 +#define USB_CLASS_CDC_DATA 0x0a +#define USB_CLASS_SMART_CARD 0x0b +#define USB_CLASS_SECURITY 0x0d +#define USB_CLASS_VIDEO 0x0e +#define USB_CLASS_HEALTHCARE 0x0f +#define USB_CLASS_DIAG_DEVICE 0xdc +#define USB_CLASS_WIRELESS 0xe0 +#define USB_CLASS_MISC 0xef +#define USB_CLASS_APP_SPECIFIC 0xfe +#define USB_CLASS_VEND_SPECIFIC 0xff + +#define USB_DESC_TYPE_DEVICE 0x01 +#define USB_DESC_TYPE_CONFIGURATION 0x02 +#define USB_DESC_TYPE_STRING 0x03 +#define USB_DESC_TYPE_INTERFACE 0x04 +#define USB_DESC_TYPE_ENDPOINT 0x05 +#define USB_DESC_TYPE_DEVICEQUALIFIER 0x06 +#define USB_DESC_TYPE_OTHERSPEED 0x07 +#define USB_DESC_TYPE_IAD 0x0b +#define USB_DESC_TYPE_HID 0x21 +#define USB_DESC_TYPE_REPORT 0x22 +#define USB_DESC_TYPE_PHYSICAL 0x23 +#define USB_DESC_TYPE_HUB 0x29 + +#define USB_DESC_LENGTH_DEVICE 0x12 +#define USB_DESC_LENGTH_CONFIG 0x9 +#define USB_DESC_LENGTH_IAD 0x8 +#define USB_DESC_LENGTH_STRING 0x4 +#define USB_DESC_LENGTH_INTERFACE 0x9 +#define USB_DESC_LENGTH_ENDPOINT 0x7 + +#define USB_REQ_TYPE_STANDARD 0x00 +#define USB_REQ_TYPE_CLASS 0x20 +#define USB_REQ_TYPE_VENDOR 0x40 +#define USB_REQ_TYPE_MASK 0x60 + +#define USB_REQ_TYPE_DIR_OUT 0x00 +#define USB_REQ_TYPE_DIR_IN 0x80 + +#define USB_REQ_TYPE_DEVICE 0x00 +#define USB_REQ_TYPE_INTERFACE 0x01 +#define USB_REQ_TYPE_ENDPOINT 0x02 +#define USB_REQ_TYPE_OTHER 0x03 +#define USB_REQ_TYPE_RECIPIENT_MASK 0x1f + +#define USB_FEATURE_ENDPOINT_HALT 0x00 +#define USB_FEATURE_DEV_REMOTE_WAKEUP 0x01 +#define USB_FEATURE_TEST_MODE 0x02 + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C +#define USB_REQ_SET_ENCRYPTION 0x0D +#define USB_REQ_GET_ENCRYPTION 0x0E +#define USB_REQ_RPIPE_ABORT 0x0E +#define USB_REQ_SET_HANDSHAKE 0x0F +#define USB_REQ_RPIPE_RESET 0x0F +#define USB_REQ_GET_HANDSHAKE 0x10 +#define USB_REQ_SET_CONNECTION 0x11 +#define USB_REQ_SET_SECURITY_DATA 0x12 +#define USB_REQ_GET_SECURITY_DATA 0x13 +#define USB_REQ_SET_WUSB_DATA 0x14 +#define USB_REQ_LOOPBACK_DATA_WRITE 0x15 +#define USB_REQ_LOOPBACK_DATA_READ 0x16 +#define USB_REQ_SET_INTERFACE_DS 0x17 + +#define USB_STRING_LANGID_INDEX 0x00 +#define USB_STRING_MANU_INDEX 0x01 +#define USB_STRING_PRODUCT_INDEX 0x02 +#define USB_STRING_SERIAL_INDEX 0x03 +#define USB_STRING_CONFIG_INDEX 0x04 +#define USB_STRING_INTERFACE_INDEX 0x05 +#define USB_STRING_OS_INDEX 0x06 +#define USB_STRING_MAX USB_STRING_OS_INDEX + +#define USB_STRING_OS "MSFT100A" + +#define USB_PID_OUT 0x01 +#define USB_PID_ACK 0x02 +#define USB_PID_DATA0 0x03 +#define USB_PID_SOF 0x05 +#define USB_PID_IN 0x09 +#define USB_PID_NACK 0x0A +#define USB_PID_DATA1 0x0B +#define USB_PID_PRE 0x0C +#define USB_PID_SETUP 0x0D +#define USB_PID_STALL 0x0E + +#define USB_EP_DESC_OUT 0x00 +#define USB_EP_DESC_IN 0x80 +#define USB_EP_DESC_NUM_MASK 0x0f + +#define USB_EP_ATTR_CONTROL 0x00 +#define USB_EP_ATTR_ISOC 0x01 +#define USB_EP_ATTR_BULK 0x02 +#define USB_EP_ATTR_INT 0x03 +#define USB_EP_ATTR_TYPE_MASK 0x03 + +#define USB_EPNO_MASK 0x7f +#define USB_DIR_OUT 0x00 +#define USB_DIR_IN 0x80 +#define USB_DIR_INOUT 0x40 +#define USB_DIR_MASK 0x80 + +#define ID_UNASSIGNED 0 +#define ID_ASSIGNED 1 + +#define RH_GET_PORT_STATUS 0 +#define RH_SET_PORT_STATUS 1 +#define RH_CLEAR_PORT_FEATURE 2 +#define RH_SET_PORT_FEATURE 3 + +#define USB_BUS_POWERED 0 +#define USB_SELF_POWERED 1 +#define USB_REMOTE_WAKEUP 1 +#define USB_EP_HALT 0 + +/* + * Port feature numbers + */ +#define PORT_FEAT_CONNECTION 0 +#define PORT_FEAT_ENABLE 1 +#define PORT_FEAT_SUSPEND 2 +#define PORT_FEAT_OVER_CURRENT 3 +#define PORT_FEAT_RESET 4 +#define PORT_FEAT_POWER 8 +#define PORT_FEAT_LOWSPEED 9 +#define PORT_FEAT_HIGHSPEED 10 +#define PORT_FEAT_C_CONNECTION 16 +#define PORT_FEAT_C_ENABLE 17 +#define PORT_FEAT_C_SUSPEND 18 +#define PORT_FEAT_C_OVER_CURRENT 19 +#define PORT_FEAT_C_RESET 20 + +/* + The HcRhPortStatus[1:NDP] register is used to control and report port events on a per-port + basis. NumberDownstreamPorts represents the number of HcRhPortStatus registers that are + implemented in hardware. The lower word is used to reflect the port status, whereas the upper + word reflects the status change bits. Some status bits are implemented with special write behavior + (see below). If a transaction (token through handshake) is in progress when a write to change + port status occurs, the resulting port status change must be postponed until the transaction + completes. Reserved bits should always be written '0'. +*/ +#define PORT_CCS 0x00000001UL /* R:CurrentConnectStatus - W:ClearPortEnable */ +#define PORT_PES 0x00000002UL /* R:PortEnableStatus - W:SetPortEnable */ +#define PORT_PSS 0x00000004UL /* R:PortSuspendStatus - W:SetPortSuspend */ +#define PORT_POCI 0x00000008UL /* R:PortOverCurrentIndicator - W:ClearSuspendStatus */ +#define PORT_PRS 0x00000010UL /* R:PortResetStatus - W: SetPortReset */ +#define PORT_PPS 0x00000100UL /* R:PortPowerStatus - W: SetPortPower */ +#define PORT_LSDA 0x00000200UL /* R:LowSpeedDeviceAttached - W:ClearPortPower */ +#define PORT_CCSC 0x00010000UL +#define PORT_PESC 0x00020000UL +#define PORT_PSSC 0x00040000UL +#define PORT_POCIC 0x00080000UL +#define PORT_PRSC 0x00100000UL + +/* + *Hub Status & Hub Change bit masks + */ +#define HUB_STATUS_LOCAL_POWER 0x0001 +#define HUB_STATUS_OVERCURRENT 0x0002 + +#define HUB_CHANGE_LOCAL_POWER 0x0001 +#define HUB_CHANGE_OVERCURRENT 0x0002 + +#define USB_EP_ATTR(attr) (attr & USB_EP_ATTR_TYPE_MASK) +#define USB_EP_DESC_NUM(addr) (addr & USB_EP_DESC_NUM_MASK) +#define USB_EP_DIR(addr) ((addr & USB_DIR_MASK)>>7) + +#define HID_REPORT_ID_KEYBOARD1 1 +#define HID_REPORT_ID_KEYBOARD2 2 +#define HID_REPORT_ID_KEYBOARD3 3 +#define HID_REPORT_ID_KEYBOARD4 7 +#define HID_REPORT_ID_MEDIA 4 +#define HID_REPORT_ID_GENERAL 5 +#define HID_REPORT_ID_MOUSE 6 + +#define uswap_32(x) \ + ((((x) & 0xff000000) >> 24) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x000000ff) << 24)) + +#define uswap_8(x) \ + (((rt_uint16_t)(*((rt_uint8_t *)(x)))) + \ + (((rt_uint16_t)(*(((rt_uint8_t *)(x)) + 1))) << 8)) + +typedef void (*func_callback)(void *context); +typedef enum +{ + USB_STATE_NOTATTACHED = 0, + USB_STATE_ATTACHED, + USB_STATE_POWERED, + USB_STATE_RECONNECTING, + USB_STATE_UNAUTHENTICATED, + USB_STATE_DEFAULT, + USB_STATE_ADDRESS, + USB_STATE_CONFIGURED, + USB_STATE_SUSPENDED +}udevice_state_t; + +typedef enum +{ + STAGE_IDLE, + STAGE_SETUP, + STAGE_STATUS_IN, + STAGE_STATUS_OUT, + STAGE_DIN, + STAGE_DOUT +} uep0_stage_t; + +#pragma pack(1) + +struct usb_descriptor +{ + rt_uint8_t bLength; + rt_uint8_t type; +}; +typedef struct usb_descriptor* udesc_t; + +struct udevice_descriptor +{ + rt_uint8_t bLength; + rt_uint8_t type; + rt_uint16_t bcdUSB; + rt_uint8_t bDeviceClass; + rt_uint8_t bDeviceSubClass; + rt_uint8_t bDeviceProtocol; + rt_uint8_t bMaxPacketSize0; + rt_uint16_t idVendor; + rt_uint16_t idProduct; + rt_uint16_t bcdDevice; + rt_uint8_t iManufacturer; + rt_uint8_t iProduct; + rt_uint8_t iSerialNumber; + rt_uint8_t bNumConfigurations; +}; +typedef struct udevice_descriptor* udev_desc_t; + +struct uconfig_descriptor +{ + rt_uint8_t bLength; + rt_uint8_t type; + rt_uint16_t wTotalLength; + rt_uint8_t bNumInterfaces; + rt_uint8_t bConfigurationValue; + rt_uint8_t iConfiguration; + rt_uint8_t bmAttributes; + rt_uint8_t MaxPower; + rt_uint8_t data[256]; +}; +typedef struct uconfig_descriptor* ucfg_desc_t; + +struct uinterface_descriptor +{ + rt_uint8_t bLength; + rt_uint8_t type; + rt_uint8_t bInterfaceNumber; + rt_uint8_t bAlternateSetting; + rt_uint8_t bNumEndpoints; + rt_uint8_t bInterfaceClass; + rt_uint8_t bInterfaceSubClass; + rt_uint8_t bInterfaceProtocol; + rt_uint8_t iInterface; +}; +typedef struct uinterface_descriptor* uintf_desc_t; + +/* Interface Association Descriptor (IAD) */ +struct uiad_descriptor +{ + rt_uint8_t bLength; + rt_uint8_t bDescriptorType; + rt_uint8_t bFirstInterface; + rt_uint8_t bInterfaceCount; + rt_uint8_t bFunctionClass; + rt_uint8_t bFunctionSubClass; + rt_uint8_t bFunctionProtocol; + rt_uint8_t iFunction; +}; +typedef struct uiad_descriptor* uiad_desc_t; + +struct uendpoint_descriptor +{ + rt_uint8_t bLength; + rt_uint8_t type; + rt_uint8_t bEndpointAddress; + rt_uint8_t bmAttributes; + rt_uint16_t wMaxPacketSize; + rt_uint8_t bInterval; +}; +typedef struct uendpoint_descriptor* uep_desc_t; + +struct ustring_descriptor +{ + rt_uint8_t bLength; + rt_uint8_t type; + rt_uint8_t String[64]; +}; +typedef struct ustring_descriptor* ustr_desc_t; + +struct uhub_descriptor +{ + rt_uint8_t length; + rt_uint8_t type; + rt_uint8_t num_ports; + rt_uint16_t characteristics; + rt_uint8_t pwron_to_good; /* power on to power good */ + rt_uint8_t current; + rt_uint8_t removable[8]; + rt_uint8_t pwr_ctl[8]; +}; +typedef struct uhub_descriptor* uhub_desc_t; + +/* USB_DESC_TYPE_DEVICEQUALIFIER: Device Qualifier descriptor */ +struct usb_qualifier_descriptor +{ + rt_uint8_t bLength; + rt_uint8_t bDescriptorType; + + rt_uint16_t bcdUSB; // TODO: big-endian. + rt_uint8_t bDeviceClass; + rt_uint8_t bDeviceSubClass; + rt_uint8_t bDeviceProtocol; + rt_uint8_t bMaxPacketSize0; + rt_uint8_t bNumConfigurations; + rt_uint8_t bRESERVED; +} __attribute__ ((packed)); + +struct usb_os_header_comp_id_descriptor +{ + rt_uint32_t dwLength; + rt_uint16_t bcdVersion; + rt_uint16_t wIndex; + rt_uint8_t bCount; + rt_uint8_t reserved[7]; +}; +typedef struct usb_os_header_comp_id_descriptor * usb_os_header_desc_t; + +struct usb_os_function_comp_id_descriptor +{ + rt_list_t list; + rt_uint8_t bFirstInterfaceNumber; + rt_uint8_t reserved1; + rt_uint8_t compatibleID[8]; + rt_uint8_t subCompatibleID[8]; + rt_uint8_t reserved2[6]; +}; +typedef struct usb_os_function_comp_id_descriptor * usb_os_func_comp_id_desc_t; + +struct usb_os_comp_id_descriptor +{ + struct usb_os_header_comp_id_descriptor head_desc; + rt_list_t func_desc; +}; +typedef struct usb_os_comp_id_descriptor * usb_os_comp_id_desc_t; + +struct usb_os_property_header +{ + rt_uint32_t dwLength; + rt_uint16_t bcdVersion; + rt_uint16_t wIndex; + rt_uint16_t wCount; +}; +typedef struct usb_os_property_header * usb_os_property_header_t; +struct usb_os_proerty +{ + rt_uint32_t dwSize; + rt_uint32_t dwPropertyDataType; + rt_uint16_t wPropertyNameLength; + const char * bPropertyName; + rt_uint32_t dwPropertyDataLength; + const char * bPropertyData; +}; +typedef struct usb_os_proerty * usb_os_proerty_t; + +// Value Description +// 1 A NULL-terminated Unicode String (REG_SZ) +// 2 A NULL-terminated Unicode String that includes environment variables (REG_EXPAND_SZ) +// 3 Free-form binary (REG_BINARY) +// 4 A little-endian 32-bit integer (REG_DWORD_LITTLE_ENDIAN) +// 5 A big-endian 32-bit integer (REG_DWORD_BIG_ENDIAN) +// 6 A NULL-terminated Unicode string that contains a symbolic link (REG_LINK) +// 7 Multiple NULL-terminated Unicode strings (REG_MULTI_SZ) +#define USB_OS_PROERTY_TYPE_REG_SZ 0x01UL +#define USB_OS_PROERTY_TYPE_REG_EXPAND_SZ 0x02UL +#define USB_OS_PROERTY_TYPE_REG_BINARY 0x03UL +#define USB_OS_PROERTY_TYPE_REG_DWORD_LITTLE_ENDIAN 0x04UL +#define USB_OS_PROERTY_TYPE_REG_DWORD_BIG_ENDIAN 0x05UL +#define USB_OS_PROERTY_TYPE_REG_LINK 0x06UL +#define USB_OS_PROERTY_TYPE_REG_MULTI_SZ 0x07UL + +#define USB_OS_PROERTY_DESC(PropertyDataType,PropertyName,PropertyData) \ +{\ + .dwSize = sizeof(struct usb_os_proerty)-sizeof(const char *)*2\ + +sizeof(PropertyName)*2+sizeof(PropertyData)*2,\ + .dwPropertyDataType = PropertyDataType,\ + .wPropertyNameLength = sizeof(PropertyName)*2,\ + .bPropertyName = PropertyName,\ + .dwPropertyDataLength = sizeof(PropertyData)*2,\ + .bPropertyData = PropertyData\ +} + + +#ifndef HID_SUB_DESCRIPTOR_MAX +#define HID_SUB_DESCRIPTOR_MAX 1 +#endif + +struct uhid_descriptor +{ + rt_uint8_t bLength; + rt_uint8_t type; + rt_uint16_t bcdHID; + rt_uint8_t bCountryCode; + rt_uint8_t bNumDescriptors; + struct hid_descriptor_list + { + rt_uint8_t type; + rt_uint16_t wLength; + }Descriptor[HID_SUB_DESCRIPTOR_MAX]; +}; +typedef struct uhid_descriptor* uhid_desc_t; + +struct hid_report +{ + rt_uint8_t report_id; + rt_uint8_t report[63]; + rt_uint8_t size; +}; +typedef struct hid_report* hid_report_t; +extern void HID_Report_Received(hid_report_t report); + +struct urequest +{ + rt_uint8_t request_type; + rt_uint8_t bRequest; + rt_uint16_t wValue; + rt_uint16_t wIndex; + rt_uint16_t wLength; +}; +typedef struct urequest* ureq_t; + +#ifndef MIN +#define MIN(a, b) (a < b ? a : b) +#endif +#ifndef MAX +#define MAX(a, b) (a > b ? a : b) +#endif + +/* + * the define related to mass storage + */ +#define USBREQ_GET_MAX_LUN 0xfe +#define USBREQ_MASS_STORAGE_RESET 0xff + +#define SIZEOF_CSW 0x0d +#define SIZEOF_CBW 0x1f +#define SIZEOF_INQUIRY_CMD 0x24 +#define SIZEOF_MODE_SENSE_6 0x4 +#define SIZEOF_READ_CAPACITIES 0xc +#define SIZEOF_READ_CAPACITY 0x8 +#define SIZEOF_REQUEST_SENSE 0x12 + +#define CBWFLAGS_DIR_M 0x80 +#define CBWFLAGS_DIR_IN 0x80 +#define CBWFLAGS_DIR_OUT 0x00 + +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_INQUIRY_CMD 0x12 +#define SCSI_ALLOW_REMOVAL 0x1e +#define SCSI_MODE_SENSE_6 0x1a +#define SCSI_START_STOP 0x1b +#define SCSI_READ_CAPACITIES 0x23 +#define SCSI_READ_CAPACITY 0x25 +#define SCSI_READ_10 0x28 +#define SCSI_WRITE_10 0x2a +#define SCSI_VERIFY_10 0x2f + +#define CBW_SIGNATURE 0x43425355 +#define CSW_SIGNATURE 0x53425355 +#define CBW_TAG_VALUE 0x12345678 + +struct ustorage_cbw +{ + rt_uint32_t signature; + rt_uint32_t tag; + rt_uint32_t xfer_len; + rt_uint8_t dflags; + rt_uint8_t lun; + rt_uint8_t cb_len; + rt_uint8_t cb[16]; +}; +typedef struct ustorage_cbw* ustorage_cbw_t; + +struct ustorage_csw +{ + rt_uint32_t signature; + rt_uint32_t tag; + rt_int32_t data_reside; + rt_uint8_t status; +}; +typedef struct ustorage_csw* ustorage_csw_t; + +#pragma pack() + +/* + * USB device event loop thread configurations + */ +/* the stack size of USB thread */ +#ifndef RT_USBD_THREAD_STACK_SZ +#define RT_USBD_THREAD_STACK_SZ 512 +#endif + +/* the priority of USB thread */ +#ifndef RT_USBD_THREAD_PRIO +#define RT_USBD_THREAD_PRIO 8 +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/drivers/usb_device.h b/rt-thread/components/drivers/include/drivers/usb_device.h new file mode 100644 index 0000000..572c7d0 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/usb_device.h @@ -0,0 +1,470 @@ +/* + * File : usb_device.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-10-01 Yi Qiu first version + * 2012-12-12 heyuanjie87 change endpoint and function handler + * 2013-04-26 aozima add DEVICEQUALIFIER support. + * 2017-11-15 ZYH fix ep0 transform error + */ + +#ifndef __USB_DEVICE_H__ +#define __USB_DEVICE_H__ + +#include +#include "drivers/usb_common.h" + +/* Vendor ID */ +#ifdef USB_VENDOR_ID +#define _VENDOR_ID USB_VENDOR_ID +#else +#define _VENDOR_ID 0x0EFF +#endif +/* Product ID */ +#ifdef USB_PRODUCT_ID +#define _PRODUCT_ID USB_PRODUCT_ID +#else +#define _PRODUCT_ID 0x0001 +#endif + +#define USB_BCD_DEVICE 0x0200 /* USB Specification Release Number in Binary-Coded Decimal */ +#define USB_BCD_VERSION 0x0200 /* USB 2.0 */ +#define EP0_IN_ADDR 0x80 +#define EP0_OUT_ADDR 0x00 +#define EP_HANDLER(ep, func, size) RT_ASSERT(ep != RT_NULL); ep->handler(func, size) +#define EP_ADDRESS(ep) ep->ep_desc->bEndpointAddress +#define EP_MAXPACKET(ep) ep->ep_desc->wMaxPacketSize +#define FUNC_ENABLE(func) do{ \ + if(func->ops->enable != RT_NULL && \ + func->enabled == RT_FALSE) \ + { \ + if(func->ops->enable(func) == RT_EOK) \ + func->enabled = RT_TRUE; \ + } \ + }while(0) +#define FUNC_DISABLE(func) do{ \ + if(func->ops->disable != RT_NULL && \ + func->enabled == RT_TRUE) \ + { \ + func->enabled = RT_FALSE; \ + func->ops->disable(func); \ + } \ + }while(0) + +struct ufunction; +struct udevice; +struct uendpoint; + +typedef enum +{ + /* request to read full count */ + UIO_REQUEST_READ_FULL, + /* request to read any count */ + UIO_REQUEST_READ_BEST, + /* request to write full count */ + UIO_REQUEST_WRITE, +}UIO_REQUEST_TYPE; + +struct udcd_ops +{ + rt_err_t (*set_address)(rt_uint8_t address); + rt_err_t (*set_config)(rt_uint8_t address); + rt_err_t (*ep_set_stall)(rt_uint8_t address); + rt_err_t (*ep_clear_stall)(rt_uint8_t address); + rt_err_t (*ep_enable)(struct uendpoint* ep); + rt_err_t (*ep_disable)(struct uendpoint* ep); + rt_size_t (*ep_read_prepare)(rt_uint8_t address, void *buffer, rt_size_t size); + rt_size_t (*ep_read)(rt_uint8_t address, void *buffer); + rt_size_t (*ep_write)(rt_uint8_t address, void *buffer, rt_size_t size); + rt_err_t (*ep0_send_status)(void); + rt_err_t (*suspend)(void); + rt_err_t (*wakeup)(void); +}; + +struct ep_id +{ + rt_uint8_t addr; + rt_uint8_t type; + rt_uint8_t dir; + rt_uint16_t maxpacket; + rt_uint8_t status; +}; + +typedef rt_err_t (*udep_handler_t)(struct ufunction* func, rt_size_t size); + +struct uio_request +{ + rt_list_t list; + UIO_REQUEST_TYPE req_type; + rt_uint8_t* buffer; + rt_size_t size; + rt_size_t remain_size; +}; +typedef struct uio_request* uio_request_t; + +struct uendpoint +{ + rt_list_t list; + uep_desc_t ep_desc; + rt_list_t request_list; + struct uio_request request; + rt_uint8_t* buffer; + rt_bool_t stalled; + struct ep_id* id; + udep_handler_t handler; + rt_err_t (*rx_indicate)(struct udevice* dev, rt_size_t size); +}; +typedef struct uendpoint* uep_t; + +struct udcd +{ + struct rt_device parent; + const struct udcd_ops* ops; + struct uendpoint ep0; + uep0_stage_t stage; + struct ep_id* ep_pool; + rt_uint8_t device_is_hs; +}; +typedef struct udcd* udcd_t; + +struct ualtsetting +{ + rt_list_t list; + uintf_desc_t intf_desc; + void* desc; + rt_size_t desc_size; + rt_list_t ep_list; +}; +typedef struct ualtsetting* ualtsetting_t; + +typedef rt_err_t (*uintf_handler_t)(struct ufunction* func, ureq_t setup); + +struct uinterface +{ + rt_list_t list; + rt_uint8_t intf_num; + ualtsetting_t curr_setting; + rt_list_t setting_list; + uintf_handler_t handler; +}; +typedef struct uinterface* uintf_t; + +struct ufunction_ops +{ + rt_err_t (*enable)(struct ufunction* func); + rt_err_t (*disable)(struct ufunction* func); + rt_err_t (*sof_handler)(struct ufunction* func); +}; +typedef struct ufunction_ops* ufunction_ops_t; + +struct ufunction +{ + rt_list_t list; + ufunction_ops_t ops; + struct udevice* device; + udev_desc_t dev_desc; + void* user_data; + rt_bool_t enabled; + + rt_list_t intf_list; +}; +typedef struct ufunction* ufunction_t; + +struct uconfig +{ + rt_list_t list; + struct uconfig_descriptor cfg_desc; + rt_list_t func_list; +}; +typedef struct uconfig* uconfig_t; + +struct udevice +{ + rt_list_t list; + struct udevice_descriptor dev_desc; + + struct usb_qualifier_descriptor * dev_qualifier; + usb_os_comp_id_desc_t os_comp_id_desc; + const char** str; + + udevice_state_t state; + rt_list_t cfg_list; + uconfig_t curr_cfg; + rt_uint8_t nr_intf; + + udcd_t dcd; +}; +typedef struct udevice* udevice_t; + +struct udclass +{ + rt_list_t list; + ufunction_t (*rt_usbd_function_create)(udevice_t device); +}; +typedef struct udclass* udclass_t; + +enum udev_msg_type +{ + USB_MSG_SETUP_NOTIFY, + USB_MSG_DATA_NOTIFY, + USB_MSG_EP0_OUT, + USB_MSG_EP_CLEAR_FEATURE, + USB_MSG_SOF, + USB_MSG_RESET, + USB_MSG_PLUG_IN, + /* we don't need to add a "PLUG_IN" event because after the cable is + * plugged in(before any SETUP) the classed have nothing to do. If the host + * is ready, it will send RESET and we will have USB_MSG_RESET. So, a RESET + * should reset and run the class while plug_in is not. */ + USB_MSG_PLUG_OUT, +}; +typedef enum udev_msg_type udev_msg_type; + +struct ep_msg +{ + rt_size_t size; + rt_uint8_t ep_addr; +}; + +struct udev_msg +{ + udev_msg_type type; + udcd_t dcd; + union + { + struct ep_msg ep_msg; + struct urequest setup; + } content; +}; +typedef struct udev_msg* udev_msg_t; + +int rt_usbd_class_list_init(void); +udevice_t rt_usbd_device_new(void); +uconfig_t rt_usbd_config_new(void); +ufunction_t rt_usbd_function_new(udevice_t device, udev_desc_t dev_desc, + ufunction_ops_t ops); +uintf_t rt_usbd_interface_new(udevice_t device, uintf_handler_t handler); +uep_t rt_usbd_endpoint_new(uep_desc_t ep_desc, udep_handler_t handler); +ualtsetting_t rt_usbd_altsetting_new(rt_size_t desc_size); + +rt_err_t rt_usbd_core_init(void); +rt_err_t rt_usb_device_init(void); +rt_err_t rt_usbd_event_signal(struct udev_msg* msg); +rt_err_t rt_usbd_device_set_controller(udevice_t device, udcd_t dcd); +rt_err_t rt_usbd_device_set_descriptor(udevice_t device, udev_desc_t dev_desc); +rt_err_t rt_usbd_device_set_string(udevice_t device, const char** ustring); +rt_err_t rt_usbd_device_set_qualifier(udevice_t device, struct usb_qualifier_descriptor* qualifier); +rt_err_t rt_usbd_device_set_os_comp_id_desc(udevice_t device, usb_os_comp_id_desc_t os_comp_id_desc); +rt_err_t rt_usbd_device_add_config(udevice_t device, uconfig_t cfg); +rt_err_t rt_usbd_config_add_function(uconfig_t cfg, ufunction_t func); +rt_err_t rt_usbd_class_register(udclass_t udclass); +rt_err_t rt_usbd_function_add_interface(ufunction_t func, uintf_t intf); +rt_err_t rt_usbd_interface_add_altsetting(uintf_t intf, ualtsetting_t setting); +rt_err_t rt_usbd_altsetting_add_endpoint(ualtsetting_t setting, uep_t ep); +rt_err_t rt_usbd_os_comp_id_desc_add_os_func_comp_id_desc(usb_os_comp_id_desc_t os_comp_id_desc, usb_os_func_comp_id_desc_t os_func_comp_id_desc); +rt_err_t rt_usbd_altsetting_config_descriptor(ualtsetting_t setting, const void* desc, rt_off_t intf_pos); +rt_err_t rt_usbd_set_config(udevice_t device, rt_uint8_t value); +rt_err_t rt_usbd_set_altsetting(uintf_t intf, rt_uint8_t value); + +udevice_t rt_usbd_find_device(udcd_t dcd); +uconfig_t rt_usbd_find_config(udevice_t device, rt_uint8_t value); +uintf_t rt_usbd_find_interface(udevice_t device, rt_uint8_t value, ufunction_t *pfunc); +uep_t rt_usbd_find_endpoint(udevice_t device, ufunction_t* pfunc, rt_uint8_t ep_addr); +rt_size_t rt_usbd_io_request(udevice_t device, uep_t ep, uio_request_t req); +rt_size_t rt_usbd_ep0_write(udevice_t device, void *buffer, rt_size_t size); +rt_size_t rt_usbd_ep0_read(udevice_t device, void *buffer, rt_size_t size, + rt_err_t (*rx_ind)(udevice_t device, rt_size_t size)); + +int rt_usbd_vcom_class_register(void); +int rt_usbd_ecm_class_register(void); +int rt_usbd_hid_class_register(void); +int rt_usbd_msc_class_register(void); +int rt_usbd_rndis_class_register(void); +int rt_usbd_winusb_class_register(void); + +#ifdef RT_USB_DEVICE_COMPOSITE +rt_err_t rt_usbd_function_set_iad(ufunction_t func, uiad_desc_t iad_desc); +#endif + +rt_err_t rt_usbd_set_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index); +rt_err_t rt_usbd_clear_feature(udevice_t device, rt_uint16_t value, rt_uint16_t index); +rt_err_t rt_usbd_ep_set_stall(udevice_t device, uep_t ep); +rt_err_t rt_usbd_ep_clear_stall(udevice_t device, uep_t ep); +rt_err_t rt_usbd_ep0_set_stall(udevice_t device); +rt_err_t rt_usbd_ep0_clear_stall(udevice_t device); +rt_err_t rt_usbd_ep0_setup_handler(udcd_t dcd, struct urequest* setup); +rt_err_t rt_usbd_ep0_in_handler(udcd_t dcd); +rt_err_t rt_usbd_ep0_out_handler(udcd_t dcd, rt_size_t size); +rt_err_t rt_usbd_ep_in_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size); +rt_err_t rt_usbd_ep_out_handler(udcd_t dcd, rt_uint8_t address, rt_size_t size); +rt_err_t rt_usbd_reset_handler(udcd_t dcd); +rt_err_t rt_usbd_connect_handler(udcd_t dcd); +rt_err_t rt_usbd_disconnect_handler(udcd_t dcd); +rt_err_t rt_usbd_sof_handler(udcd_t dcd); + +rt_inline rt_err_t dcd_set_address(udcd_t dcd, rt_uint8_t address) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->set_address != RT_NULL); + + return dcd->ops->set_address(address); +} + +rt_inline rt_err_t dcd_set_config(udcd_t dcd, rt_uint8_t address) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->set_config != RT_NULL); + + return dcd->ops->set_config(address); +} + +rt_inline rt_err_t dcd_ep_enable(udcd_t dcd, uep_t ep) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep_enable != RT_NULL); + + return dcd->ops->ep_enable(ep); +} + +rt_inline rt_err_t dcd_ep_disable(udcd_t dcd, uep_t ep) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep_disable != RT_NULL); + + return dcd->ops->ep_disable(ep); +} + +rt_inline rt_size_t dcd_ep_read_prepare(udcd_t dcd, rt_uint8_t address, void *buffer, + rt_size_t size) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + + if(dcd->ops->ep_read_prepare != RT_NULL) + { + return dcd->ops->ep_read_prepare(address, buffer, size); + } + else + { + return 0; + } +} + +rt_inline rt_size_t dcd_ep_read(udcd_t dcd, rt_uint8_t address, void *buffer) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + + if(dcd->ops->ep_read != RT_NULL) + { + return dcd->ops->ep_read(address, buffer); + } + else + { + return 0; + } +} + +rt_inline rt_size_t dcd_ep_write(udcd_t dcd, rt_uint8_t address, void *buffer, + rt_size_t size) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep_write != RT_NULL); + + return dcd->ops->ep_write(address, buffer, size); +} + +rt_inline rt_err_t dcd_ep0_send_status(udcd_t dcd) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep0_send_status != RT_NULL); + + return dcd->ops->ep0_send_status(); +} + +rt_inline rt_err_t dcd_ep_set_stall(udcd_t dcd, rt_uint8_t address) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep_set_stall != RT_NULL); + + return dcd->ops->ep_set_stall(address); +} + +rt_inline rt_err_t dcd_ep_clear_stall(udcd_t dcd, rt_uint8_t address) +{ + RT_ASSERT(dcd != RT_NULL); + RT_ASSERT(dcd->ops != RT_NULL); + RT_ASSERT(dcd->ops->ep_clear_stall != RT_NULL); + + return dcd->ops->ep_clear_stall(address); +} +rt_inline void usbd_os_proerty_descriptor_send(ufunction_t func, ureq_t setup, usb_os_proerty_t usb_os_proerty, rt_uint8_t number_of_proerty) +{ + struct usb_os_property_header header; + static rt_uint8_t * data; + rt_uint8_t * pdata; + rt_uint8_t index,i; + if(data == RT_NULL) + { + header.dwLength = sizeof(struct usb_os_property_header); + header.bcdVersion = 0x0100; + header.wIndex = 0x05; + header.wCount = number_of_proerty; + for(index = 0;index < number_of_proerty;index++) + { + header.dwLength += usb_os_proerty[index].dwSize; + } + data = (rt_uint8_t *)rt_malloc(header.dwLength); + RT_ASSERT(data != RT_NULL); + pdata = data; + rt_memcpy((void *)pdata,(void *)&header,sizeof(struct usb_os_property_header)); + pdata += sizeof(struct usb_os_property_header); + for(index = 0;index < number_of_proerty;index++) + { + rt_memcpy((void *)pdata,(void *)&usb_os_proerty[index],10); + pdata += 10; + for(i = 0;i < usb_os_proerty[index].wPropertyNameLength/2;i++) + { + *pdata = usb_os_proerty[index].bPropertyName[i]; + pdata++; + *pdata = 0; + pdata++; + } + *((rt_uint32_t *)pdata) = usb_os_proerty[index].dwPropertyDataLength; + pdata += 4; + for(i = 0;i < usb_os_proerty[index].dwPropertyDataLength/2;i++) + { + *pdata = usb_os_proerty[index].bPropertyData[i]; + pdata++; + *pdata = 0; + pdata++; + } + } + } + rt_usbd_ep0_write(func->device, data, setup->wLength); +} +#endif diff --git a/rt-thread/components/drivers/include/drivers/usb_host.h b/rt-thread/components/drivers/include/drivers/usb_host.h new file mode 100644 index 0000000..92adaa3 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/usb_host.h @@ -0,0 +1,283 @@ +/* + * File : usb_host.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2011, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-3-12 Yi Qiu first version + */ + +#ifndef __RT_USB_HOST_H__ +#define __RT_USB_HOST_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "usb_common.h" + +#define USB_MAX_DEVICE 0x20 +#define USB_MAX_INTERFACE 0x08 +#define USB_HUB_PORT_NUM 0x04 +#define SIZEOF_USB_REQUEST 0x08 + +#define DEV_STATUS_IDLE 0x00 +#define DEV_STATUS_BUSY 0x01 +#define DEV_STATUS_ERROR 0x02 + +#define UPIPE_STATUS_OK 0x00 +#define UPIPE_STATUS_STALL 0x01 +#define UPIPE_STATUS_ERROR 0x02 + +#define USBH_PID_SETUP 0x00 +#define USBH_PID_DATA 0x01 + +struct uhcd; +struct uhintf; +struct uhub; +struct upipe; + +struct uclass_driver +{ + rt_list_t list; + int class_code; + int subclass_code; + + rt_err_t (*enable)(void* arg); + rt_err_t (*disable)(void* arg); + + void* user_data; +}; +typedef struct uclass_driver* ucd_t; + +struct uprotocal +{ + rt_list_t list; + int pro_id; + + rt_err_t (*init)(void* arg); + rt_err_t (*callback)(void* arg); +}; +typedef struct uprotocal* uprotocal_t; + +struct uinstance +{ + struct rt_device parent; + + struct udevice_descriptor dev_desc; + ucfg_desc_t cfg_desc; + struct uhcd *hcd; + + struct upipe * pipe_ep0_out; + struct upipe * pipe_ep0_in; + rt_list_t pipe; + + rt_uint8_t status; + rt_uint8_t type; + rt_uint8_t index; + rt_uint8_t address; + rt_uint8_t speed; + rt_uint8_t max_packet_size; + rt_uint8_t port; + + struct uhub* parent_hub; + struct uhintf* intf[USB_MAX_INTERFACE]; +}; +typedef struct uinstance* uinst_t; + +struct uhintf +{ + struct uinstance* device; + uintf_desc_t intf_desc; + + ucd_t drv; + void *user_data; +}; + +struct upipe +{ + rt_list_t list; + rt_uint8_t pipe_index; + rt_uint32_t status; + struct uendpoint_descriptor ep; + uinst_t inst; + func_callback callback; + void* user_data; +}; +typedef struct upipe* upipe_t; + +struct uhub +{ + struct uhub_descriptor hub_desc; + rt_uint8_t num_ports; + rt_uint32_t port_status[USB_HUB_PORT_NUM]; + struct uinstance* child[USB_HUB_PORT_NUM]; + + rt_bool_t is_roothub; + + rt_uint8_t buffer[8]; + struct uinstance* self; + struct uhcd *hcd; +}; +typedef struct uhub* uhub_t; + +struct uhcd_ops +{ + rt_err_t (*reset_port) (rt_uint8_t port); + int (*pipe_xfer) (upipe_t pipe, rt_uint8_t token, void* buffer, int nbytes, int timeout); + rt_err_t (*open_pipe) (upipe_t pipe); + rt_err_t (*close_pipe) (upipe_t pipe); +}; +typedef struct uhcd_ops* uhcd_ops_t; +struct uhcd +{ + struct rt_device parent; + uhcd_ops_t ops; + rt_uint8_t num_ports; + uhub_t roothub; +}; +typedef struct uhcd* uhcd_t; + +enum uhost_msg_type +{ + USB_MSG_CONNECT_CHANGE, + USB_MSG_CALLBACK, +}; +typedef enum uhost_msg_type uhost_msg_type; + +struct uhost_msg +{ + uhost_msg_type type; + union + { + struct uhub* hub; + struct + { + func_callback function; + void *context; + }cb; + }content; +}; +typedef struct uhost_msg* uhost_msg_t; + +/* usb host system interface */ +rt_err_t rt_usb_host_init(void); +void rt_usbh_hub_init(struct uhcd *hcd); + +/* usb host core interface */ +struct uinstance* rt_usbh_alloc_instance(uhcd_t uhcd); +rt_err_t rt_usbh_attatch_instance(struct uinstance* device); +rt_err_t rt_usbh_detach_instance(struct uinstance* device); +rt_err_t rt_usbh_get_descriptor(struct uinstance* device, rt_uint8_t type, void* buffer, int nbytes); +rt_err_t rt_usbh_set_configure(struct uinstance* device, int config); +rt_err_t rt_usbh_set_address(struct uinstance* device); +rt_err_t rt_usbh_set_interface(struct uinstance* device, int intf); +rt_err_t rt_usbh_clear_feature(struct uinstance* device, int endpoint, int feature); +rt_err_t rt_usbh_get_interface_descriptor(ucfg_desc_t cfg_desc, int num, uintf_desc_t* intf_desc); +rt_err_t rt_usbh_get_endpoint_descriptor(uintf_desc_t intf_desc, int num, uep_desc_t* ep_desc); + +/* usb class driver interface */ +rt_err_t rt_usbh_class_driver_init(void); +rt_err_t rt_usbh_class_driver_register(ucd_t drv); +rt_err_t rt_usbh_class_driver_unregister(ucd_t drv); +rt_err_t rt_usbh_class_driver_enable(ucd_t drv, void* args); +rt_err_t rt_usbh_class_driver_disable(ucd_t drv, void* args); +ucd_t rt_usbh_class_driver_find(int class_code, int subclass_code); + +/* usb class driver implement */ +ucd_t rt_usbh_class_driver_hub(void); +ucd_t rt_usbh_class_driver_storage(void); + + + +/* usb hub interface */ +rt_err_t rt_usbh_hub_get_descriptor(struct uinstance* device, rt_uint8_t *buffer, + rt_size_t size); +rt_err_t rt_usbh_hub_get_status(struct uinstance* device, rt_uint32_t* buffer); +rt_err_t rt_usbh_hub_get_port_status(uhub_t uhub, rt_uint16_t port, + rt_uint32_t* buffer); +rt_err_t rt_usbh_hub_clear_port_feature(uhub_t uhub, rt_uint16_t port, + rt_uint16_t feature); +rt_err_t rt_usbh_hub_set_port_feature(uhub_t uhub, rt_uint16_t port, + rt_uint16_t feature); +rt_err_t rt_usbh_hub_reset_port(uhub_t uhub, rt_uint16_t port); +rt_err_t rt_usbh_event_signal(struct uhost_msg* msg); + + +void rt_usbh_root_hub_connect_handler(struct uhcd *hcd, rt_uint8_t port, rt_bool_t isHS); +void rt_usbh_root_hub_disconnect_handler(struct uhcd *hcd, rt_uint8_t port); + +/* usb host controller driver interface */ +rt_inline rt_err_t rt_usb_instance_add_pipe(uinst_t inst, upipe_t pipe) +{ + RT_ASSERT(inst != RT_NULL); + RT_ASSERT(pipe != RT_NULL); + rt_list_insert_before(&inst->pipe, &pipe->list); + return RT_EOK; +} +rt_inline upipe_t rt_usb_instance_find_pipe(uinst_t inst,rt_uint8_t ep_address) +{ + rt_list_t * l; + for(l = inst->pipe.next;l != &inst->pipe;l = l->next) + { + if(rt_list_entry(l,struct upipe,list)->ep.bEndpointAddress == ep_address) + { + return rt_list_entry(l,struct upipe,list); + } + } + return RT_NULL; +} +rt_inline rt_err_t rt_usb_hcd_alloc_pipe(uhcd_t hcd, upipe_t* pipe, uinst_t inst, uep_desc_t ep) +{ + *pipe = (upipe_t)rt_malloc(sizeof(struct upipe)); + if(*pipe == RT_NULL) + { + return RT_ERROR; + } + rt_memset(*pipe,0,sizeof(struct upipe)); + (*pipe)->inst = inst; + rt_memcpy(&(*pipe)->ep,ep,sizeof(struct uendpoint_descriptor)); + return hcd->ops->open_pipe(*pipe); +} +rt_inline void rt_usb_pipe_add_callback(upipe_t pipe, func_callback callback) +{ + pipe->callback = callback; +} + +rt_inline rt_err_t rt_usb_hcd_free_pipe(uhcd_t hcd, upipe_t pipe) +{ + RT_ASSERT(pipe != RT_NULL); + hcd->ops->close_pipe(pipe); + rt_free(pipe); + return RT_EOK; +} + +int rt_usb_hcd_pipe_xfer(uhcd_t hcd, upipe_t pipe, void* buffer, int nbytes, int timeout); +rt_inline int rt_usb_hcd_setup_xfer(uhcd_t hcd, upipe_t pipe, ureq_t setup, int timeout) +{ + return hcd->ops->pipe_xfer(pipe, USBH_PID_SETUP, (void *)setup, 8, timeout); +} + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/rt-thread/components/drivers/include/drivers/watchdog.h b/rt-thread/components/drivers/include/drivers/watchdog.h new file mode 100644 index 0000000..5c74dc8 --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/watchdog.h @@ -0,0 +1,56 @@ +/* + * File : watchdog.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012-2014, Shanghai Real-Thread Electronic Technology Co.,Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-09-12 heyuanjie87 first version. + */ + +#ifndef __WATCHDOG_H__ +#define __WATCHDOG_H__ + +#include + +#define RT_DEVICE_CTRL_WDT_GET_TIMEOUT (1) /* get timeout(in seconds) */ +#define RT_DEVICE_CTRL_WDT_SET_TIMEOUT (2) /* set timeout(in seconds) */ +#define RT_DEVICE_CTRL_WDT_GET_TIMELEFT (3) /* get the left time before reboot(in seconds) */ +#define RT_DEVICE_CTRL_WDT_KEEPALIVE (4) /* refresh watchdog */ +#define RT_DEVICE_CTRL_WDT_START (5) /* start watchdog */ +#define RT_DEVICE_CTRL_WDT_STOP (6) /* stop watchdog */ + +struct rt_watchdog_ops; +struct rt_watchdog_device +{ + struct rt_device parent; + const struct rt_watchdog_ops *ops; +}; +typedef struct rt_watchdog_device rt_watchdog_t; + +struct rt_watchdog_ops +{ + rt_err_t (*init)(rt_watchdog_t *wdt); + rt_err_t (*control)(rt_watchdog_t *wdt, int cmd, void *arg); +}; + +rt_err_t rt_hw_watchdog_register(rt_watchdog_t *wdt, + const char *name, + rt_uint32_t flag, + void *data); + +#endif /* __WATCHDOG_H__ */ diff --git a/rt-thread/components/drivers/include/drivers/wlan.h b/rt-thread/components/drivers/include/drivers/wlan.h new file mode 100644 index 0000000..724e61d --- /dev/null +++ b/rt-thread/components/drivers/include/drivers/wlan.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-09-15 tyx the first version + */ + +#ifndef __WLAN_H__ +#define __WLAN_H__ + +#include +#include +#include +#include +#include +#include + +#endif diff --git a/rt-thread/components/drivers/include/ipc/completion.h b/rt-thread/components/drivers/include/ipc/completion.h new file mode 100644 index 0000000..e3e883b --- /dev/null +++ b/rt-thread/components/drivers/include/ipc/completion.h @@ -0,0 +1,23 @@ +#ifndef COMPLETION_H_ +#define COMPLETION_H_ + +#include + +/** + * Completion + */ + +struct rt_completion +{ + rt_uint32_t flag; + + /* suspended list */ + rt_list_t suspended_list; +}; + +void rt_completion_init(struct rt_completion *completion); +rt_err_t rt_completion_wait(struct rt_completion *completion, + rt_int32_t timeout); +void rt_completion_done(struct rt_completion *completion); + +#endif diff --git a/rt-thread/components/drivers/include/ipc/dataqueue.h b/rt-thread/components/drivers/include/ipc/dataqueue.h new file mode 100644 index 0000000..44ffed6 --- /dev/null +++ b/rt-thread/components/drivers/include/ipc/dataqueue.h @@ -0,0 +1,53 @@ +#ifndef DATAQUEUE_H__ +#define DATAQUEUE_H__ + +#include + +#define RT_DATAQUEUE_EVENT_UNKNOWN 0x00 +#define RT_DATAQUEUE_EVENT_POP 0x01 +#define RT_DATAQUEUE_EVENT_PUSH 0x02 +#define RT_DATAQUEUE_EVENT_LWM 0x03 + +struct rt_data_item; +#define RT_DATAQUEUE_SIZE(dq) ((dq)->put_index - (dq)->get_index) +#define RT_DATAQUEUE_EMPTY(dq) ((dq)->size - RT_DATAQUEUE_SIZE(dq)) +/* data queue implementation */ +struct rt_data_queue +{ + rt_uint16_t size; + rt_uint16_t lwm; + rt_bool_t waiting_lwm; + + rt_uint16_t get_index; + rt_uint16_t put_index; + + struct rt_data_item *queue; + + rt_list_t suspended_push_list; + rt_list_t suspended_pop_list; + + /* event notify */ + void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event); +}; + +/** + * DataQueue for DeviceDriver + */ +rt_err_t rt_data_queue_init(struct rt_data_queue *queue, + rt_uint16_t size, + rt_uint16_t lwm, + void (*evt_notify)(struct rt_data_queue *queue, rt_uint32_t event)); +rt_err_t rt_data_queue_push(struct rt_data_queue *queue, + const void *data_ptr, + rt_size_t data_size, + rt_int32_t timeout); +rt_err_t rt_data_queue_pop(struct rt_data_queue *queue, + const void **data_ptr, + rt_size_t *size, + rt_int32_t timeout); +rt_err_t rt_data_queue_peak(struct rt_data_queue *queue, + const void **data_ptr, + rt_size_t *size); +void rt_data_queue_reset(struct rt_data_queue *queue); + +#endif diff --git a/rt-thread/components/drivers/include/ipc/pipe.h b/rt-thread/components/drivers/include/ipc/pipe.h new file mode 100644 index 0000000..ca20c2a --- /dev/null +++ b/rt-thread/components/drivers/include/ipc/pipe.h @@ -0,0 +1,36 @@ +#ifndef PIPE_H__ +#define PIPE_H__ + +/** + * Pipe Device + */ +#include +#include + +#ifndef RT_PIPE_BUFSZ +#define PIPE_BUFSZ 512 +#else +#define PIPE_BUFSZ RT_PIPE_BUFSZ +#endif + +struct rt_pipe_device +{ + struct rt_device parent; + + /* ring buffer in pipe device */ + struct rt_ringbuffer *fifo; + rt_uint16_t bufsz; + + rt_uint8_t readers; + rt_uint8_t writers; + + rt_wqueue_t reader_queue; + rt_wqueue_t writer_queue; + + struct rt_mutex lock; +}; +typedef struct rt_pipe_device rt_pipe_t; + +rt_pipe_t *rt_pipe_create(const char *name, int bufsz); +int rt_pipe_delete(const char *name); +#endif /* PIPE_H__ */ diff --git a/rt-thread/components/drivers/include/ipc/poll.h b/rt-thread/components/drivers/include/ipc/poll.h new file mode 100644 index 0000000..0279fe3 --- /dev/null +++ b/rt-thread/components/drivers/include/ipc/poll.h @@ -0,0 +1,53 @@ +/* + * File : poll.h + * This file is part of Device File System in RT-Thread RTOS + * COPYRIGHT (C) 2006-2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2016-09-19 Heyuanjie The first version. + * 2016-12-26 Bernard Update poll interface + */ +#ifndef IPC_POLL_H__ +#define IPC_POLL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct rt_pollreq; +typedef void (*poll_queue_proc)(rt_wqueue_t *, struct rt_pollreq *); + +typedef struct rt_pollreq +{ + poll_queue_proc _proc; + short _key; +} rt_pollreq_t; + +rt_inline void rt_poll_add(rt_wqueue_t *wq, rt_pollreq_t *req) +{ + if (req && req->_proc && wq) + { + req->_proc(wq, req); + } +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/ipc/ringblk_buf.h b/rt-thread/components/drivers/include/ipc/ringblk_buf.h new file mode 100644 index 0000000..26ffbdb --- /dev/null +++ b/rt-thread/components/drivers/include/ipc/ringblk_buf.h @@ -0,0 +1,115 @@ +/* + * File : ringblk_buf.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2018-08-25 armink the first version + */ + +#ifndef _RINGBLK_BUF_H_ +#define _RINGBLK_BUF_H_ + +/* + * Introduction: + * The rbb is the ring buffer which is composed with many blocks. It is different from the ring buffer. + * The ring buffer is only composed with chars. The rbb put and get supported zero copies. So the rbb + * is very suitable for put block and get block by a certain order. Such as DMA block transmit, + * communicate frame send/recv, and so on. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +enum rt_rbb_status +{ + /* unused status when first initialize or after blk_free() */ + RT_RBB_BLK_UNUSED, + /* initialized status after blk_alloc() */ + RT_RBB_BLK_INITED, + /* put status after blk_put() */ + RT_RBB_BLK_PUT, + /* get status after blk_get() */ + RT_RBB_BLK_GET, +}; +typedef enum rt_rbb_status rt_rbb_status_t; + +/** + * the block of rbb + */ +struct rt_rbb_blk +{ + rt_rbb_status_t status :8; + /* less then 2^24 */ + rt_size_t size :24; + rt_uint8_t *buf; + rt_slist_t list; +}; +typedef struct rt_rbb_blk *rt_rbb_blk_t; + +/** + * Rbb block queue: the blocks (from block1->buf to blockn->buf) memory which on this queue is continuous. + */ +struct rt_rbb_blk_queue +{ + rt_rbb_blk_t blocks; + rt_size_t blk_num; +}; +typedef struct rt_rbb_blk_queue *rt_rbb_blk_queue_t; + +/** + * ring block buffer + */ +struct rt_rbb +{ + rt_uint8_t *buf; + rt_size_t buf_size; + /* all of blocks */ + rt_rbb_blk_t blk_set; + rt_size_t blk_max_num; + /* saved the initialized and put status blocks */ + rt_slist_t blk_list; +}; +typedef struct rt_rbb *rt_rbb_t; + +/* rbb (ring block buffer) API */ +void rt_rbb_init(rt_rbb_t rbb, rt_uint8_t *buf, rt_size_t buf_size, rt_rbb_blk_t block_set, rt_size_t blk_max_num); +rt_rbb_t rt_rbb_create(rt_size_t buf_size, rt_size_t blk_max_num); +void rt_rbb_destroy(rt_rbb_t rbb); +rt_size_t rt_rbb_get_buf_size(rt_rbb_t rbb); + +/* rbb block API */ +rt_rbb_blk_t rt_rbb_blk_alloc(rt_rbb_t rbb, rt_size_t blk_size); +void rt_rbb_blk_put(rt_rbb_blk_t block); +rt_rbb_blk_t rt_rbb_blk_get(rt_rbb_t rbb); +void rt_rbb_blk_free(rt_rbb_t rbb, rt_rbb_blk_t block); + +/* rbb block queue API */ +rt_size_t rt_rbb_blk_queue_get(rt_rbb_t rbb, rt_size_t queue_data_len, rt_rbb_blk_queue_t blk_queue); +rt_size_t rt_rbb_blk_queue_len(rt_rbb_blk_queue_t blk_queue); +rt_uint8_t *rt_rbb_blk_queue_buf(rt_rbb_blk_queue_t blk_queue); +void rt_rbb_blk_queue_free(rt_rbb_t rbb, rt_rbb_blk_queue_t blk_queue); +rt_size_t rt_rbb_next_blk_queue_len(rt_rbb_t rbb); + + +#ifdef __cplusplus +} +#endif + +#endif /* _RINGBLK_BUF_H_ */ diff --git a/rt-thread/components/drivers/include/ipc/ringbuffer.h b/rt-thread/components/drivers/include/ipc/ringbuffer.h new file mode 100644 index 0000000..4cfab6d --- /dev/null +++ b/rt-thread/components/drivers/include/ipc/ringbuffer.h @@ -0,0 +1,88 @@ +#ifndef RINGBUFFER_H__ +#define RINGBUFFER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* ring buffer */ +struct rt_ringbuffer +{ + rt_uint8_t *buffer_ptr; + /* use the msb of the {read,write}_index as mirror bit. You can see this as + * if the buffer adds a virtual mirror and the pointers point either to the + * normal or to the mirrored buffer. If the write_index has the same value + * with the read_index, but in a different mirror, the buffer is full. + * While if the write_index and the read_index are the same and within the + * same mirror, the buffer is empty. The ASCII art of the ringbuffer is: + * + * mirror = 0 mirror = 1 + * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+ + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Full + * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+ + * read_idx-^ write_idx-^ + * + * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+ + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 ||| 0 | 1 | 2 | 3 | 4 | 5 | 6 | Empty + * +---+---+---+---+---+---+---+|+~~~+~~~+~~~+~~~+~~~+~~~+~~~+ + * read_idx-^ ^-write_idx + * + * The tradeoff is we could only use 32KiB of buffer for 16 bit of index. + * But it should be enough for most of the cases. + * + * Ref: http://en.wikipedia.org/wiki/Circular_buffer#Mirroring */ + rt_uint16_t read_mirror : 1; + rt_uint16_t read_index : 15; + rt_uint16_t write_mirror : 1; + rt_uint16_t write_index : 15; + /* as we use msb of index as mirror bit, the size should be signed and + * could only be positive. */ + rt_int16_t buffer_size; +}; + +enum rt_ringbuffer_state +{ + RT_RINGBUFFER_EMPTY, + RT_RINGBUFFER_FULL, + /* half full is neither full nor empty */ + RT_RINGBUFFER_HALFFULL, +}; + +/** + * RingBuffer for DeviceDriver + * + * Please note that the ring buffer implementation of RT-Thread + * has no thread wait or resume feature. + */ +void rt_ringbuffer_init(struct rt_ringbuffer *rb, rt_uint8_t *pool, rt_int16_t size); +void rt_ringbuffer_reset(struct rt_ringbuffer *rb); +rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length); +rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb, const rt_uint8_t *ptr, rt_uint16_t length); +rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch); +rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch); +rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb, rt_uint8_t *ptr, rt_uint16_t length); +rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch); +rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb); + +#ifdef RT_USING_HEAP +struct rt_ringbuffer* rt_ringbuffer_create(rt_uint16_t length); +void rt_ringbuffer_destroy(struct rt_ringbuffer *rb); +#endif + +rt_inline rt_uint16_t rt_ringbuffer_get_size(struct rt_ringbuffer *rb) +{ + RT_ASSERT(rb != RT_NULL); + return rb->buffer_size; +} + +/** return the size of empty space in rb */ +#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb)) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/drivers/include/ipc/waitqueue.h b/rt-thread/components/drivers/include/ipc/waitqueue.h new file mode 100644 index 0000000..8cb0989 --- /dev/null +++ b/rt-thread/components/drivers/include/ipc/waitqueue.h @@ -0,0 +1,73 @@ +/* + * File : waitqueue.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2018/06/26 Bernard Fix the wait queue issue when wakeup a soon + * to blocked thread. + */ + +#ifndef WAITQUEUE_H__ +#define WAITQUEUE_H__ + +#include + +#define RT_WQ_FLAG_CLEAN 0x00 +#define RT_WQ_FLAG_WAKEUP 0x01 + +struct rt_wqueue_node; +typedef int (*rt_wqueue_func_t)(struct rt_wqueue_node *wait, void *key); + +struct rt_wqueue_node +{ + rt_thread_t polling_thread; + rt_list_t list; + + rt_wqueue_func_t wakeup; + rt_uint32_t key; +}; +typedef struct rt_wqueue_node rt_wqueue_node_t; + +int __wqueue_default_wake(struct rt_wqueue_node *wait, void *key); + +rt_inline void rt_wqueue_init(rt_wqueue_t *queue) +{ + RT_ASSERT(queue != RT_NULL); + + queue->flag = RT_WQ_FLAG_CLEAN; + rt_list_init(&(queue->waiting_list)); +} + +void rt_wqueue_add(rt_wqueue_t *queue, struct rt_wqueue_node *node); +void rt_wqueue_remove(struct rt_wqueue_node *node); +int rt_wqueue_wait(rt_wqueue_t *queue, int condition, int timeout); +void rt_wqueue_wakeup(rt_wqueue_t *queue, void *key); + +#define DEFINE_WAIT_FUNC(name, function) \ + struct rt_wqueue_node name = { \ + rt_current_thread, \ + RT_LIST_OBJECT_INIT(((name).list)), \ + \ + function, \ + 0 \ + } + +#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, __wqueue_default_wake) + +#endif diff --git a/rt-thread/components/drivers/include/ipc/workqueue.h b/rt-thread/components/drivers/include/ipc/workqueue.h new file mode 100644 index 0000000..0b044b5 --- /dev/null +++ b/rt-thread/components/drivers/include/ipc/workqueue.h @@ -0,0 +1,44 @@ +#ifndef WORKQUEUE_H__ +#define WORKQUEUE_H__ + +#include + +/* workqueue implementation */ +struct rt_workqueue +{ + rt_list_t work_list; + struct rt_work *work_current; /* current work */ + + struct rt_semaphore sem; + rt_thread_t work_thread; +}; + +struct rt_work +{ + rt_list_t list; + + void (*work_func)(struct rt_work* work, void* work_data); + void *work_data; +}; + +#ifdef RT_USING_HEAP +/** + * WorkQueue for DeviceDriver + */ +struct rt_workqueue *rt_workqueue_create(const char* name, rt_uint16_t stack_size, rt_uint8_t priority); +rt_err_t rt_workqueue_destroy(struct rt_workqueue* queue); +rt_err_t rt_workqueue_dowork(struct rt_workqueue* queue, struct rt_work* work); +rt_err_t rt_workqueue_cancel_work(struct rt_workqueue* queue, struct rt_work* work); +rt_err_t rt_workqueue_cancel_work_sync(struct rt_workqueue* queue, struct rt_work* work); + +rt_inline void rt_work_init(struct rt_work* work, void (*work_func)(struct rt_work* work, void* work_data), + void* work_data) +{ + rt_list_init(&(work->list)); + work->work_func = work_func; + work->work_data = work_data; +} +#endif + +#endif + diff --git a/rt-thread/components/drivers/include/rtdevice.h b/rt-thread/components/drivers/include/rtdevice.h new file mode 100644 index 0000000..e0499dc --- /dev/null +++ b/rt-thread/components/drivers/include/rtdevice.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2012-01-08 bernard first version. + * 2014-07-12 bernard Add workqueue implementation. + */ + +#ifndef __RT_DEVICE_H__ +#define __RT_DEVICE_H__ + +#include + +#include "ipc/ringbuffer.h" +#include "ipc/completion.h" +#include "ipc/dataqueue.h" +#include "ipc/workqueue.h" +#include "ipc/waitqueue.h" +#include "ipc/pipe.h" +#include "ipc/poll.h" +#include "ipc/ringblk_buf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define RT_DEVICE(device) ((rt_device_t)device) + +#ifdef RT_USING_RTC +#include "drivers/rtc.h" +#ifdef RT_USING_ALARM +#include "drivers/alarm.h" +#endif +#endif /* RT_USING_RTC */ + +#ifdef RT_USING_SPI +#include "drivers/spi.h" +#endif /* RT_USING_SPI */ + +#ifdef RT_USING_MTD_NOR +#include "drivers/mtd_nor.h" +#endif /* RT_USING_MTD_NOR */ + +#ifdef RT_USING_MTD_NAND +#include "drivers/mtd_nand.h" +#endif /* RT_USING_MTD_NAND */ + +#ifdef RT_USING_USB_DEVICE +#include "drivers/usb_device.h" +#endif /* RT_USING_USB_DEVICE */ + +#ifdef RT_USING_USB_HOST +#include "drivers/usb_host.h" +#endif /* RT_USING_USB_HOST */ + +#ifdef RT_USING_SERIAL +#include "drivers/serial.h" +#endif /* RT_USING_SERIAL */ + +#ifdef RT_USING_I2C +#include "drivers/i2c.h" +#include "drivers/i2c_dev.h" + +#ifdef RT_USING_I2C_BITOPS +#include "drivers/i2c-bit-ops.h" +#endif /* RT_USING_I2C_BITOPS */ +#endif /* RT_USING_I2C */ + +#ifdef RT_USING_SDIO +#include "drivers/mmcsd_core.h" +#include "drivers/sd.h" +#include "drivers/sdio.h" +#endif + +#ifdef RT_USING_WDT +#include "drivers/watchdog.h" +#endif + +#ifdef RT_USING_PIN +#include "drivers/pin.h" +#endif + +#ifdef RT_USING_CAN +#include "drivers/can.h" +#endif + +#ifdef RT_USING_HWTIMER +#include "drivers/hwtimer.h" +#endif + +#ifdef RT_USING_AUDIO +#include "drivers/audio.h" +#endif + +#ifdef RT_USING_CPUTIME +#include "drivers/cputime.h" +#endif + +#ifdef RT_USING_PWM +#include "drivers/rt_drv_pwm.h" +#endif + +#ifdef RT_USING_WIFI +#include "drivers/wlan.h" +#endif + +#ifdef MTD_USING_NOR +#include "drivers/mtdnor.h" +#endif +#ifdef MTD_USING_NAND +#include "drivers/mtdnand.h" +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __RT_DEVICE_H__ */ diff --git a/rt-thread/components/drivers/serial/SConscript b/rt-thread/components/drivers/serial/SConscript new file mode 100644 index 0000000..a6eb115 --- /dev/null +++ b/rt-thread/components/drivers/serial/SConscript @@ -0,0 +1,8 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd + '/../include'] +group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SERIAL'], CPPPATH = CPPPATH) + +Return('group') diff --git a/rt-thread/components/drivers/serial/serial.c b/rt-thread/components/drivers/serial/serial.c new file mode 100644 index 0000000..856e33e --- /dev/null +++ b/rt-thread/components/drivers/serial/serial.c @@ -0,0 +1,1265 @@ +/* + * File : serial.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2006-03-13 bernard first version + * 2012-05-15 lgnq modified according bernard's implementation. + * 2012-05-28 bernard code cleanup + * 2012-11-23 bernard fix compiler warning. + * 2013-02-20 bernard use RT_SERIAL_RB_BUFSZ to define + * the size of ring buffer. + * 2014-07-10 bernard rewrite serial framework + * 2014-12-31 bernard use open_flag for poll_tx stream mode. + * 2015-05-19 Quintin fix DMA tx mod tx_dma->activated flag !=RT_FALSE BUG + * in open function. + * 2015-11-10 bernard fix the poll rx issue when there is no data. + * 2016-05-10 armink add fifo mode to DMA rx when serial->config.bufsz != 0. + * 2017-01-19 aubr.cool prevent change serial rx bufsz when serial is opened. + * 2017-11-07 JasonJia fix data bits error issue when using tcsetattr. + * 2017-11-15 JasonJia fix poll rx issue when data is full. + * add TCFLSH and FIONREAD support. + */ + +#include +#include +#include + +// #define DEBUG_ENABLE +#define DEBUG_LEVEL DBG_LOG +#define DBG_SECTION_NAME "UART" +#define DEBUG_COLOR +#include + +#ifdef RT_USING_POSIX +#include +#include + +#ifdef RT_USING_POSIX_TERMIOS +#include +#endif + +/* it's possible the 'getc/putc' is defined by stdio.h in gcc/newlib. */ +#ifdef getc +#undef getc +#endif + +#ifdef putc +#undef putc +#endif + +static rt_err_t serial_fops_rx_ind(rt_device_t dev, rt_size_t size) +{ + rt_wqueue_wakeup(&(dev->wait_queue), (void*)POLLIN); + + return RT_EOK; +} + +/* fops for serial */ +static int serial_fops_open(struct dfs_fd *fd) +{ + rt_err_t ret = 0; + rt_uint16_t flags = 0; + rt_device_t device; + + device = (rt_device_t)fd->data; + RT_ASSERT(device != RT_NULL); + + switch (fd->flags & O_ACCMODE) + { + case O_RDONLY: + dbg_log(DBG_LOG, "fops open: O_RDONLY!\n"); + flags = RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_RDONLY; + break; + case O_WRONLY: + dbg_log(DBG_LOG, "fops open: O_WRONLY!\n"); + flags = RT_DEVICE_FLAG_WRONLY; + break; + case O_RDWR: + dbg_log(DBG_LOG, "fops open: O_RDWR!\n"); + flags = RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_RDWR; + break; + default: + dbg_log(DBG_ERROR, "fops open: unknown mode - %d!\n", fd->flags & O_ACCMODE); + break; + } + + if ((fd->flags & O_ACCMODE) != O_WRONLY) + rt_device_set_rx_indicate(device, serial_fops_rx_ind); + ret = rt_device_open(device, flags); + if (ret == RT_EOK) return 0; + + return ret; +} + +static int serial_fops_close(struct dfs_fd *fd) +{ + rt_device_t device; + + device = (rt_device_t)fd->data; + + rt_device_set_rx_indicate(device, RT_NULL); + rt_device_close(device); + + return 0; +} + +static int serial_fops_ioctl(struct dfs_fd *fd, int cmd, void *args) +{ + rt_device_t device; + + device = (rt_device_t)fd->data; + switch (cmd) + { + case FIONREAD: + break; + case FIONWRITE: + break; + } + + return rt_device_control(device, cmd, args); +} + +static int serial_fops_read(struct dfs_fd *fd, void *buf, size_t count) +{ + int size = 0; + rt_device_t device; + + device = (rt_device_t)fd->data; + + do + { + size = rt_device_read(device, -1, buf, count); + if (size <= 0) + { + if (fd->flags & O_NONBLOCK) + { + size = -EAGAIN; + break; + } + + rt_wqueue_wait(&(device->wait_queue), 0, RT_WAITING_FOREVER); + } + }while (size <= 0); + + return size; +} + +static int serial_fops_write(struct dfs_fd *fd, const void *buf, size_t count) +{ + rt_device_t device; + + device = (rt_device_t)fd->data; + return rt_device_write(device, -1, buf, count); +} + +static int serial_fops_poll(struct dfs_fd *fd, struct rt_pollreq *req) +{ + int mask = 0; + int flags = 0; + rt_device_t device; + struct rt_serial_device *serial; + + device = (rt_device_t)fd->data; + RT_ASSERT(device != RT_NULL); + + serial = (struct rt_serial_device *)device; + + /* only support POLLIN */ + flags = fd->flags & O_ACCMODE; + if (flags == O_RDONLY || flags == O_RDWR) + { + rt_base_t level; + struct rt_serial_rx_fifo* rx_fifo; + + rt_poll_add(&(device->wait_queue), req); + + rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx; + + level = rt_hw_interrupt_disable(); + if ((rx_fifo->get_index != rx_fifo->put_index) || (rx_fifo->get_index == rx_fifo->put_index && rx_fifo->is_full == RT_TRUE)) + mask |= POLLIN; + rt_hw_interrupt_enable(level); + } + + return mask; +} + +const static struct dfs_file_ops _serial_fops = +{ + serial_fops_open, + serial_fops_close, + serial_fops_ioctl, + serial_fops_read, + serial_fops_write, + RT_NULL, /* flush */ + RT_NULL, /* lseek */ + RT_NULL, /* getdents */ + serial_fops_poll, +}; +#endif + +/* + * Serial poll routines + */ +rt_inline int _serial_poll_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length) +{ + int ch; + int size; + + RT_ASSERT(serial != RT_NULL); + size = length; + + while (length) + { + ch = serial->ops->getc(serial); + if (ch == -1) break; + + *data = ch; + data ++; length --; + + if (ch == '\n') break; + } + + return size - length; +} + +rt_inline int _serial_poll_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length) +{ + int size; + RT_ASSERT(serial != RT_NULL); + + size = length; + while (length) + { + /* + * to be polite with serial console add a line feed + * to the carriage return character + */ + if (*data == '\n' && (serial->parent.open_flag & RT_DEVICE_FLAG_STREAM)) + { + serial->ops->putc(serial, '\r'); + } + + serial->ops->putc(serial, *data); + + ++ data; + -- length; + } + + return size - length; +} + +/* + * Serial interrupt routines + */ +rt_inline int _serial_int_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length) +{ + int size; + struct rt_serial_rx_fifo* rx_fifo; + + RT_ASSERT(serial != RT_NULL); + size = length; + + rx_fifo = (struct rt_serial_rx_fifo*) serial->serial_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + /* read from software FIFO */ + while (length) + { + int ch; + rt_base_t level; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* there's no data: */ + if ((rx_fifo->get_index == rx_fifo->put_index) && (rx_fifo->is_full == RT_FALSE)) + { + /* no data, enable interrupt and break out */ + rt_hw_interrupt_enable(level); + break; + } + + /* otherwise there's the data: */ + ch = rx_fifo->buffer[rx_fifo->get_index]; + rx_fifo->get_index += 1; + if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0; + + if (rx_fifo->is_full == RT_TRUE) + { + rx_fifo->is_full = RT_FALSE; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + *data = ch & 0xff; + data ++; length --; + } + + return size - length; +} + +rt_inline int _serial_int_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length) +{ + int size; + struct rt_serial_tx_fifo *tx; + + RT_ASSERT(serial != RT_NULL); + + size = length; + tx = (struct rt_serial_tx_fifo*) serial->serial_tx; + RT_ASSERT(tx != RT_NULL); + + while (length) + { + if (serial->ops->putc(serial, *(char*)data) == -1) + { + rt_completion_wait(&(tx->completion), RT_WAITING_FOREVER); + continue; + } + + data ++; length --; + } + + return size - length; +} + +static rt_size_t _serial_fifo_calc_recved_len(struct rt_serial_device *serial) +{ + struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; + + RT_ASSERT(rx_fifo != RT_NULL); + + if (rx_fifo->put_index == rx_fifo->get_index) + { + return (rx_fifo->is_full == RT_FALSE ? 0 : serial->config.bufsz); + } + else + { + if (rx_fifo->put_index > rx_fifo->get_index) + { + return rx_fifo->put_index - rx_fifo->get_index; + } + else + { + return serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index); + } + } +} + +/** + * Calculate DMA received data length. + * + * @param serial serial device + * + * @return length + */ +static rt_size_t rt_dma_calc_recved_len(struct rt_serial_device *serial) +{ + return _serial_fifo_calc_recved_len(serial); +} + +/** + * Read data finish by DMA mode then update the get index for receive fifo. + * + * @param serial serial device + * @param len get data length for this operate + */ +static void rt_dma_recv_update_get_index(struct rt_serial_device *serial, rt_size_t len) +{ + struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; + + RT_ASSERT(rx_fifo != RT_NULL); + RT_ASSERT(len <= rt_dma_calc_recved_len(serial)); + + if (rx_fifo->is_full && len != 0) rx_fifo->is_full = RT_FALSE; + + rx_fifo->get_index += len; + if (rx_fifo->get_index >= serial->config.bufsz) + { + rx_fifo->get_index %= serial->config.bufsz; + } +} + +/** + * DMA received finish then update put index for receive fifo. + * + * @param serial serial device + * @param len received length for this transmit + */ +static void rt_dma_recv_update_put_index(struct rt_serial_device *serial, rt_size_t len) +{ + struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx; + + RT_ASSERT(rx_fifo != RT_NULL); + + if (rx_fifo->get_index <= rx_fifo->put_index) + { + rx_fifo->put_index += len; + /* beyond the fifo end */ + if (rx_fifo->put_index >= serial->config.bufsz) + { + rx_fifo->put_index %= serial->config.bufsz; + /* force overwrite get index */ + if (rx_fifo->put_index >= rx_fifo->get_index) + { + rx_fifo->is_full = RT_TRUE; + } + } + } + else + { + rx_fifo->put_index += len; + if (rx_fifo->put_index >= rx_fifo->get_index) + { + /* beyond the fifo end */ + if (rx_fifo->put_index >= serial->config.bufsz) + { + rx_fifo->put_index %= serial->config.bufsz; + } + /* force overwrite get index */ + rx_fifo->is_full = RT_TRUE; + } + } + + if(rx_fifo->is_full == RT_TRUE) + { + rx_fifo->get_index = rx_fifo->put_index; + } + + if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0; +} + +/* + * Serial DMA routines + */ +rt_inline int _serial_dma_rx(struct rt_serial_device *serial, rt_uint8_t *data, int length) +{ + rt_base_t level; + + RT_ASSERT((serial != RT_NULL) && (data != RT_NULL)); + + level = rt_hw_interrupt_disable(); + + if (serial->config.bufsz == 0) + { + int result = RT_EOK; + struct rt_serial_rx_dma *rx_dma; + + rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx; + RT_ASSERT(rx_dma != RT_NULL); + + if (rx_dma->activated != RT_TRUE) + { + rx_dma->activated = RT_TRUE; + RT_ASSERT(serial->ops->dma_transmit != RT_NULL); + serial->ops->dma_transmit(serial, data, length, RT_SERIAL_DMA_RX); + } + else result = -RT_EBUSY; + rt_hw_interrupt_enable(level); + + if (result == RT_EOK) return length; + + rt_set_errno(result); + return 0; + } + else + { + struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; + rt_size_t recv_len = 0, fifo_recved_len = rt_dma_calc_recved_len(serial); + + RT_ASSERT(rx_fifo != RT_NULL); + + if (length < fifo_recved_len) + recv_len = length; + else + recv_len = fifo_recved_len; + + if (rx_fifo->get_index + recv_len < serial->config.bufsz) + rt_memcpy(data, rx_fifo->buffer + rx_fifo->get_index, recv_len); + else + { + rt_memcpy(data, rx_fifo->buffer + rx_fifo->get_index, + serial->config.bufsz - rx_fifo->get_index); + rt_memcpy(data + serial->config.bufsz - rx_fifo->get_index, rx_fifo->buffer, + recv_len + rx_fifo->get_index - serial->config.bufsz); + } + rt_dma_recv_update_get_index(serial, recv_len); + rt_hw_interrupt_enable(level); + return recv_len; + } +} + +rt_inline int _serial_dma_tx(struct rt_serial_device *serial, const rt_uint8_t *data, int length) +{ + rt_base_t level; + rt_err_t result; + struct rt_serial_tx_dma *tx_dma; + + tx_dma = (struct rt_serial_tx_dma*)(serial->serial_tx); + + result = rt_data_queue_push(&(tx_dma->data_queue), data, length, RT_WAITING_FOREVER); + if (result == RT_EOK) + { + level = rt_hw_interrupt_disable(); + if (tx_dma->activated != RT_TRUE) + { + tx_dma->activated = RT_TRUE; + rt_hw_interrupt_enable(level); + + /* make a DMA transfer */ + serial->ops->dma_transmit(serial, (rt_uint8_t *)data, length, RT_SERIAL_DMA_TX); + } + else + { + rt_hw_interrupt_enable(level); + } + + return length; + } + else + { + rt_set_errno(result); + return 0; + } +} + +/* RT-Thread Device Interface */ +/* + * This function initializes serial device. + */ +static rt_err_t rt_serial_init(struct rt_device *dev) +{ + rt_err_t result = RT_EOK; + struct rt_serial_device *serial; + + RT_ASSERT(dev != RT_NULL); + serial = (struct rt_serial_device *)dev; + + /* initialize rx/tx */ + serial->serial_rx = RT_NULL; + serial->serial_tx = RT_NULL; + + /* apply configuration */ + if (serial->ops->configure) + result = serial->ops->configure(serial, &serial->config); + + return result; +} + +static rt_err_t rt_serial_open(struct rt_device *dev, rt_uint16_t oflag) +{ + rt_uint16_t stream_flag = 0; + struct rt_serial_device *serial; + + RT_ASSERT(dev != RT_NULL); + serial = (struct rt_serial_device *)dev; + + dbg_log(DBG_LOG, "open serial device: 0x%08x with open flag: 0x%04x\n", + dev, oflag); + /* check device flag with the open flag */ + if ((oflag & RT_DEVICE_FLAG_DMA_RX) && !(dev->flag & RT_DEVICE_FLAG_DMA_RX)) + return -RT_EIO; + if ((oflag & RT_DEVICE_FLAG_DMA_TX) && !(dev->flag & RT_DEVICE_FLAG_DMA_TX)) + return -RT_EIO; + if ((oflag & RT_DEVICE_FLAG_INT_RX) && !(dev->flag & RT_DEVICE_FLAG_INT_RX)) + return -RT_EIO; + if ((oflag & RT_DEVICE_FLAG_INT_TX) && !(dev->flag & RT_DEVICE_FLAG_INT_TX)) + return -RT_EIO; + + /* keep steam flag */ + if ((oflag & RT_DEVICE_FLAG_STREAM) || (dev->open_flag & RT_DEVICE_FLAG_STREAM)) + stream_flag = RT_DEVICE_FLAG_STREAM; + + /* get open flags */ + dev->open_flag = oflag & 0xff; + + /* initialize the Rx/Tx structure according to open flag */ + if (serial->serial_rx == RT_NULL) + { + if (oflag & RT_DEVICE_FLAG_DMA_RX) + { + if (serial->config.bufsz == 0) { + struct rt_serial_rx_dma* rx_dma; + + rx_dma = (struct rt_serial_rx_dma*) rt_malloc (sizeof(struct rt_serial_rx_dma)); + RT_ASSERT(rx_dma != RT_NULL); + rx_dma->activated = RT_FALSE; + + serial->serial_rx = rx_dma; + } else { + struct rt_serial_rx_fifo* rx_fifo; + + rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) + + serial->config.bufsz); + RT_ASSERT(rx_fifo != RT_NULL); + rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1); + rt_memset(rx_fifo->buffer, 0, serial->config.bufsz); + rx_fifo->put_index = 0; + rx_fifo->get_index = 0; + rx_fifo->is_full = RT_FALSE; + serial->serial_rx = rx_fifo; + /* configure fifo address and length to low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_CONFIG, (void *) RT_DEVICE_FLAG_DMA_RX); + } + dev->open_flag |= RT_DEVICE_FLAG_DMA_RX; + } + else if (oflag & RT_DEVICE_FLAG_INT_RX) + { + struct rt_serial_rx_fifo* rx_fifo; + + rx_fifo = (struct rt_serial_rx_fifo*) rt_malloc (sizeof(struct rt_serial_rx_fifo) + + serial->config.bufsz); + RT_ASSERT(rx_fifo != RT_NULL); + rx_fifo->buffer = (rt_uint8_t*) (rx_fifo + 1); + rt_memset(rx_fifo->buffer, 0, serial->config.bufsz); + rx_fifo->put_index = 0; + rx_fifo->get_index = 0; + rx_fifo->is_full = RT_FALSE; + + serial->serial_rx = rx_fifo; + dev->open_flag |= RT_DEVICE_FLAG_INT_RX; + /* configure low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_RX); + } + else + { + serial->serial_rx = RT_NULL; + } + } + else + { + if (oflag & RT_DEVICE_FLAG_DMA_RX) + dev->open_flag |= RT_DEVICE_FLAG_DMA_RX; + else if (oflag & RT_DEVICE_FLAG_INT_RX) + dev->open_flag |= RT_DEVICE_FLAG_INT_RX; + } + + if (serial->serial_tx == RT_NULL) + { + if (oflag & RT_DEVICE_FLAG_DMA_TX) + { + struct rt_serial_tx_dma* tx_dma; + + tx_dma = (struct rt_serial_tx_dma*) rt_malloc (sizeof(struct rt_serial_tx_dma)); + RT_ASSERT(tx_dma != RT_NULL); + tx_dma->activated = RT_FALSE; + + rt_data_queue_init(&(tx_dma->data_queue), 8, 4, RT_NULL); + serial->serial_tx = tx_dma; + + dev->open_flag |= RT_DEVICE_FLAG_DMA_TX; + } + else if (oflag & RT_DEVICE_FLAG_INT_TX) + { + struct rt_serial_tx_fifo *tx_fifo; + + tx_fifo = (struct rt_serial_tx_fifo*) rt_malloc(sizeof(struct rt_serial_tx_fifo)); + RT_ASSERT(tx_fifo != RT_NULL); + + rt_completion_init(&(tx_fifo->completion)); + serial->serial_tx = tx_fifo; + + dev->open_flag |= RT_DEVICE_FLAG_INT_TX; + /* configure low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_SET_INT, (void *)RT_DEVICE_FLAG_INT_TX); + } + else + { + serial->serial_tx = RT_NULL; + } + } + else + { + if (oflag & RT_DEVICE_FLAG_DMA_TX) + dev->open_flag |= RT_DEVICE_FLAG_DMA_TX; + else if (oflag & RT_DEVICE_FLAG_INT_TX) + dev->open_flag |= RT_DEVICE_FLAG_INT_TX; + } + + /* set stream flag */ + dev->open_flag |= stream_flag; + + return RT_EOK; +} + +static rt_err_t rt_serial_close(struct rt_device *dev) +{ + struct rt_serial_device *serial; + + RT_ASSERT(dev != RT_NULL); + serial = (struct rt_serial_device *)dev; + + /* this device has more reference count */ + if (dev->ref_count > 1) return RT_EOK; + + if (dev->open_flag & RT_DEVICE_FLAG_INT_RX) + { + struct rt_serial_rx_fifo* rx_fifo; + + rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + rt_free(rx_fifo); + serial->serial_rx = RT_NULL; + dev->open_flag &= ~RT_DEVICE_FLAG_INT_RX; + /* configure low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_RX); + } + else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX) + { + if (serial->config.bufsz == 0) { + struct rt_serial_rx_dma* rx_dma; + + rx_dma = (struct rt_serial_rx_dma*)serial->serial_rx; + RT_ASSERT(rx_dma != RT_NULL); + + rt_free(rx_dma); + } else { + struct rt_serial_rx_fifo* rx_fifo; + + rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + rt_free(rx_fifo); + } + /* configure low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void *) RT_DEVICE_FLAG_DMA_RX); + serial->serial_rx = RT_NULL; + dev->open_flag &= ~RT_DEVICE_FLAG_DMA_RX; + } + + if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) + { + struct rt_serial_tx_fifo* tx_fifo; + + tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx; + RT_ASSERT(tx_fifo != RT_NULL); + + rt_free(tx_fifo); + serial->serial_tx = RT_NULL; + dev->open_flag &= ~RT_DEVICE_FLAG_INT_TX; + /* configure low level device */ + serial->ops->control(serial, RT_DEVICE_CTRL_CLR_INT, (void*)RT_DEVICE_FLAG_INT_TX); + } + else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX) + { + struct rt_serial_tx_dma* tx_dma; + + tx_dma = (struct rt_serial_tx_dma*)serial->serial_tx; + RT_ASSERT(tx_dma != RT_NULL); + + rt_free(tx_dma); + serial->serial_tx = RT_NULL; + dev->open_flag &= ~RT_DEVICE_FLAG_DMA_TX; + } + + return RT_EOK; +} + +static rt_size_t rt_serial_read(struct rt_device *dev, + rt_off_t pos, + void *buffer, + rt_size_t size) +{ + struct rt_serial_device *serial; + + RT_ASSERT(dev != RT_NULL); + if (size == 0) return 0; + + serial = (struct rt_serial_device *)dev; + + if (dev->open_flag & RT_DEVICE_FLAG_INT_RX) + { + return _serial_int_rx(serial, buffer, size); + } + else if (dev->open_flag & RT_DEVICE_FLAG_DMA_RX) + { + return _serial_dma_rx(serial, buffer, size); + } + + return _serial_poll_rx(serial, buffer, size); +} + +static rt_size_t rt_serial_write(struct rt_device *dev, + rt_off_t pos, + const void *buffer, + rt_size_t size) +{ + struct rt_serial_device *serial; + + RT_ASSERT(dev != RT_NULL); + if (size == 0) return 0; + + serial = (struct rt_serial_device *)dev; + + if (dev->open_flag & RT_DEVICE_FLAG_INT_TX) + { + return _serial_int_tx(serial, buffer, size); + } + else if (dev->open_flag & RT_DEVICE_FLAG_DMA_TX) + { + return _serial_dma_tx(serial, buffer, size); + } + else + { + return _serial_poll_tx(serial, buffer, size); + } +} + +#ifdef RT_USING_POSIX_TERMIOS +struct speed_baudrate_item +{ + speed_t speed; + int baudrate; +}; + +const static struct speed_baudrate_item _tbl[] = +{ + {B2400, BAUD_RATE_2400}, + {B4800, BAUD_RATE_4800}, + {B9600, BAUD_RATE_9600}, + {B19200, BAUD_RATE_19200}, + {B38400, BAUD_RATE_38400}, + {B57600, BAUD_RATE_57600}, + {B115200, BAUD_RATE_115200}, + {B230400, BAUD_RATE_230400}, + {B460800, BAUD_RATE_460800}, + {B921600, BAUD_RATE_921600}, + {B2000000, BAUD_RATE_2000000}, + {B3000000, BAUD_RATE_3000000}, +}; + +static speed_t _get_speed(int baudrate) +{ + int index; + + for (index = 0; index < sizeof(_tbl)/sizeof(_tbl[0]); index ++) + { + if (_tbl[index].baudrate == baudrate) + return _tbl[index].speed; + } + + return B0; +} + +static int _get_baudrate(speed_t speed) +{ + int index; + + for (index = 0; index < sizeof(_tbl)/sizeof(_tbl[0]); index ++) + { + if (_tbl[index].speed == speed) + return _tbl[index].baudrate; + } + + return 0; +} + +static void _tc_flush(struct rt_serial_device *serial, int queue) +{ + int ch = -1; + struct rt_serial_rx_fifo *rx_fifo = RT_NULL; + struct rt_device *device = RT_NULL; + + RT_ASSERT(serial != RT_NULL); + + device = &(serial->parent); + rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; + + switch(queue) + { + case TCIFLUSH: + case TCIOFLUSH: + + RT_ASSERT(rx_fifo != RT_NULL); + + if((device->open_flag & RT_DEVICE_FLAG_INT_RX) || (device->open_flag & RT_DEVICE_FLAG_DMA_RX)) + { + RT_ASSERT(RT_NULL != rx_fifo); + rt_memset(rx_fifo->buffer, 0, serial->config.bufsz); + rx_fifo->put_index = 0; + rx_fifo->get_index = 0; + rx_fifo->is_full = RT_FALSE; + } + else + { + while (1) + { + ch = serial->ops->getc(serial); + if (ch == -1) break; + } + } + + break; + + case TCOFLUSH: + break; + } + +} + +#endif + +static rt_err_t rt_serial_control(struct rt_device *dev, + int cmd, + void *args) +{ + rt_err_t ret = RT_EOK; + struct rt_serial_device *serial; + + RT_ASSERT(dev != RT_NULL); + serial = (struct rt_serial_device *)dev; + + switch (cmd) + { + case RT_DEVICE_CTRL_SUSPEND: + /* suspend device */ + dev->flag |= RT_DEVICE_FLAG_SUSPENDED; + break; + + case RT_DEVICE_CTRL_RESUME: + /* resume device */ + dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED; + break; + + case RT_DEVICE_CTRL_CONFIG: + if (args) + { + struct serial_configure *pconfig = (struct serial_configure *) args; + if (pconfig->bufsz != serial->config.bufsz && serial->parent.ref_count) + { + /*can not change buffer size*/ + return RT_EBUSY; + } + /* set serial configure */ + serial->config = *pconfig; + if (serial->parent.ref_count) + { + /* serial device has been opened, to configure it */ + serial->ops->configure(serial, (struct serial_configure *) args); + } + } + + break; + +#ifdef RT_USING_POSIX_TERMIOS + case TCGETA: + { + struct termios *tio = (struct termios*)args; + if (tio == RT_NULL) return -RT_EINVAL; + + tio->c_iflag = 0; + tio->c_oflag = 0; + tio->c_lflag = 0; + + /* update oflag for console device */ + if (rt_console_get_device() == dev) + tio->c_oflag = OPOST | ONLCR; + + /* set cflag */ + tio->c_cflag = 0; + if (serial->config.data_bits == DATA_BITS_5) + tio->c_cflag = CS5; + else if (serial->config.data_bits == DATA_BITS_6) + tio->c_cflag = CS6; + else if (serial->config.data_bits == DATA_BITS_7) + tio->c_cflag = CS7; + else if (serial->config.data_bits == DATA_BITS_8) + tio->c_cflag = CS8; + + if (serial->config.stop_bits == STOP_BITS_2) + tio->c_cflag |= CSTOPB; + + if (serial->config.parity == PARITY_EVEN) + tio->c_cflag |= PARENB; + else if (serial->config.parity == PARITY_ODD) + tio->c_cflag |= (PARODD | PARENB); + + cfsetospeed(tio, _get_speed(serial->config.baud_rate)); + } + break; + + case TCSETAW: + case TCSETAF: + case TCSETA: + { + int baudrate; + struct serial_configure config; + + struct termios *tio = (struct termios*)args; + if (tio == RT_NULL) return -RT_EINVAL; + + config = serial->config; + + baudrate = _get_baudrate(cfgetospeed(tio)); + config.baud_rate = baudrate; + + switch (tio->c_cflag & CSIZE) + { + case CS5: + config.data_bits = DATA_BITS_5; + break; + case CS6: + config.data_bits = DATA_BITS_6; + break; + case CS7: + config.data_bits = DATA_BITS_7; + break; + default: + config.data_bits = DATA_BITS_8; + break; + } + + if (tio->c_cflag & CSTOPB) config.stop_bits = STOP_BITS_2; + else config.stop_bits = STOP_BITS_1; + + if (tio->c_cflag & PARENB) + { + if (tio->c_cflag & PARODD) config.parity = PARITY_ODD; + else config.parity = PARITY_EVEN; + } + else config.parity = PARITY_NONE; + + serial->ops->configure(serial, &config); + } + break; + case TCFLSH: + { + int queue = (int)args; + + _tc_flush(serial, queue); + } + + break; + case TCXONC: + break; +#endif +#ifdef RT_USING_POSIX + case FIONREAD: + { + rt_size_t recved = 0; + rt_base_t level; + + level = rt_hw_interrupt_disable(); + recved = _serial_fifo_calc_recved_len(serial); + rt_hw_interrupt_enable(level); + + *(rt_size_t *)args = recved; + } + break; +#endif + default : + /* control device */ + ret = serial->ops->control(serial, cmd, args); + break; + } + + return ret; +} + +#ifdef RT_USING_DEVICE_OPS +const static struct rt_device_ops serial_ops = +{ + rt_serial_init, + rt_serial_open, + rt_serial_close, + rt_serial_read, + rt_serial_write, + rt_serial_control +}; +#endif + +/* + * serial register + */ +rt_err_t rt_hw_serial_register(struct rt_serial_device *serial, + const char *name, + rt_uint32_t flag, + void *data) +{ + rt_err_t ret; + struct rt_device *device; + RT_ASSERT(serial != RT_NULL); + + device = &(serial->parent); + + device->type = RT_Device_Class_Char; + device->rx_indicate = RT_NULL; + device->tx_complete = RT_NULL; + +#ifdef RT_USING_DEVICE_OPS + device->ops = &serial_ops; +#else + device->init = rt_serial_init; + device->open = rt_serial_open; + device->close = rt_serial_close; + device->read = rt_serial_read; + device->write = rt_serial_write; + device->control = rt_serial_control; +#endif + device->user_data = data; + + /* register a character device */ + ret = rt_device_register(device, name, flag); + +#if defined(RT_USING_POSIX) + /* set fops */ + device->fops = &_serial_fops; +#endif + + return ret; +} + +/* ISR for serial interrupt */ +void rt_hw_serial_isr(struct rt_serial_device *serial, int event) +{ + switch (event & 0xff) + { + case RT_SERIAL_EVENT_RX_IND: + { + int ch = -1; + rt_base_t level; + struct rt_serial_rx_fifo* rx_fifo; + + /* interrupt mode receive */ + rx_fifo = (struct rt_serial_rx_fifo*)serial->serial_rx; + RT_ASSERT(rx_fifo != RT_NULL); + + while (1) + { + ch = serial->ops->getc(serial); + if (ch == -1) break; + + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + rx_fifo->buffer[rx_fifo->put_index] = ch; + rx_fifo->put_index += 1; + if (rx_fifo->put_index >= serial->config.bufsz) rx_fifo->put_index = 0; + + /* if the next position is read index, discard this 'read char' */ + if (rx_fifo->put_index == rx_fifo->get_index) + { + rx_fifo->get_index += 1; + rx_fifo->is_full = RT_TRUE; + if (rx_fifo->get_index >= serial->config.bufsz) rx_fifo->get_index = 0; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + } + + /* invoke callback */ + if (serial->parent.rx_indicate != RT_NULL) + { + rt_size_t rx_length; + + /* get rx length */ + level = rt_hw_interrupt_disable(); + rx_length = (rx_fifo->put_index >= rx_fifo->get_index)? (rx_fifo->put_index - rx_fifo->get_index): + (serial->config.bufsz - (rx_fifo->get_index - rx_fifo->put_index)); + rt_hw_interrupt_enable(level); + + if (rx_length) + { + serial->parent.rx_indicate(&serial->parent, rx_length); + } + } + break; + } + case RT_SERIAL_EVENT_TX_DONE: + { + struct rt_serial_tx_fifo* tx_fifo; + + tx_fifo = (struct rt_serial_tx_fifo*)serial->serial_tx; + rt_completion_done(&(tx_fifo->completion)); + break; + } + case RT_SERIAL_EVENT_TX_DMADONE: + { + const void *data_ptr; + rt_size_t data_size; + const void *last_data_ptr; + struct rt_serial_tx_dma* tx_dma; + + tx_dma = (struct rt_serial_tx_dma*) serial->serial_tx; + + rt_data_queue_pop(&(tx_dma->data_queue), &last_data_ptr, &data_size, 0); + if (rt_data_queue_peak(&(tx_dma->data_queue), &data_ptr, &data_size) == RT_EOK) + { + /* transmit next data node */ + tx_dma->activated = RT_TRUE; + serial->ops->dma_transmit(serial, (rt_uint8_t *)data_ptr, data_size, RT_SERIAL_DMA_TX); + } + else + { + tx_dma->activated = RT_FALSE; + } + + /* invoke callback */ + if (serial->parent.tx_complete != RT_NULL) + { + serial->parent.tx_complete(&serial->parent, (void*)last_data_ptr); + } + break; + } + case RT_SERIAL_EVENT_RX_DMADONE: + { + int length; + rt_base_t level; + + /* get DMA rx length */ + length = (event & (~0xff)) >> 8; + + if (serial->config.bufsz == 0) + { + struct rt_serial_rx_dma* rx_dma; + + rx_dma = (struct rt_serial_rx_dma*) serial->serial_rx; + RT_ASSERT(rx_dma != RT_NULL); + + RT_ASSERT(serial->parent.rx_indicate != RT_NULL); + serial->parent.rx_indicate(&(serial->parent), length); + rx_dma->activated = RT_FALSE; + } + else + { + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + /* update fifo put index */ + rt_dma_recv_update_put_index(serial, length); + /* calculate received total length */ + length = rt_dma_calc_recved_len(serial); + /* enable interrupt */ + rt_hw_interrupt_enable(level); + /* invoke callback */ + if (serial->parent.rx_indicate != RT_NULL) + { + serial->parent.rx_indicate(&(serial->parent), length); + } + } + break; + } + } +} + diff --git a/rt-thread/components/drivers/src/SConscript b/rt-thread/components/drivers/src/SConscript new file mode 100644 index 0000000..9f921ec --- /dev/null +++ b/rt-thread/components/drivers/src/SConscript @@ -0,0 +1,13 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd + '/../include'] + +if not GetDepend('RT_USING_HEAP'): + SrcRemove(src, 'dataqueue.c') + SrcRemove(src, 'pipe.c') + +group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_DEVICE_IPC'], CPPPATH = CPPPATH) + +Return('group') diff --git a/rt-thread/components/drivers/src/ringbuffer.c b/rt-thread/components/drivers/src/ringbuffer.c new file mode 100644 index 0000000..48bf590 --- /dev/null +++ b/rt-thread/components/drivers/src/ringbuffer.c @@ -0,0 +1,375 @@ +/* + * File : ringbuffer.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-09-30 Bernard first version. + * 2013-05-08 Grissiom reimplement + * 2016-08-18 heyuanjie add interface + */ + +#include +#include +#include + +rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb) +{ + if (rb->read_index == rb->write_index) + { + if (rb->read_mirror == rb->write_mirror) + return RT_RINGBUFFER_EMPTY; + else + return RT_RINGBUFFER_FULL; + } + return RT_RINGBUFFER_HALFFULL; +} + +void rt_ringbuffer_init(struct rt_ringbuffer *rb, + rt_uint8_t *pool, + rt_int16_t size) +{ + RT_ASSERT(rb != RT_NULL); + RT_ASSERT(size > 0); + + /* initialize read and write index */ + rb->read_mirror = rb->read_index = 0; + rb->write_mirror = rb->write_index = 0; + + /* set buffer pool and size */ + rb->buffer_ptr = pool; + rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE); +} +RTM_EXPORT(rt_ringbuffer_init); + +/** + * put a block of data into ring buffer + */ +rt_size_t rt_ringbuffer_put(struct rt_ringbuffer *rb, + const rt_uint8_t *ptr, + rt_uint16_t length) +{ + rt_uint16_t size; + + RT_ASSERT(rb != RT_NULL); + + /* whether has enough space */ + size = rt_ringbuffer_space_len(rb); + + /* no space */ + if (size == 0) + return 0; + + /* drop some data */ + if (size < length) + length = size; + + if (rb->buffer_size - rb->write_index > length) + { + /* read_index - write_index = empty space */ + memcpy(&rb->buffer_ptr[rb->write_index], ptr, length); + /* this should not cause overflow because there is enough space for + * length of data in current mirror */ + rb->write_index += length; + return length; + } + + memcpy(&rb->buffer_ptr[rb->write_index], + &ptr[0], + rb->buffer_size - rb->write_index); + memcpy(&rb->buffer_ptr[0], + &ptr[rb->buffer_size - rb->write_index], + length - (rb->buffer_size - rb->write_index)); + + /* we are going into the other side of the mirror */ + rb->write_mirror = ~rb->write_mirror; + rb->write_index = length - (rb->buffer_size - rb->write_index); + + return length; +} +RTM_EXPORT(rt_ringbuffer_put); + +/** + * put a block of data into ring buffer + * + * When the buffer is full, it will discard the old data. + */ +rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb, + const rt_uint8_t *ptr, + rt_uint16_t length) +{ + rt_uint16_t space_length; + + RT_ASSERT(rb != RT_NULL); + + space_length = rt_ringbuffer_space_len(rb); + + if (length > rb->buffer_size) + { + ptr = &ptr[length - rb->buffer_size]; + length = rb->buffer_size; + } + + if (rb->buffer_size - rb->write_index > length) + { + /* read_index - write_index = empty space */ + memcpy(&rb->buffer_ptr[rb->write_index], ptr, length); + /* this should not cause overflow because there is enough space for + * length of data in current mirror */ + rb->write_index += length; + + if (length > space_length) + rb->read_index = rb->write_index; + + return length; + } + + memcpy(&rb->buffer_ptr[rb->write_index], + &ptr[0], + rb->buffer_size - rb->write_index); + memcpy(&rb->buffer_ptr[0], + &ptr[rb->buffer_size - rb->write_index], + length - (rb->buffer_size - rb->write_index)); + + /* we are going into the other side of the mirror */ + rb->write_mirror = ~rb->write_mirror; + rb->write_index = length - (rb->buffer_size - rb->write_index); + + if (length > space_length) + { + rb->read_mirror = ~rb->read_mirror; + rb->read_index = rb->write_index; + } + + return length; +} +RTM_EXPORT(rt_ringbuffer_put_force); + +/** + * get data from ring buffer + */ +rt_size_t rt_ringbuffer_get(struct rt_ringbuffer *rb, + rt_uint8_t *ptr, + rt_uint16_t length) +{ + rt_size_t size; + + RT_ASSERT(rb != RT_NULL); + + /* whether has enough data */ + size = rt_ringbuffer_data_len(rb); + + /* no data */ + if (size == 0) + return 0; + + /* less data */ + if (size < length) + length = size; + + if (rb->buffer_size - rb->read_index > length) + { + /* copy all of data */ + memcpy(ptr, &rb->buffer_ptr[rb->read_index], length); + /* this should not cause overflow because there is enough space for + * length of data in current mirror */ + rb->read_index += length; + return length; + } + + memcpy(&ptr[0], + &rb->buffer_ptr[rb->read_index], + rb->buffer_size - rb->read_index); + memcpy(&ptr[rb->buffer_size - rb->read_index], + &rb->buffer_ptr[0], + length - (rb->buffer_size - rb->read_index)); + + /* we are going into the other side of the mirror */ + rb->read_mirror = ~rb->read_mirror; + rb->read_index = length - (rb->buffer_size - rb->read_index); + + return length; +} +RTM_EXPORT(rt_ringbuffer_get); + +/** + * put a character into ring buffer + */ +rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch) +{ + RT_ASSERT(rb != RT_NULL); + + /* whether has enough space */ + if (!rt_ringbuffer_space_len(rb)) + return 0; + + rb->buffer_ptr[rb->write_index] = ch; + + /* flip mirror */ + if (rb->write_index == rb->buffer_size-1) + { + rb->write_mirror = ~rb->write_mirror; + rb->write_index = 0; + } + else + { + rb->write_index++; + } + + return 1; +} +RTM_EXPORT(rt_ringbuffer_putchar); + +/** + * put a character into ring buffer + * + * When the buffer is full, it will discard one old data. + */ +rt_size_t rt_ringbuffer_putchar_force(struct rt_ringbuffer *rb, const rt_uint8_t ch) +{ + enum rt_ringbuffer_state old_state; + + RT_ASSERT(rb != RT_NULL); + + old_state = rt_ringbuffer_status(rb); + + rb->buffer_ptr[rb->write_index] = ch; + + /* flip mirror */ + if (rb->write_index == rb->buffer_size-1) + { + rb->write_mirror = ~rb->write_mirror; + rb->write_index = 0; + if (old_state == RT_RINGBUFFER_FULL) + { + rb->read_mirror = ~rb->read_mirror; + rb->read_index = rb->write_index; + } + } + else + { + rb->write_index++; + if (old_state == RT_RINGBUFFER_FULL) + rb->read_index = rb->write_index; + } + + return 1; +} +RTM_EXPORT(rt_ringbuffer_putchar_force); + +/** + * get a character from a ringbuffer + */ +rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch) +{ + RT_ASSERT(rb != RT_NULL); + + /* ringbuffer is empty */ + if (!rt_ringbuffer_data_len(rb)) + return 0; + + /* put character */ + *ch = rb->buffer_ptr[rb->read_index]; + + if (rb->read_index == rb->buffer_size-1) + { + rb->read_mirror = ~rb->read_mirror; + rb->read_index = 0; + } + else + { + rb->read_index++; + } + + return 1; +} +RTM_EXPORT(rt_ringbuffer_getchar); + +/** + * get the size of data in rb + */ +rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb) +{ + switch (rt_ringbuffer_status(rb)) + { + case RT_RINGBUFFER_EMPTY: + return 0; + case RT_RINGBUFFER_FULL: + return rb->buffer_size; + case RT_RINGBUFFER_HALFFULL: + default: + if (rb->write_index > rb->read_index) + return rb->write_index - rb->read_index; + else + return rb->buffer_size - (rb->read_index - rb->write_index); + }; +} +RTM_EXPORT(rt_ringbuffer_data_len); + +/** + * empty the rb + */ +void rt_ringbuffer_reset(struct rt_ringbuffer *rb) +{ + RT_ASSERT(rb != RT_NULL); + + rb->read_mirror = 0; + rb->read_index = 0; + rb->write_mirror = 0; + rb->write_index = 0; +} +RTM_EXPORT(rt_ringbuffer_reset); + +#ifdef RT_USING_HEAP + +struct rt_ringbuffer* rt_ringbuffer_create(rt_uint16_t size) +{ + struct rt_ringbuffer *rb; + rt_uint8_t *pool; + + RT_ASSERT(size > 0); + + size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE); + + rb = rt_malloc(sizeof(struct rt_ringbuffer)); + if (rb == RT_NULL) + goto exit; + + pool = rt_malloc(size); + if (pool == RT_NULL) + { + rt_free(rb); + goto exit; + } + rt_ringbuffer_init(rb, pool, size); + +exit: + return rb; +} +RTM_EXPORT(rt_ringbuffer_create); + +void rt_ringbuffer_destroy(struct rt_ringbuffer *rb) +{ + RT_ASSERT(rb != RT_NULL); + + rt_free(rb->buffer_ptr); + rt_free(rb); +} +RTM_EXPORT(rt_ringbuffer_destroy); + +#endif diff --git a/rt-thread/components/finsh/Kconfig b/rt-thread/components/finsh/Kconfig new file mode 100644 index 0000000..8722fcd --- /dev/null +++ b/rt-thread/components/finsh/Kconfig @@ -0,0 +1,81 @@ +menu "Command shell" + +config RT_USING_FINSH + bool "finsh shell" + default y + +if RT_USING_FINSH + +config FINSH_THREAD_NAME + string "The finsh thread name" + default "tshell" +config FINSH_USING_HISTORY + bool "Enable command history feature" + default y +if FINSH_USING_HISTORY +config FINSH_HISTORY_LINES + int "The command history line number" + default 5 +endif + +config FINSH_USING_SYMTAB + bool "Using symbol table for commands" + default y + +config FINSH_USING_DESCRIPTION + bool "Keeping description in symbol table" + default y + +config FINSH_ECHO_DISABLE_DEFAULT + bool "Disable the echo mode in default" + default n + +config FINSH_THREAD_PRIORITY + int "The priority level value of finsh thread" + default 20 + +config FINSH_THREAD_STACK_SIZE + int "The stack size for finsh thread" + default 4096 + +config FINSH_CMD_SIZE + int "The command line size for shell" + default 80 + +config FINSH_USING_AUTH + bool "shell support authentication" + default n + +if FINSH_USING_AUTH +config FINSH_DEFAULT_PASSWORD + string "The default password for shell authentication" + default "rtthread" +config FINSH_PASSWORD_MIN + int "The password min length" + default 6 +config FINSH_PASSWORD_MAX + int "The password max length" + default RT_NAME_MAX +endif + +config FINSH_USING_MSH + bool "Using module shell" + default y + +if FINSH_USING_MSH +config FINSH_USING_MSH_DEFAULT + bool "Using module shell in default" + default y + +config FINSH_USING_MSH_ONLY + bool "Only using module shell" + default n + +config FINSH_ARG_MAX + int "The command arg num for shell" + default 10 +endif + +endif + +endmenu diff --git a/rt-thread/components/finsh/SConscript b/rt-thread/components/finsh/SConscript new file mode 100644 index 0000000..639cbeb --- /dev/null +++ b/rt-thread/components/finsh/SConscript @@ -0,0 +1,46 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = Split(''' +shell.c +symbol.c +cmd.c +''') + +fsh_src = Split(''' +finsh_compiler.c +finsh_error.c +finsh_heap.c +finsh_init.c +finsh_node.c +finsh_ops.c +finsh_parser.c +finsh_var.c +finsh_vm.c +finsh_token.c +''') + +msh_src = Split(''' +msh.c +msh_cmd.c +msh_file.c +''') + +CPPPATH = [cwd] +if rtconfig.CROSS_TOOL == 'keil': + LINKFLAGS = ' --keep *.o(FSymTab)' + + if not GetDepend('FINSH_USING_MSH_ONLY'): + LINKFLAGS = LINKFLAGS + ' --keep *.o(VSymTab) ' +else: + LINKFLAGS = '' + +if GetDepend('FINSH_USING_MSH'): + src = src + msh_src +if not GetDepend('FINSH_USING_MSH_ONLY'): + src = src + fsh_src + +group = DefineGroup('finsh', src, depend = ['RT_USING_FINSH'], CPPPATH = CPPPATH, LINKFLAGS = LINKFLAGS) + +Return('group') diff --git a/rt-thread/components/finsh/cmd.c b/rt-thread/components/finsh/cmd.c new file mode 100644 index 0000000..edb7c0c --- /dev/null +++ b/rt-thread/components/finsh/cmd.c @@ -0,0 +1,852 @@ +/* + * RT-Thread finsh shell commands + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2006-04-30 Bernard first implementation + * 2006-05-04 Bernard add list_thread, + * list_sem, + * list_timer + * 2006-05-20 Bernard add list_mutex, + * list_mailbox, + * list_msgqueue, + * list_event, + * list_fevent, + * list_mempool + * 2006-06-03 Bernard display stack information in list_thread + * 2006-08-10 Bernard change version to invoke rt_show_version + * 2008-09-10 Bernard update the list function for finsh syscall + * list and sysvar list + * 2009-05-30 Bernard add list_device + * 2010-04-21 yi.qiu add list_module + * 2012-04-29 goprife improve the command line auto-complete feature. + * 2012-06-02 lgnq add list_memheap + * 2012-10-22 Bernard add MS VC++ patch. + * 2016-06-02 armink beautify the list_thread command + */ + +#include +#include "finsh.h" + +long hello(void) +{ + rt_kprintf("Hello RT-Thread!\n"); + + return 0; +} +FINSH_FUNCTION_EXPORT(hello, say hello world); + +extern void rt_show_version(void); +long version(void) +{ + rt_show_version(); + + return 0; +} +FINSH_FUNCTION_EXPORT(version, show RT-Thread version information); +MSH_CMD_EXPORT(version, show RT-Thread version information); + +static int object_name_maxlen(const char *type_name, struct rt_list_node *list) +{ + struct rt_list_node *node; + struct rt_object *object = NULL; + int max_length = rt_strlen(type_name), length; + + rt_enter_critical(); + for (node = list->next; node != list; node = node->next) + { + object = rt_list_entry(node, struct rt_object, list); + + length = rt_strlen(object->name); + if (length > max_length) max_length = length; + } + rt_exit_critical(); + + if (max_length > RT_NAME_MAX || max_length == 0) max_length = RT_NAME_MAX; + + return max_length; +} + +rt_inline void object_split(int len) +{ + while (len--) rt_kprintf("-"); +} + +static long _list_thread(struct rt_list_node *list) +{ + int maxlen; + rt_uint8_t *ptr; + struct rt_thread *thread; + struct rt_list_node *node; + const char *item_title = "thread"; + + maxlen = object_name_maxlen(item_title, list); + + rt_kprintf("%-*.s pri status sp stack size max used left tick error\n", maxlen, item_title); object_split(maxlen); + rt_kprintf( " --- ------- ---------- ---------- ------ ---------- ---\n"); + for (node = list->next; node != list; node = node->next) + { + rt_uint8_t stat; + thread = rt_list_entry(node, struct rt_thread, list); + rt_kprintf("%-*.*s %3d ", maxlen, RT_NAME_MAX, thread->name, thread->current_priority); + + stat = (thread->stat & RT_THREAD_STAT_MASK); + if (stat == RT_THREAD_READY) rt_kprintf(" ready "); + else if (stat == RT_THREAD_SUSPEND) rt_kprintf(" suspend"); + else if (stat == RT_THREAD_INIT) rt_kprintf(" init "); + else if (stat == RT_THREAD_CLOSE) rt_kprintf(" close "); + + ptr = (rt_uint8_t *)thread->stack_addr; + while (*ptr == '#')ptr ++; + + rt_kprintf(" 0x%08x 0x%08x %02d%% 0x%08x %03d\n", + thread->stack_size + ((rt_uint32_t)thread->stack_addr - (rt_uint32_t)thread->sp), + thread->stack_size, + (thread->stack_size - ((rt_uint32_t) ptr - (rt_uint32_t) thread->stack_addr)) * 100 + / thread->stack_size, + thread->remaining_tick, + thread->error); + } + + return 0; +} + +long list_thread(void) +{ + struct rt_object_information *info; + + info = rt_object_get_information(RT_Object_Class_Thread); + return _list_thread(&info->object_list); +} +FINSH_FUNCTION_EXPORT(list_thread, list thread); +MSH_CMD_EXPORT(list_thread, list thread); + +static void show_wait_queue(struct rt_list_node *list) +{ + struct rt_thread *thread; + struct rt_list_node *node; + + for (node = list->next; node != list; node = node->next) + { + thread = rt_list_entry(node, struct rt_thread, tlist); + rt_kprintf("%s", thread->name); + + if (node->next != list) + rt_kprintf("/"); + } +} + +#ifdef RT_USING_SEMAPHORE +static long _list_sem(struct rt_list_node *list) +{ + int maxlen; + struct rt_semaphore *sem; + struct rt_list_node *node; + const char *item_title = "semaphore"; + + maxlen = object_name_maxlen(item_title, list); + + rt_kprintf("%-*.s v suspend thread\n", maxlen, item_title); object_split(maxlen); + rt_kprintf( " --- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + sem = (struct rt_semaphore *)(rt_list_entry(node, struct rt_object, list)); + if (!rt_list_isempty(&sem->parent.suspend_thread)) + { + rt_kprintf("%-*.*s %03d %d:", + maxlen, RT_NAME_MAX, + sem->parent.parent.name, + sem->value, + rt_list_len(&sem->parent.suspend_thread)); + show_wait_queue(&(sem->parent.suspend_thread)); + rt_kprintf("\n"); + } + else + { + rt_kprintf("%-*.*s %03d %d\n", + maxlen, RT_NAME_MAX, + sem->parent.parent.name, + sem->value, + rt_list_len(&sem->parent.suspend_thread)); + } + } + + return 0; +} + +long list_sem(void) +{ + struct rt_object_information *info; + + info = rt_object_get_information(RT_Object_Class_Semaphore); + + return _list_sem(&info->object_list); +} +FINSH_FUNCTION_EXPORT(list_sem, list semaphone in system); +MSH_CMD_EXPORT(list_sem, list semaphore in system); +#endif + +#ifdef RT_USING_EVENT +static long _list_event(struct rt_list_node *list) +{ + int maxlen; + struct rt_event *e; + struct rt_list_node *node; + const char *item_title = "event"; + + maxlen = object_name_maxlen(item_title, list); + + rt_kprintf("%-*.s set suspend thread\n", maxlen, item_title); object_split(maxlen); + rt_kprintf( " ---------- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + e = (struct rt_event *)(rt_list_entry(node, struct rt_object, list)); + if (!rt_list_isempty(&e->parent.suspend_thread)) + { + rt_kprintf("%-*.*s 0x%08x %03d:", + maxlen, RT_NAME_MAX, + e->parent.parent.name, + e->set, + rt_list_len(&e->parent.suspend_thread)); + show_wait_queue(&(e->parent.suspend_thread)); + rt_kprintf("\n"); + } + else + { + rt_kprintf("%-*.*s 0x%08x 0\n", + maxlen, RT_NAME_MAX, e->parent.parent.name, e->set); + } + } + + return 0; +} + +long list_event(void) +{ + struct rt_object_information *info; + + info = rt_object_get_information(RT_Object_Class_Event); + return _list_event(&info->object_list); +} +FINSH_FUNCTION_EXPORT(list_event, list event in system); +MSH_CMD_EXPORT(list_event, list event in system); +#endif + +#ifdef RT_USING_MUTEX +static long _list_mutex(struct rt_list_node *list) +{ + int maxlen; + struct rt_mutex *m; + struct rt_list_node *node; + const char *item_title = "mutex"; + + maxlen = object_name_maxlen(item_title, list); + + rt_kprintf("%-*.s owner hold suspend thread\n", maxlen, item_title); object_split(maxlen); + rt_kprintf( " -------- ---- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + m = (struct rt_mutex *)(rt_list_entry(node, struct rt_object, list)); + rt_kprintf("%-*.*s %-8.*s %04d %d\n", + maxlen, RT_NAME_MAX, + m->parent.parent.name, + RT_NAME_MAX, + m->owner->name, + m->hold, + rt_list_len(&m->parent.suspend_thread)); + } + + return 0; +} + +long list_mutex(void) +{ + struct rt_object_information *info; + + info = rt_object_get_information(RT_Object_Class_Mutex); + + return _list_mutex(&info->object_list); +} +FINSH_FUNCTION_EXPORT(list_mutex, list mutex in system); +MSH_CMD_EXPORT(list_mutex, list mutex in system); +#endif + +#ifdef RT_USING_MAILBOX +static long _list_mailbox(struct rt_list_node *list) +{ + int maxlen; + struct rt_mailbox *m; + struct rt_list_node *node; + const char *item_title = "mailbox"; + + maxlen = object_name_maxlen(item_title, list); + + rt_kprintf("%-*.s entry size suspend thread\n", maxlen, item_title); object_split(maxlen); + rt_kprintf( " ---- ---- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + m = (struct rt_mailbox *)(rt_list_entry(node, struct rt_object, list)); + if (!rt_list_isempty(&m->parent.suspend_thread)) + { + rt_kprintf("%-*.*s %04d %04d %d:", + maxlen, RT_NAME_MAX, + m->parent.parent.name, + m->entry, + m->size, + rt_list_len(&m->parent.suspend_thread)); + show_wait_queue(&(m->parent.suspend_thread)); + rt_kprintf("\n"); + } + else + { + rt_kprintf("%-*.*s %04d %04d %d\n", + maxlen, RT_NAME_MAX, + m->parent.parent.name, + m->entry, + m->size, + rt_list_len(&m->parent.suspend_thread)); + } + } + + return 0; +} + +long list_mailbox(void) +{ + struct rt_object_information *info; + + info = rt_object_get_information(RT_Object_Class_MailBox); + return _list_mailbox(&info->object_list); +} +FINSH_FUNCTION_EXPORT(list_mailbox, list mail box in system); +MSH_CMD_EXPORT(list_mailbox, list mail box in system); +#endif + +#ifdef RT_USING_MESSAGEQUEUE +static long _list_msgqueue(struct rt_list_node *list) +{ + int maxlen; + struct rt_messagequeue *m; + struct rt_list_node *node; + const char *item_title = "msgqueue"; + + maxlen = object_name_maxlen(item_title, list); + + rt_kprintf("%-*.s entry suspend thread\n", maxlen, item_title); object_split(maxlen); + rt_kprintf( " ---- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + m = (struct rt_messagequeue *)(rt_list_entry(node, struct rt_object, list)); + if (!rt_list_isempty(&m->parent.suspend_thread)) + { + rt_kprintf("%-*.*s %04d %d:", + maxlen, RT_NAME_MAX, + m->parent.parent.name, + m->entry, + rt_list_len(&m->parent.suspend_thread)); + show_wait_queue(&(m->parent.suspend_thread)); + rt_kprintf("\n"); + } + else + { + rt_kprintf("%-*.*s %04d %d\n", + maxlen, RT_NAME_MAX, + m->parent.parent.name, + m->entry, + rt_list_len(&m->parent.suspend_thread)); + } + } + + return 0; +} + +long list_msgqueue(void) +{ + struct rt_object_information *info; + + info = rt_object_get_information(RT_Object_Class_MessageQueue); + return _list_msgqueue(&info->object_list); +} +FINSH_FUNCTION_EXPORT(list_msgqueue, list message queue in system); +MSH_CMD_EXPORT(list_msgqueue, list message queue in system); +#endif + +#ifdef RT_USING_MEMHEAP +static long _list_memheap(struct rt_list_node *list) +{ + int maxlen; + struct rt_memheap *mh; + struct rt_list_node *node; + const char *item_title = "memheap"; + + maxlen = object_name_maxlen(item_title, list); + + rt_kprintf("%-*.s pool size max used size available size\n", maxlen, item_title); object_split(maxlen); + rt_kprintf( " ---------- ------------- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + mh = (struct rt_memheap *)rt_list_entry(node, struct rt_object, list); + + rt_kprintf("%-*.*s %-010d %-013d %-05d\n", + maxlen, RT_NAME_MAX, + mh->parent.name, + mh->pool_size, + mh->max_used_size, + mh->available_size); + } + + return 0; +} + +long list_memheap(void) +{ + struct rt_object_information *info; + + info = rt_object_get_information(RT_Object_Class_MemHeap); + return _list_memheap(&info->object_list); +} +FINSH_FUNCTION_EXPORT(list_memheap, list memory heap in system); +MSH_CMD_EXPORT(list_memheap, list memory heap in system); +#endif + +#ifdef RT_USING_MEMPOOL +static long _list_mempool(struct rt_list_node *list) +{ + int maxlen; + struct rt_mempool *mp; + struct rt_list_node *node; + const char *item_title = "mempool"; + + maxlen = object_name_maxlen(item_title, list); + + rt_kprintf("%-*.s block total free suspend thread\n", maxlen, item_title); object_split(maxlen); + rt_kprintf( " ---- ---- ---- --------------\n"); + for (node = list->next; node != list; node = node->next) + { + mp = (struct rt_mempool *)rt_list_entry(node, struct rt_object, list); + if (mp->suspend_thread_count > 0) + { + rt_kprintf("%-*.*s %04d %04d %04d %d:", + maxlen, RT_NAME_MAX, + mp->parent.name, + mp->block_size, + mp->block_total_count, + mp->block_free_count, + mp->suspend_thread_count); + show_wait_queue(&(mp->suspend_thread)); + rt_kprintf("\n"); + } + else + { + rt_kprintf("%-*.*s %04d %04d %04d %d\n", + maxlen, RT_NAME_MAX, + mp->parent.name, + mp->block_size, + mp->block_total_count, + mp->block_free_count, + mp->suspend_thread_count); + } + } + + return 0; +} + +long list_mempool(void) +{ + struct rt_object_information *info; + + info = rt_object_get_information(RT_Object_Class_MemPool); + return _list_mempool(&info->object_list); +} +FINSH_FUNCTION_EXPORT(list_mempool, list memory pool in system) +MSH_CMD_EXPORT(list_mempool, list memory pool in system); +#endif + +static long _list_timer(struct rt_list_node *list) +{ + int maxlen; + struct rt_timer *timer; + struct rt_list_node *node; + const char *item_title = "timer"; + + maxlen = object_name_maxlen(item_title, list); + + rt_kprintf("%-*.s periodic timeout flag\n", maxlen, item_title); object_split(maxlen); + rt_kprintf( " ---------- ---------- -----------\n"); + for (node = list->next; node != list; node = node->next) + { + timer = (struct rt_timer *)(rt_list_entry(node, struct rt_object, list)); + rt_kprintf("%-*.*s 0x%08x 0x%08x ", + maxlen, RT_NAME_MAX, + timer->parent.name, + timer->init_tick, + timer->timeout_tick); + if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) + rt_kprintf("activated\n"); + else + rt_kprintf("deactivated\n"); + } + + rt_kprintf("current tick:0x%08x\n", rt_tick_get()); + + return 0; +} + +long list_timer(void) +{ + struct rt_object_information *info; + + info = rt_object_get_information(RT_Object_Class_Timer); + return _list_timer(&info->object_list); +} +FINSH_FUNCTION_EXPORT(list_timer, list timer in system); +MSH_CMD_EXPORT(list_timer, list timer in system); + +#ifdef RT_USING_DEVICE +static long _list_device(struct rt_list_node *list) +{ + int maxlen; + struct rt_device *device; + struct rt_list_node *node; + char *const device_type_str[] = + { + "Character Device", + "Block Device", + "Network Interface", + "MTD Device", + "CAN Device", + "RTC", + "Sound Device", + "Graphic Device", + "I2C Bus", + "USB Slave Device", + "USB Host Bus", + "SPI Bus", + "SPI Device", + "SDIO Bus", + "PM Pseudo Device", + "Pipe", + "Portal Device", + "Timer Device", + "Miscellaneous Device", + "Unknown" + }; + const char *item_title = "device"; + + maxlen = object_name_maxlen(item_title, list); + + rt_kprintf("%-*.s type ref count\n", maxlen, item_title); object_split(maxlen); + rt_kprintf( " -------------------- ----------\n"); + for (node = list->next; node != list; node = node->next) + { + device = (struct rt_device *)(rt_list_entry(node, struct rt_object, list)); + rt_kprintf("%-*.*s %-20s %-8d\n", + maxlen, RT_NAME_MAX, + device->parent.name, + (device->type <= RT_Device_Class_Unknown) ? + device_type_str[device->type] : + device_type_str[RT_Device_Class_Unknown], + device->ref_count); + } + + return 0; +} + +long list_device(void) +{ + struct rt_object_information *info; + + info = rt_object_get_information(RT_Object_Class_Device); + return _list_device(&info->object_list); +} +FINSH_FUNCTION_EXPORT(list_device, list device in system); +MSH_CMD_EXPORT(list_device, list device in system); +#endif + +long list(void) +{ +#ifndef FINSH_USING_MSH_ONLY + struct finsh_syscall_item *syscall_item; + struct finsh_sysvar_item *sysvar_item; +#endif + + rt_kprintf("--Function List:\n"); + { + struct finsh_syscall *index; + for (index = _syscall_table_begin; + index < _syscall_table_end; + FINSH_NEXT_SYSCALL(index)) + { + /* skip the internal command */ + if (strncmp((char *)index->name, "__", 2) == 0) continue; + +#ifdef FINSH_USING_DESCRIPTION + rt_kprintf("%-16s -- %s\n", index->name, index->desc); +#else + rt_kprintf("%s\n", index->name); +#endif + } + } + +#ifndef FINSH_USING_MSH_ONLY + /* list syscall list */ + syscall_item = global_syscall_list; + while (syscall_item != NULL) + { + rt_kprintf("[l] %s\n", syscall_item->syscall.name); + syscall_item = syscall_item->next; + } + + rt_kprintf("--Variable List:\n"); + { + struct finsh_sysvar *index; + for (index = _sysvar_table_begin; + index < _sysvar_table_end; + FINSH_NEXT_SYSVAR(index)) + { +#ifdef FINSH_USING_DESCRIPTION + rt_kprintf("%-16s -- %s\n", index->name, index->desc); +#else + rt_kprintf("%s\n", index->name); +#endif + } + } + + sysvar_item = global_sysvar_list; + while (sysvar_item != NULL) + { + rt_kprintf("[l] %s\n", sysvar_item->sysvar.name); + sysvar_item = sysvar_item->next; + } +#endif + + return 0; +} +FINSH_FUNCTION_EXPORT(list, list all symbol in system) + +#ifndef FINSH_USING_MSH_ONLY +static int str_is_prefix(const char *prefix, const char *str) +{ + while ((*prefix) && (*prefix == *str)) + { + prefix ++; + str ++; + } + + if (*prefix == 0) + return 0; + + return -1; +} + +static int str_common(const char *str1, const char *str2) +{ + const char *str = str1; + + while ((*str != 0) && (*str2 != 0) && (*str == *str2)) + { + str ++; + str2 ++; + } + + return (str - str1); +} + +void list_prefix(char *prefix) +{ + struct finsh_syscall_item *syscall_item; + struct finsh_sysvar_item *sysvar_item; + rt_uint16_t func_cnt, var_cnt; + int length, min_length; + const char *name_ptr; + + func_cnt = 0; + var_cnt = 0; + min_length = 0; + name_ptr = RT_NULL; + + /* checks in system function call */ + { + struct finsh_syscall *index; + for (index = _syscall_table_begin; + index < _syscall_table_end; + FINSH_NEXT_SYSCALL(index)) + { + /* skip internal command */ + if (str_is_prefix("__", index->name) == 0) continue; + + if (str_is_prefix(prefix, index->name) == 0) + { + if (func_cnt == 0) + { + rt_kprintf("--function:\n"); + + if (*prefix != 0) + { + /* set name_ptr */ + name_ptr = index->name; + + /* set initial length */ + min_length = strlen(name_ptr); + } + } + + func_cnt ++; + + if (*prefix != 0) + { + length = str_common(name_ptr, index->name); + if (length < min_length) + min_length = length; + } + +#ifdef FINSH_USING_DESCRIPTION + rt_kprintf("%-16s -- %s\n", index->name, index->desc); +#else + rt_kprintf("%s\n", index->name); +#endif + } + } + } + + /* checks in dynamic system function call */ + syscall_item = global_syscall_list; + while (syscall_item != NULL) + { + if (str_is_prefix(prefix, syscall_item->syscall.name) == 0) + { + if (func_cnt == 0) + { + rt_kprintf("--function:\n"); + if (*prefix != 0 && name_ptr == NULL) + { + /* set name_ptr */ + name_ptr = syscall_item->syscall.name; + + /* set initial length */ + min_length = strlen(name_ptr); + } + } + + func_cnt ++; + + if (*prefix != 0) + { + length = str_common(name_ptr, syscall_item->syscall.name); + if (length < min_length) + min_length = length; + } + + rt_kprintf("[l] %s\n", syscall_item->syscall.name); + } + syscall_item = syscall_item->next; + } + + /* checks in system variable */ + { + struct finsh_sysvar *index; + for (index = _sysvar_table_begin; + index < _sysvar_table_end; + FINSH_NEXT_SYSVAR(index)) + { + if (str_is_prefix(prefix, index->name) == 0) + { + if (var_cnt == 0) + { + rt_kprintf("--variable:\n"); + + if (*prefix != 0 && name_ptr == NULL) + { + /* set name_ptr */ + name_ptr = index->name; + + /* set initial length */ + min_length = strlen(name_ptr); + + } + } + + var_cnt ++; + + if (*prefix != 0) + { + length = str_common(name_ptr, index->name); + if (length < min_length) + min_length = length; + } + +#ifdef FINSH_USING_DESCRIPTION + rt_kprintf("%-16s -- %s\n", index->name, index->desc); +#else + rt_kprintf("%s\n", index->name); +#endif + } + } + } + + /* checks in dynamic system variable */ + sysvar_item = global_sysvar_list; + while (sysvar_item != NULL) + { + if (str_is_prefix(prefix, sysvar_item->sysvar.name) == 0) + { + if (var_cnt == 0) + { + rt_kprintf("--variable:\n"); + if (*prefix != 0 && name_ptr == NULL) + { + /* set name_ptr */ + name_ptr = sysvar_item->sysvar.name; + + /* set initial length */ + min_length = strlen(name_ptr); + } + } + + var_cnt ++; + + if (*prefix != 0) + { + length = str_common(name_ptr, sysvar_item->sysvar.name); + if (length < min_length) + min_length = length; + } + + rt_kprintf("[v] %s\n", sysvar_item->sysvar.name); + } + sysvar_item = sysvar_item->next; + } + + /* only one matched */ + if (name_ptr != NULL) + { + rt_strncpy(prefix, name_ptr, min_length); + } +} +#endif + +#if defined(FINSH_USING_SYMTAB) && !defined(FINSH_USING_MSH_ONLY) +static int dummy = 0; +FINSH_VAR_EXPORT(dummy, finsh_type_int, dummy variable for finsh) +#endif diff --git a/rt-thread/components/finsh/finsh.h b/rt-thread/components/finsh/finsh.h new file mode 100644 index 0000000..4452d4a --- /dev/null +++ b/rt-thread/components/finsh/finsh.h @@ -0,0 +1,262 @@ +/* + * File : finsh.h + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#ifndef __FINSH_H__ +#define __FINSH_H__ + +#include +#include "finsh_api.h" + +/* -- the beginning of option -- */ +#define FINSH_NAME_MAX 16 /* max length of identifier */ +#define FINSH_NODE_MAX 16 /* max number of node */ + +#define FINSH_HEAP_MAX 128 /* max length of heap */ +#define FINSH_STRING_MAX 128 /* max length of string */ +#define FINSH_VARIABLE_MAX 8 /* max number of variable */ + +#define FINSH_STACK_MAX 64 /* max stack size */ +#define FINSH_TEXT_MAX 128 /* max text segment size */ + +#define HEAP_ALIGNMENT 4 /* heap alignment */ + +#define FINSH_GET16(x) (*(x)) | (*((x)+1) << 8) +#define FINSH_GET32(x) (rt_uint32_t)(*(x)) | ((rt_uint32_t)*((x)+1) << 8) | \ + ((rt_uint32_t)*((x)+2) << 16) | ((rt_uint32_t)*((x)+3) << 24) + +#define FINSH_SET16(x, v) \ + do \ + { \ + *(x) = (v) & 0x00ff; \ + (*((x)+1)) = (v) >> 8; \ + } while ( 0 ) + +#define FINSH_SET32(x, v) \ + do \ + { \ + *(x) = (rt_uint32_t)(v) & 0x000000ff; \ + (*((x)+1)) = ((rt_uint32_t)(v) >> 8) & 0x000000ff; \ + (*((x)+2)) = ((rt_uint32_t)(v) >> 16) & 0x000000ff; \ + (*((x)+3)) = ((rt_uint32_t)(v) >> 24); \ + } while ( 0 ) + +/* -- the end of option -- */ + +/* std header file */ +#include +#include +#include +#include +#include + +#define FINSH_VERSION_MAJOR 1 +#define FINSH_VERSION_MINOR 0 + +/** + * @addtogroup finsh + */ +/*@{*/ +#define FINSH_ERROR_OK 0 /**< No error */ +#define FINSH_ERROR_INVALID_TOKEN 1 /**< Invalid token */ +#define FINSH_ERROR_EXPECT_TYPE 2 /**< Expect a type */ +#define FINSH_ERROR_UNKNOWN_TYPE 3 /**< Unknown type */ +#define FINSH_ERROR_VARIABLE_EXIST 4 /**< Variable exist */ +#define FINSH_ERROR_EXPECT_OPERATOR 5 /**< Expect a operator */ +#define FINSH_ERROR_MEMORY_FULL 6 /**< Memory full */ +#define FINSH_ERROR_UNKNOWN_OP 7 /**< Unknown operator */ +#define FINSH_ERROR_UNKNOWN_NODE 8 /**< Unknown node */ +#define FINSH_ERROR_EXPECT_CHAR 9 /**< Expect a character */ +#define FINSH_ERROR_UNEXPECT_END 10 /**< Unexpect end */ +#define FINSH_ERROR_UNKNOWN_TOKEN 11 /**< Unknown token */ +#define FINSH_ERROR_NO_FLOAT 12 /**< Float not supported */ +#define FINSH_ERROR_UNKNOWN_SYMBOL 13 /**< Unknown symbol */ +#define FINSH_ERROR_NULL_NODE 14 /**< Null node */ +/*@}*/ + +/* system call item */ +struct finsh_syscall_item +{ + struct finsh_syscall_item* next; /* next item */ + struct finsh_syscall syscall; /* syscall */ +}; +extern struct finsh_syscall_item *global_syscall_list; + +/* system variable table */ +struct finsh_sysvar +{ + const char* name; /* the name of variable */ +#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB) + const char* desc; /* description of system variable */ +#endif + uint8_t type; /* the type of variable */ + void* var ; /* the address of variable */ +}; + +#if defined(_MSC_VER) || (defined(__GNUC__) && defined(__x86_64__)) +struct finsh_syscall* finsh_syscall_next(struct finsh_syscall* call); +struct finsh_sysvar* finsh_sysvar_next(struct finsh_sysvar* call); +#define FINSH_NEXT_SYSCALL(index) index=finsh_syscall_next(index) +#define FINSH_NEXT_SYSVAR(index) index=finsh_sysvar_next(index) +#else +#define FINSH_NEXT_SYSCALL(index) index++ +#define FINSH_NEXT_SYSVAR(index) index++ +#endif + +/* system variable item */ +struct finsh_sysvar_item +{ + struct finsh_sysvar_item *next; /* next item */ + struct finsh_sysvar sysvar; /* system variable */ +}; +extern struct finsh_sysvar *_sysvar_table_begin, *_sysvar_table_end; +extern struct finsh_sysvar_item* global_sysvar_list; + +/* find out system variable, which should be implemented in user program */ +struct finsh_sysvar* finsh_sysvar_lookup(const char* name); + + +struct finsh_token +{ + char eof; + char replay; + + int position; + uint8_t current_token; + + union { + char char_value; + int int_value; + long long_value; + } value; + uint8_t string[FINSH_STRING_MAX]; + + uint8_t* line; +}; + +#define FINSH_IDTYPE_VAR 0x01 +#define FINSH_IDTYPE_SYSVAR 0x02 +#define FINSH_IDTYPE_SYSCALL 0x04 +#define FINSH_IDTYPE_ADDRESS 0x08 +struct finsh_node +{ + uint8_t node_type; /* node node_type */ + uint8_t data_type; /* node data node_type */ + uint8_t idtype; /* id node information */ + + union { /* value node */ + char char_value; + short short_value; + int int_value; + long long_value; + void* ptr; + } value; + union + { + /* point to variable identifier or function identifier */ + struct finsh_var *var; + struct finsh_sysvar *sysvar; + struct finsh_syscall*syscall; + }id; + + /* sibling and child node */ + struct finsh_node *sibling, *child; +}; + +struct finsh_parser +{ + uint8_t* parser_string; + + struct finsh_token token; + struct finsh_node* root; +}; + +/** + * @ingroup finsh + * + * The basic data type in finsh shell + */ +enum finsh_type { + finsh_type_unknown = 0, /**< unknown data type */ + finsh_type_void, /**< void */ + finsh_type_voidp, /**< void pointer */ + finsh_type_char, /**< char */ + finsh_type_uchar, /**< unsigned char */ + finsh_type_charp, /**< char pointer */ + finsh_type_short, /**< short */ + finsh_type_ushort, /**< unsigned short */ + finsh_type_shortp, /**< short pointer */ + finsh_type_int, /**< int */ + finsh_type_uint, /**< unsigned int */ + finsh_type_intp, /**< int pointer */ + finsh_type_long, /**< long */ + finsh_type_ulong, /**< unsigned long */ + finsh_type_longp /**< long pointer */ +}; + +/* init finsh environment */ +int finsh_init(struct finsh_parser* parser); +/* flush finsh node, text segment */ +int finsh_flush(struct finsh_parser* parser); +/* reset all of finsh */ +int finsh_reset(struct finsh_parser* parser); +#ifdef RT_USING_DEVICE +void finsh_set_device(const char* device_name); +#endif + +/* run finsh parser to generate abstract synatx tree */ +void finsh_parser_run (struct finsh_parser* parser, const unsigned char* string); +/* run compiler to compile abstract syntax tree */ +int finsh_compiler_run(struct finsh_node* node); +/* run finsh virtual machine */ +void finsh_vm_run(void); + +/* get variable value */ +struct finsh_var* finsh_var_lookup(const char* name); +/* get bottom value of stack */ +long finsh_stack_bottom(void); + +/* get error number of finsh */ +uint8_t finsh_errno(void); +/* get error string */ +const char* finsh_error_string(uint8_t type); + +#ifdef RT_USING_HEAP +/** + * @ingroup finsh + * + * This function appends a system call to finsh runtime environment + * @param name the name of system call + * @param func the function pointer of system call + */ +void finsh_syscall_append(const char* name, syscall_func func); + +/** + * @ingroup finsh + * + * This function appends a system variable to finsh runtime environment + * @param name the name of system variable + * @param type the data type of system variable + * @param addr the address of system variable + */ +void finsh_sysvar_append(const char* name, uint8_t type, void* addr); +#endif +#endif diff --git a/rt-thread/components/finsh/finsh_api.h b/rt-thread/components/finsh/finsh_api.h new file mode 100644 index 0000000..3b7c77d --- /dev/null +++ b/rt-thread/components/finsh/finsh_api.h @@ -0,0 +1,231 @@ +/* + * File : finsh_api.h + * COPYRIGHT (C) 2006 - 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#ifndef FINSH_API_H__ +#define FINSH_API_H__ + +#if defined(_MSC_VER) +#pragma section("FSymTab$f",read) +#pragma section("VSymTab",read) +#endif + +typedef long (*syscall_func)(void); + +/* system call table */ +struct finsh_syscall +{ + const char* name; /* the name of system call */ +#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB) + const char* desc; /* description of system call */ +#endif + syscall_func func; /* the function address of system call */ +}; +extern struct finsh_syscall *_syscall_table_begin, *_syscall_table_end; + +/* find out system call, which should be implemented in user program */ +struct finsh_syscall* finsh_syscall_lookup(const char* name); + +#ifdef FINSH_USING_SYMTAB + +#ifdef __TI_COMPILER_VERSION__ +#define __TI_FINSH_EXPORT_FUNCTION(f) PRAGMA(DATA_SECTION(f,"FSymTab")) +#define __TI_FINSH_EXPORT_VAR(v) PRAGMA(DATA_SECTION(v,"VSymTab")) +#endif + + #ifdef FINSH_USING_DESCRIPTION + #ifdef _MSC_VER + #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ + const char __fsym_##cmd##_name[] = #cmd; \ + const char __fsym_##cmd##_desc[] = #desc; \ + __declspec(allocate("FSymTab$f")) \ + const struct finsh_syscall __fsym_##cmd = \ + { \ + __fsym_##cmd##_name, \ + __fsym_##cmd##_desc, \ + (syscall_func)&name \ + }; + #pragma comment(linker, "/merge:FSymTab=mytext") + + #define FINSH_VAR_EXPORT(name, type, desc) \ + const char __vsym_##name##_name[] = #name; \ + const char __vsym_##name##_desc[] = #desc; \ + __declspec(allocate("VSymTab")) \ + const struct finsh_sysvar __vsym_##name = \ + { \ + __vsym_##name##_name, \ + __vsym_##name##_desc, \ + type, \ + (void*)&name \ + }; + + #elif defined(__TI_COMPILER_VERSION__) + #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ + __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd); \ + const char __fsym_##cmd##_name[] = #cmd; \ + const char __fsym_##cmd##_desc[] = #desc; \ + const struct finsh_syscall __fsym_##cmd = \ + { \ + __fsym_##cmd##_name, \ + __fsym_##cmd##_desc, \ + (syscall_func)&name \ + }; + + #define FINSH_VAR_EXPORT(name, type, desc) \ + __TI_FINSH_EXPORT_VAR(__vsym_##name); \ + const char __vsym_##name##_name[] = #name; \ + const char __vsym_##name##_desc[] = #desc; \ + const struct finsh_sysvar __vsym_##name = \ + { \ + __vsym_##name##_name, \ + __vsym_##name##_desc, \ + type, \ + (void*)&name \ + }; + + #else + #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ + const char __fsym_##cmd##_name[] SECTION(".rodata.name") = #cmd; \ + const char __fsym_##cmd##_desc[] SECTION(".rodata.name") = #desc; \ + RT_USED const struct finsh_syscall __fsym_##cmd SECTION("FSymTab")= \ + { \ + __fsym_##cmd##_name, \ + __fsym_##cmd##_desc, \ + (syscall_func)&name \ + }; + + #define FINSH_VAR_EXPORT(name, type, desc) \ + const char __vsym_##name##_name[] SECTION(".rodata.name") = #name; \ + const char __vsym_##name##_desc[] SECTION(".rodata.name") = #desc; \ + RT_USED const struct finsh_sysvar __vsym_##name SECTION("VSymTab")= \ + { \ + __vsym_##name##_name, \ + __vsym_##name##_desc, \ + type, \ + (void*)&name \ + }; + + #endif + #else + #ifdef _MSC_VER + #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ + const char __fsym_##cmd##_name[] = #cmd; \ + __declspec(allocate("FSymTab$f")) \ + const struct finsh_syscall __fsym_##cmd = \ + { \ + __fsym_##cmd##_name, \ + (syscall_func)&name \ + }; + #pragma comment(linker, "/merge:FSymTab=mytext") + + #define FINSH_VAR_EXPORT(name, type, desc) \ + const char __vsym_##name##_name[] = #name; \ + __declspec(allocate("VSymTab")) const struct finsh_sysvar __vsym_##name = \ + { \ + __vsym_##name##_name, \ + type, \ + (void*)&name \ + }; + + #elif defined(__TI_COMPILER_VERSION__) + #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ + __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd); \ + const char __fsym_##cmd##_name[] = #cmd; \ + const struct finsh_syscall __fsym_##cmd = \ + { \ + __fsym_##cmd##_name, \ + (syscall_func)&name \ + }; + + #define FINSH_VAR_EXPORT(name, type, desc) \ + __TI_FINSH_EXPORT_VAR(__vsym_##name); \ + const char __vsym_##name##_name[] = #name; \ + const struct finsh_sysvar __vsym_##name = \ + { \ + __vsym_##name##_name, \ + type, \ + (void*)&name \ + }; + + #else + #define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \ + const char __fsym_##cmd##_name[] = #cmd; \ + RT_USED const struct finsh_syscall __fsym_##cmd SECTION("FSymTab")= \ + { \ + __fsym_##cmd##_name, \ + (syscall_func)&name \ + }; + + #define FINSH_VAR_EXPORT(name, type, desc) \ + const char __vsym_##name##_name[] = #name; \ + RT_USED const struct finsh_sysvar __vsym_##name SECTION("VSymTab")= \ + { \ + __vsym_##name##_name, \ + type, \ + (void*)&name \ + }; + + #endif + #endif /* end of FINSH_USING_DESCRIPTION */ +#endif /* end of FINSH_USING_SYMTAB */ + +/** + * @ingroup finsh + * + * This macro exports a system function to finsh shell. + * + * @param name the name of function. + * @param desc the description of function, which will show in help. + */ +#define FINSH_FUNCTION_EXPORT(name, desc) \ + FINSH_FUNCTION_EXPORT_CMD(name, name, desc) + +/** + * @ingroup finsh + * + * This macro exports a system function with an alias name to finsh shell. + * + * @param name the name of function. + * @param alias the alias name of function. + * @param desc the description of function, which will show in help. + */ +#define FINSH_FUNCTION_EXPORT_ALIAS(name, alias, desc) \ + FINSH_FUNCTION_EXPORT_CMD(name, alias, desc) + +/** + * @ingroup finsh + * + * This macro exports a command to module shell. + * + * @param command the name of command. + * @param desc the description of command, which will show in help. + */ +#ifdef FINSH_USING_MSH +#define MSH_CMD_EXPORT(command, desc) \ + FINSH_FUNCTION_EXPORT_CMD(command, __cmd_##command, desc) +#define MSH_CMD_EXPORT_ALIAS(command, alias, desc) \ + FINSH_FUNCTION_EXPORT_ALIAS(command, __cmd_##alias, desc) +#else +#define MSH_CMD_EXPORT(command, desc) +#define MSH_CMD_EXPORT_ALIAS(command, alias, desc) +#endif + +#endif diff --git a/rt-thread/components/finsh/finsh_compiler.c b/rt-thread/components/finsh/finsh_compiler.c new file mode 100644 index 0000000..cf6bb0f --- /dev/null +++ b/rt-thread/components/finsh/finsh_compiler.c @@ -0,0 +1,937 @@ +/* + * RT-Thread finsh shell compiler + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#include + +#include "finsh_node.h" +#include "finsh_error.h" +#include "finsh_var.h" +#include "finsh_ops.h" + +union finsh_value* finsh_compile_sp; /* stack pointer */ +uint8_t* finsh_compile_pc; /* PC */ + +#define finsh_code_byte(x) do { *finsh_compile_pc = (x); finsh_compile_pc ++; } while(0) +#define finsh_code_word(x) do { FINSH_SET16(finsh_compile_pc, x); finsh_compile_pc +=2; } while(0) +#define finsh_code_dword(x) do { FINSH_SET32(finsh_compile_pc, x); finsh_compile_pc +=4; } while(0) + +static int finsh_compile(struct finsh_node* node) +{ + if (node != NULL) + { + /* compile child node */ + if (finsh_node_child(node) != NULL) + finsh_compile(finsh_node_child(node)); + + /* compile current node */ + switch (node->node_type) + { + case FINSH_NODE_ID: + { + /* identifier::syscall */ + if (node->idtype & FINSH_IDTYPE_SYSCALL) + { + /* load address */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword((long)node->id.syscall->func); + } + /* identifier::sysvar */ + else if (node->idtype & FINSH_IDTYPE_SYSVAR) + { + struct finsh_sysvar* sysvar; + + sysvar = node->id.sysvar; + if (sysvar != NULL) + { + switch (sysvar->type) + { + case finsh_type_char: + case finsh_type_uchar: + if (node->idtype & FINSH_IDTYPE_ADDRESS) + { + /* load address */ + finsh_code_byte(FINSH_OP_LD_DWORD); + } + else + { + /* load value */ + finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); + } + + finsh_code_dword((long)(sysvar->var)); + break; + + case finsh_type_short: + case finsh_type_ushort: + if (node->idtype & FINSH_IDTYPE_ADDRESS) + { + /* load address */ + finsh_code_byte(FINSH_OP_LD_DWORD); + } + else + { + /* load value */ + finsh_code_byte(FINSH_OP_LD_VALUE_WORD); + } + + finsh_code_dword((long)(sysvar->var)); + break; + + case finsh_type_int: + case finsh_type_uint: + case finsh_type_long: + case finsh_type_ulong: + case finsh_type_charp: + case finsh_type_shortp: + case finsh_type_intp: + case finsh_type_longp: + if (node->idtype & FINSH_IDTYPE_ADDRESS) + { + /* load address */ + finsh_code_byte(FINSH_OP_LD_DWORD); + } + else + { + /* load value */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); + } + + finsh_code_dword((long)(sysvar->var)); + break; + } + } + } + /* identifier::var */ + else + { + struct finsh_var* var; + + var = node->id.var; + if (var != NULL) + { + switch (var->type) + { + case finsh_type_char: + case finsh_type_uchar: + if (node->idtype & FINSH_IDTYPE_ADDRESS) + { + /* load address */ + finsh_code_byte(FINSH_OP_LD_DWORD); + } + else + { + /* load value */ + finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); + } + + finsh_code_dword((long)&(var->value.char_value)); + break; + + case finsh_type_short: + case finsh_type_ushort: + if (node->idtype & FINSH_IDTYPE_ADDRESS) + { + /* load address */ + finsh_code_byte(FINSH_OP_LD_DWORD); + } + else + { + /* load value */ + finsh_code_byte(FINSH_OP_LD_VALUE_WORD); + } + + finsh_code_dword((long)&(var->value.short_value)); + break; + + case finsh_type_int: + case finsh_type_uint: + case finsh_type_long: + case finsh_type_ulong: + case finsh_type_charp: + case finsh_type_shortp: + case finsh_type_intp: + case finsh_type_longp: + if (node->idtype & FINSH_IDTYPE_ADDRESS) + { + /* load address */ + finsh_code_byte(FINSH_OP_LD_DWORD); + } + else + { + /* load value */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); + } + + finsh_code_dword((long)&(var->value.long_value)); + break; + } + } + } + } + break; + + /* load const */ + case FINSH_NODE_VALUE_CHAR: + finsh_code_byte(FINSH_OP_LD_BYTE); + finsh_code_byte(node->value.char_value); + break; + + case FINSH_NODE_VALUE_INT: + case FINSH_NODE_VALUE_LONG: + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword(node->value.long_value); + break; + + case FINSH_NODE_VALUE_NULL: + case FINSH_NODE_VALUE_STRING: + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword((uint32_t)node->value.ptr); + break; + + /* arithmetic operation */ + case FINSH_NODE_SYS_ADD: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_ADD_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_ADD_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_ADD_DWORD); + break; + + case FINSH_NODE_SYS_SUB: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_SUB_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_SUB_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_SUB_DWORD); + break; + + case FINSH_NODE_SYS_MUL: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_MUL_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_MUL_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_MUL_DWORD); + break; + + case FINSH_NODE_SYS_DIV: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_DIV_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_DIV_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_DIV_DWORD); + break; + + case FINSH_NODE_SYS_MOD: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_MOD_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_MOD_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_MOD_DWORD); + break; + + /* bit operation */ + case FINSH_NODE_SYS_AND: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_AND_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_AND_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_AND_DWORD); + break; + + case FINSH_NODE_SYS_OR: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_OR_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_OR_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_OR_DWORD); + break; + + case FINSH_NODE_SYS_XOR: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_XOR_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_XOR_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_XOR_DWORD); + break; + + case FINSH_NODE_SYS_BITWISE: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_BITWISE_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_BITWISE_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_BITWISE_DWORD); + break; + + case FINSH_NODE_SYS_SHL: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_SHL_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_SHL_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_SHL_DWORD); + break; + + case FINSH_NODE_SYS_SHR: + if (node->data_type == FINSH_DATA_TYPE_BYTE) finsh_code_byte(FINSH_OP_SHR_BYTE); + else if (node->data_type == FINSH_DATA_TYPE_WORD) finsh_code_byte(FINSH_OP_SHR_WORD); + else if (node->data_type == FINSH_DATA_TYPE_DWORD) finsh_code_byte(FINSH_OP_SHR_DWORD); + break; + + /* syscall */ + case FINSH_NODE_SYS_FUNC: + { + int parameters; + struct finsh_node* sibling; + + parameters = 0; + if (finsh_node_child(node) != NULL) + { + sibling = finsh_node_sibling(finsh_node_child(node)); + while (sibling != NULL) + { + parameters ++; + sibling = finsh_node_sibling(sibling); + } + + /* load address of function */ + // finsh_code_dword((long)&(node->var->value.ptr)); + + /* syscall parameters */ + finsh_code_byte(FINSH_OP_SYSCALL); + finsh_code_byte(parameters); + } + } + break; + + /* assign expression */ + case FINSH_NODE_SYS_ASSIGN: + if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID) + { + switch (finsh_node_child(node)->data_type) + { + case FINSH_DATA_TYPE_BYTE: + finsh_code_byte(FINSH_OP_ST_BYTE); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_BYTE_STACK); + break; + + case FINSH_DATA_TYPE_WORD: + finsh_code_byte(FINSH_OP_ST_WORD); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_WORD_STACK); + break; + + case FINSH_DATA_TYPE_DWORD: + finsh_code_byte(FINSH_OP_ST_DWORD); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); + break; + + default: + finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE); + } + } + else if (finsh_node_child(node)->node_type == FINSH_NODE_SYS_GETVALUE) + { + switch ((finsh_node_child(node)->data_type) & 0x0F) + { + case FINSH_DATA_TYPE_BYTE: + finsh_code_byte(FINSH_OP_ST_BYTE); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_BYTE_STACK); + break; + + case FINSH_DATA_TYPE_WORD: + finsh_code_byte(FINSH_OP_ST_WORD); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_WORD_STACK); + break; + + case FINSH_DATA_TYPE_DWORD: + finsh_code_byte(FINSH_OP_ST_DWORD); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); + break; + + default: + finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE); + } + } + break; + + /* pre-increase */ + case FINSH_NODE_SYS_PREINC: + if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID) + { + struct finsh_var* var; + var = finsh_node_child(node)->id.var; + + /* ld_dword &id */ + // finsh_code_byte(FINSH_OP_LD_DWORD); + + switch (node->data_type) + { + case FINSH_DATA_TYPE_BYTE: + /* address */ + // finsh_code_dword((long)&(var->value.char_value)); + + /* ld_value_byte &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); + finsh_code_dword((long)&(var->value.char_value)); + + /* ld_byte 1 */ + finsh_code_byte(FINSH_OP_LD_BYTE); + finsh_code_byte(1); + + /* add_byte */ + finsh_code_byte(FINSH_OP_ADD_BYTE); + /* st_byte */ + finsh_code_byte(FINSH_OP_ST_BYTE); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); + + break; + + case FINSH_DATA_TYPE_WORD: + /* address */ + // finsh_code_dword((long)&(var->value.short_value)); + + /* ld_value_word &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_WORD); + finsh_code_dword((long)&(var->value.short_value)); + + /* ld_word 1 */ + finsh_code_byte(FINSH_OP_LD_WORD); + finsh_code_word(1); + + /* add_word */ + finsh_code_byte(FINSH_OP_ADD_WORD); + /* st_word */ + finsh_code_byte(FINSH_OP_ST_WORD); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); + + break; + + case FINSH_DATA_TYPE_DWORD: + /* address */ + // finsh_code_dword((long)&(var->value.long_value)); + + /* ld_dword &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); + finsh_code_dword((long)&(var->value.long_value)); + + /* ld_dword 1 */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword(1); + + /* add_dword */ + finsh_code_byte(FINSH_OP_ADD_DWORD); + /* st_dword */ + finsh_code_byte(FINSH_OP_ST_DWORD); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); + + break; + } + } + break; + + /* pre-decrease */ + case FINSH_NODE_SYS_PREDEC: + if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID) + { + struct finsh_var* var; + var = finsh_node_child(node)->id.var; + + /* ld_dword &id */ + // finsh_code_byte(FINSH_OP_LD_DWORD); + + switch (node->data_type) + { + case FINSH_DATA_TYPE_BYTE: + /* address */ + // finsh_code_dword((long)&(var->value.char_value)); + + /* ld_value_byte &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); + finsh_code_dword((long)&(var->value.char_value)); + + /* ld_byte 1 */ + finsh_code_byte(FINSH_OP_LD_BYTE); + finsh_code_byte(1); + + /* add_byte */ + finsh_code_byte(FINSH_OP_SUB_BYTE); + /* st_byte */ + finsh_code_byte(FINSH_OP_ST_BYTE); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); + + break; + + case FINSH_DATA_TYPE_WORD: + /* address */ + // finsh_code_dword((long)&(var->value.short_value)); + + /* ld_value_word &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_WORD); + finsh_code_dword((long)&(var->value.short_value)); + + /* ld_word 1 */ + finsh_code_byte(FINSH_OP_LD_WORD); + finsh_code_word(1); + + /* add_word */ + finsh_code_byte(FINSH_OP_SUB_WORD); + /* st_word */ + finsh_code_byte(FINSH_OP_ST_WORD); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); + + break; + + case FINSH_DATA_TYPE_DWORD: + /* address */ + // finsh_code_dword((long)&(var->value.long_value)); + + /* ld_dword &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); + finsh_code_dword((long)&(var->value.long_value)); + + /* ld_dword 1 */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword(1); + + /* add_dword */ + finsh_code_byte(FINSH_OP_SUB_DWORD); + /* st_dword */ + finsh_code_byte(FINSH_OP_ST_DWORD); + + /* load value again */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); + + break; + } + } + break; + + /* increase */ + case FINSH_NODE_SYS_INC: + if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID) + { + struct finsh_var* var; + var = finsh_node_child(node)->id.var; + + switch (node->data_type) + { + case FINSH_DATA_TYPE_BYTE: + /* ld_value_byte &id */ + // finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); + // finsh_code_dword((long)&(var->value.char_value)); + + /* ld_dword &id */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword((long)&(var->value.char_value)); + + /* ld_value_byte &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); + finsh_code_dword((long)&(var->value.char_value)); + + /* ld_byte 1 */ + finsh_code_byte(FINSH_OP_LD_BYTE); + finsh_code_byte(1); + + /* add_byte */ + finsh_code_byte(FINSH_OP_ADD_BYTE); + /* get byte */ + finsh_code_byte(FINSH_OP_ST_BYTE); + + /* pop */ + finsh_code_byte(FINSH_OP_POP); + break; + + case FINSH_DATA_TYPE_WORD: + /* ld_value_word &id */ + // finsh_code_byte(FINSH_OP_LD_VALUE_WORD); + // finsh_code_dword((long)&(var->value.short_value)); + + /* ld_dword &id */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword((long)&(var->value.short_value)); + + /* ld_value_word &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_WORD); + finsh_code_dword((long)&(var->value.short_value)); + + /* ld_word 1 */ + finsh_code_byte(FINSH_OP_LD_WORD); + finsh_code_word(1); + + /* add_byte */ + finsh_code_byte(FINSH_OP_ADD_WORD); + /* get byte */ + finsh_code_byte(FINSH_OP_ST_WORD); + + /* pop */ + finsh_code_byte(FINSH_OP_POP); + break; + + case FINSH_DATA_TYPE_DWORD: + /* ld_value_dword &id */ + // finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); + // finsh_code_dword((long)&(var->value.long_value)); + + /* ld_dword &id */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword((long)&(var->value.long_value)); + + /* ld_value_dword &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); + finsh_code_dword((long)&(var->value.long_value)); + + /* ld_dword 1 */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword(1); + + /* add_byte */ + finsh_code_byte(FINSH_OP_ADD_DWORD); + /* get byte */ + finsh_code_byte(FINSH_OP_ST_DWORD); + + /* pop */ + finsh_code_byte(FINSH_OP_POP); + break; + } + } + break; + + /* decrease */ + case FINSH_NODE_SYS_DEC: + if (finsh_node_child(node) && finsh_node_child(node)->node_type == FINSH_NODE_ID) + { + struct finsh_var* var; + var = finsh_node_child(node)->id.var; + + switch (node->data_type) + { + case FINSH_DATA_TYPE_BYTE: + /* ld_value_byte &id */ + // finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); + // finsh_code_dword((long)&(var->value.char_value)); + + /* ld_dword &id */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword((long)&(var->value.char_value)); + + /* ld_value_byte &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_BYTE); + finsh_code_dword((long)&(var->value.char_value)); + + /* ld_byte 1 */ + finsh_code_byte(FINSH_OP_LD_BYTE); + finsh_code_byte(1); + + /* add_byte */ + finsh_code_byte(FINSH_OP_SUB_BYTE); + /* get byte */ + finsh_code_byte(FINSH_OP_ST_BYTE); + + /* pop */ + finsh_code_byte(FINSH_OP_POP); + break; + + case FINSH_DATA_TYPE_WORD: + /* ld_value_word &id */ + // finsh_code_byte(FINSH_OP_LD_VALUE_WORD); + // finsh_code_dword((long)&(var->value.short_value)); + + /* ld_dword &id */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword((long)&(var->value.short_value)); + + /* ld_value_word &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_WORD); + finsh_code_dword((long)&(var->value.short_value)); + + /* ld_word 1 */ + finsh_code_byte(FINSH_OP_LD_WORD); + finsh_code_word(1); + + /* add_byte */ + finsh_code_byte(FINSH_OP_SUB_WORD); + /* get byte */ + finsh_code_byte(FINSH_OP_ST_WORD); + + /* pop */ + finsh_code_byte(FINSH_OP_POP); + break; + + case FINSH_DATA_TYPE_DWORD: + /* ld_value_dword &id */ + // finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); + // finsh_code_dword((long)&(var->value.long_value)); + + /* ld_dword &id */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword((long)&(var->value.long_value)); + + /* ld_value_dword &id */ + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD); + finsh_code_dword((long)&(var->value.long_value)); + + /* ld_dword 1 */ + finsh_code_byte(FINSH_OP_LD_DWORD); + finsh_code_dword(1); + + /* add_byte */ + finsh_code_byte(FINSH_OP_SUB_DWORD); + /* get byte */ + finsh_code_byte(FINSH_OP_ST_DWORD); + + /* pop */ + finsh_code_byte(FINSH_OP_POP); + break; + } + } + break; + + case FINSH_NODE_SYS_NULL: + finsh_code_dword(0); + break; + + case FINSH_NODE_SYS_GETVALUE: + if (node->idtype & FINSH_IDTYPE_ADDRESS) + { + /* nothing will be generated */ + } + else + { + switch (node->data_type) + { + case FINSH_DATA_TYPE_BYTE: + finsh_code_byte(FINSH_OP_LD_VALUE_BYTE_STACK); + break; + case FINSH_DATA_TYPE_WORD: + finsh_code_byte(FINSH_OP_LD_VALUE_WORD_STACK); + break; + case FINSH_DATA_TYPE_DWORD: + finsh_code_byte(FINSH_OP_LD_VALUE_DWORD_STACK); + break; + default: + break; + } + } + break; + + case FINSH_NODE_SYS_GETADDR: + /* nothing will be generated */ + break; + + default: + finsh_error_set(FINSH_ERROR_UNKNOWN_NODE); + break; + } + + /* compile sibling node */ + if (finsh_node_sibling(node) != NULL) + finsh_compile(finsh_node_sibling(node)); + } + + return 0; +} + +static int finsh_type_check(struct finsh_node* node, uint8_t is_addr) +{ + if (node != NULL) + { + /* address & value */ + if (node->node_type == FINSH_NODE_SYS_ASSIGN || + node->node_type == FINSH_NODE_SYS_PREINC || + node->node_type == FINSH_NODE_SYS_PREDEC || + node->node_type == FINSH_NODE_SYS_GETADDR) + { + /* address */ + finsh_type_check(finsh_node_child(node), FINSH_IDTYPE_ADDRESS); + } + else if (node->node_type == FINSH_NODE_SYS_GETVALUE && is_addr) + { + /* change the attribute of getvalue in left expr */ + finsh_type_check(finsh_node_child(node), 0); + } + else + { + /* transfer 'av' to child node */ + finsh_type_check(finsh_node_child(node), is_addr); + } + + /* always does not load address in sibling */ + finsh_type_check(finsh_node_sibling(node), FINSH_NODE_VALUE); + + /** set attribute of current node */ + + /* make sure the current node is address or value */ + if (node->idtype != FINSH_IDTYPE_SYSCALL) node->idtype |= is_addr; + + if (finsh_node_child(node) != NULL) + { + node->data_type = finsh_node_child(node)->data_type; + return 0; + } + + if (node->node_type == FINSH_NODE_ID) + { + if (node->idtype & FINSH_IDTYPE_VAR) + { + struct finsh_var* var; + + var = node->id.var; + if (var != NULL) + { + switch (var->type) + { + case finsh_type_void: + node->data_type = FINSH_DATA_TYPE_VOID; + break; + + case finsh_type_char: + case finsh_type_uchar: + node->data_type = FINSH_DATA_TYPE_BYTE; + break; + + case finsh_type_short: + case finsh_type_ushort: + node->data_type = FINSH_DATA_TYPE_WORD; + break; + + case finsh_type_int: + case finsh_type_uint: + case finsh_type_long: + case finsh_type_ulong: + node->data_type = FINSH_DATA_TYPE_DWORD; + break; + + case finsh_type_charp: + case finsh_type_voidp: + case finsh_type_shortp: + case finsh_type_intp: + case finsh_type_longp: + node->data_type = FINSH_DATA_TYPE_DWORD; + break; + + default: + finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE); + break; + } + } + } + else if (node->idtype & FINSH_IDTYPE_SYSVAR) + { + struct finsh_sysvar *sysvar; + + sysvar = node->id.sysvar; + if (sysvar != NULL) + { + switch (sysvar->type) + { + case finsh_type_void: + node->data_type = FINSH_DATA_TYPE_VOID; + break; + + case finsh_type_char: + case finsh_type_uchar: + node->data_type = FINSH_DATA_TYPE_BYTE; + break; + + case finsh_type_short: + case finsh_type_ushort: + node->data_type = FINSH_DATA_TYPE_WORD; + break; + + case finsh_type_int: + case finsh_type_uint: + case finsh_type_long: + case finsh_type_ulong: + node->data_type = FINSH_DATA_TYPE_DWORD; + break; + + case finsh_type_charp: + case finsh_type_voidp: + case finsh_type_shortp: + case finsh_type_intp: + case finsh_type_longp: + node->data_type = FINSH_DATA_TYPE_DWORD; + break; + + default: + finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE); + break; + } + } + } + } + else if (node->node_type == FINSH_NODE_VALUE_CHAR) + { + node->data_type = FINSH_DATA_TYPE_BYTE; + } + else if (node->node_type == FINSH_NODE_VALUE_INT || + node->node_type == FINSH_NODE_VALUE_LONG || + node->node_type == FINSH_NODE_VALUE_STRING || + node->node_type == FINSH_NODE_VALUE_NULL) + { + node->data_type = FINSH_DATA_TYPE_DWORD; + } + } + return 0; +} + +int finsh_compiler_run(struct finsh_node* node) +{ + struct finsh_node* sibling; + + /* type check */ + finsh_type_check(node, FINSH_NODE_VALUE); + + /* clean text segment and vm stack */ + memset(&text_segment[0], 0, sizeof(text_segment)); + memset(&finsh_vm_stack[0], 0, sizeof(finsh_vm_stack[0])); + + /* reset compile stack pointer and pc */ + finsh_compile_sp = &finsh_vm_stack[0]; + finsh_compile_pc = &text_segment[0]; + + /* compile node */ + sibling = node; + while (sibling != NULL) + { + struct finsh_node* current_node; + current_node = sibling; + + /* get sibling node */ + sibling = current_node->sibling; + + /* clean sibling node */ + current_node->sibling = NULL; + finsh_compile(current_node); + + /* pop current value */ + if (sibling != NULL) finsh_code_byte(FINSH_OP_POP); + } + + return 0; +} diff --git a/rt-thread/components/finsh/finsh_error.c b/rt-thread/components/finsh/finsh_error.c new file mode 100644 index 0000000..962aee1 --- /dev/null +++ b/rt-thread/components/finsh/finsh_error.c @@ -0,0 +1,74 @@ +/* + * error number for finsh shell. + * + * COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#include "finsh_error.h" + +uint8_t global_errno; + +static const char * finsh_error_string_table[] = +{ + "No error", + "Invalid token", + "Expect a type", + "Unknown type", + "Variable exist", + "Expect a operater", + "Memory full", + "Unknown operator", + "Unknown node", + "Expect a character", + "Unexpect end", + "Unknown token", + "Float not supported", + "Unknown symbol", + "Null node" +}; + +int finsh_error_init() +{ + global_errno = FINSH_ERROR_OK; + + return 0; +} + +int finsh_error_set(uint8_t type) +{ + global_errno = type; + + return 0; +} + +uint8_t finsh_errno() +{ + return global_errno; +} + +const char* finsh_error_string(uint8_t type) +{ + return finsh_error_string_table[type]; +} diff --git a/rt-thread/components/finsh/finsh_error.h b/rt-thread/components/finsh/finsh_error.h new file mode 100644 index 0000000..bec5d85 --- /dev/null +++ b/rt-thread/components/finsh/finsh_error.h @@ -0,0 +1,42 @@ +/* + * error number for finsh shell. + * + * COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#ifndef __FINSH_ERROR_H__ +#define __FINSH_ERROR_H__ + +#include + +int finsh_error_init(void); + +/* get error number */ +uint8_t finsh_errno(void); + +int finsh_error_set(uint8_t type); +const char* finsh_error_string(uint8_t type); + +#endif diff --git a/rt-thread/components/finsh/finsh_heap.c b/rt-thread/components/finsh/finsh_heap.c new file mode 100644 index 0000000..f2f4beb --- /dev/null +++ b/rt-thread/components/finsh/finsh_heap.c @@ -0,0 +1,298 @@ +/* + * heap management in finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#include + +#include "finsh_var.h" + +ALIGN(RT_ALIGN_SIZE) +uint8_t finsh_heap[FINSH_HEAP_MAX]; +struct finsh_block_header +{ + uint32_t length; + struct finsh_block_header* next; +}; +#define BLOCK_HEADER(x) (struct finsh_block_header*)(x) +#define finsh_block_get_header(data) (struct finsh_block_header*)((uint8_t*)data - sizeof(struct finsh_block_header)) +#define finsh_block_get_data(header) (uint8_t*)((struct finsh_block_header*)header + 1) +#define HEAP_ALIGN_SIZE(size) (((size) + HEAP_ALIGNMENT - 1) & ~(HEAP_ALIGNMENT-1)) + +static struct finsh_block_header* free_list; +static struct finsh_block_header* allocate_list; + +static void finsh_heap_gc(void); + +static void finsh_block_insert(struct finsh_block_header** list, struct finsh_block_header* header); +static void finsh_block_remove(struct finsh_block_header** list, struct finsh_block_header* header); +static void finsh_block_split(struct finsh_block_header* header, size_t size); +static void finsh_block_merge(struct finsh_block_header** list, struct finsh_block_header* header); + +int finsh_heap_init(void) +{ + /* clear heap to zero */ + memset(&finsh_heap[0], 0, sizeof(finsh_heap)); + + /* init free and alloc list */ + free_list = BLOCK_HEADER(&finsh_heap[0]); + free_list->length = FINSH_HEAP_MAX - sizeof(struct finsh_block_header); + free_list->next = NULL; + + allocate_list = NULL; + + return 0; +} + +/** + * allocate a block from heap + */ +void* finsh_heap_allocate(size_t size) +{ + struct finsh_block_header* header; + + size = HEAP_ALIGN_SIZE(size); + + /* find the first fit block */ + for (header = free_list; + ((header != NULL) && (header->length <= size + sizeof(struct finsh_block_header))); + header = header->next) ; + + if (header == NULL) + { + finsh_heap_gc(); + + /* find the first fit block */ + for (header = free_list; + ((header != NULL) && (header->length < size + sizeof(struct finsh_block_header))); + header = header->next) ; + + /* there is no memory */ + if (header == NULL) return NULL; + } + + /* split block */ + finsh_block_split(header, size); + + /* remove from free list */ + finsh_block_remove(&free_list, header); + header->next = NULL; + + /* insert to allocate list */ + finsh_block_insert(&allocate_list, header); + + memset(finsh_block_get_data(header), 0, size); + + return finsh_block_get_data(header); +} + +/** + * release the allocated block + */ +void finsh_heap_free(void*ptr) +{ + struct finsh_block_header* header; + + /* get block header */ + header = finsh_block_get_header(ptr); + + /* remove from allocate list */ + finsh_block_remove(&allocate_list, header); + + /* insert to free list */ + finsh_block_insert(&free_list, header); + finsh_block_merge(&free_list, header); +} + +/** + * garbage collector + */ +static void finsh_heap_gc(void) +{ + int i; + struct finsh_block_header *header, *temp; + + temp = NULL; + + /* find the first fit block */ + for (header = allocate_list; header != NULL; ) + { + for (i = 0; i < FINSH_VARIABLE_MAX; i ++) + { + if (global_variable[i].type != finsh_type_unknown) + { + if (global_variable[i].value.ptr == finsh_block_get_data(header)) + break; + } + } + + temp = header; + header = header->next; + + /* this block is an unused block, release it */ + if (i == FINSH_VARIABLE_MAX) + { + finsh_heap_free(finsh_block_get_data(temp)); + } + } +} + +/** + * insert a block to list + */ +void finsh_block_insert(struct finsh_block_header** list, struct finsh_block_header* header) +{ + struct finsh_block_header* node; + + if (*list == NULL) + { + *list = header; + return; + } + + /* find out insert point */ + node = *list; + + if (node > header) + { + /* insert node in the header of list */ + header->next = node; + *list = header; + + return; + } + else + { + for (node = *list; node; node = node->next) + { + if (node->next > header) break; + + if (node->next == NULL) break; + } + } + + /* insert node */ + if (node->next != NULL) header->next = node->next; + node->next = header; +} + +/** + * remove block from list + */ +void finsh_block_remove(struct finsh_block_header** list, struct finsh_block_header* header) +{ + struct finsh_block_header* node; + + node = *list; + if (node == header) + { + /* remove list header */ + *list = header->next; + header->next = NULL; + + return; + } + + for (node = *list; node != NULL; node = node->next) + { + if (node->next == header) + { + node->next = header->next; + break; + } + } +} + +/** + * split block + */ +void finsh_block_split(struct finsh_block_header* header, size_t size) +{ + struct finsh_block_header* next; + + /* + * split header into two node: + * header->next->... + */ + next = BLOCK_HEADER((uint8_t*)header + sizeof(struct finsh_block_header) + size); + next->length = header->length - sizeof(struct finsh_block_header) - size; + header->length = size; + next->next = header->next; + + header->next = next; +} + +void finsh_block_merge(struct finsh_block_header** list, struct finsh_block_header* header) +{ + struct finsh_block_header* prev_node; + struct finsh_block_header* next_node; + + next_node = header->next; + + if (*list == header) prev_node = NULL; + else + { + /* find out the previous header */ + for (prev_node = *list; prev_node; prev_node =prev_node->next) + { + if (prev_node->next == header) + break; + } + } + + /* try merge node */ + + /* merge to previous node */ + if (prev_node != NULL && + ((uint8_t*)prev_node + prev_node->length + sizeof(struct finsh_block_header) + == (uint8_t*)header)) + { + /* is it close to next node? */ + if ((next_node != NULL) && + ((uint8_t*)header + header->length + sizeof(struct finsh_block_header) + == (uint8_t*)next_node)) + { + /* merge three node */ + prev_node->length += header->length + next_node->length + + 2 * sizeof(struct finsh_block_header); + + prev_node->next = next_node->next; + } + else + { + prev_node->length += header->length + sizeof(struct finsh_block_header); + prev_node->next = header->next; + } + } + else /* merge to last node */ + if ( (next_node != NULL) && + ((uint8_t*)header + header->length + sizeof(struct finsh_block_header) + == (uint8_t*)next_node)) + { + header->length += next_node->length + sizeof(struct finsh_block_header); + header->next = next_node->next; + } +} diff --git a/rt-thread/components/finsh/finsh_heap.h b/rt-thread/components/finsh/finsh_heap.h new file mode 100644 index 0000000..7ea61d4 --- /dev/null +++ b/rt-thread/components/finsh/finsh_heap.h @@ -0,0 +1,38 @@ +/* + * heap management in finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#include + +#ifndef __FINSH_HEAP_H__ +#define __FINSH_HEAP_H__ + +int finsh_heap_init(void); +void* finsh_heap_allocate(size_t size); +void finsh_heap_free(void*ptr); + +#endif diff --git a/rt-thread/components/finsh/finsh_init.c b/rt-thread/components/finsh/finsh_init.c new file mode 100644 index 0000000..a285209 --- /dev/null +++ b/rt-thread/components/finsh/finsh_init.c @@ -0,0 +1,76 @@ +/* + * Initialization procedure for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#include + +#include "finsh_node.h" +#include "finsh_vm.h" +#include "finsh_parser.h" +#include "finsh_var.h" +#include "finsh_error.h" +#include "finsh_heap.h" + +int finsh_init(struct finsh_parser* parser) +{ + finsh_parser_init(parser); + + /* finsh init */ + finsh_node_init(); + finsh_var_init(); + finsh_error_init(); + finsh_heap_init(); + + return 0; +} + +long finsh_stack_bottom() +{ + return finsh_vm_stack[0].long_value; +} + +int finsh_flush(struct finsh_parser* parser) +{ + finsh_parser_init(parser); + + /* finsh init */ + finsh_node_init(); + finsh_error_init(); + + return 0; +} + +int finsh_reset(struct finsh_parser* parser) +{ + /* finsh init */ + finsh_node_init(); + finsh_var_init(); + finsh_error_init(); + finsh_heap_init(); + + return 0; +} diff --git a/rt-thread/components/finsh/finsh_node.c b/rt-thread/components/finsh/finsh_node.c new file mode 100644 index 0000000..ae28a6a --- /dev/null +++ b/rt-thread/components/finsh/finsh_node.c @@ -0,0 +1,202 @@ +/* + * node routines for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#include + +#include "finsh_node.h" +#include "finsh_error.h" +#include "finsh_var.h" +#include "finsh_heap.h" + +struct finsh_node global_node_table[FINSH_NODE_MAX]; + +int finsh_node_init() +{ + memset(global_node_table, 0, sizeof(global_node_table)); + + return 0; +} + +struct finsh_node* finsh_node_allocate(uint8_t type) +{ + int i; + + /* find an empty entry */ + for (i = 0; i < FINSH_NODE_MAX; i ++) + { + if (global_node_table[i].node_type == FINSH_NODE_UNKNOWN) break; + } + + if (i == FINSH_NODE_MAX) return NULL; + + /* fill type field */ + global_node_table[i].node_type = type; + + /* return this allocated node */ + return &global_node_table[i]; +} + +struct finsh_node* finsh_node_new_id(char* id) +{ + struct finsh_node* node; + void* symbol; + unsigned char type; + + symbol = NULL; + type = 0; + node = NULL; + + /* lookup variable firstly */ + symbol = (void*)finsh_var_lookup(id); + if (symbol == NULL) + { + /* then lookup system variable */ + symbol = (void*)finsh_sysvar_lookup(id); + if (symbol == NULL) + { + /* then lookup system call */ + symbol = (void*)finsh_syscall_lookup(id); + if (symbol != NULL) type = FINSH_IDTYPE_SYSCALL; + } + else type = FINSH_IDTYPE_SYSVAR; + } + else type = FINSH_IDTYPE_VAR; + + if (symbol != NULL) + { + /* allocate a new node */ + node = finsh_node_allocate(FINSH_NODE_ID); + + /* allocate node error */ + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + /* fill node value according type */ + switch (type) + { + case FINSH_IDTYPE_VAR: + node->id.var = (struct finsh_var*)symbol; + break; + + case FINSH_IDTYPE_SYSVAR: + node->id.sysvar = (struct finsh_sysvar*)symbol; + break; + + case FINSH_IDTYPE_SYSCALL: + node->id.syscall = (struct finsh_syscall*)symbol; + break; + } + /* fill identifier type */ + node->idtype = type; + } + else finsh_error_set(FINSH_ERROR_UNKNOWN_SYMBOL); + + return node; +} + +struct finsh_node* finsh_node_new_char(char c) +{ + struct finsh_node* node; + + node = finsh_node_allocate(FINSH_NODE_VALUE_CHAR); + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + node->value.char_value = c; + return node; +} + +struct finsh_node* finsh_node_new_int(int i) +{ + struct finsh_node* node; + + node = finsh_node_allocate(FINSH_NODE_VALUE_INT); + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + node->value.int_value = i; + return node; +} + +struct finsh_node* finsh_node_new_long(long l) +{ + struct finsh_node* node; + + node = finsh_node_allocate(FINSH_NODE_VALUE_LONG); + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + node->value.long_value = l; + return node; +} + +struct finsh_node* finsh_node_new_string(char* s) +{ + struct finsh_node* node; + + node = finsh_node_allocate(FINSH_NODE_VALUE_STRING); + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + /* make string */ + node->value.ptr = finsh_heap_allocate(strlen(s) + 1); + strncpy(node->value.ptr, s, strlen(s)); + ((uint8_t*)node->value.ptr)[strlen(s)] = '\0'; + + return node; +} + +struct finsh_node* finsh_node_new_ptr(void* ptr) +{ + struct finsh_node* node; + + node = finsh_node_allocate(FINSH_NODE_VALUE_NULL); + if (node == NULL) + { + finsh_error_set(FINSH_ERROR_MEMORY_FULL); + return NULL; + } + + node->value.ptr = ptr; + return node; +} diff --git a/rt-thread/components/finsh/finsh_node.h b/rt-thread/components/finsh/finsh_node.h new file mode 100644 index 0000000..5e0e4a3 --- /dev/null +++ b/rt-thread/components/finsh/finsh_node.h @@ -0,0 +1,88 @@ +/* + * node routines for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#ifndef __FINSH_NODE_H__ +#define __FINSH_NODE_H__ + +#include + +#define FINSH_NODE_UNKNOWN 0 +#define FINSH_NODE_ID 1 + +#define FINSH_NODE_VALUE_CHAR 2 +#define FINSH_NODE_VALUE_INT 3 +#define FINSH_NODE_VALUE_LONG 4 +#define FINSH_NODE_VALUE_STRING 5 +#define FINSH_NODE_VALUE_NULL 6 + +#define FINSH_NODE_SYS_ADD 7 +#define FINSH_NODE_SYS_SUB 8 +#define FINSH_NODE_SYS_MUL 9 +#define FINSH_NODE_SYS_DIV 10 +#define FINSH_NODE_SYS_MOD 11 +#define FINSH_NODE_SYS_AND 12 +#define FINSH_NODE_SYS_OR 13 +#define FINSH_NODE_SYS_XOR 14 +#define FINSH_NODE_SYS_BITWISE 15 +#define FINSH_NODE_SYS_SHL 16 +#define FINSH_NODE_SYS_SHR 17 +#define FINSH_NODE_SYS_FUNC 18 +#define FINSH_NODE_SYS_ASSIGN 19 +#define FINSH_NODE_SYS_CAST 20 +#define FINSH_NODE_SYS_PREINC 21 +#define FINSH_NODE_SYS_PREDEC 22 +#define FINSH_NODE_SYS_INC 23 +#define FINSH_NODE_SYS_DEC 24 +#define FINSH_NODE_SYS_GETVALUE 25 +#define FINSH_NODE_SYS_GETADDR 26 +#define FINSH_NODE_SYS_NULL 27 + +#define FINSH_DATA_TYPE_VOID 0x00 +#define FINSH_DATA_TYPE_BYTE 0x01 +#define FINSH_DATA_TYPE_WORD 0x02 +#define FINSH_DATA_TYPE_DWORD 0x03 +#define FINSH_DATA_TYPE_PTR 0x10 + +#define FINSH_NODE_VALUE 0 +#define FINSH_NODE_ADDRESS 1 +#define FINSH_NODE_FUNCTION 2 + +int finsh_node_init(void); + +struct finsh_node* finsh_node_allocate(uint8_t type); +struct finsh_node* finsh_node_new_id(char* id); +struct finsh_node* finsh_node_new_char(char c); +struct finsh_node* finsh_node_new_int(int i); +struct finsh_node* finsh_node_new_long(long l); +struct finsh_node* finsh_node_new_string(char* s); +struct finsh_node* finsh_node_new_ptr(void* ptr); + +#define finsh_node_sibling(node) ((node)->sibling) +#define finsh_node_child(node) ((node)->child) + +#endif diff --git a/rt-thread/components/finsh/finsh_ops.c b/rt-thread/components/finsh/finsh_ops.c new file mode 100644 index 0000000..cefdf3c --- /dev/null +++ b/rt-thread/components/finsh/finsh_ops.c @@ -0,0 +1,622 @@ +/* + * operations for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#include "finsh_ops.h" +#include "finsh_vm.h" + +#define OP_BIN_BYTE(x) do {\ + (finsh_sp - 2)->char_value = (finsh_sp - 2)->char_value x (finsh_sp - 1)->char_value; \ + finsh_sp--; \ + }while (0) + +#define OP_BIN_WORD(x) do {\ + (finsh_sp - 2)->short_value = (finsh_sp - 2)->short_value x (finsh_sp - 1)->short_value; \ + finsh_sp--; \ + }while (0) + +#define OP_BIN_DWORD(x) do {\ + (finsh_sp - 2)->long_value = (finsh_sp - 2)->long_value x (finsh_sp - 1)->long_value; \ + finsh_sp--; \ + }while (0) + +/* --- noop --- */ +void OP_no_op() +{ + /* none */ + return ; +} + +/* --- add --- */ +void OP_add_byte() +{ + OP_BIN_BYTE(+); + + return ; +} + +void OP_add_word() +{ + OP_BIN_WORD(+); + + return ; +} + +void OP_add_dword() +{ + OP_BIN_DWORD(+); + + return ; +} + +/* --- sub --- */ +void OP_sub_byte() +{ + OP_BIN_BYTE(-); + + return ; +} + +void OP_sub_word() +{ + OP_BIN_WORD(-); + + return ; +} + +void OP_sub_dword() +{ + OP_BIN_DWORD(-); + + return ; +} + +/* --- div --- */ +void OP_div_byte() +{ + OP_BIN_BYTE(/); + + return ; +} + +void OP_div_word() +{ + OP_BIN_WORD(/); + + return ; +} + +void OP_div_dword() +{ + OP_BIN_DWORD(/); + + return ; +} + +/* --- mod --- */ +void OP_mod_byte() +{ + OP_BIN_BYTE(%); + + return ; +} + +void OP_mod_word() +{ + OP_BIN_WORD(%); + + return ; +} + +void OP_mod_dword() +{ + OP_BIN_DWORD(%); + + return ; +} + +/* --- mul --- */ +void OP_mul_byte() +{ + OP_BIN_BYTE(*); + + return ; +} + +void OP_mul_word() +{ + OP_BIN_WORD(*); + + return ; +} + +void OP_mul_dword() +{ + OP_BIN_DWORD(*); + + return ; +} + +/* --- and --- */ +void OP_and_byte() +{ + OP_BIN_BYTE(&); + + return ; +} + +void OP_and_word() +{ + OP_BIN_WORD(&); + + return ; +} + +void OP_and_dword() +{ + OP_BIN_DWORD(&); + + return ; +} + +/* --- or --- */ +void OP_or_byte() +{ + OP_BIN_BYTE(|); + + return ; +} + +void OP_or_word() +{ + OP_BIN_WORD(|); + + return ; +} + +void OP_or_dword() +{ + OP_BIN_DWORD(|); + + return ; +} + +/* --- xor --- */ +void OP_xor_byte() +{ + OP_BIN_BYTE(^); + + return ; +} + +void OP_xor_word() +{ + OP_BIN_WORD(^); + + return ; +} + +void OP_xor_dword() +{ + OP_BIN_DWORD(^); + + return ; +} + +/* --- bw --- */ +void OP_bw_byte() +{ + (finsh_sp - 1)->char_value = ~ ((finsh_sp - 1)->char_value); + + return ; +} + +void OP_bw_word() +{ + (finsh_sp - 1)->short_value = ~ ((finsh_sp - 1)->short_value); + + return ; +} + +void OP_bw_dword() +{ + (finsh_sp - 1)->long_value = ~ ((finsh_sp - 1)->long_value); + + return ; +} + +/* --- shl --- */ +void OP_shl_byte() +{ + OP_BIN_BYTE(<<); + + return ; +} + +void OP_shl_word() +{ + OP_BIN_WORD(<<); + + return ; +} + +void OP_shl_dword() +{ + OP_BIN_DWORD(<<); + + return ; +} + +/* --- shr --- */ +void OP_shr_byte() +{ + OP_BIN_BYTE(>>); + + return ; +} + +void OP_shr_word() +{ + OP_BIN_WORD(>>); + + return ; +} + +void OP_shr_dword() +{ + OP_BIN_DWORD(>>); + + return ; +} + +/* --- ld --- */ +void OP_ld_byte() +{ + finsh_sp->char_value = *finsh_pc; + + finsh_sp++; + finsh_pc++; + + return ; +} + +void OP_ld_word() +{ + finsh_sp->short_value = FINSH_GET16(finsh_pc); + + finsh_sp ++; + finsh_pc += 2; + + return ; +} + +void OP_ld_dword() +{ + finsh_sp->long_value = FINSH_GET32(finsh_pc); + + finsh_sp ++; + finsh_pc += 4; + + return ; +} + +void OP_ld_value_byte() +{ + char* c; + + c = (char*) (FINSH_GET32(finsh_pc)); + + finsh_sp->char_value = *c; + + finsh_sp ++; + finsh_pc += 4; + + return; +} + +void OP_ld_value_byte_stack() +{ + char* c; + + c = (char *)(finsh_sp - 1)->long_value; + (finsh_sp - 1)->char_value = *c; + + return; +} + +void OP_ld_value_word() +{ + short* s; + + s = (short*) (FINSH_GET32(finsh_pc)); + + finsh_sp->short_value = *s; + + finsh_sp ++; + finsh_pc += 4; + + return; +} + +void OP_ld_value_word_stack() +{ + short* s; + + s = (short *)(finsh_sp - 1)->long_value; + (finsh_sp - 1)->short_value = *s; + + return; +} + +void OP_ld_value_dword() +{ + long* l; + + l = (long*) (FINSH_GET32(finsh_pc)); + + finsh_sp->long_value = *l; + + finsh_sp ++; + finsh_pc += 4; + + return; +} + +void OP_ld_value_dword_stack() +{ + long* l; + + l = (long *)(finsh_sp - 1)->long_value; + (finsh_sp - 1)->long_value = *l; + + return; +} + +/* --- st --- */ +/* + * 2006-4-16 bernard + * fixed the sp move bug + */ +void OP_st_byte() +{ + *(char*)((finsh_sp - 2)->long_value) = (finsh_sp - 1)->char_value; + finsh_sp --; + + return ; +} + +/* + * 2006-4-16 bernard + * fixed the sp move bug + */ +void OP_st_word() +{ + *(short*)((finsh_sp - 2)->long_value) = (finsh_sp - 1)->short_value; + finsh_sp --; + + return ; +} + +/* + * 2006-4-16 bernard + * fixed the sp move bug + */ +void OP_st_dword() +{ + *(long*)((finsh_sp - 2)->long_value) = (finsh_sp - 1)->long_value; + finsh_sp --; + + return ; +} + +/* --- pop --- */ +void OP_pop() +{ + finsh_sp --; + return ; +} + +/* --- call --- */ +void OP_call() +{ + /* the max number of arg*/ + unsigned long parameterv[16]; + unsigned int parameters, i; + + typedef unsigned long var_t; + typedef var_t (*op_func)(); + op_func f; + var_t r; + + parameters = *finsh_pc ++; + + i = 0; finsh_sp --; + while (i < parameters) + { + parameterv[parameters - 1 - i] = finsh_sp->long_value; + finsh_sp --; + i++; + } + + f = (op_func)(finsh_sp->long_value); + switch (parameters) + { + case 0: + r = f(0); + break; + + case 1: + r = f(parameterv[0]); + break; + + case 2: + r = f(parameterv[0], parameterv[1]); + break; + + case 3: + r = f(parameterv[0], parameterv[1], parameterv[2]); + break; + + case 4: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3]); + break; + + case 5: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4]); + break; + + case 6: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5]); + break; + + case 7: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6]); + break; + + case 8: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7]); + break; + + case 9: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8]); + break; + + case 10: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9]); + break; + + case 11: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10]); + break; + + case 12: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10], parameterv[11]); + break; + + case 13: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10], parameterv[11], + parameterv[12]); + break; + + case 14: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10], parameterv[11], + parameterv[12], parameterv[13]); + break; + + case 15: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10], parameterv[11], + parameterv[12], parameterv[13], parameterv[14]); + break; + + case 16: + r = f(parameterv[0], parameterv[1], parameterv[2], parameterv[3], + parameterv[4], parameterv[5], parameterv[6], parameterv[7], + parameterv[8], parameterv[9], parameterv[10], parameterv[11], + parameterv[12], parameterv[13], parameterv[14], parameterv[15]); + break; + + default: + r = 0; + break; + } + + finsh_sp->long_value = r; + finsh_sp ++; + + return ; +} + +const op_func op_table[] = +{ + /* 00 */ OP_no_op, + /* 01 */ OP_add_byte, + /* 02 */ OP_add_word, + /* 03 */ OP_add_dword, + /* 04 */ OP_sub_byte, + /* 05 */ OP_sub_word, + /* 06 */ OP_sub_dword, + /* 07 */ OP_div_byte, + /* 08 */ OP_div_word, + /* 09 */ OP_div_dword, + /* 10 */ OP_mod_byte, + /* 11 */ OP_mod_word, + /* 12 */ OP_mod_dword, + /* 13 */ OP_mul_byte, + /* 14 */ OP_mul_word, + /* 15 */ OP_mul_dword, + /* 16 */ OP_and_byte, + /* 17 */ OP_and_word, + /* 18 */ OP_and_dword, + /* 19 */ OP_or_byte, + /* 20 */ OP_or_word, + /* 21 */ OP_or_dword, + /* 22 */ OP_xor_byte, + /* 23 */ OP_xor_word, + /* 24 */ OP_xor_dword, + /* 25 */ OP_bw_byte, + /* 26 */ OP_bw_word, + /* 27 */ OP_bw_dword, + /* 28 */ OP_shl_byte, + /* 29 */ OP_shl_word, + /* 30 */ OP_shl_dword, + /* 31 */ OP_shr_byte, + /* 32 */ OP_shr_word, + /* 33 */ OP_shr_dword, + /* 34 */ OP_ld_byte, + /* 35 */ OP_ld_word, + /* 36 */ OP_ld_dword, + /* 37 */ OP_ld_value_byte, + /* 38 */ OP_ld_value_word, + /* 39 */ OP_ld_value_dword, + /* 40 */ OP_st_byte, + /* 41 */ OP_st_word, + /* 42 */ OP_st_dword, + /* 43 */ OP_pop, + /* 44 */ OP_call, + /* 45 */ OP_ld_value_byte_stack, + /* 46 */ OP_ld_value_word_stack, + /* 47 */ OP_ld_value_dword_stack, + NULL +}; diff --git a/rt-thread/components/finsh/finsh_ops.h b/rt-thread/components/finsh/finsh_ops.h new file mode 100644 index 0000000..4e4c5c9 --- /dev/null +++ b/rt-thread/components/finsh/finsh_ops.h @@ -0,0 +1,135 @@ +/* + * operations for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#ifndef __FINSH_OP_H__ +#define __FINSH_OP_H__ + +#include "finsh_vm.h" + +/* + * FinC VM specification + * Memory + * .VAR + * + * .STACK + * + * .HEAP + * + * .TEXT + * OP [op1] + */ + +#define FINSH_OP_NOOP 0x00 + +/* add @ r1 = r2 + r3 */ +#define FINSH_OP_ADD_BYTE 0x01 +#define FINSH_OP_ADD_WORD 0x02 +#define FINSH_OP_ADD_DWORD 0x03 + +/* sub @ r1 = r2 - r3 */ +#define FINSH_OP_SUB_BYTE 0x04 +#define FINSH_OP_SUB_WORD 0x05 +#define FINSH_OP_SUB_DWORD 0x06 + +/* div @ r1 = r2 / r3 */ +#define FINSH_OP_DIV_BYTE 0x07 +#define FINSH_OP_DIV_WORD 0x08 +#define FINSH_OP_DIV_DWORD 0x09 + +/* mod @ r1 = r2 % r3 */ +#define FINSH_OP_MOD_BYTE 0x0A +#define FINSH_OP_MOD_WORD 0x0B +#define FINSH_OP_MOD_DWORD 0x0C + +/* mul @ r1 = r2 * r3 */ +#define FINSH_OP_MUL_BYTE 0x0D +#define FINSH_OP_MUL_WORD 0x0E +#define FINSH_OP_MUL_DWORD 0x0F + +/* and @ r1 = r2 & r3 */ +#define FINSH_OP_AND_BYTE 0x10 +#define FINSH_OP_AND_WORD 0x11 +#define FINSH_OP_AND_DWORD 0x12 + +/* or @ r1 = r2 | r3 */ +#define FINSH_OP_OR_BYTE 0x13 +#define FINSH_OP_OR_WORD 0x14 +#define FINSH_OP_OR_DWORD 0x15 + +/* xor @ r1 = r2 ^ r3 */ +#define FINSH_OP_XOR_BYTE 0x16 +#define FINSH_OP_XOR_WORD 0x17 +#define FINSH_OP_XOR_DWORD 0x18 + +/* bw @ r1 = ~r2 */ +#define FINSH_OP_BITWISE_BYTE 0x19 +#define FINSH_OP_BITWISE_WORD 0x1A +#define FINSH_OP_BITWISE_DWORD 0x1B + +/* shl @ r1 = r2 << r3 */ +#define FINSH_OP_SHL_BYTE 0x1C +#define FINSH_OP_SHL_WORD 0x1D +#define FINSH_OP_SHL_DWORD 0x1E + +/* shr @ r1 = r2 >> r3 */ +#define FINSH_OP_SHR_BYTE 0x1F +#define FINSH_OP_SHR_WORD 0x20 +#define FINSH_OP_SHR_DWORD 0x21 + +/* ld @ r1 = [r2] */ +#define FINSH_OP_LD_BYTE 0x22 +#define FINSH_OP_LD_WORD 0x23 +#define FINSH_OP_LD_DWORD 0x24 + +#define FINSH_OP_LD_VALUE_BYTE 0x25 +#define FINSH_OP_LD_VALUE_WORD 0x26 +#define FINSH_OP_LD_VALUE_DWORD 0x27 + +/* st @ [r2] = r1 */ +#define FINSH_OP_ST_BYTE 0x28 +#define FINSH_OP_ST_WORD 0x29 +#define FINSH_OP_ST_DWORD 0x2A + +/* pop */ +#define FINSH_OP_POP 0x2B + +/* call r1 @ [r1](stack) */ +#define FINSH_OP_SYSCALL 0x2C + +/* load value from stack */ +#define FINSH_OP_LD_VALUE_BYTE_STACK 0x2D +#define FINSH_OP_LD_VALUE_WORD_STACK 0x2E +#define FINSH_OP_LD_VALUE_DWORD_STACK 0x2F + +/* halt */ +#define FINSH_OP_HALT 0xFF + +typedef void (*op_func)(); +extern const op_func op_table[]; + +#endif diff --git a/rt-thread/components/finsh/finsh_parser.c b/rt-thread/components/finsh/finsh_parser.c new file mode 100644 index 0000000..aa85509 --- /dev/null +++ b/rt-thread/components/finsh/finsh_parser.c @@ -0,0 +1,1005 @@ +/* + * script parser for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + * 2013-10-09 Bernard fix the command line too long issue. + */ +#include + +#include "finsh_token.h" +#include "finsh_node.h" +#include "finsh_error.h" +#include "finsh_parser.h" +#include "finsh_var.h" + +/* + * the structure of abstract syntax tree: + * root____________ + * | \ + * child__ sibling__ + * | \ | \ + * child sibling child sibling + * ... + */ +static enum finsh_type proc_type(struct finsh_parser* self); +static int proc_identifier(struct finsh_parser* self, char* id); +static struct finsh_node* proc_variable_decl(struct finsh_parser* self); +static struct finsh_node* proc_expr(struct finsh_parser* self); +static struct finsh_node* proc_assign_expr(struct finsh_parser* self); +static struct finsh_node* proc_inclusive_or_expr(struct finsh_parser* self); +static struct finsh_node* proc_exclusive_or_expr(struct finsh_parser* self); +static struct finsh_node* proc_and_expr(struct finsh_parser* self); +static struct finsh_node* proc_shift_expr(struct finsh_parser* self); +static struct finsh_node* proc_additive_expr(struct finsh_parser* self); +static struct finsh_node* proc_multiplicative_expr(struct finsh_parser* self); +static struct finsh_node* proc_cast_expr(struct finsh_parser* self); +static struct finsh_node* proc_unary_expr(struct finsh_parser* self); +static struct finsh_node* proc_postfix_expr(struct finsh_parser* self); +static struct finsh_node* proc_primary_expr(struct finsh_parser* self); +static struct finsh_node* proc_param_list(struct finsh_parser* self); +static struct finsh_node* proc_expr_statement(struct finsh_parser* self); +static struct finsh_node* make_sys_node(uint8_t type, struct finsh_node* node1, + struct finsh_node* node2); + +/* check token */ +#define check_token(token, lex, type) if ( (token) != (type) ) \ + { \ + finsh_error_set(FINSH_ERROR_INVALID_TOKEN); \ + finsh_token_replay(lex); \ + } + +/* is the token a data type? */ +#define is_base_type(token) ((token) == finsh_token_type_void \ + || (token) == finsh_token_type_char \ + || (token) == finsh_token_type_short \ + || (token) == finsh_token_type_int \ + || (token) == finsh_token_type_long) + +/* get the next token */ +#define next_token(token, lex) (token) = finsh_token_token(lex) + +/* match a specified token */ +#define match_token(token, lex, type) next_token(token, lex); \ + check_token(token, lex, type) + +/* +process for function and variable declaration. +decl_variable -> type declaration_list ';' +declarator_list -> declarator_list ',' declarator + | declarator +declarator -> identifier + | identifier ASSIGN expr_assign +*/ +static struct finsh_node* proc_variable_decl(struct finsh_parser* self) +{ + enum finsh_token_type token; + enum finsh_type type; + char id[FINSH_NAME_MAX + 1]; + + struct finsh_node *node; + struct finsh_node *end; + struct finsh_node *assign; + + node = NULL; + end = NULL; + + /* get type */ + type = proc_type(self); + + /*process id.*/ + if (proc_identifier(self, id) == 0) + { + /* if add variable failed */ + if (finsh_var_insert(id, type) < 0) + { + finsh_error_set(FINSH_ERROR_VARIABLE_EXIST); + } + } + + next_token(token, &(self->token)); + switch ( token ) + { + case finsh_token_type_comma:/*',', it's a variable_list declaration.*/ + if (proc_identifier(self, id) == 0) + { + /* if add variable failed */ + if (finsh_var_insert(id, type) < 0) + { + finsh_error_set(FINSH_ERROR_VARIABLE_EXIST); + } + } + + next_token(token, &(self->token)); + if ( token == finsh_token_type_assign ) + { + /* get the right side of assign expression */ + assign = proc_assign_expr(self); + + if (assign != NULL) + { + struct finsh_node* idnode; + + idnode = finsh_node_new_id(id); + end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + node = end; + + next_token(token, &(self->token)); + } + } + + while ( token == finsh_token_type_comma ) + { + if (proc_identifier(self, id) == 0) + { + /* if add variable failed */ + if (finsh_var_insert(id, type) < 0) + { + finsh_error_set(FINSH_ERROR_VARIABLE_EXIST); + } + } + + next_token(token, &(self->token)); + if ( token == finsh_token_type_assign ) + { + /* get the right side of assign expression */ + assign = proc_assign_expr(self); + + if (assign != NULL) + { + struct finsh_node* idnode; + + idnode = finsh_node_new_id(id); + + /* make assign expression node */ + if (node != NULL) + { + finsh_node_sibling(end) = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + end = finsh_node_sibling(end); + } + else + { + end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + node = end; + } + + next_token(token, &(self->token)); + } + } + } + + check_token(token, &(self->token), finsh_token_type_semicolon); + return node; + + case finsh_token_type_assign:/*'=', it's a variable with assign declaration.*/ + { + struct finsh_node *idnode; + + assign = proc_assign_expr(self); + if (assign != NULL) + { + idnode = finsh_node_new_id(id); + + /* make assign expression node */ + end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + node = end; + + next_token(token, &(self->token)); + } + + while ( token == finsh_token_type_comma ) + { + if (proc_identifier(self, id) == 0) + { + /* if add variable failed */ + if (finsh_var_insert(id, type) < 0) + { + finsh_error_set(FINSH_ERROR_VARIABLE_EXIST); + } + } + + next_token(token, &(self->token)); + if (token == finsh_token_type_assign) + { + /* get the right side of assign expression */ + assign = proc_assign_expr(self); + + if (assign != NULL) + { + idnode = finsh_node_new_id(id); + + /* make assign expression node */ + if (node != NULL) + { + finsh_node_sibling(end) = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + end = finsh_node_sibling(end); + } + else + { + end = make_sys_node(FINSH_NODE_SYS_ASSIGN, idnode, assign); + node = end; + } + + next_token(token, &(self->token)); + } + } + } + + check_token(token, &(self->token), finsh_token_type_semicolon); + return node; + } + + case finsh_token_type_semicolon:/*';', it's a variable declaration.*/ + return node; + + default: + finsh_error_set(FINSH_ERROR_EXPECT_TYPE); + + return NULL; + } +} + +/* +type -> type_prefix type_basic | type_basic +type_prefix -> UNSIGNED +type_basic -> VOID + | CHAR + | SHORT + | INT + | STRING +*/ +static enum finsh_type proc_type(struct finsh_parser* self) +{ + enum finsh_type type; + enum finsh_token_type token; + + /* set init type */ + type = finsh_type_unknown; + + next_token(token, &(self->token)); + if ( is_base_type(token) ) /* base_type */ + { + switch (token) + { + case finsh_token_type_void: + type = finsh_type_void; + break; + + case finsh_token_type_char: + type = finsh_type_char; + break; + + case finsh_token_type_short: + type = finsh_type_short; + break; + + case finsh_token_type_int: + type = finsh_type_int; + break; + + case finsh_token_type_long: + type = finsh_type_long; + break; + + default: + goto __return; + } + } + else if ( token == finsh_token_type_unsigned ) /* unsigned base_type */ + { + next_token(token, &(self->token)); + if ( is_base_type(token) ) + { + switch (token) + { + case finsh_token_type_char: + type = finsh_type_uchar; + break; + + case finsh_token_type_short: + type = finsh_type_ushort; + break; + + case finsh_token_type_int: + type = finsh_type_uint; + break; + + case finsh_token_type_long: + type = finsh_type_ulong; + break; + + default: + goto __return; + } + } + else + { + finsh_token_replay(&(self->token)); + finsh_error_set(FINSH_ERROR_EXPECT_TYPE); + } + } + else + { + goto __return; + } + + /* parse for pointer */ + next_token(token, &(self->token)); + if (token == finsh_token_type_mul) + { + switch (type) + { + case finsh_type_void: + type = finsh_type_voidp; + break; + + case finsh_type_char: + case finsh_type_uchar: + type = finsh_type_charp; + break; + + case finsh_type_short: + case finsh_type_ushort: + type = finsh_type_shortp; + break; + + case finsh_type_int: + case finsh_type_uint: + type = finsh_type_intp; + break; + + case finsh_type_long: + case finsh_type_ulong: + type = finsh_type_longp; + break; + + default: + type = finsh_type_voidp; + break; + } + } + else finsh_token_replay(&(self->token)); + + return type; + +__return: + finsh_token_replay(&(self->token)); + finsh_error_set(FINSH_ERROR_UNKNOWN_TYPE); + + return type; +} + +/* +identifier -> IDENTIFIER +*/ +static int proc_identifier(struct finsh_parser* self, char* id) +{ + enum finsh_token_type token; + + match_token(token, &(self->token), finsh_token_type_identifier); + + strncpy(id, (char*)self->token.string, FINSH_NAME_MAX); + + return 0; +} + +/* +statement_expr -> ';' + | expr ';' +*/ +static struct finsh_node* proc_expr_statement(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* expr; + + expr = NULL; + next_token(token, &(self->token)); + if ( token != finsh_token_type_semicolon ) + { + finsh_token_replay(&(self->token)); + expr = proc_expr(self); + + match_token(token, &(self->token), finsh_token_type_semicolon); + } + + return expr; +} + +/* +expr -> expr_assign +*/ +static struct finsh_node* proc_expr(struct finsh_parser* self) +{ + return proc_assign_expr(self); +} + +/* +expr_assign -> expr_inclusive_or + | expr_unary ASSIGN expr_assign +*/ +static struct finsh_node* proc_assign_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* or; + struct finsh_node* assign; + + or = proc_inclusive_or_expr(self); + + next_token(token, &(self->token)); + + if (token == finsh_token_type_assign) + { + assign = proc_assign_expr(self); + + return make_sys_node(FINSH_NODE_SYS_ASSIGN, or, assign); + } + else finsh_token_replay(&(self->token)); + + return or; +} + +/* +expr_inclusive_or -> expr_exclusive_or + | expr_inclusive_or '|' expr_exclusive_or +*/ +static struct finsh_node* proc_inclusive_or_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* xor; + struct finsh_node* xor_new; + + xor = proc_exclusive_or_expr(self); + + next_token(token, &(self->token)); + while ( token == finsh_token_type_or ) + { + xor_new = proc_exclusive_or_expr(self); + + if (xor_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else xor = make_sys_node(FINSH_NODE_SYS_OR, xor, xor_new); + + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return xor; +} + +/* +expr_exclusive_or -> expr_and + | expr_exclusive '^' expr_and +*/ +static struct finsh_node* proc_exclusive_or_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* and; + struct finsh_node* and_new; + + and = proc_and_expr(self); + next_token(token, &(self->token)); + while ( token == finsh_token_type_xor ) + { + and_new = proc_and_expr(self); + if (and_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else and = make_sys_node(FINSH_NODE_SYS_XOR, and, and_new); + + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return and; +} + +/* +expr_and -> expr_shift + | expr_and '&' expr_shift +*/ +static struct finsh_node* proc_and_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* shift; + struct finsh_node* shift_new; + + shift = proc_shift_expr(self); + + next_token(token, &(self->token)); + while ( token == finsh_token_type_and ) + { + shift_new = proc_shift_expr(self); + + if (shift_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else shift = make_sys_node(FINSH_NODE_SYS_AND, shift, shift_new); + + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return shift; +} + +/* +expr_shift -> expr_additive + | expr_shift '<<' expr_additive + | expr_shift '>>' expr_additive +*/ +static struct finsh_node* proc_shift_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* add; + struct finsh_node* add_new; + + add = proc_additive_expr(self); + + next_token(token, &(self->token)); + while ( token == finsh_token_type_shl || token == finsh_token_type_shr) + { + add_new = proc_additive_expr(self); + if (add_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else + { + switch (token) + { + case finsh_token_type_shl: + add = make_sys_node(FINSH_NODE_SYS_SHL, add, add_new); + break; + case finsh_token_type_shr: + add = make_sys_node(FINSH_NODE_SYS_SHR, add, add_new); + break; + default: + finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + break; + } + } + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return add; +} + +/* +expr_additive -> expr_multiplicative + | expr_additive SUB expr_multiplicative + | expr_additive ADD expr_multiplicative +*/ +static struct finsh_node* proc_additive_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* mul; + struct finsh_node* mul_new; + + mul = proc_multiplicative_expr(self); + + next_token(token, &(self->token)); + while ( token == finsh_token_type_sub || token == finsh_token_type_add ) + { + mul_new = proc_multiplicative_expr(self); + if (mul_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else + { + switch (token) + { + case finsh_token_type_sub: + mul = make_sys_node(FINSH_NODE_SYS_SUB, mul, mul_new); + break; + case finsh_token_type_add: + mul = make_sys_node(FINSH_NODE_SYS_ADD, mul, mul_new); + break; + default: + finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + break; + } + } + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return mul; +} + +/* +expr_multiplicative -> expr_cast + | expr_multiplicative '*' expr_cast + | expr_multiplicative '/' expr_cast + | expr_multiplicative '%' expr_cast +*/ +static struct finsh_node* proc_multiplicative_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* cast; + struct finsh_node* cast_new; + + cast = proc_cast_expr(self); + next_token(token, &(self->token)); + while (token == finsh_token_type_mul || + token == finsh_token_type_div || + token == finsh_token_type_mod ) + { + cast_new = proc_cast_expr(self); + if (cast_new == NULL) finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + else + { + switch (token) + { + case finsh_token_type_mul: + cast = make_sys_node(FINSH_NODE_SYS_MUL, cast, cast_new); + break; + + case finsh_token_type_div: + cast = make_sys_node(FINSH_NODE_SYS_DIV, cast, cast_new); + break; + + case finsh_token_type_mod: + cast = make_sys_node(FINSH_NODE_SYS_MOD, cast, cast_new); + break; + + default: + finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + break; + } + } + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return cast; +} + +/* +20060313, add recast parse +expr_cast -> expr_unary + | '(' type ')' expr_cast +*/ +static struct finsh_node* proc_cast_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + enum finsh_type type; + struct finsh_node* cast; + + next_token(token, &(self->token)); + if (token == finsh_token_type_left_paren) + { + type = proc_type(self); + match_token(token, &(self->token), finsh_token_type_right_paren); + + cast = proc_cast_expr(self); + if (cast != NULL) + { + cast->data_type = type; + return cast; + } + } + + finsh_token_replay(&(self->token)); + return proc_unary_expr(self); +} + +/* +20050921, add '*' and '&' +expr_unary -> expr_postfix + | ADD expr_cast + | INC expr_cast + | SUB expr_cast + | DEC expr_cast + | '~' expr_cast + | '*' expr_cast + | '&' expr_cast +*/ +static struct finsh_node* proc_unary_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node *cast; + + next_token(token, &(self->token)); + switch (token) + { + case finsh_token_type_add: /* + */ + cast = proc_cast_expr(self); + return cast; + + case finsh_token_type_inc: /* ++ */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_PREINC, cast, NULL); + + case finsh_token_type_sub: /* - */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_SUB, finsh_node_new_long(0), cast); + + case finsh_token_type_dec: /* -- */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_PREDEC, cast, NULL); + + case finsh_token_type_bitwise: /* ~ */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_BITWISE, cast, NULL); + + case finsh_token_type_mul: /* * */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_GETVALUE, cast, NULL); + + case finsh_token_type_and: /* & */ + cast = proc_cast_expr(self); + return make_sys_node(FINSH_NODE_SYS_GETADDR, cast, NULL); + + default: + finsh_token_replay(&(self->token)); + return proc_postfix_expr(self); + } +} + +/* +expr_postfix -> expr_primary + | expr_postfix INC + | expr_postfix DEC + | expr_postfix '(' param_list ')' +*/ +static struct finsh_node* proc_postfix_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* postfix; + + postfix = proc_primary_expr(self); + + next_token(token, &(self->token)); + while ( token == finsh_token_type_inc || + token == finsh_token_type_dec || + token == finsh_token_type_left_paren ) + { + switch (token) + { + case finsh_token_type_inc :/* '++' */ + postfix = make_sys_node(FINSH_NODE_SYS_INC, postfix, NULL); + break; + + case finsh_token_type_dec :/* '--' */ + postfix = make_sys_node(FINSH_NODE_SYS_DEC, postfix, NULL); + break; + + case finsh_token_type_left_paren :/* '(' */ + { + struct finsh_node* param_list; + + param_list = NULL; + next_token(token, &(self->token)); + if (token != finsh_token_type_right_paren) + { + finsh_token_replay(&(self->token)); + param_list = proc_param_list(self); + + match_token(token, &(self->token), finsh_token_type_right_paren); + } + + postfix = make_sys_node(FINSH_NODE_SYS_FUNC, postfix, param_list); + } + break; + + default: + break; + } + + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + return postfix; +} + +/* +expr_primary -> literal + | '(' expr ')' + | identifier +*/ +static struct finsh_node* proc_primary_expr(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node* expr; + + next_token(token, &(self->token)); + switch ( token ) + { + case finsh_token_type_identifier: + { + char id[FINSH_NAME_MAX + 1]; + + finsh_token_replay(&(self->token)); + proc_identifier(self, id); + return finsh_node_new_id(id); + } + + case finsh_token_type_left_paren: + expr = proc_expr(self); + match_token(token, &(self->token), finsh_token_type_right_paren); + return expr; + + case finsh_token_type_value_int: + return finsh_node_new_int(self->token.value.int_value); + + case finsh_token_type_value_long: + return finsh_node_new_long(self->token.value.long_value); + + case finsh_token_type_value_char: + return finsh_node_new_char(self->token.value.char_value); + + case finsh_token_type_value_string: + return finsh_node_new_string((char*)self->token.string); + + case finsh_token_type_value_null: + return finsh_node_new_ptr(NULL); + + default: + finsh_error_set(FINSH_ERROR_INVALID_TOKEN); + break; + } + + return NULL; +} + +/* +param_list -> empty + | expr_assign + | param_list ',' expr_assign +*/ +static struct finsh_node* proc_param_list(struct finsh_parser* self) +{ + enum finsh_token_type token; + struct finsh_node *node, *assign; + + assign = proc_assign_expr(self); + if (assign == NULL) return NULL; + node = assign; + + next_token(token, &(self->token)); + while (token == finsh_token_type_comma ) + { + finsh_node_sibling(assign) = proc_assign_expr(self); + + if (finsh_node_sibling(assign) != NULL) assign = finsh_node_sibling(assign); + else finsh_error_set(FINSH_ERROR_EXPECT_OPERATOR); + + next_token(token, &(self->token)); + } + + finsh_token_replay(&(self->token)); + + return node; +} + +/* +make a new node as following tree: +new_node +| +node1__ + \ + node2 +*/ +static struct finsh_node* make_sys_node(uint8_t type, struct finsh_node* node1, struct finsh_node* node2) +{ + struct finsh_node* node; + + node = finsh_node_allocate(type); + + if ((node1 != NULL) && (node != NULL)) + { + finsh_node_child(node) = node1; + finsh_node_sibling(node1) = node2; + } + else finsh_error_set(FINSH_ERROR_NULL_NODE); + + return node; +} + +/* +start -> statement_expr | decl_variable +*/ +void finsh_parser_run(struct finsh_parser* self, const uint8_t* string) +{ + enum finsh_token_type token; + struct finsh_node *node; + + node = NULL; + + /* init parser */ + self->parser_string = (uint8_t*)string; + + /* init token */ + finsh_token_init(&(self->token), self->parser_string); + + /* get next token */ + next_token(token, &(self->token)); + while (token != finsh_token_type_eof && token != finsh_token_type_bad) + { + switch (token) + { + case finsh_token_type_identifier: + /* process expr_statement */ + finsh_token_replay(&(self->token)); + + if (self->root != NULL) + { + finsh_node_sibling(node) = proc_expr_statement(self); + if (finsh_node_sibling(node) != NULL) + node = finsh_node_sibling(node); + } + else + { + node = proc_expr_statement(self); + self->root = node; + } + break; + + default: + if (is_base_type(token) || token == finsh_token_type_unsigned) + { + /* variable decl */ + finsh_token_replay(&(self->token)); + + if (self->root != NULL) + { + finsh_node_sibling(node) = proc_variable_decl(self); + if (finsh_node_sibling(node) != NULL) + node = finsh_node_sibling(node); + } + else + { + node = proc_variable_decl(self); + self->root = node; + } + } + else + { + /* process expr_statement */ + finsh_token_replay(&(self->token)); + + if (self->root != NULL) + { + finsh_node_sibling(node) = proc_expr_statement(self); + if (finsh_node_sibling(node) != NULL) + node = finsh_node_sibling(node); + else next_token(token, &(self->token)); + } + else + { + node = proc_expr_statement(self); + self->root = node; + } + } + + break; + } + + /* no root found, break out */ + if (self->root == NULL) break; + + /* get next token */ + next_token(token, &(self->token)); + } +} + +int finsh_parser_init(struct finsh_parser* self) +{ + memset(self, 0, sizeof(struct finsh_parser)); + + return 0; +} diff --git a/rt-thread/components/finsh/finsh_parser.h b/rt-thread/components/finsh/finsh_parser.h new file mode 100644 index 0000000..00d440a --- /dev/null +++ b/rt-thread/components/finsh/finsh_parser.h @@ -0,0 +1,37 @@ +/* + * script parser for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#ifndef __FINSH_PARSER_H__ +#define __FINSH_PARSER_H__ + +#include + +int finsh_parser_init(struct finsh_parser* self); +void finsh_parser_run(struct finsh_parser* self, const uint8_t* string); + +#endif diff --git a/rt-thread/components/finsh/finsh_token.c b/rt-thread/components/finsh/finsh_token.c new file mode 100644 index 0000000..a9fd0ac --- /dev/null +++ b/rt-thread/components/finsh/finsh_token.c @@ -0,0 +1,617 @@ +/* + * token lex for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + * 2013-04-03 Bernard strip more characters. + */ +#include +#include + +#include "finsh_token.h" +#include "finsh_error.h" + +#define is_alpha(ch) ((ch | 0x20) - 'a') < 26u +#define is_digit(ch) ((ch) >= '0' && (ch) <= '9') +#define is_xdigit(ch) (((ch) >= '0' && (ch) <= '9') || (((ch | 0x20) - 'a') < 6u)) +#define is_separator(ch) !(((ch) >= 'a' && (ch) <= 'z') \ + || ((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= '0' && (ch) <= '9') || ((ch) == '_')) +#define is_eof(self) (self)->eof + +struct name_table +{ + char* name; + enum finsh_token_type type; +}; + +/* keyword */ +static const struct name_table finsh_name_table[] = +{ + {"void", finsh_token_type_void}, + {"char", finsh_token_type_char}, + {"short", finsh_token_type_short}, + {"int", finsh_token_type_int}, + {"long", finsh_token_type_long}, + {"unsigned", finsh_token_type_unsigned}, + + {"NULL", finsh_token_type_value_null}, + {"null", finsh_token_type_value_null} +}; + +static char token_next_char(struct finsh_token* self); +static void token_prev_char(struct finsh_token* self); +static long token_spec_number(char* string, int length, int b); +static void token_run(struct finsh_token* self); +static int token_match_name(struct finsh_token* self, const char* str); +static void token_proc_number(struct finsh_token* self); +static uint8_t* token_proc_string(struct finsh_token* self); +static void token_trim_space(struct finsh_token* self); +static char token_proc_char(struct finsh_token* self); +static int token_proc_escape(struct finsh_token* self); + +void finsh_token_init(struct finsh_token* self, uint8_t* line) +{ + memset(self, 0, sizeof(struct finsh_token)); + + self->line = line; +} + +enum finsh_token_type finsh_token_token(struct finsh_token* self) +{ + if ( self->replay ) self->replay = 0; + else token_run(self); + + return (enum finsh_token_type)self->current_token; +} + +void finsh_token_get_token(struct finsh_token* self, uint8_t* token) +{ + strncpy((char*)token, (char*)self->string, FINSH_NAME_MAX); +} + +int token_get_string(struct finsh_token* self, uint8_t* str) +{ + unsigned char *p=str; + char ch; + + ch = token_next_char(self); + if (is_eof(self)) return -1; + + str[0] = '\0'; + + if ( is_digit(ch) )/*the first character of identifier is not a digit.*/ + { + token_prev_char(self); + return -1; + } + + while (!is_separator(ch) && !is_eof(self)) + { + *p++ = ch; + + ch = token_next_char(self); + } + self->eof = 0; + + token_prev_char(self); + *p = '\0'; + + return 0; +} + +/* +get next character. +*/ +static char token_next_char(struct finsh_token* self) +{ + if (self->eof) return '\0'; + + if (self->position == (int)strlen((char*)self->line) || self->line[self->position] =='\n') + { + self->eof = 1; + self->position = 0; + return '\0'; + } + + return self->line[self->position++]; +} + +static void token_prev_char(struct finsh_token* self) +{ + if ( self->eof ) return; + + if ( self->position == 0 ) return; + else self->position--; +} + +static void token_run(struct finsh_token* self) +{ + char ch; + + token_trim_space(self); /* first trim space and tab. */ + token_get_string(self, &(self->string[0])); + + if ( is_eof(self) ) /*if it is eof, break;*/ + { + self->current_token = finsh_token_type_eof; + return ; + } + + if (self->string[0] != '\0') /*It is a key word or a identifier.*/ + { + if ( !token_match_name(self, (char*)self->string) ) + { + self->current_token = finsh_token_type_identifier; + } + } + else/*It is a operator character.*/ + { + ch = token_next_char(self); + + switch ( ch ) + { + case '(': + self->current_token = finsh_token_type_left_paren; + break; + + case ')': + self->current_token = finsh_token_type_right_paren; + break; + + case ',': + self->current_token = finsh_token_type_comma; + break; + + case ';': + self->current_token = finsh_token_type_semicolon; + break; + + case '&': + self->current_token = finsh_token_type_and; + break; + + case '*': + self->current_token = finsh_token_type_mul; + break; + + case '+': + ch = token_next_char(self); + + if ( ch == '+' ) + { + self->current_token = finsh_token_type_inc; + } + else + { + token_prev_char(self); + self->current_token = finsh_token_type_add; + } + break; + + case '-': + ch = token_next_char(self); + + if ( ch == '-' ) + { + self->current_token = finsh_token_type_dec; + } + else + { + token_prev_char(self); + self->current_token = finsh_token_type_sub; + } + break; + + case '/': + ch = token_next_char(self); + if (ch == '/') + { + /* line comments, set to end of file */ + self->current_token = finsh_token_type_eof; + } + else + { + token_prev_char(self); + self->current_token = finsh_token_type_div; + } + break; + + case '<': + ch = token_next_char(self); + + if ( ch == '<' ) + { + self->current_token = finsh_token_type_shl; + } + else + { + token_prev_char(self); + self->current_token = finsh_token_type_bad; + } + break; + + case '>': + ch = token_next_char(self); + + if ( ch == '>' ) + { + self->current_token = finsh_token_type_shr; + } + else + { + token_prev_char(self); + self->current_token = finsh_token_type_bad; + } + break; + + case '|': + self->current_token = finsh_token_type_or; + break; + + case '%': + self->current_token = finsh_token_type_mod; + break; + + case '~': + self->current_token = finsh_token_type_bitwise; + break; + + case '^': + self->current_token = finsh_token_type_xor; + break; + + case '=': + self->current_token = finsh_token_type_assign; + break; + + case '\'': + self->value.char_value = token_proc_char(self); + self->current_token = finsh_token_type_value_char; + break; + + case '"': + token_proc_string(self); + self->current_token = finsh_token_type_value_string; + break; + + default: + if ( is_digit(ch) ) + { + token_prev_char(self); + token_proc_number(self); + break; + } + + finsh_error_set(FINSH_ERROR_UNKNOWN_TOKEN); + self->current_token = finsh_token_type_bad; + + break; + } + } +} + +static int token_match_name(struct finsh_token* self, const char* str) +{ + int i; + + for (i = 0; i < sizeof(finsh_name_table)/sizeof(struct name_table); i++) + { + if ( strcmp(finsh_name_table[i].name, str)==0 ) + { + self->current_token = finsh_name_table[i].type; + return 1; + } + } + + return 0; +} + +static void token_trim_space(struct finsh_token* self) +{ + char ch; + while ( (ch = token_next_char(self)) ==' ' || + ch == '\t' || + ch == '\r'); + + token_prev_char(self); +} + +static char token_proc_char(struct finsh_token* self) +{ + char ch; + char buf[4], *p; + + p = buf; + ch = token_next_char(self); + + if ( ch == '\\' ) + { + ch = token_next_char(self); + switch ( ch ) + { + case 'n': ch = '\n'; break; + case 't': ch = '\t'; break; + case 'v': ch = '\v'; break; + case 'b': ch = '\b'; break; + case 'r': ch = '\r'; break; + case '\\': ch = '\\'; break; + case '\'': ch = '\''; break; + default : + while ( is_digit(ch) )/*for '\113' char*/ + { + ch = token_next_char(self); + *p++ = ch; + } + + token_prev_char(self); + *p = '\0'; + ch = atoi(p); + break; + } + } + + if ( token_next_char(self) != '\'' ) + { + token_prev_char(self); + finsh_error_set(FINSH_ERROR_EXPECT_CHAR); + return ch; + } + + return ch; +} + +static uint8_t* token_proc_string(struct finsh_token* self) +{ + uint8_t* p; + + for ( p = &self->string[0]; p - &(self->string[0]) < FINSH_STRING_MAX; ) + { + char ch = token_next_char(self); + + if ( is_eof(self) ) + { + finsh_error_set(FINSH_ERROR_UNEXPECT_END); + return NULL;; + } + if ( ch == '\\' ) + { + ch = token_proc_escape(self); + } + else if ( ch == '"' )/*end of string.*/ + { + *p = '\0'; + return self->string; + } + + *p++ = ch; + } + + return NULL; +} + +static int token_proc_escape(struct finsh_token* self) +{ + char ch; + int result=0; + + ch = token_next_char(self); + switch (ch) + { + case 'n': + result = '\n'; + break; + case 't': + result = '\t'; + break; + case 'v': + result = '\v'; + break; + case 'b': + result = '\b'; + break; + case 'r': + result = '\r'; + break; + case 'f': + result = '\f'; + break; + case 'a': + result = '\007'; + break; + case '"': + result = '"'; + break; + case 'x': + case 'X': + result = 0; + ch = token_next_char(self); + while (is_xdigit(ch)) + { + result = result * 16 + ((ch < 'A') ? (ch - '0') : (ch | 0x20) - 'a' + 10); + ch = token_next_char(self); + } + token_prev_char(self); + break; + default: + if ( (ch - '0') < 8u) + { + result = 0; + while ( (ch - '0') < 8u ) + { + result = result*8 + ch - '0'; + ch = token_next_char(self); + } + + token_prev_char(self); + } + break; + } + + return result; +} + +/* +(0|0x|0X|0b|0B)number+(l|L) +*/ +static void token_proc_number(struct finsh_token* self) +{ + char ch; + char *p, buf[128]; + long value; + + value = 0; + p = buf; + + ch = token_next_char(self); + if ( ch == '0' ) + { + int b; + ch = token_next_char(self); + if ( ch == 'x' || ch == 'X' )/*it's a hex number*/ + { + b = 16; + ch = token_next_char(self); + while ( is_digit(ch) || is_alpha(ch) ) + { + *p++ = ch; + ch = token_next_char(self); + } + + *p = '\0'; + } + else if ( ch == 'b' || ch == 'B' ) + { + b = 2; + ch = token_next_char(self); + while ( (ch=='0')||(ch=='1') ) + { + *p++ = ch; + ch = token_next_char(self); + } + + *p = '\0'; + } + else if ( '0' <= ch && ch <= '7' ) + { + b = 8; + while ( '0' <= ch && ch <= '7' ) + { + *p++ = ch; + ch = token_next_char(self); + } + + *p = '\0'; + } + else + { + token_prev_char(self); + + /* made as 0 value */ + self->value.int_value = 0; + self->current_token = finsh_token_type_value_int; + return; + } + + self->value.int_value = token_spec_number(buf, strlen(buf), b); + self->current_token = finsh_token_type_value_int; + } + else + { + while ( is_digit(ch) ) + { + value = value*10 + ( ch - '0' ); + ch = token_next_char(self); + } + + self->value.int_value = value; + self->current_token = finsh_token_type_value_int; + } + + switch ( ch ) + { + case 'l': + case 'L': + self->current_token = finsh_token_type_value_long; + break; + + default: + token_prev_char(self); + break; + } +} + +/*use 64 bit number*/ +#define BN_SIZE 2 + +static long token_spec_number(char* string, int length, int b) +{ + char* p; + int t; + int i, j, shift=1; + unsigned int bn[BN_SIZE], v; + long d; + + p = string; + i = 0; + + switch ( b ) + { + case 16: shift = 4; + break; + case 8: shift = 3; + break; + case 2: shift = 1; + break; + default: break; + } + + for ( j=0; j='a' && t <='f' ) + { + t = t - 'a' +10; + } + else if ( t >='A' && t <='F' ) + { + t = t - 'A' +10; + } + else t = t - '0'; + + for ( j=0; j> (32 - shift); + } + i++; + } + + d = (long)bn[0]; + + return d; +} diff --git a/rt-thread/components/finsh/finsh_token.h b/rt-thread/components/finsh/finsh_token.h new file mode 100644 index 0000000..fd7e259 --- /dev/null +++ b/rt-thread/components/finsh/finsh_token.h @@ -0,0 +1,82 @@ +/* + * token lex for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#ifndef __FINSH_TOKEN_H__ +#define __FINSH_TOKEN_H__ + +#include + +enum finsh_token_type +{ + finsh_token_type_left_paren = 1, /* ( */ + finsh_token_type_right_paren , /* ) */ + finsh_token_type_comma , /* , */ + finsh_token_type_semicolon , /* ; */ + finsh_token_type_mul , /* * */ + finsh_token_type_add , /* + */ + finsh_token_type_inc , /* ++ */ + finsh_token_type_sub , /* - */ + finsh_token_type_dec , /* -- */ + finsh_token_type_div , /* / */ + finsh_token_type_mod , /* % */ + finsh_token_type_assign , /* = */ + finsh_token_type_and, /* & */ + finsh_token_type_or, /* | */ + finsh_token_type_xor, /* ^ */ + finsh_token_type_bitwise, /* ~ */ + finsh_token_type_shl, /* << */ + finsh_token_type_shr, /* >> */ + finsh_token_type_comments, /* // */ + /*-- data type --*/ + finsh_token_type_void, /* void */ + finsh_token_type_char, /* char */ + finsh_token_type_short, /* short */ + finsh_token_type_int, /* int */ + finsh_token_type_long, /* long */ + finsh_token_type_unsigned, /* unsigned */ + /* data value type */ + finsh_token_type_value_char, /* v:char */ + finsh_token_type_value_int, /* v:int */ + finsh_token_type_value_long, /* v:long */ + finsh_token_type_value_string, /* v:string */ + finsh_token_type_value_null, /* NULL */ + /*-- others --*/ + finsh_token_type_identifier, /* ID */ + finsh_token_type_bad, /* bad token */ + finsh_token_type_eof +}; + +#define finsh_token_position(self) (self)->position +#define finsh_token_replay(self) (self)->replay = 1 + +void finsh_token_init(struct finsh_token* self, uint8_t* script); + +enum finsh_token_type finsh_token_token(struct finsh_token* self); +void finsh_token_get_token(struct finsh_token* self, uint8_t* token); + +#endif diff --git a/rt-thread/components/finsh/finsh_var.c b/rt-thread/components/finsh/finsh_var.c new file mode 100644 index 0000000..7e39492 --- /dev/null +++ b/rt-thread/components/finsh/finsh_var.c @@ -0,0 +1,161 @@ +/* + * Variable implementation in finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + * 2012-04-27 Bernard fixed finsh_var_delete issue which + * is found by Grissiom. + */ +#include +#include "finsh_var.h" + +struct finsh_var global_variable[FINSH_VARIABLE_MAX]; +struct finsh_sysvar_item* global_sysvar_list; + +int finsh_var_init() +{ + memset(global_variable, 0, sizeof(global_variable)); + + return 0; +} + +int finsh_var_insert(const char* name, int type) +{ + int i, empty; + + empty = -1; + for (i = 0; i < FINSH_VARIABLE_MAX; i ++) + { + /* there is a same name variable exist. */ + if (strncmp(global_variable[i].name, name, FINSH_NAME_MAX) == 0) + return -1; + + if (global_variable[i].type == finsh_type_unknown && empty == -1) + { + empty = i; + } + } + + /* there is no empty entry */ + if (empty == -1) return -1; + + /* insert entry */ + strncpy(global_variable[empty].name, name, FINSH_NAME_MAX); + global_variable[empty].type = type; + + /* return the offset */ + return empty; +} + +int finsh_var_delete(const char* name) +{ + int i; + + for (i = 0; i < FINSH_VARIABLE_MAX; i ++) + { + if (strncmp(global_variable[i].name, name, FINSH_NAME_MAX) == 0) + break; + } + + /* can't find variable */ + if (i == FINSH_VARIABLE_MAX) return -1; + + memset(&global_variable[i], 0, sizeof(struct finsh_var)); + + return 0; +} + +struct finsh_var* finsh_var_lookup(const char* name) +{ + int i; + + for (i = 0; i < FINSH_VARIABLE_MAX; i ++) + { + if (strncmp(global_variable[i].name, name, FINSH_NAME_MAX) == 0) + break; + } + + /* can't find variable */ + if (i == FINSH_VARIABLE_MAX) return NULL; + + return &global_variable[i]; +} + +#ifdef RT_USING_HEAP +void finsh_sysvar_append(const char* name, uint8_t type, void* var_addr) +{ + /* create a sysvar */ + struct finsh_sysvar_item* item; + + item = (struct finsh_sysvar_item*) rt_malloc (sizeof(struct finsh_sysvar_item)); + if (item != NULL) + { + item->next = NULL; + item->sysvar.name = rt_strdup(name); + item->sysvar.type = type; + item->sysvar.var = var_addr; + + if (global_sysvar_list == NULL) + { + global_sysvar_list = item; + } + else + { + item->next = global_sysvar_list; + global_sysvar_list = item; + } + } +} +#endif + +struct finsh_sysvar* finsh_sysvar_lookup(const char* name) +{ + struct finsh_sysvar* index; + struct finsh_sysvar_item* item; + + for (index = _sysvar_table_begin; + index < _sysvar_table_end; + FINSH_NEXT_SYSVAR(index)) + { + if (strcmp(index->name, name) == 0) + return index; + } + + /* find in sysvar list */ + item = global_sysvar_list; + while (item != NULL) + { + if (strncmp(item->sysvar.name, name, strlen(name)) == 0) + { + return &(item->sysvar); + } + + /* move to next item */ + item = item->next; + } + + /* can't find variable */ + return NULL; +} diff --git a/rt-thread/components/finsh/finsh_var.h b/rt-thread/components/finsh/finsh_var.h new file mode 100644 index 0000000..f8013ac --- /dev/null +++ b/rt-thread/components/finsh/finsh_var.h @@ -0,0 +1,60 @@ +/* + * Variable implementation in finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#ifndef __FINSH_VAR_H__ +#define __FINSH_VAR_H__ + +#include + +/* + * The variable in finsh is put in data segment as a global variable. + * The 'finsh_var' structure presents the structure of variable in data segment. + */ +struct finsh_var +{ + char name[FINSH_NAME_MAX + 1]; /* the name of variable */ + + uint8_t type; /* the type of variable */ + + /* variable value */ + union { + char char_value; + short short_value; + int int_value; + long long_value; + void* ptr; + }value; +}; +extern struct finsh_var global_variable[]; + +int finsh_var_init(void); +int finsh_var_insert(const char* name, int type); +int finsh_var_delete(const char* name); +struct finsh_var* finsh_var_lookup(const char* name); + +#endif diff --git a/rt-thread/components/finsh/finsh_vm.c b/rt-thread/components/finsh/finsh_vm.c new file mode 100644 index 0000000..8a3b894 --- /dev/null +++ b/rt-thread/components/finsh/finsh_vm.c @@ -0,0 +1,404 @@ +/* + * Virtual machine of finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#include + +#include "finsh_vm.h" +#include "finsh_ops.h" +#include "finsh_var.h" + +/* stack */ +union finsh_value finsh_vm_stack[FINSH_STACK_MAX]; +/* text segment */ +uint8_t text_segment[FINSH_TEXT_MAX]; + +union finsh_value* finsh_sp; /* stack pointer */ +uint8_t* finsh_pc; /* PC */ + +/* syscall list, for dynamic system call register */ +struct finsh_syscall_item* global_syscall_list = NULL; + +// #define FINSH_VM_DISASSEMBLE +void finsh_vm_run() +{ + uint8_t op; + + /* if you want to disassemble the byte code, please define FINSH_VM_DISASSEMBLE */ +#ifdef FINSH_VM_DISASSEMBLE + void finsh_disassemble(); + finsh_disassemble(); +#endif + + /* set sp(stack pointer) to the beginning of stack */ + finsh_sp = &finsh_vm_stack[0]; + + /* set pc to the beginning of text segment */ + finsh_pc = &text_segment[0]; + + while ((finsh_pc - &text_segment[0] >= 0) && + (finsh_pc - &text_segment[0] < FINSH_TEXT_MAX)) + { + /* get op */ + op = *finsh_pc++; + + /* call op function */ + op_table[op](); + } +} + +#ifdef RT_USING_HEAP +void finsh_syscall_append(const char* name, syscall_func func) +{ + /* create the syscall */ + struct finsh_syscall_item* item; + + item = (struct finsh_syscall_item*)rt_malloc(sizeof(struct finsh_syscall_item)); + if (item != RT_NULL) + { + item->next = NULL; + item->syscall.name = rt_strdup(name); + item->syscall.func = func; + + if (global_syscall_list == NULL) + { + global_syscall_list = item; + } + else + { + item->next = global_syscall_list; + global_syscall_list = item; + } + } +} +#endif + +#if defined(_MSC_VER) || (defined(__GNUC__) && defined(__x86_64__)) +struct finsh_syscall* finsh_syscall_next(struct finsh_syscall* call) +{ + unsigned int *ptr; + ptr = (unsigned int*) (call + 1); + while ((*ptr == 0) && ((unsigned int*)ptr < (unsigned int*) _syscall_table_end)) + ptr ++; + + return (struct finsh_syscall*)ptr; +} + +struct finsh_sysvar* finsh_sysvar_next(struct finsh_sysvar* call) +{ + unsigned int *ptr; + ptr = (unsigned int*) (call + 1); + while ((*ptr == 0) && ((unsigned int*)ptr < (unsigned int*) _sysvar_table_end)) + ptr ++; + + return (struct finsh_sysvar*)ptr; +} +#endif + +struct finsh_syscall* finsh_syscall_lookup(const char* name) +{ + struct finsh_syscall* index; + struct finsh_syscall_item* item; + + for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index)) + { + if (strcmp(index->name, name) == 0) + return index; + } + + /* find on syscall list */ + item = global_syscall_list; + while (item != NULL) + { + if (strncmp(item->syscall.name, name, strlen(name)) == 0) + { + return &(item->syscall); + } + + item = item->next; + } + + return NULL; +} + +#ifdef FINSH_VM_DISASSEMBLE +void finsh_disassemble() +{ + uint8_t *pc, op; + + pc = &text_segment[0]; + while (*pc != 0) + { + op = *pc; + switch (op) + { + case FINSH_OP_ADD_BYTE: + pc ++; + rt_kprintf("addb\n"); + break; + + case FINSH_OP_SUB_BYTE: + pc ++; + rt_kprintf("subb\n"); + break; + + case FINSH_OP_DIV_BYTE: + pc ++; + rt_kprintf("divb\n"); + break; + + case FINSH_OP_MOD_BYTE: + pc ++; + rt_kprintf("modb\n"); + break; + + case FINSH_OP_MUL_BYTE: + pc ++; + rt_kprintf("mulb\n"); + break; + + case FINSH_OP_AND_BYTE: + pc ++; + rt_kprintf("andb\n"); + break; + + case FINSH_OP_OR_BYTE: + pc ++; + rt_kprintf("orb\n"); + break; + + case FINSH_OP_XOR_BYTE: + pc ++; + rt_kprintf("xorb\n"); + break; + + case FINSH_OP_BITWISE_BYTE: + pc ++; + rt_kprintf("bwb\n"); + break; + + case FINSH_OP_SHL_BYTE: + pc ++; + rt_kprintf("shlb\n"); + break; + + case FINSH_OP_SHR_BYTE: + pc ++; + rt_kprintf("shrb\n"); + break; + + case FINSH_OP_LD_BYTE: + pc ++; + rt_kprintf("ldb %d\n", *pc++); + break; + + case FINSH_OP_LD_VALUE_BYTE: + pc ++; + rt_kprintf("ldb [0x%x]\n", FINSH_GET32(pc)); + pc += 4; + break; + + case FINSH_OP_ST_BYTE: + pc ++; + rt_kprintf("stb\n"); + break; + + case FINSH_OP_ADD_WORD: + pc ++; + rt_kprintf("addw\n"); + break; + + case FINSH_OP_SUB_WORD: + pc ++; + rt_kprintf("subw\n"); + break; + + case FINSH_OP_DIV_WORD: + pc ++; + rt_kprintf("divw\n"); + break; + + case FINSH_OP_MOD_WORD: + pc ++; + rt_kprintf("modw\n"); + break; + + case FINSH_OP_MUL_WORD: + pc ++; + rt_kprintf("mulw\n"); + break; + + case FINSH_OP_AND_WORD: + pc ++; + rt_kprintf("andw\n"); + break; + + case FINSH_OP_OR_WORD: + pc ++; + rt_kprintf("orw\n"); + break; + + case FINSH_OP_XOR_WORD: + pc ++; + rt_kprintf("xorw\n"); + break; + + case FINSH_OP_BITWISE_WORD: + pc ++; + rt_kprintf("bww\n"); + break; + + case FINSH_OP_SHL_WORD: + pc ++; + rt_kprintf("shlw\n"); + break; + + case FINSH_OP_SHR_WORD: + pc ++; + rt_kprintf("shrw\n"); + break; + + case FINSH_OP_LD_WORD: + pc ++; + rt_kprintf("ldw %d\n", FINSH_GET16(pc)); + pc += 2; + break; + + case FINSH_OP_LD_VALUE_WORD: + pc ++; + rt_kprintf("ldw [0x%x]\n", FINSH_GET32(pc)); + pc += 4; + break; + + case FINSH_OP_ST_WORD: + pc ++; + rt_kprintf("stw\n"); + break; + + case FINSH_OP_ADD_DWORD: + pc ++; + rt_kprintf("addd\n"); + break; + + case FINSH_OP_SUB_DWORD: + pc ++; + rt_kprintf("subd\n"); + break; + + case FINSH_OP_DIV_DWORD: + pc ++; + rt_kprintf("divd\n"); + break; + + case FINSH_OP_MOD_DWORD: + pc ++; + rt_kprintf("modd\n"); + break; + + case FINSH_OP_MUL_DWORD: + pc ++; + rt_kprintf("muld\n"); + break; + + case FINSH_OP_AND_DWORD: + pc ++; + rt_kprintf("andd\n"); + break; + + case FINSH_OP_OR_DWORD: + pc ++; + rt_kprintf("ord\n"); + break; + + case FINSH_OP_XOR_DWORD: + pc ++; + rt_kprintf("xord\n"); + break; + + case FINSH_OP_BITWISE_DWORD: + pc ++; + rt_kprintf("bwd\n"); + break; + + case FINSH_OP_SHL_DWORD: + pc ++; + rt_kprintf("shld\n"); + break; + + case FINSH_OP_SHR_DWORD: + pc ++; + rt_kprintf("shrd\n"); + break; + + case FINSH_OP_LD_DWORD: + pc ++; + rt_kprintf("ldd 0x%x\n", FINSH_GET32(pc)); + pc += 4; + break; + + case FINSH_OP_LD_VALUE_DWORD: + pc ++; + rt_kprintf("ldd [0x%x]\n", FINSH_GET32(pc)); + pc += 4; + break; + + case FINSH_OP_ST_DWORD: + pc ++; + rt_kprintf("std\n"); + break; + + case FINSH_OP_POP: + rt_kprintf("pop\n"); + pc ++; + break; + + case FINSH_OP_SYSCALL: + pc ++; + rt_kprintf("syscall %d\n", *pc++); + break; + + case FINSH_OP_LD_VALUE_BYTE_STACK: + pc ++; + rt_kprintf("ldb [sp]\n"); + break; + + case FINSH_OP_LD_VALUE_WORD_STACK: + pc ++; + rt_kprintf("ldw [sp]\n"); + break; + + case FINSH_OP_LD_VALUE_DWORD_STACK: + pc ++; + rt_kprintf("ldd [sp]\n"); + break; + + default: + return; + } + } +} +#endif diff --git a/rt-thread/components/finsh/finsh_vm.h b/rt-thread/components/finsh/finsh_vm.h new file mode 100644 index 0000000..478a757 --- /dev/null +++ b/rt-thread/components/finsh/finsh_vm.h @@ -0,0 +1,54 @@ +/* + * Virtual machine finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#ifndef __FINSH_VM_H__ +#define __FINSH_VM_H__ + +#include + +#include "finsh_var.h" + +union finsh_value { + char char_value; + short short_value; + long long_value; + void* ptr; +}; + +extern union finsh_value* finsh_sp; /* stack pointer */ +extern uint8_t* finsh_pc; /* PC */ + +/* stack */ +extern union finsh_value finsh_vm_stack[FINSH_STACK_MAX]; +/* text segment */ +extern uint8_t text_segment[FINSH_TEXT_MAX]; + +void finsh_vm_run(void); +//void finsh_disassemble(void); + +#endif diff --git a/rt-thread/components/finsh/msh.c b/rt-thread/components/finsh/msh.c new file mode 100644 index 0000000..a724b65 --- /dev/null +++ b/rt-thread/components/finsh/msh.c @@ -0,0 +1,631 @@ +/* + * RT-Thread module shell implementation. + * + * COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-03-30 Bernard the first verion for finsh + * 2014-01-03 Bernard msh can execute module. + * 2017-07-19 Aubr.Cool limit argc to RT_FINSH_ARG_MAX + */ + +#include "msh.h" +#include +#include + +#ifdef RT_USING_DFS +#include +#endif + +#ifdef RT_USING_MODULE +#include +#endif + +#ifndef FINSH_ARG_MAX +#define FINSH_ARG_MAX 8 +#endif + +typedef int (*cmd_function_t)(int argc, char **argv); + +#ifdef FINSH_USING_MSH +#ifdef FINSH_USING_MSH_ONLY +rt_bool_t msh_is_used(void) +{ + return RT_TRUE; +} +#else +#ifdef FINSH_USING_MSH_DEFAULT +static rt_bool_t __msh_state = RT_TRUE; +#else +static rt_bool_t __msh_state = RT_FALSE; +#endif +rt_bool_t msh_is_used(void) +{ + return __msh_state; +} + +static int msh_exit(int argc, char **argv) +{ + /* return to finsh shell mode */ + __msh_state = RT_FALSE; + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(msh_exit, __cmd_exit, return to RT-Thread shell mode.); + +static int msh_enter(void) +{ + /* enter module shell mode */ + __msh_state = RT_TRUE; + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(msh_enter, msh, use module shell); +#endif + +int msh_help(int argc, char **argv) +{ + rt_kprintf("RT-Thread shell commands:\n"); + { + struct finsh_syscall *index; + + for (index = _syscall_table_begin; + index < _syscall_table_end; + FINSH_NEXT_SYSCALL(index)) + { + if (strncmp(index->name, "__cmd_", 6) != 0) continue; +#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB) + rt_kprintf("%-16s - %s\n", &index->name[6], index->desc); +#else + rt_kprintf("%s ", &index->name[6]); +#endif + } + } + rt_kprintf("\n"); + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(msh_help, __cmd_help, RT-Thread shell help.); + +static int msh_split(char *cmd, rt_size_t length, char *argv[FINSH_ARG_MAX]) +{ + char *ptr; + rt_size_t position; + rt_size_t argc; + rt_size_t i; + + ptr = cmd; + position = 0; argc = 0; + + while (position < length) + { + /* strip bank and tab */ + while ((*ptr == ' ' || *ptr == '\t') && position < length) + { + *ptr = '\0'; + ptr ++; position ++; + } + + if(argc >= FINSH_ARG_MAX) + { + rt_kprintf("Too many args ! We only Use:\n"); + for(i = 0; i < argc; i++) + { + rt_kprintf("%s ", argv[i]); + } + rt_kprintf("\n"); + break; + } + + if (position >= length) break; + + /* handle string */ + if (*ptr == '"') + { + ptr ++; position ++; + argv[argc] = ptr; argc ++; + + /* skip this string */ + while (*ptr != '"' && position < length) + { + if (*ptr == '\\') + { + if (*(ptr + 1) == '"') + { + ptr ++; position ++; + } + } + ptr ++; position ++; + } + if (position >= length) break; + + /* skip '"' */ + *ptr = '\0'; ptr ++; position ++; + } + else + { + argv[argc] = ptr; + argc ++; + while ((*ptr != ' ' && *ptr != '\t') && position < length) + { + ptr ++; position ++; + } + if (position >= length) break; + } + } + + return argc; +} + +static cmd_function_t msh_get_cmd(char *cmd, int size) +{ + struct finsh_syscall *index; + cmd_function_t cmd_func = RT_NULL; + + for (index = _syscall_table_begin; + index < _syscall_table_end; + FINSH_NEXT_SYSCALL(index)) + { + if (strncmp(index->name, "__cmd_", 6) != 0) continue; + + if (strncmp(&index->name[6], cmd, size) == 0 && + index->name[6 + size] == '\0') + { + cmd_func = (cmd_function_t)index->func; + break; + } + } + + return cmd_func; +} + +#if defined(RT_USING_MODULE) && defined(RT_USING_DFS) +/* Return 0 on module executed. Other value indicate error. + */ +int msh_exec_module(const char *cmd_line, int size) +{ + int ret; + int fd = -1; + char *pg_name; + int length, cmd_length = 0; + + if (size == 0) + return -RT_ERROR; + /* get the length of command0 */ + while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size) + cmd_length ++; + + /* get name length */ + length = cmd_length + 32; + + /* allocate program name memory */ + pg_name = (char *) rt_malloc(length); + if (pg_name == RT_NULL) + return -RT_ENOMEM; + + /* copy command0 */ + memcpy(pg_name, cmd_line, cmd_length); + pg_name[cmd_length] = '\0'; + + if (strstr(pg_name, ".mo") != RT_NULL || strstr(pg_name, ".MO") != RT_NULL) + { + /* try to open program */ + fd = open(pg_name, O_RDONLY, 0); + + /* search in /bin path */ + if (fd < 0) + { + rt_snprintf(pg_name, length - 1, "/bin/%.*s", cmd_length, cmd_line); + fd = open(pg_name, O_RDONLY, 0); + } + } + else + { + /* add .mo and open program */ + + /* try to open program */ + strcat(pg_name, ".mo"); + fd = open(pg_name, O_RDONLY, 0); + + /* search in /bin path */ + if (fd < 0) + { + rt_snprintf(pg_name, length - 1, "/bin/%.*s.mo", cmd_length, cmd_line); + fd = open(pg_name, O_RDONLY, 0); + } + } + + if (fd >= 0) + { + /* found program */ + close(fd); + dlmodule_exec(pg_name, cmd_line, size); + ret = 0; + } + else + { + ret = -1; + } + + rt_free(pg_name); + return ret; +} + +int system(const char *command) +{ + int ret = -RT_ENOMEM; + char *cmd = rt_strdup(command); + + if (cmd) + { + ret = msh_exec(cmd, rt_strlen(cmd)); + rt_free(cmd); + } + + return ret; +} +RTM_EXPORT(system); +#endif + +static int _msh_exec_cmd(char *cmd, rt_size_t length, int *retp) +{ + int argc; + rt_size_t cmd0_size = 0; + cmd_function_t cmd_func; + char *argv[FINSH_ARG_MAX]; + + RT_ASSERT(cmd); + RT_ASSERT(retp); + + /* find the size of first command */ + while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length) + cmd0_size ++; + if (cmd0_size == 0) + return -RT_ERROR; + + cmd_func = msh_get_cmd(cmd, cmd0_size); + if (cmd_func == RT_NULL) + return -RT_ERROR; + + /* split arguments */ + memset(argv, 0x00, sizeof(argv)); + argc = msh_split(cmd, length, argv); + if (argc == 0) + return -RT_ERROR; + + /* exec this command */ + *retp = cmd_func(argc, argv); + return 0; +} + +#if defined(RT_USING_LWP) && defined(RT_USING_DFS) +static int _msh_exec_lwp(char *cmd, rt_size_t length) +{ + int argc; + int cmd0_size = 0; + char *argv[FINSH_ARG_MAX]; + int fd = -1; + char *pg_name; + + extern int exec(char*, int, char**); + + /* find the size of first command */ + while ((cmd[cmd0_size] != ' ' && cmd[cmd0_size] != '\t') && cmd0_size < length) + cmd0_size ++; + if (cmd0_size == 0) + return -1; + + /* split arguments */ + rt_memset(argv, 0x00, sizeof(argv)); + argc = msh_split(cmd, length, argv); + if (argc == 0) + return -1; + + pg_name = argv[0]; + /* try to open program */ + fd = open(pg_name, O_RDONLY, 0); + + if (fd < 0) + return -1; + + /* found program */ + close(fd); + exec(pg_name, argc, argv); + + return 0; +} +#endif + +int msh_exec(char *cmd, rt_size_t length) +{ + int cmd_ret; + + /* strim the beginning of command */ + while (*cmd == ' ' || *cmd == '\t') + { + cmd++; + length--; + } + + if (length == 0) + return 0; + + /* Exec sequence: + * 1. built-in command + * 2. module(if enabled) + */ + if (_msh_exec_cmd(cmd, length, &cmd_ret) == 0) + { + return cmd_ret; + } +#ifdef RT_USING_DFS +#ifdef DFS_USING_WORKDIR + if (msh_exec_script(cmd, length) == 0) + { + return 0; + } +#endif + +#ifdef RT_USING_MODULE + if (msh_exec_module(cmd, length) == 0) + { + return 0; + } +#endif + +#ifdef RT_USING_LWP + if (_msh_exec_lwp(cmd, length) == 0) + { + return 0; + } +#endif +#endif + + /* truncate the cmd at the first space. */ + { + char *tcmd; + tcmd = cmd; + while (*tcmd != ' ' && *tcmd != '\0') + { + tcmd++; + } + *tcmd = '\0'; + } + rt_kprintf("%s: command not found.\n", cmd); + return -1; +} + +static int str_common(const char *str1, const char *str2) +{ + const char *str = str1; + + while ((*str != 0) && (*str2 != 0) && (*str == *str2)) + { + str ++; + str2 ++; + } + + return (str - str1); +} + +#ifdef RT_USING_DFS +void msh_auto_complete_path(char *path) +{ + DIR *dir = RT_NULL; + struct dirent *dirent = RT_NULL; + char *full_path, *ptr, *index; + + if (!path) + return; + + full_path = (char *)rt_malloc(256); + if (full_path == RT_NULL) return; /* out of memory */ + + if (*path != '/') + { + getcwd(full_path, 256); + if (full_path[rt_strlen(full_path) - 1] != '/') + strcat(full_path, "/"); + } + else *full_path = '\0'; + + index = RT_NULL; + ptr = path; + for (;;) + { + if (*ptr == '/') index = ptr + 1; + if (!*ptr) break; + + ptr ++; + } + if (index == RT_NULL) index = path; + + if (index != RT_NULL) + { + char *dest = index; + + /* fill the parent path */ + ptr = full_path; + while (*ptr) ptr ++; + + for (index = path; index != dest;) + *ptr++ = *index++; + *ptr = '\0'; + + dir = opendir(full_path); + if (dir == RT_NULL) /* open directory failed! */ + { + rt_free(full_path); + return; + } + + /* restore the index position */ + index = dest; + } + + /* auto complete the file or directory name */ + if (*index == '\0') /* display all of files and directories */ + { + for (;;) + { + dirent = readdir(dir); + if (dirent == RT_NULL) break; + + rt_kprintf("%s\n", dirent->d_name); + } + } + else + { + rt_size_t length, min_length; + + min_length = 0; + for (;;) + { + dirent = readdir(dir); + if (dirent == RT_NULL) break; + + /* matched the prefix string */ + if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0) + { + if (min_length == 0) + { + min_length = rt_strlen(dirent->d_name); + /* save dirent name */ + strcpy(full_path, dirent->d_name); + } + + length = str_common(dirent->d_name, full_path); + + if (length < min_length) + { + min_length = length; + } + } + } + + if (min_length) + { + if (min_length < rt_strlen(full_path)) + { + /* list the candidate */ + rewinddir(dir); + + for (;;) + { + dirent = readdir(dir); + if (dirent == RT_NULL) break; + + if (strncmp(index, dirent->d_name, rt_strlen(index)) == 0) + rt_kprintf("%s\n", dirent->d_name); + } + } + + length = index - path; + memcpy(index, full_path, min_length); + path[length + min_length] = '\0'; + } + } + + closedir(dir); + rt_free(full_path); +} +#endif + +void msh_auto_complete(char *prefix) +{ + int length, min_length; + const char *name_ptr, *cmd_name; + struct finsh_syscall *index; + + min_length = 0; + name_ptr = RT_NULL; + + if (*prefix == '\0') + { + msh_help(0, RT_NULL); + return; + } + +#ifdef RT_USING_DFS + /* check whether a spare in the command */ + { + char *ptr; + + ptr = prefix + rt_strlen(prefix); + while (ptr != prefix) + { + if (*ptr == ' ') + { + msh_auto_complete_path(ptr + 1); + break; + } + + ptr --; + } +#ifdef RT_USING_MODULE + /* There is a chance that the user want to run the module directly. So + * try to complete the file names. If the completed path is not a + * module, the system won't crash anyway. */ + if (ptr == prefix) + { + msh_auto_complete_path(ptr); + } +#endif + } +#endif + + /* checks in internal command */ + { + for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index)) + { + /* skip finsh shell function */ + if (strncmp(index->name, "__cmd_", 6) != 0) continue; + + cmd_name = (const char *) &index->name[6]; + if (strncmp(prefix, cmd_name, strlen(prefix)) == 0) + { + if (min_length == 0) + { + /* set name_ptr */ + name_ptr = cmd_name; + /* set initial length */ + min_length = strlen(name_ptr); + } + + length = str_common(name_ptr, cmd_name); + if (length < min_length) + min_length = length; + + rt_kprintf("%s\n", cmd_name); + } + } + } + + /* auto complete string */ + if (name_ptr != NULL) + { + rt_strncpy(prefix, name_ptr, min_length); + } + + return ; +} +#endif + diff --git a/rt-thread/components/finsh/msh.h b/rt-thread/components/finsh/msh.h new file mode 100644 index 0000000..df49732 --- /dev/null +++ b/rt-thread/components/finsh/msh.h @@ -0,0 +1,42 @@ +/* + * RT-Thread module shell implementation. + * + * COPYRIGHT (C) 2013, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-03-30 Bernard the first verion for FinSH + */ + +#ifndef __M_SHELL__ +#define __M_SHELL__ + +#include + +rt_bool_t msh_is_used(void); +int msh_exec(char *cmd, rt_size_t length); +void msh_auto_complete(char *prefix); + +int msh_exec_module(const char *cmd_line, int size); +int msh_exec_script(const char *cmd_line, int size); + +#endif diff --git a/rt-thread/components/finsh/msh_cmd.c b/rt-thread/components/finsh/msh_cmd.c new file mode 100644 index 0000000..47ca031 --- /dev/null +++ b/rt-thread/components/finsh/msh_cmd.c @@ -0,0 +1,441 @@ +/* + * internal commands for RT-Thread module shell + * + * COPYRIGHT (C) 2013-2015, Shanghai Real-Thread Technology Co., Ltd + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-03-30 Bernard the first verion for FinSH + * 2015-08-28 Bernard Add mkfs command. + */ + +#include +#include + +#include "msh.h" + +#ifdef FINSH_USING_MSH +#ifdef RT_USING_DFS +#include + +#ifdef DFS_USING_WORKDIR +extern char working_directory[]; +#endif + +int cmd_ls(int argc, char **argv) +{ + extern void ls(const char *pathname); + + if (argc == 1) + { +#ifdef DFS_USING_WORKDIR + ls(working_directory); +#else + ls("/"); +#endif + } + else + { + ls(argv[1]); + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_ls, __cmd_ls, List information about the FILEs.); + +int cmd_cp(int argc, char **argv) +{ + void copy(const char *src, const char *dst); + + if (argc != 3) + { + rt_kprintf("Usage: cp SOURCE DEST\n"); + rt_kprintf("Copy SOURCE to DEST.\n"); + } + else + { + copy(argv[1], argv[2]); + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_cp, __cmd_cp, Copy SOURCE to DEST.); + +int cmd_mv(int argc, char **argv) +{ + if (argc != 3) + { + rt_kprintf("Usage: mv SOURCE DEST\n"); + rt_kprintf("Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.\n"); + } + else + { + int fd; + char *dest = RT_NULL; + + rt_kprintf("%s => %s\n", argv[1], argv[2]); + + fd = open(argv[2], O_DIRECTORY, 0); + if (fd >= 0) + { + char *src; + + close(fd); + + /* it's a directory */ + dest = (char *)rt_malloc(DFS_PATH_MAX); + if (dest == RT_NULL) + { + rt_kprintf("out of memory\n"); + return -RT_ENOMEM; + } + + src = argv[1] + rt_strlen(argv[1]); + while (src != argv[1]) + { + if (*src == '/') break; + src --; + } + + rt_snprintf(dest, DFS_PATH_MAX - 1, "%s/%s", argv[2], src); + } + else + { + fd = open(argv[2], O_RDONLY, 0); + if (fd >= 0) + { + close(fd); + + unlink(argv[2]); + } + + dest = argv[2]; + } + + rename(argv[1], dest); + if (dest != RT_NULL && dest != argv[2]) rt_free(dest); + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_mv, __cmd_mv, Rename SOURCE to DEST.); + +int cmd_cat(int argc, char **argv) +{ + int index; + extern void cat(const char *filename); + + if (argc == 1) + { + rt_kprintf("Usage: cat [FILE]...\n"); + rt_kprintf("Concatenate FILE(s)\n"); + return 0; + } + + for (index = 1; index < argc; index ++) + { + cat(argv[index]); + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_cat, __cmd_cat, Concatenate FILE(s)); + +int cmd_rm(int argc, char **argv) +{ + int index; + + if (argc == 1) + { + rt_kprintf("Usage: rm FILE...\n"); + rt_kprintf("Remove (unlink) the FILE(s).\n"); + return 0; + } + + for (index = 1; index < argc; index ++) + { + unlink(argv[index]); + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_rm, __cmd_rm, Remove(unlink) the FILE(s).); + +#ifdef DFS_USING_WORKDIR +int cmd_cd(int argc, char **argv) +{ + if (argc == 1) + { + rt_kprintf("%s\n", working_directory); + } + else if (argc == 2) + { + if (chdir(argv[1]) != 0) + { + rt_kprintf("No such directory: %s\n", argv[1]); + } + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_cd, __cmd_cd, Change the shell working directory.); + +int cmd_pwd(int argc, char **argv) +{ + rt_kprintf("%s\n", working_directory); + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_pwd, __cmd_pwd, Print the name of the current working directory.); +#endif + +int cmd_mkdir(int argc, char **argv) +{ + if (argc == 1) + { + rt_kprintf("Usage: mkdir [OPTION] DIRECTORY\n"); + rt_kprintf("Create the DIRECTORY, if they do not already exist.\n"); + } + else + { + mkdir(argv[1], 0); + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_mkdir, __cmd_mkdir, Create the DIRECTORY.); + +int cmd_mkfs(int argc, char **argv) +{ + int result = 0; + char *type = "elm"; /* use the default file system type as 'fatfs' */ + + if (argc == 2) + { + result = dfs_mkfs(type, argv[1]); + } + else if (argc == 4) + { + if (strcmp(argv[1], "-t") == 0) + { + type = argv[2]; + result = dfs_mkfs(type, argv[3]); + } + } + else + { + rt_kprintf("Usage: mkfs [-t type] device\n"); + return 0; + } + + if (result != RT_EOK) + { + rt_kprintf("mkfs failed, result=%d\n", result); + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_mkfs, __cmd_mkfs, format disk with file system); + +extern int df(const char *path); +int cmd_df(int argc, char** argv) +{ + if (argc != 2) + { + df("/"); + } + else + { + if ((strcmp(argv[1], "--help") == 0) || (strcmp(argv[1], "-h") == 0)) + { + rt_kprintf("df [path]\n"); + } + else + { + df(argv[1]); + } + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_df, __cmd_df, disk free); + +int cmd_echo(int argc, char** argv) +{ + if (argc == 2) + { + rt_kprintf("%s\n", argv[1]); + } + else if (argc == 3) + { + int fd; + + fd = open(argv[2], O_RDWR | O_APPEND | O_CREAT, 0); + if (fd >= 0) + { + write (fd, argv[1], strlen(argv[1])); + close(fd); + } + else + { + rt_kprintf("open file:%s failed!\n", argv[2]); + } + } + else + { + rt_kprintf("Usage: echo \"string\" [filename]\n"); + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_echo, __cmd_echo, echo string to file); +#endif + +#ifdef RT_USING_LWIP +int cmd_ifconfig(int argc, char **argv) +{ + extern void list_if(void); + extern void set_if(char *netif_name, char *ip_addr, char *gw_addr, char *nm_addr); + + + if (argc == 1) + { + list_if(); + } + else if (argc == 5) + { + rt_kprintf("config : %s\n", argv[1]); + rt_kprintf("IP addr: %s\n", argv[2]); + rt_kprintf("Gateway: %s\n", argv[3]); + rt_kprintf("netmask: %s\n", argv[4]); + set_if(argv[1], argv[2], argv[3], argv[4]); + } + else + { + rt_kprintf("bad parameter! e.g: ifconfig e0 192.168.1.30 192.168.1.1 255.255.255.0\n"); + } + + return 0; +} +FINSH_FUNCTION_EXPORT_ALIAS(cmd_ifconfig, __cmd_ifconfig, list the information of network interfaces); + +#ifdef RT_LWIP_DNS +#include +#include +#include +#include + +int cmd_dns(int argc, char **argv) +{ + extern void set_dns(char* dns_server); + + if (argc == 1) + { + int index; + +#if (LWIP_VERSION) < 0x02000000U + ip_addr_t ip_addr; + for(index=0; index + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-09-25 Bernard the first verion for FinSH + */ + +#include +#include + +#include "msh.h" + +#if defined(FINSH_USING_MSH) && defined(RT_USING_DFS) +#include + +static int msh_readline(int fd, char *line_buf, int size) +{ + char ch; + int index = 0; + + do + { + if (read(fd, &ch, 1) != 1) + { + /* nothing in this file */ + return 0; + } + } + while (ch == '\n' || ch == '\r'); + + /* set the first character */ + line_buf[index ++] = ch; + + while (index < size) + { + if (read(fd, &ch, 1) == 1) + { + if (ch == '\n' || ch == '\r') + { + line_buf[index] = '\0'; + break; + } + + line_buf[index++] = ch; + } + else + { + line_buf[index] = '\0'; + break; + } + } + + return index; +} + +int msh_exec_script(const char *cmd_line, int size) +{ + int ret; + int fd = -1; + char *pg_name; + int length, cmd_length = 0; + + if (size == 0) return -RT_ERROR; + + /* get the length of command0 */ + while ((cmd_line[cmd_length] != ' ' && cmd_line[cmd_length] != '\t') && cmd_length < size) + cmd_length ++; + + /* get name length */ + length = cmd_length + 32; + + /* allocate program name memory */ + pg_name = (char *) rt_malloc(length); + if (pg_name == RT_NULL) return -RT_ENOMEM; + + /* copy command0 */ + memcpy(pg_name, cmd_line, cmd_length); + pg_name[cmd_length] = '\0'; + + if (strstr(pg_name, ".sh") != RT_NULL || strstr(pg_name, ".SH") != RT_NULL) + { + /* try to open program */ + fd = open(pg_name, O_RDONLY, 0); + + /* search in /bin path */ + if (fd < 0) + { + rt_snprintf(pg_name, length - 1, "/bin/%.*s", cmd_length, cmd_line); + fd = open(pg_name, O_RDONLY, 0); + } + } + + rt_free(pg_name); + if (fd >= 0) + { + /* found script */ + char *line_buf; + int length; + + line_buf = (char *) rt_malloc(RT_CONSOLEBUF_SIZE); + + /* read line by line and then exec it */ + do + { + length = msh_readline(fd, line_buf, RT_CONSOLEBUF_SIZE); + if (length > 0) + { + char ch = '\0'; + int index; + + for (index = 0; index < length; index ++) + { + ch = line_buf[index]; + if (ch == ' ' || ch == '\t') continue; + else break; + } + + if (ch != '#') /* not a comment */ + msh_exec(line_buf, length); + } + } + while (length > 0); + + close(fd); + rt_free(line_buf); + + ret = 0; + } + else + { + ret = -1; + } + + return ret; +} + +#endif diff --git a/rt-thread/components/finsh/shell.c b/rt-thread/components/finsh/shell.c new file mode 100644 index 0000000..441f6c3 --- /dev/null +++ b/rt-thread/components/finsh/shell.c @@ -0,0 +1,868 @@ +/* + * shell implementation for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2006-04-30 Bernard the first version for FinSH + * 2006-05-08 Bernard change finsh thread stack to 2048 + * 2006-06-03 Bernard add support for skyeye + * 2006-09-24 Bernard remove the code related with hardware + * 2010-01-18 Bernard fix down then up key bug. + * 2010-03-19 Bernard fix backspace issue and fix device read in shell. + * 2010-04-01 Bernard add prompt output when start and remove the empty history + * 2011-02-23 Bernard fix variable section end issue of finsh shell + * initialization when use GNU GCC compiler. + * 2016-11-26 armink add password authentication + * 2018-07-02 aozima add custome prompt support. + */ + +#include + +#include "finsh.h" +#include "shell.h" + +#ifdef FINSH_USING_MSH +#include "msh.h" +#endif + +#ifdef _WIN32 +#include /* for putchar */ +#endif + +/* finsh thread */ +#ifndef RT_USING_HEAP +static struct rt_thread finsh_thread; +ALIGN(RT_ALIGN_SIZE) +static char finsh_thread_stack[FINSH_THREAD_STACK_SIZE]; +struct finsh_shell _shell; +#endif + +struct finsh_shell *shell; +static char *finsh_prompt_custom = RT_NULL; + +#ifdef RT_USING_HEAP +int finsh_set_prompt(const char * prompt) +{ + if(finsh_prompt_custom) + { + rt_free(finsh_prompt_custom); + finsh_prompt_custom = RT_NULL; + } + + /* strdup */ + if(prompt) + { + finsh_prompt_custom = rt_malloc(strlen(prompt)+1); + if(finsh_prompt_custom) + { + strcpy(finsh_prompt_custom, prompt); + } + } + + return 0; +} +#endif /* RT_USING_HEAP */ + +#if defined(RT_USING_DFS) +#include +#endif /* RT_USING_DFS */ + +const char *finsh_get_prompt() +{ +#define _MSH_PROMPT "msh " +#define _PROMPT "finsh " + static char finsh_prompt[RT_CONSOLEBUF_SIZE + 1] = {0}; + + /* check prompt mode */ + if (!shell->prompt_mode) + { + finsh_prompt[0] = '\0'; + return finsh_prompt; + } + + if(finsh_prompt_custom) + { + strncpy(finsh_prompt, finsh_prompt_custom, sizeof(finsh_prompt)-1); + return finsh_prompt; + } + +#ifdef FINSH_USING_MSH + if (msh_is_used()) strcpy(finsh_prompt, _MSH_PROMPT); + else +#endif + strcpy(finsh_prompt, _PROMPT); + +#if defined(RT_USING_DFS) && defined(DFS_USING_WORKDIR) + /* get current working directory */ + getcwd(&finsh_prompt[rt_strlen(finsh_prompt)], RT_CONSOLEBUF_SIZE - rt_strlen(finsh_prompt)); +#endif + + strcat(finsh_prompt, ">"); + + return finsh_prompt; +} + +/** + * @ingroup finsh + * + * This function get the prompt mode of finsh shell. + * + * @return prompt the prompt mode, 0 disable prompt mode, other values enable prompt mode. + */ +rt_uint32_t finsh_get_prompt_mode(void) +{ + RT_ASSERT(shell != RT_NULL); + return shell->prompt_mode; +} + +/** + * @ingroup finsh + * + * This function set the prompt mode of finsh shell. + * + * The parameter 0 disable prompt mode, other values enable prompt mode. + * + * @param prompt the prompt mode + */ +void finsh_set_prompt_mode(rt_uint32_t prompt_mode) +{ + RT_ASSERT(shell != RT_NULL); + shell->prompt_mode = prompt_mode; +} + +static char finsh_getchar(void) +{ +#ifdef RT_USING_POSIX + return getchar(); +#else + char ch; + + RT_ASSERT(shell != RT_NULL); + while (rt_device_read(shell->device, -1, &ch, 1) != 1) + rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER); + + return ch; +#endif +} + +#ifndef RT_USING_POSIX +static rt_err_t finsh_rx_ind(rt_device_t dev, rt_size_t size) +{ + RT_ASSERT(shell != RT_NULL); + + /* release semaphore to let finsh thread rx data */ + rt_sem_release(&shell->rx_sem); + + return RT_EOK; +} + +/** + * @ingroup finsh + * + * This function sets the input device of finsh shell. + * + * @param device_name the name of new input device. + */ +void finsh_set_device(const char *device_name) +{ + rt_device_t dev = RT_NULL; + + RT_ASSERT(shell != RT_NULL); + dev = rt_device_find(device_name); + if (dev == RT_NULL) + { + rt_kprintf("finsh: can not find device: %s\n", device_name); + return; + } + + /* check whether it's a same device */ + if (dev == shell->device) return; + /* open this device and set the new device in finsh shell */ + if (rt_device_open(dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | \ + RT_DEVICE_FLAG_STREAM) == RT_EOK) + { + if (shell->device != RT_NULL) + { + /* close old finsh device */ + rt_device_close(shell->device); + rt_device_set_rx_indicate(shell->device, RT_NULL); + } + + /* clear line buffer before switch to new device */ + memset(shell->line, 0, sizeof(shell->line)); + shell->line_curpos = shell->line_position = 0; + + shell->device = dev; + rt_device_set_rx_indicate(dev, finsh_rx_ind); + } +} + +/** + * @ingroup finsh + * + * This function returns current finsh shell input device. + * + * @return the finsh shell input device name is returned. + */ +const char *finsh_get_device() +{ + RT_ASSERT(shell != RT_NULL); + return shell->device->parent.name; +} +#endif + +/** + * @ingroup finsh + * + * This function set the echo mode of finsh shell. + * + * FINSH_OPTION_ECHO=0x01 is echo mode, other values are none-echo mode. + * + * @param echo the echo mode + */ +void finsh_set_echo(rt_uint32_t echo) +{ + RT_ASSERT(shell != RT_NULL); + shell->echo_mode = (rt_uint8_t)echo; +} + +/** + * @ingroup finsh + * + * This function gets the echo mode of finsh shell. + * + * @return the echo mode + */ +rt_uint32_t finsh_get_echo() +{ + RT_ASSERT(shell != RT_NULL); + + return shell->echo_mode; +} + +#ifdef FINSH_USING_AUTH +/** + * set a new password for finsh + * + * @param password new password + * + * @return result, RT_EOK on OK, -RT_ERROR on the new password length is less than + * FINSH_PASSWORD_MIN or greater than FINSH_PASSWORD_MAX + */ +rt_err_t finsh_set_password(const char *password) { + rt_ubase_t level; + rt_size_t pw_len = rt_strlen(password); + + if (pw_len < FINSH_PASSWORD_MIN || pw_len > FINSH_PASSWORD_MAX) + return -RT_ERROR; + + level = rt_hw_interrupt_disable(); + rt_strncpy(shell->password, password, FINSH_PASSWORD_MAX); + rt_hw_interrupt_enable(level); + + return RT_EOK; +} + +/** + * get the finsh password + * + * @return password + */ +const char *finsh_get_password(void) +{ + return shell->password; +} + +static void finsh_wait_auth(void) +{ + char ch; + rt_bool_t input_finish = RT_FALSE; + char password[FINSH_PASSWORD_MAX] = { 0 }; + rt_size_t cur_pos = 0; + /* password not set */ + if (rt_strlen(finsh_get_password()) == 0) return; + + while (1) + { + rt_kprintf("Password for login: "); + while (!input_finish) + { + while (1) + { + /* read one character from device */ + ch = finsh_getchar(); + + if (ch >= ' ' && ch <= '~' && cur_pos < FINSH_PASSWORD_MAX) + { + /* change the printable characters to '*' */ + rt_kprintf("*"); + password[cur_pos++] = ch; + } + else if (ch == '\b' && cur_pos > 0) + { + /* backspace */ + password[cur_pos] = '\0'; + cur_pos--; + rt_kprintf("\b \b"); + } + else if (ch == '\r' || ch == '\n') + { + rt_kprintf("\n"); + input_finish = RT_TRUE; + break; + } + } + } + if (!rt_strncmp(shell->password, password, FINSH_PASSWORD_MAX)) return; + else + { + /* authentication failed, delay 2S for retry */ + rt_thread_delay(2 * RT_TICK_PER_SECOND); + rt_kprintf("Sorry, try again.\n"); + cur_pos = 0; + input_finish = RT_FALSE; + rt_memset(password, '\0', FINSH_PASSWORD_MAX); + } + } +} +#endif /* FINSH_USING_AUTH */ + +static void shell_auto_complete(char *prefix) +{ + + rt_kprintf("\n"); +#ifdef FINSH_USING_MSH + if (msh_is_used() == RT_TRUE) + { + msh_auto_complete(prefix); + } + else +#endif + { +#ifndef FINSH_USING_MSH_ONLY + extern void list_prefix(char * prefix); + list_prefix(prefix); +#endif + } + + rt_kprintf("%s%s", FINSH_PROMPT, prefix); +} + +#ifndef FINSH_USING_MSH_ONLY +void finsh_run_line(struct finsh_parser *parser, const char *line) +{ + const char *err_str; + + if(shell->echo_mode) + rt_kprintf("\n"); + finsh_parser_run(parser, (unsigned char *)line); + + /* compile node root */ + if (finsh_errno() == 0) + { + finsh_compiler_run(parser->root); + } + else + { + err_str = finsh_error_string(finsh_errno()); + rt_kprintf("%s\n", err_str); + } + + /* run virtual machine */ + if (finsh_errno() == 0) + { + char ch; + finsh_vm_run(); + + ch = (unsigned char)finsh_stack_bottom(); + if (ch > 0x20 && ch < 0x7e) + { + rt_kprintf("\t'%c', %d, 0x%08x\n", + (unsigned char)finsh_stack_bottom(), + (unsigned int)finsh_stack_bottom(), + (unsigned int)finsh_stack_bottom()); + } + else + { + rt_kprintf("\t%d, 0x%08x\n", + (unsigned int)finsh_stack_bottom(), + (unsigned int)finsh_stack_bottom()); + } + } + + finsh_flush(parser); +} +#endif + +#ifdef FINSH_USING_HISTORY +static rt_bool_t shell_handle_history(struct finsh_shell *shell) +{ +#if defined(_WIN32) + int i; + rt_kprintf("\r"); + + for (i = 0; i <= 60; i++) + putchar(' '); + rt_kprintf("\r"); + +#else + rt_kprintf("\033[2K\r"); +#endif + rt_kprintf("%s%s", FINSH_PROMPT, shell->line); + return RT_FALSE; +} + +static void shell_push_history(struct finsh_shell *shell) +{ + if (shell->line_position != 0) + { + /* push history */ + if (shell->history_count >= FINSH_HISTORY_LINES) + { + /* if current cmd is same as last cmd, don't push */ + if (memcmp(&shell->cmd_history[FINSH_HISTORY_LINES - 1], shell->line, FINSH_CMD_SIZE)) + { + /* move history */ + int index; + for (index = 0; index < FINSH_HISTORY_LINES - 1; index ++) + { + memcpy(&shell->cmd_history[index][0], + &shell->cmd_history[index + 1][0], FINSH_CMD_SIZE); + } + memset(&shell->cmd_history[index][0], 0, FINSH_CMD_SIZE); + memcpy(&shell->cmd_history[index][0], shell->line, shell->line_position); + + /* it's the maximum history */ + shell->history_count = FINSH_HISTORY_LINES; + } + } + else + { + /* if current cmd is same as last cmd, don't push */ + if (shell->history_count == 0 || memcmp(&shell->cmd_history[shell->history_count - 1], shell->line, FINSH_CMD_SIZE)) + { + shell->current_history = shell->history_count; + memset(&shell->cmd_history[shell->history_count][0], 0, FINSH_CMD_SIZE); + memcpy(&shell->cmd_history[shell->history_count][0], shell->line, shell->line_position); + + /* increase count and set current history position */ + shell->history_count ++; + } + } + } + shell->current_history = shell->history_count; +} +#endif + +void finsh_thread_entry(void *parameter) +{ + char ch; + + /* normal is echo mode */ +#ifndef FINSH_ECHO_DISABLE_DEFAULT + shell->echo_mode = 1; +#else + shell->echo_mode = 0; +#endif + +#ifndef FINSH_USING_MSH_ONLY + finsh_init(&shell->parser); +#endif + +#ifndef RT_USING_POSIX + /* set console device as shell device */ + if (shell->device == RT_NULL) + { + rt_device_t console = rt_console_get_device(); + if (console) + { + finsh_set_device(console->parent.name); + } + } +#endif + +#ifdef FINSH_USING_AUTH + /* set the default password when the password isn't setting */ + if (rt_strlen(finsh_get_password()) == 0) + { + if (finsh_set_password(FINSH_DEFAULT_PASSWORD) != RT_EOK) + { + rt_kprintf("Finsh password set failed.\n"); + } + } + /* waiting authenticate success */ + finsh_wait_auth(); +#endif + + rt_kprintf(FINSH_PROMPT); + + while (1) + { + ch = finsh_getchar(); + + /* + * handle control key + * up key : 0x1b 0x5b 0x41 + * down key: 0x1b 0x5b 0x42 + * right key:0x1b 0x5b 0x43 + * left key: 0x1b 0x5b 0x44 + */ + if (ch == 0x1b) + { + shell->stat = WAIT_SPEC_KEY; + continue; + } + else if (shell->stat == WAIT_SPEC_KEY) + { + if (ch == 0x5b) + { + shell->stat = WAIT_FUNC_KEY; + continue; + } + + shell->stat = WAIT_NORMAL; + } + else if (shell->stat == WAIT_FUNC_KEY) + { + shell->stat = WAIT_NORMAL; + + if (ch == 0x41) /* up key */ + { +#ifdef FINSH_USING_HISTORY + /* prev history */ + if (shell->current_history > 0) + shell->current_history --; + else + { + shell->current_history = 0; + continue; + } + + /* copy the history command */ + memcpy(shell->line, &shell->cmd_history[shell->current_history][0], + FINSH_CMD_SIZE); + shell->line_curpos = shell->line_position = strlen(shell->line); + shell_handle_history(shell); +#endif + continue; + } + else if (ch == 0x42) /* down key */ + { +#ifdef FINSH_USING_HISTORY + /* next history */ + if (shell->current_history < shell->history_count - 1) + shell->current_history ++; + else + { + /* set to the end of history */ + if (shell->history_count != 0) + shell->current_history = shell->history_count - 1; + else + continue; + } + + memcpy(shell->line, &shell->cmd_history[shell->current_history][0], + FINSH_CMD_SIZE); + shell->line_curpos = shell->line_position = strlen(shell->line); + shell_handle_history(shell); +#endif + continue; + } + else if (ch == 0x44) /* left key */ + { + if (shell->line_curpos) + { + rt_kprintf("\b"); + shell->line_curpos --; + } + + continue; + } + else if (ch == 0x43) /* right key */ + { + if (shell->line_curpos < shell->line_position) + { + rt_kprintf("%c", shell->line[shell->line_curpos]); + shell->line_curpos ++; + } + + continue; + } + } + + /* received null or error */ + if (ch == '\0' || ch == 0xFF) continue; + /* handle tab key */ + else if (ch == '\t') + { + int i; + /* move the cursor to the beginning of line */ + for (i = 0; i < shell->line_curpos; i++) + rt_kprintf("\b"); + + /* auto complete */ + shell_auto_complete(&shell->line[0]); + /* re-calculate position */ + shell->line_curpos = shell->line_position = strlen(shell->line); + + continue; + } + /* handle backspace key */ + else if (ch == 0x7f || ch == 0x08) + { + /* note that shell->line_curpos >= 0 */ + if (shell->line_curpos == 0) + continue; + + shell->line_position--; + shell->line_curpos--; + + if (shell->line_position > shell->line_curpos) + { + int i; + + rt_memmove(&shell->line[shell->line_curpos], + &shell->line[shell->line_curpos + 1], + shell->line_position - shell->line_curpos); + shell->line[shell->line_position] = 0; + + rt_kprintf("\b%s \b", &shell->line[shell->line_curpos]); + + /* move the cursor to the origin position */ + for (i = shell->line_curpos; i <= shell->line_position; i++) + rt_kprintf("\b"); + } + else + { + rt_kprintf("\b \b"); + shell->line[shell->line_position] = 0; + } + + continue; + } + + /* handle end of line, break */ + if (ch == '\r' || ch == '\n') + { +#ifdef FINSH_USING_HISTORY + shell_push_history(shell); +#endif + +#ifdef FINSH_USING_MSH + if (msh_is_used() == RT_TRUE) + { + if (shell->echo_mode) + rt_kprintf("\n"); + msh_exec(shell->line, shell->line_position); + } + else +#endif + { +#ifndef FINSH_USING_MSH_ONLY + /* add ';' and run the command line */ + shell->line[shell->line_position] = ';'; + + if (shell->line_position != 0) finsh_run_line(&shell->parser, shell->line); + else + if (shell->echo_mode) rt_kprintf("\n"); +#endif + } + + rt_kprintf(FINSH_PROMPT); + memset(shell->line, 0, sizeof(shell->line)); + shell->line_curpos = shell->line_position = 0; + continue; + } + + /* it's a large line, discard it */ + if (shell->line_position >= FINSH_CMD_SIZE) + shell->line_position = 0; + + /* normal character */ + if (shell->line_curpos < shell->line_position) + { + int i; + + rt_memmove(&shell->line[shell->line_curpos + 1], + &shell->line[shell->line_curpos], + shell->line_position - shell->line_curpos); + shell->line[shell->line_curpos] = ch; + if (shell->echo_mode) + rt_kprintf("%s", &shell->line[shell->line_curpos]); + + /* move the cursor to new position */ + for (i = shell->line_curpos; i < shell->line_position; i++) + rt_kprintf("\b"); + } + else + { + shell->line[shell->line_position] = ch; + if (shell->echo_mode) + rt_kprintf("%c", ch); + } + + ch = 0; + shell->line_position ++; + shell->line_curpos++; + if (shell->line_position >= FINSH_CMD_SIZE) + { + /* clear command line */ + shell->line_position = 0; + shell->line_curpos = 0; + } + } /* end of device read */ +} + +void finsh_system_function_init(const void *begin, const void *end) +{ + _syscall_table_begin = (struct finsh_syscall *) begin; + _syscall_table_end = (struct finsh_syscall *) end; +} + +void finsh_system_var_init(const void *begin, const void *end) +{ + _sysvar_table_begin = (struct finsh_sysvar *) begin; + _sysvar_table_end = (struct finsh_sysvar *) end; +} + +#if defined(__ICCARM__) || defined(__ICCRX__) /* for IAR compiler */ +#ifdef FINSH_USING_SYMTAB +#pragma section="FSymTab" +#pragma section="VSymTab" +#endif +#elif defined(__ADSPBLACKFIN__) /* for VisaulDSP++ Compiler*/ +#ifdef FINSH_USING_SYMTAB +extern "asm" int __fsymtab_start; +extern "asm" int __fsymtab_end; +extern "asm" int __vsymtab_start; +extern "asm" int __vsymtab_end; +#endif +#elif defined(_MSC_VER) +#pragma section("FSymTab$a", read) +const char __fsym_begin_name[] = "__start"; +const char __fsym_begin_desc[] = "begin of finsh"; +__declspec(allocate("FSymTab$a")) const struct finsh_syscall __fsym_begin = +{ + __fsym_begin_name, + __fsym_begin_desc, + NULL +}; + +#pragma section("FSymTab$z", read) +const char __fsym_end_name[] = "__end"; +const char __fsym_end_desc[] = "end of finsh"; +__declspec(allocate("FSymTab$z")) const struct finsh_syscall __fsym_end = +{ + __fsym_end_name, + __fsym_end_desc, + NULL +}; +#endif + +/* + * @ingroup finsh + * + * This function will initialize finsh shell + */ +int finsh_system_init(void) +{ + rt_err_t result = RT_EOK; + rt_thread_t tid; + +#ifdef FINSH_USING_SYMTAB +#if defined(__CC_ARM) || defined(__CLANG_ARM) /* ARM C Compiler */ + extern const int FSymTab$$Base; + extern const int FSymTab$$Limit; + extern const int VSymTab$$Base; + extern const int VSymTab$$Limit; + finsh_system_function_init(&FSymTab$$Base, &FSymTab$$Limit); +#ifndef FINSH_USING_MSH_ONLY + finsh_system_var_init(&VSymTab$$Base, &VSymTab$$Limit); +#endif +#elif defined (__ICCARM__) || defined(__ICCRX__) /* for IAR Compiler */ + finsh_system_function_init(__section_begin("FSymTab"), + __section_end("FSymTab")); + finsh_system_var_init(__section_begin("VSymTab"), + __section_end("VSymTab")); +#elif defined (__GNUC__) || defined(__TI_COMPILER_VERSION__) + /* GNU GCC Compiler and TI CCS */ + extern const int __fsymtab_start; + extern const int __fsymtab_end; + extern const int __vsymtab_start; + extern const int __vsymtab_end; + finsh_system_function_init(&__fsymtab_start, &__fsymtab_end); + finsh_system_var_init(&__vsymtab_start, &__vsymtab_end); +#elif defined(__ADSPBLACKFIN__) /* for VisualDSP++ Compiler */ + finsh_system_function_init(&__fsymtab_start, &__fsymtab_end); + finsh_system_var_init(&__vsymtab_start, &__vsymtab_end); +#elif defined(_MSC_VER) + unsigned int *ptr_begin, *ptr_end; + + if(shell) + { + rt_kprintf("finsh shell already init.\n"); + return RT_EOK; + } + + ptr_begin = (unsigned int *)&__fsym_begin; + ptr_begin += (sizeof(struct finsh_syscall) / sizeof(unsigned int)); + while (*ptr_begin == 0) ptr_begin ++; + + ptr_end = (unsigned int *) &__fsym_end; + ptr_end --; + while (*ptr_end == 0) ptr_end --; + + finsh_system_function_init(ptr_begin, ptr_end); +#endif +#endif + +#ifdef RT_USING_HEAP + /* create or set shell structure */ + shell = (struct finsh_shell *)rt_calloc(1, sizeof(struct finsh_shell)); + if (shell == RT_NULL) + { + rt_kprintf("no memory for shell\n"); + return -1; + } + tid = rt_thread_create(FINSH_THREAD_NAME, + finsh_thread_entry, RT_NULL, + FINSH_THREAD_STACK_SIZE, FINSH_THREAD_PRIORITY, 10); +#else + shell = &_shell; + tid = &finsh_thread; + result = rt_thread_init(&finsh_thread, + FINSH_THREAD_NAME, + finsh_thread_entry, RT_NULL, + &finsh_thread_stack[0], sizeof(finsh_thread_stack), + FINSH_THREAD_PRIORITY, 10); +#endif /* RT_USING_HEAP */ + + rt_sem_init(&(shell->rx_sem), "shrx", 0, 0); + finsh_set_prompt_mode(1); + + if (tid != NULL && result == RT_EOK) + rt_thread_startup(tid); + return 0; +} +INIT_APP_EXPORT(finsh_system_init); diff --git a/rt-thread/components/finsh/shell.h b/rt-thread/components/finsh/shell.h new file mode 100644 index 0000000..d0fd66e --- /dev/null +++ b/rt-thread/components/finsh/shell.h @@ -0,0 +1,129 @@ +/* + * shell implementation for finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-06-02 Bernard Add finsh_get_prompt function declaration + */ + +#ifndef __SHELL_H__ +#define __SHELL_H__ + +#include +#include "finsh.h" + +#ifndef FINSH_THREAD_PRIORITY +#define FINSH_THREAD_PRIORITY 20 +#endif +#ifndef FINSH_THREAD_STACK_SIZE +#define FINSH_THREAD_STACK_SIZE 2048 +#endif +#ifndef FINSH_CMD_SIZE +#define FINSH_CMD_SIZE 80 +#endif + +#define FINSH_OPTION_ECHO 0x01 + +#define FINSH_PROMPT finsh_get_prompt() +const char* finsh_get_prompt(void); +int finsh_set_prompt(const char * prompt); + +#ifdef FINSH_USING_HISTORY + #ifndef FINSH_HISTORY_LINES + #define FINSH_HISTORY_LINES 5 + #endif +#endif + +#ifdef FINSH_USING_AUTH + #ifndef FINSH_PASSWORD_MAX + #define FINSH_PASSWORD_MAX RT_NAME_MAX + #endif + #ifndef FINSH_PASSWORD_MIN + #define FINSH_PASSWORD_MIN 6 + #endif + #ifndef FINSH_DEFAULT_PASSWORD + #define FINSH_DEFAULT_PASSWORD "rtthread" + #endif +#endif /* FINSH_USING_AUTH */ + +#ifndef FINSH_THREAD_NAME +#define FINSH_THREAD_NAME "tshell" +#endif + +enum input_stat +{ + WAIT_NORMAL, + WAIT_SPEC_KEY, + WAIT_FUNC_KEY, +}; +struct finsh_shell +{ + struct rt_semaphore rx_sem; + + enum input_stat stat; + + rt_uint8_t echo_mode:1; + rt_uint8_t prompt_mode: 1; + +#ifdef FINSH_USING_HISTORY + rt_uint16_t current_history; + rt_uint16_t history_count; + + char cmd_history[FINSH_HISTORY_LINES][FINSH_CMD_SIZE]; +#endif + +#ifndef FINSH_USING_MSH_ONLY + struct finsh_parser parser; +#endif + + char line[FINSH_CMD_SIZE]; + rt_uint8_t line_position; + rt_uint8_t line_curpos; + +#ifndef RT_USING_POSIX + rt_device_t device; +#endif + +#ifdef FINSH_USING_AUTH + char password[FINSH_PASSWORD_MAX]; +#endif +}; + +void finsh_set_echo(rt_uint32_t echo); +rt_uint32_t finsh_get_echo(void); + +int finsh_system_init(void); +void finsh_set_device(const char* device_name); +const char* finsh_get_device(void); + +rt_uint32_t finsh_get_prompt_mode(void); +void finsh_set_prompt_mode(rt_uint32_t prompt_mode); + +#ifdef FINSH_USING_AUTH +rt_err_t finsh_set_password(const char *password); +const char *finsh_get_password(void); +#endif + +#endif + diff --git a/rt-thread/components/finsh/symbol.c b/rt-thread/components/finsh/symbol.c new file mode 100644 index 0000000..8e026c4 --- /dev/null +++ b/rt-thread/components/finsh/symbol.c @@ -0,0 +1,84 @@ +/* + * symbols in finsh shell. + * + * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team + * + * This file is part of RT-Thread (http://www.rt-thread.org) + * Maintainer: bernard.xiong + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2010-03-22 Bernard first version + */ +#include "finsh.h" + +long hello(void); +long version(void); +long list(void); +long list_thread(void); +long list_sem(void); +long list_mutex(void); +long list_fevent(void); +long list_event(void); +long list_mailbox(void); +long list_msgqueue(void); +long list_mempool(void); +long list_timer(void); + +#ifdef FINSH_USING_SYMTAB +struct finsh_syscall *_syscall_table_begin = NULL; +struct finsh_syscall *_syscall_table_end = NULL; +struct finsh_sysvar *_sysvar_table_begin = NULL; +struct finsh_sysvar *_sysvar_table_end = NULL; +#else +struct finsh_syscall _syscall_table[] = +{ + {"hello", hello}, + {"version", version}, + {"list", list}, + {"list_thread", list_thread}, +#ifdef RT_USING_SEMAPHORE + {"list_sem", list_sem}, +#endif +#ifdef RT_USING_MUTEX + {"list_mutex", list_mutex}, +#endif +#ifdef RT_USING_FEVENT + {"list_fevent", list_fevent}, +#endif +#ifdef RT_USING_EVENT + {"list_event", list_event}, +#endif +#ifdef RT_USING_MAILBOX + {"list_mb", list_mailbox}, +#endif +#ifdef RT_USING_MESSAGEQUEUE + {"list_mq", list_msgqueue}, +#endif +#ifdef RT_USING_MEMPOOL + {"list_memp", list_mempool}, +#endif + {"list_timer", list_timer}, +}; +struct finsh_syscall *_syscall_table_begin = &_syscall_table[0]; +struct finsh_syscall *_syscall_table_end = &_syscall_table[sizeof(_syscall_table) / sizeof(struct finsh_syscall)]; + +struct finsh_sysvar *_sysvar_table_begin = NULL; +struct finsh_sysvar *_sysvar_table_end = NULL; +#endif diff --git a/rt-thread/components/libc/Kconfig b/rt-thread/components/libc/Kconfig new file mode 100644 index 0000000..b2abe69 --- /dev/null +++ b/rt-thread/components/libc/Kconfig @@ -0,0 +1,36 @@ +menu "POSIX layer and C standard library" + +config RT_USING_LIBC + bool "Enable libc APIs from toolchain" + default y + +config RT_USING_PTHREADS + bool "Enable pthreads APIs" + default n + +if RT_USING_LIBC && RT_USING_DFS + config RT_USING_POSIX + bool "Enable POSIX layer for poll/select, stdin etc" + select RT_USING_DFS_DEVFS + default y + + if RT_USING_POSIX + config RT_USING_POSIX_MMAP + bool "Enable mmap() api" + default n + + config RT_USING_POSIX_TERMIOS + bool "Enable termios feature" + default n + + config RT_USING_POSIX_AIO + bool "Enable AIO" + default n + endif + + config RT_USING_MODULE + bool "Enable dynamic module with dlopen/dlsym/dlclose feature" + default n +endif + +endmenu diff --git a/rt-thread/components/libc/SConscript b/rt-thread/components/libc/SConscript new file mode 100644 index 0000000..4c815c4 --- /dev/null +++ b/rt-thread/components/libc/SConscript @@ -0,0 +1,15 @@ +# RT-Thread building script for bridge + +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/rt-thread/components/libc/compilers/SConscript b/rt-thread/components/libc/compilers/SConscript new file mode 100644 index 0000000..4c815c4 --- /dev/null +++ b/rt-thread/components/libc/compilers/SConscript @@ -0,0 +1,15 @@ +# RT-Thread building script for bridge + +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/rt-thread/components/libc/compilers/armlibc/SConscript b/rt-thread/components/libc/compilers/armlibc/SConscript new file mode 100644 index 0000000..081efa7 --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/SConscript @@ -0,0 +1,21 @@ +from building import * +Import('rtconfig') + +src = Glob('*.c') + Glob('*.cpp') +cwd = GetCurrentDir() +group = [] + +CPPPATH = [cwd] +CPPDEFINES = ['RT_USING_ARM_LIBC'] + +if GetDepend('RT_USING_DFS') == False: + SrcRemove(src, ['stdio.c']) + +if GetDepend('RT_USING_MODULE') == False: + SrcRemove(src, ['libc_syms.c']) + +if rtconfig.PLATFORM == 'armcc': + group = DefineGroup('libc', src, depend = ['RT_USING_LIBC'], + CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES) + +Return('group') diff --git a/rt-thread/components/libc/compilers/armlibc/dirent.h b/rt-thread/components/libc/compilers/armlibc/dirent.h new file mode 100644 index 0000000..1adf952 --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/dirent.h @@ -0,0 +1,54 @@ +#ifndef __RTT_DIRENT_H__ +#define __RTT_DIRENT_H__ + +#include +#include + +/* +* dirent.h - format of directory entries + * Ref: http://www.opengroup.org/onlinepubs/009695399/basedefs/dirent.h.html + */ + +/* File types */ +#define FT_REGULAR 0 /* regular file */ +#define FT_SOCKET 1 /* socket file */ +#define FT_DIRECTORY 2 /* directory */ +#define FT_USER 3 /* user defined */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HAVE_DIR_STRUCTURE +typedef struct +{ + int fd; /* directory file */ + char buf[512]; + int num; + int cur; +} DIR; +#endif + +#ifndef HAVE_DIRENT_STRUCTURE +struct dirent +{ + rt_uint8_t d_type; /* The type of the file */ + rt_uint8_t d_namlen; /* The length of the not including the terminating null file name */ + rt_uint16_t d_reclen; /* length of this record */ + char d_name[256]; /* The null-terminated file name */ +}; +#endif + +int closedir(DIR *); +DIR *opendir(const char *); +struct dirent *readdir(DIR *); +int readdir_r(DIR *, struct dirent *, struct dirent **); +void rewinddir(DIR *); +void seekdir(DIR *, long int); +long telldir(DIR *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/libc/compilers/armlibc/fcntl.h b/rt-thread/components/libc/compilers/armlibc/fcntl.h new file mode 100644 index 0000000..324b73f --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/fcntl.h @@ -0,0 +1,8 @@ +#ifndef FCNTL_H__ +#define FCNTL_H__ + +#ifdef RT_USING_DFS +#include +#endif + +#endif diff --git a/rt-thread/components/libc/compilers/armlibc/libc.c b/rt-thread/components/libc/compilers/armlibc/libc.c new file mode 100644 index 0000000..c3fab19 --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/libc.c @@ -0,0 +1,59 @@ +/* + * File : libc.c + * Brief : armcc libc initialization + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/10/15 bernard the first version + */ +#include +#include + +#include + +#include "libc.h" + +#ifdef RT_USING_PTHREADS +#include +#endif + +int libc_system_init(void) +{ +#if defined(RT_USING_DFS) & defined(RT_USING_DFS_DEVFS) + rt_device_t dev_console; + + dev_console = rt_console_get_device(); + if (dev_console) + { + #if defined(RT_USING_POSIX) + libc_stdio_set_console(dev_console->parent.name, O_RDWR); + #else + libc_stdio_set_console(dev_console->parent.name, O_WRONLY); + #endif + } +#endif + +#if defined RT_USING_PTHREADS && !defined RT_USING_COMPONENTS_INIT + pthread_system_init(); +#endif + + return 0; +} +INIT_COMPONENT_EXPORT(libc_system_init); diff --git a/rt-thread/components/libc/compilers/armlibc/libc.h b/rt-thread/components/libc/compilers/armlibc/libc.h new file mode 100644 index 0000000..e57897f --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/libc.h @@ -0,0 +1,38 @@ +/* + * File : libc.h + * Brief : armcc libc header file + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/10/15 bernard the first version + */ +#ifndef __RTT_LIBC_H__ +#define __RTT_LIBC_H__ + +#include + +int libc_system_init(void); + +int libc_stdio_set_console(const char* device_name, int mode); +int libc_stdio_get_console(void); +int libc_stdio_read (void *buffer, size_t size); +int libc_stdio_write(const void *buffer, size_t size); + +#endif diff --git a/rt-thread/components/libc/compilers/armlibc/libc_syms.c b/rt-thread/components/libc/compilers/armlibc/libc_syms.c new file mode 100644 index 0000000..fc84aec --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/libc_syms.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include + +#include + +/* some export routines for module */ + +RTM_EXPORT(strstr); +RTM_EXPORT(strlen); +RTM_EXPORT(strchr); +RTM_EXPORT(strcpy); +RTM_EXPORT(strncpy); +RTM_EXPORT(strcmp); +RTM_EXPORT(strncmp); +RTM_EXPORT(strcat); +RTM_EXPORT(strtol); + +RTM_EXPORT(memcpy); +RTM_EXPORT(memcmp); +RTM_EXPORT(memmove); +RTM_EXPORT(memset); +RTM_EXPORT(memchr); + +RTM_EXPORT(toupper); +RTM_EXPORT(atoi); + +#ifdef RT_USING_RTC +RTM_EXPORT(localtime); +RTM_EXPORT(time); +#endif + +/* import the full stdio for printf */ +#if defined(RT_USING_MODULE) && defined(__MICROLIB) +#error "[RT_USING_LIBC] Please use standard libc but not microlib." +#endif + +RTM_EXPORT(puts); +RTM_EXPORT(printf); diff --git a/rt-thread/components/libc/compilers/armlibc/mem_std.c b/rt-thread/components/libc/compilers/armlibc/mem_std.c new file mode 100644 index 0000000..4393b5f --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/mem_std.c @@ -0,0 +1,48 @@ +/* + * File : mem_std.c + * Brief : implement standard memory routins. + * + * This file is part of Device File System in RT-Thread RTOS + * COPYRIGHT (C) 2014, 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: + * 2014-08-03 bernard Add file header. + */ + +#include "rtthread.h" + +#ifdef RT_USING_HEAP + +#ifdef __CC_ARM +/* avoid the heap and heap-using library functions supplied by arm */ +#pragma import(__use_no_heap) +#endif + +void *malloc(size_t n) +{ + return rt_malloc(n); +} +RTM_EXPORT(malloc); + +void *realloc(void *rmem, size_t newsize) +{ + return rt_realloc(rmem, newsize); +} +RTM_EXPORT(realloc); + +void *calloc(size_t nelem, size_t elsize) +{ + return rt_calloc(nelem, elsize); +} +RTM_EXPORT(calloc); + +void free(void *rmem) +{ + rt_free(rmem); +} +RTM_EXPORT(free); +#endif diff --git a/rt-thread/components/libc/compilers/armlibc/stdio.c b/rt-thread/components/libc/compilers/armlibc/stdio.c new file mode 100644 index 0000000..9d90823 --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/stdio.c @@ -0,0 +1,91 @@ +/* + * File : stdio.c + * Brief : stdio/console + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/10/15 bernard implement stdio for armcc. + */ + +#include +#include +#include + +#include +#include "libc.h" + +#if defined(RT_USING_DFS) && defined(RT_USING_DFS_DEVFS) +#include + +#define STDIO_DEVICE_NAME_MAX 32 + +static int std_fd = -1; +int libc_stdio_set_console(const char* device_name, int mode) +{ + int fd; + char name[STDIO_DEVICE_NAME_MAX]; + + snprintf(name, sizeof(name) - 1, "/dev/%s", device_name); + name[STDIO_DEVICE_NAME_MAX - 1] = '\0'; + + fd = open(name, mode, 0); + if (fd >= 0) + { + if (std_fd >= 0) + { + close(std_fd); + } + std_fd = fd; + } + + return std_fd; +} + +int libc_stdio_get_console(void) +{ + return std_fd; +} + +int libc_stdio_read(void *buffer, size_t size) +{ + if (std_fd >= 0) + { + return read(std_fd, buffer, size); + } + else + { + rt_kprintf("Illegal stdio input!\n"); + return 0; + } +} + +int libc_stdio_write(const void *buffer, size_t size) +{ + if (std_fd >= 0) + { + return write(std_fd, buffer, size); + } + else + { + rt_kprintf("Illegal stdio output!\n"); + return size; + } +} +#endif diff --git a/rt-thread/components/libc/compilers/armlibc/stubs.c b/rt-thread/components/libc/compilers/armlibc/stubs.c new file mode 100644 index 0000000..dbb60c8 --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/stubs.c @@ -0,0 +1,334 @@ +/* + * File : stubs.c + * Brief : reimplement some basic functions of arm standard c library + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2012-11-23 Yihui The first version + * 2013-11-24 aozima fixed _sys_read()/_sys_write() issues. + * 2014-08-03 bernard If using msh, use system() implementation + * in msh. + */ + +#include +#include + +#include "rtthread.h" +#include "libc.h" + +#ifdef RT_USING_DFS +#include "dfs_posix.h" +#endif + +#ifdef __CLANG_ARM +__asm(".global __use_no_semihosting\n\t"); +#else +#pragma import(__use_no_semihosting_swi) +#endif + +/* Standard IO device handles. */ +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 + +/* Standard IO device name defines. */ +const char __stdin_name[] = "STDIN"; +const char __stdout_name[] = "STDOUT"; +const char __stderr_name[] = "STDERR"; + +/** + * required by fopen() and freopen(). + * + * @param name - file name with path. + * @param openmode - a bitmap hose bits mostly correspond directly to + * the ISO mode specification. + * @return -1 if an error occurs. + */ +FILEHANDLE _sys_open(const char *name, int openmode) +{ +#ifdef RT_USING_DFS + int fd; + int mode = O_RDONLY; +#endif + + /* Register standard Input Output devices. */ + if (strcmp(name, __stdin_name) == 0) + return (STDIN); + if (strcmp(name, __stdout_name) == 0) + return (STDOUT); + if (strcmp(name, __stderr_name) == 0) + return (STDERR); + +#ifndef RT_USING_DFS + return -1; +#else + /* Correct openmode from fopen to open */ + if (openmode & OPEN_PLUS) + { + if (openmode & OPEN_W) + { + mode |= (O_RDWR | O_TRUNC | O_CREAT); + } + else if (openmode & OPEN_A) + { + mode |= (O_RDWR | O_APPEND | O_CREAT); + } + else + mode |= O_RDWR; + } + else + { + if (openmode & OPEN_W) + { + mode |= (O_WRONLY | O_TRUNC | O_CREAT); + } + else if (openmode & OPEN_A) + { + mode |= (O_WRONLY | O_APPEND | O_CREAT); + } + } + + fd = open(name, mode, 0); + if (fd < 0) + return -1; + else + return fd; +#endif +} + +int _sys_close(FILEHANDLE fh) +{ +#ifndef RT_USING_DFS + return 0; +#else + if (fh <= STDERR) return 0; + + return close(fh); +#endif +} + +/* + * Read from a file. Can return: + * - zero if the read was completely successful + * - the number of bytes _not_ read, if the read was partially successful + * - the number of bytes not read, plus the top bit set (0x80000000), if + * the read was partially successful due to end of file + * - -1 if some error other than EOF occurred + * + * It is also legal to signal EOF by returning no data but + * signalling no error (i.e. the top-bit-set mechanism need never + * be used). + * + * So if (for example) the user is trying to read 8 bytes at a time + * from a file in which only 5 remain, this routine can do three + * equally valid things: + * + * - it can return 0x80000003 (3 bytes not read due to EOF) + * - OR it can return 3 (3 bytes not read), and then return + * 0x80000008 (8 bytes not read due to EOF) on the next attempt + * - OR it can return 3 (3 bytes not read), and then return + * 8 (8 bytes not read, meaning 0 read, meaning EOF) on the next + * attempt + * + * `mode' exists for historical reasons and must be ignored. + */ +int _sys_read(FILEHANDLE fh, unsigned char *buf, unsigned len, int mode) +{ +#ifdef RT_USING_DFS + int size; +#endif + + if (fh == STDIN) + { +#ifdef RT_USING_POSIX + size = libc_stdio_read(buf, len); + return len - size; +#else + /* no stdin */ + return -1; +#endif + } + + if ((fh == STDOUT) || (fh == STDERR)) + return -1; + +#ifndef RT_USING_DFS + return 0; +#else + size = read(fh, buf, len); + if (size >= 0) + return len - size; + else + return -1; +#endif +} + +/* + * Write to a file. Returns 0 on success, negative on error, and + * the number of characters _not_ written on partial success. + * `mode' exists for historical reasons and must be ignored. + */ +int _sys_write(FILEHANDLE fh, const unsigned char *buf, unsigned len, int mode) +{ +#ifdef RT_USING_DFS + int size; +#endif + + if ((fh == STDOUT) || (fh == STDERR)) + { +#if !defined(RT_USING_CONSOLE) || !defined(RT_USING_DEVICE) + return 0; +#else +#ifdef RT_USING_POSIX + size = libc_stdio_write(buf, len); + return len - size; +#else + if (rt_console_get_device()) + { + rt_device_write(rt_console_get_device(), -1, buf, len); + return 0; + } + + return -1; +#endif +#endif + } + + if (fh == STDIN) return -1; + +#ifndef RT_USING_DFS + return 0; +#else + size = write(fh, buf, len); + if (size >= 0) + return len - size; + else + return -1; +#endif +} + +/* + * Move the file position to a given offset from the file start. + * Returns >=0 on success, <0 on failure. + */ +int _sys_seek(FILEHANDLE fh, long pos) +{ + if (fh < STDERR) + return -1; + +#ifndef RT_USING_DFS + return -1; +#else + + /* position is relative to the start of file fh */ + return lseek(fh, pos, 0); +#endif +} + +/** + * used by tmpnam() or tmpfile() + */ +int _sys_tmpnam(char *name, int fileno, unsigned maxlength) +{ + return -1; +} + +char *_sys_command_string(char *cmd, int len) +{ + /* no support */ + return RT_NULL; +} + +/* This function writes a character to the console. */ +void _ttywrch(int ch) +{ +#ifdef RT_USING_CONSOLE + char c; + + c = (char)ch; + rt_kprintf(&c); +#endif +} + +void _sys_exit(int return_code) +{ + /* TODO: perhaps exit the thread which is invoking this function */ + while (1); +} + +/** + * return current length of file. + * + * @param fh - file handle + * @return file length, or -1 on failed + */ +long _sys_flen(FILEHANDLE fh) +{ + return -1; +} + +int _sys_istty(FILEHANDLE fh) +{ + return 0; +} + +int remove(const char *filename) +{ +#ifndef RT_USING_DFS + return -1; +#else + return unlink(filename); +#endif +} + +#if defined(RT_USING_FINSH) && defined(FINSH_USING_MSH) && defined(RT_USING_MODULE) && defined(RT_USING_DFS) +/* use system(const char *string) implementation in the msh */ +#else +int system(const char *string) +{ + RT_ASSERT(0); + for (;;); +} +#endif + +#ifdef __MICROLIB +#include + +int fputc(int c, FILE *f) +{ + char ch[2] = {0}; + + ch[0] = c; + rt_kprintf(&ch[0]); + return 1; +} + +int fgetc(FILE *f) +{ +#ifdef RT_USING_POSIX + char ch; + + if (libc_stdio_read(&ch, 1) == 1) + return ch; +#endif + + return -1; +} +#endif diff --git a/rt-thread/components/libc/compilers/armlibc/sys/README.md b/rt-thread/components/libc/compilers/armlibc/sys/README.md new file mode 100644 index 0000000..7ad10a7 --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/sys/README.md @@ -0,0 +1 @@ +Because Keil MDK leaks some system header file, we put them in here. \ No newline at end of file diff --git a/rt-thread/components/libc/compilers/armlibc/sys/errno.h b/rt-thread/components/libc/compilers/armlibc/sys/errno.h new file mode 100644 index 0000000..8ee115e --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/sys/errno.h @@ -0,0 +1,6 @@ +#ifndef SYS_ERRNO_H__ +#define SYS_ERRNO_H__ + +#include + +#endif diff --git a/rt-thread/components/libc/compilers/armlibc/sys/mman.h b/rt-thread/components/libc/compilers/armlibc/sys/mman.h new file mode 100644 index 0000000..024a64e --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/sys/mman.h @@ -0,0 +1,72 @@ +/* + * File : mman.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/11/30 Bernard The first version. + */ + +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAP_FAILED ((void *) -1) + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_TYPE 0x0f +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS MAP_ANON +#define MAP_NORESERVE 0x4000 +#define MAP_GROWSDOWN 0x0100 +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_FILE 0 + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 + +#define MS_ASYNC 1 +#define MS_INVALIDATE 2 +#define MS_SYNC 4 + +#define MCL_CURRENT 1 +#define MCL_FUTURE 2 +#define MCL_ONFAULT 4 + +void *mmap (void *start, size_t len, int prot, int flags, int fd, off_t off); +int munmap (void *start, size_t len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/rt-thread/components/libc/compilers/armlibc/sys/stat.h b/rt-thread/components/libc/compilers/armlibc/sys/stat.h new file mode 100644 index 0000000..e69de29 diff --git a/rt-thread/components/libc/compilers/armlibc/sys/time.h b/rt-thread/components/libc/compilers/armlibc/sys/time.h new file mode 100644 index 0000000..2d60b37 --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/sys/time.h @@ -0,0 +1,45 @@ +#ifndef _SYS_TIME_H_ +#define _SYS_TIME_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _TIMEVAL_DEFINED +#define _TIMEVAL_DEFINED +/* + * Structure returned by gettimeofday(2) system call, + * and used in other calls. + */ +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif /* _TIMEVAL_DEFINED */ + +#ifndef _TIMESPEC_DEFINED +#define _TIMESPEC_DEFINED +/* + * Structure defined by POSIX.1b to be like a timeval. + */ +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* and nanoseconds */ +}; +#endif /* _TIMESPEC_DEFINED */ + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tp, void *ignore); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIME_H_ */ diff --git a/rt-thread/components/libc/compilers/armlibc/sys/types.h b/rt-thread/components/libc/compilers/armlibc/sys/types.h new file mode 100644 index 0000000..b01d828 --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/sys/types.h @@ -0,0 +1,12 @@ +#ifndef __TYPES_H__ +#define __TYPES_H__ + +#include +#include + +typedef rt_int32_t clockid_t; +typedef rt_int32_t key_t; /* Used for interprocess communication. */ +typedef rt_int32_t pid_t; /* Used for process IDs and process group IDs. */ +typedef signed long ssize_t; /* Used for a count of bytes or an error indication. */ + +#endif diff --git a/rt-thread/components/libc/compilers/armlibc/sys/unistd.h b/rt-thread/components/libc/compilers/armlibc/sys/unistd.h new file mode 100644 index 0000000..5697995 --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/sys/unistd.h @@ -0,0 +1,41 @@ +#ifndef _SYS_UNISTD_H +#define _SYS_UNISTD_H + +#include + +#ifdef RT_USING_DFS + +#define STDIN_FILENO 0 /* standard input file descriptor */ +#define STDOUT_FILENO 1 /* standard output file descriptor */ +#define STDERR_FILENO 2 /* standard error file descriptor */ + +#include +#else +#define _FREAD 0x0001 /* read enabled */ +#define _FWRITE 0x0002 /* write enabled */ +#define _FAPPEND 0x0008 /* append (writes guaranteed at the end) */ +#define _FMARK 0x0010 /* internal; mark during gc() */ +#define _FDEFER 0x0020 /* internal; defer for next gc pass */ +#define _FASYNC 0x0040 /* signal pgrp when data ready */ +#define _FSHLOCK 0x0080 /* BSD flock() shared lock present */ +#define _FEXLOCK 0x0100 /* BSD flock() exclusive lock present */ +#define _FCREAT 0x0200 /* open with file create */ +#define _FTRUNC 0x0400 /* open with truncation */ +#define _FEXCL 0x0800 /* error on open if file exists */ +#define _FNBIO 0x1000 /* non blocking I/O (sys5 style) */ +#define _FSYNC 0x2000 /* do all writes synchronously */ +#define _FNONBLOCK 0x4000 /* non blocking I/O (POSIX style) */ +#define _FNDELAY _FNONBLOCK /* non blocking I/O (4.2 style) */ +#define _FNOCTTY 0x8000 /* don't assign a ctty on this open */ + +#define O_RDONLY 0 /* +1 == FREAD */ +#define O_WRONLY 1 /* +1 == FWRITE */ +#define O_RDWR 2 /* +1 == FREAD|FWRITE */ +#define O_APPEND _FAPPEND +#define O_CREAT _FCREAT +#define O_TRUNC _FTRUNC +#define O_EXCL _FEXCL +#define O_SYNC _FSYNC +#endif + +#endif /* _SYS_UNISTD_H */ diff --git a/rt-thread/components/libc/compilers/armlibc/termios.h b/rt-thread/components/libc/compilers/armlibc/termios.h new file mode 100644 index 0000000..0b54066 --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/termios.h @@ -0,0 +1,7 @@ +#ifndef _TERMIOS_H__ +#define _TERMIOS_H__ + +#include +#include + +#endif diff --git a/rt-thread/components/libc/compilers/armlibc/time.c b/rt-thread/components/libc/compilers/armlibc/time.c new file mode 100644 index 0000000..e7ad19a --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/time.c @@ -0,0 +1,77 @@ +#include +#include + +#ifdef RT_USING_DEVICE +int gettimeofday(struct timeval *tp, void *ignore) +{ + time_t time; + rt_device_t device; + + device = rt_device_find("rtc"); + if (device != RT_NULL) + { + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time); + if (tp != RT_NULL) + { + tp->tv_sec = time; + tp->tv_usec = 0; + } + + return time; + } + + return 0; +} +#endif + +/** + * Returns the current time. + * + * @param time_t * t the timestamp pointer, if not used, keep NULL. + * + * @return time_t return timestamp current. + * + */ +/* for IAR 6.2 later Compiler */ +#if defined (__IAR_SYSTEMS_ICC__) && (__VER__) >= 6020000 +#pragma module_name = "?time" +time_t (__time32)(time_t *t) /* Only supports 32-bit timestamp */ +#else +time_t time(time_t *t) +#endif +{ + time_t time_now = 0; + +#ifdef RT_USING_RTC + static rt_device_t device = RT_NULL; + + /* optimization: find rtc device only first. */ + if (device == RT_NULL) + { + device = rt_device_find("rtc"); + } + + /* read timestamp from RTC device. */ + if (device != RT_NULL) + { + if (rt_device_open(device, 0) == RT_EOK) + { + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time_now); + rt_device_close(device); + } + } +#endif /* RT_USING_RTC */ + + /* if t is not NULL, write timestamp to *t */ + if (t != RT_NULL) + { + *t = time_now; + } + + return time_now; +} + +RT_WEAK clock_t clock(void) +{ + return rt_tick_get(); +} diff --git a/rt-thread/components/libc/compilers/armlibc/unistd.h b/rt-thread/components/libc/compilers/armlibc/unistd.h new file mode 100644 index 0000000..3de0eaf --- /dev/null +++ b/rt-thread/components/libc/compilers/armlibc/unistd.h @@ -0,0 +1 @@ +#include "sys/unistd.h" diff --git a/rt-thread/components/libc/compilers/dlib/README.md b/rt-thread/components/libc/compilers/dlib/README.md new file mode 100644 index 0000000..846eb3f --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/README.md @@ -0,0 +1,4 @@ +Dlib(IAR) porting for RT-Thread. + +Please define RT_USING_LIBC and compile RT-Thread with IAR compiler. + diff --git a/rt-thread/components/libc/compilers/dlib/SConscript b/rt-thread/components/libc/compilers/dlib/SConscript new file mode 100644 index 0000000..456b762 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/SConscript @@ -0,0 +1,26 @@ +from building import * + +Import('rtconfig') + +src = Glob('*.c') +cwd = GetCurrentDir() +group = [] + +CPPPATH = [cwd] +CPPDEFINES = ['RT_USING_DLIBC'] + +if rtconfig.PLATFORM == 'iar': + + if GetDepend('RT_USING_DFS'): + from distutils.version import LooseVersion + from iar import IARVersion + + CPPDEFINES = CPPDEFINES + ['_DLIB_FILE_DESCRIPTOR'] + + if LooseVersion(IARVersion()) < LooseVersion("8.20.1"): + CPPDEFINES = CPPDEFINES + ['_DLIB_THREAD_SUPPORT'] + + group = DefineGroup('dlib', src, depend = ['RT_USING_LIBC'], + CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES) + +Return('group') diff --git a/rt-thread/components/libc/compilers/dlib/dirent.h b/rt-thread/components/libc/compilers/dlib/dirent.h new file mode 100644 index 0000000..61e77b9 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/dirent.h @@ -0,0 +1,54 @@ +#ifndef __RTT_DIRENT_H__ +#define __RTT_DIRENT_H__ + +#include +#include + +/* +* dirent.h - format of directory entries + * Ref: http://www.opengroup.org/onlinepubs/009695399/basedefs/dirent.h.html + */ + +/* File types */ +#define FT_REGULAR 0 /* regular file */ +#define FT_SOCKET 1 /* socket file */ +#define FT_DIRECTORY 2 /* directory */ +#define FT_USER 3 /* user defined */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HAVE_DIR_STRUCTURE +typedef struct +{ + int fd; /* directory file */ + char buf[512]; + int num; + int cur; +} DIR; +#endif + +#ifndef HAVE_DIRENT_STRUCTURE +struct dirent +{ + rt_uint8_t d_type; /* The type of the file */ + rt_uint8_t d_namlen; /* The length of the not including the terminating null file name */ + rt_uint16_t d_reclen; /* length of this record */ + char d_name[256]; /* The null-terminated file name */ +}; +#endif + +int closedir(DIR *); +DIR *opendir(const char *); +struct dirent *readdir(DIR *); +int readdir_r(DIR *, struct dirent *, struct dirent **); +void rewinddir(DIR *); +void seekdir(DIR *, long int); +long telldir(DIR *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/libc/compilers/dlib/environ.c b/rt-thread/components/libc/compilers/dlib/environ.c new file mode 100644 index 0000000..1e44eb1 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/environ.c @@ -0,0 +1,25 @@ +/* File: environ.c + * this file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-28 Bernard first version + */ + +const char *__environ = "OS=RT-Thread"; + diff --git a/rt-thread/components/libc/compilers/dlib/fcntl.h b/rt-thread/components/libc/compilers/dlib/fcntl.h new file mode 100644 index 0000000..e69de29 diff --git a/rt-thread/components/libc/compilers/dlib/libc.c b/rt-thread/components/libc/compilers/dlib/libc.c new file mode 100644 index 0000000..fa977ab --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/libc.c @@ -0,0 +1,60 @@ +/* + * File : libc.c + * Brief : iar dlib initialization + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/10/15 bernard the first version + */ +#include +#include + +#include + +#include "libc.h" + +#ifdef RT_USING_PTHREADS +#include +#endif + +int libc_system_init(void) +{ +#if defined(RT_USING_DFS) && defined(RT_USING_DFS_DEVFS) + rt_device_t dev_console; + + dev_console = rt_console_get_device(); + if (dev_console) + { + #if defined(RT_USING_POSIX) + libc_stdio_set_console(dev_console->parent.name, O_RDWR); + #else + libc_stdio_set_console(dev_console->parent.name, O_WRONLY); + #endif + } +#endif + +#if defined (RT_USING_PTHREADS) && !defined (RT_USING_COMPONENTS_INIT) + pthread_system_init(); +#endif + + return 0; +} +INIT_COMPONENT_EXPORT(libc_system_init); + diff --git a/rt-thread/components/libc/compilers/dlib/libc.h b/rt-thread/components/libc/compilers/dlib/libc.h new file mode 100644 index 0000000..d0a081d --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/libc.h @@ -0,0 +1,39 @@ +/* + * File : libc.h + * Brief : iar dlib header file + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/10/15 bernard the first version + */ + +#ifndef __RTT_LIBC_H__ +#define __RTT_LIBC_H__ + +#include + +int libc_system_init(void); + +int libc_stdio_set_console(const char* device_name, int mode); +int libc_stdio_get_console(void); +int libc_stdio_read (void *buffer, size_t size); +int libc_stdio_write(const void *buffer, size_t size); + +#endif diff --git a/rt-thread/components/libc/compilers/dlib/rmtx.c b/rt-thread/components/libc/compilers/dlib/rmtx.c new file mode 100644 index 0000000..4bf7140 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/rmtx.c @@ -0,0 +1,74 @@ +/* + * File : rmtx.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-28 Bernard first version + */ +#include +#include + +/* + * for IAR compiler, we recommand to define _DLIB_THREAD_SUPPORT + * as 2 for dlib multi-thread support. + */ + +#if _DLIB_THREAD_SUPPORT +typedef void* _Rmtx; +void _Mtxinit(_Rmtx *m) +{ + rt_mutex_t mutex; + + RT_ASSERT(m != RT_NULL); + + mutex = (rt_mutex_t)m; + rt_mutex_init(mutex, "iarMtx", RT_IPC_FLAG_FIFO); +} + +void _Mtxdst(_Rmtx *m) +{ + rt_mutex_t mutex; + + RT_ASSERT(m != RT_NULL); + + mutex = (rt_mutex_t)m; + rt_mutex_detach(mutex); +} + +void _Mtxlock(_Rmtx *m) +{ + rt_mutex_t mutex; + + RT_ASSERT(m != RT_NULL); + + mutex = (rt_mutex_t)m; + rt_mutex_take(mutex, RT_WAITING_FOREVER); +} + +void _Mtxunlock(_Rmtx *m) +{ + rt_mutex_t mutex; + + RT_ASSERT(m != RT_NULL); + + mutex = (rt_mutex_t)m; + rt_mutex_release(mutex); +} +#endif + diff --git a/rt-thread/components/libc/compilers/dlib/stdio.c b/rt-thread/components/libc/compilers/dlib/stdio.c new file mode 100644 index 0000000..12c1081 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/stdio.c @@ -0,0 +1,74 @@ +/* + * File : stdio.c + * Brief : stdio/console + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/10/15 bernard implement stdio for IAR dlib. + */ + +#include +#include +#include + +#include +#include "libc.h" + +#if defined(RT_USING_DFS) && defined(RT_USING_DFS_DEVFS) +#include + +#define STDIO_DEVICE_NAME_MAX 32 + +static int std_fd = -1; +int libc_stdio_set_console(const char* device_name, int mode) +{ + int fd; + char name[STDIO_DEVICE_NAME_MAX]; + + snprintf(name, sizeof(name) - 1, "/dev/%s", device_name); + name[STDIO_DEVICE_NAME_MAX - 1] = '\0'; + + fd = open(name, mode, 0); + if (fd >= 0) + { + if (std_fd >= 0) + { + close(std_fd); + } + std_fd = fd; + } + + return std_fd; +} + +int libc_stdio_get_console(void) { + return std_fd; +} + +int libc_stdio_read(void *buffer, size_t size) +{ + return read(std_fd, buffer, size); +} + +int libc_stdio_write(const void *buffer, size_t size) +{ + return write(std_fd, buffer, size); +} +#endif diff --git a/rt-thread/components/libc/compilers/dlib/sys/README.md b/rt-thread/components/libc/compilers/dlib/sys/README.md new file mode 100644 index 0000000..4f0d203 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/sys/README.md @@ -0,0 +1 @@ +Because IAR leaks some system header file, we put them in here. \ No newline at end of file diff --git a/rt-thread/components/libc/compilers/dlib/sys/errno.h b/rt-thread/components/libc/compilers/dlib/sys/errno.h new file mode 100644 index 0000000..072892e --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/sys/errno.h @@ -0,0 +1,7 @@ +#ifndef SYS_ERRNO_H__ +#define SYS_ERRNO_H__ + +#include + + +#endif diff --git a/rt-thread/components/libc/compilers/dlib/sys/mman.h b/rt-thread/components/libc/compilers/dlib/sys/mman.h new file mode 100644 index 0000000..024a64e --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/sys/mman.h @@ -0,0 +1,72 @@ +/* + * File : mman.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/11/30 Bernard The first version. + */ + +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAP_FAILED ((void *) -1) + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_TYPE 0x0f +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS MAP_ANON +#define MAP_NORESERVE 0x4000 +#define MAP_GROWSDOWN 0x0100 +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_FILE 0 + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 + +#define MS_ASYNC 1 +#define MS_INVALIDATE 2 +#define MS_SYNC 4 + +#define MCL_CURRENT 1 +#define MCL_FUTURE 2 +#define MCL_ONFAULT 4 + +void *mmap (void *start, size_t len, int prot, int flags, int fd, off_t off); +int munmap (void *start, size_t len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/rt-thread/components/libc/compilers/dlib/sys/stat.h b/rt-thread/components/libc/compilers/dlib/sys/stat.h new file mode 100644 index 0000000..e69de29 diff --git a/rt-thread/components/libc/compilers/dlib/sys/time.h b/rt-thread/components/libc/compilers/dlib/sys/time.h new file mode 100644 index 0000000..1acb836 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/sys/time.h @@ -0,0 +1,52 @@ +#ifndef _SYS_TIME_H_ +#define _SYS_TIME_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _TIMEVAL_DEFINED +#define _TIMEVAL_DEFINED +/* + * Structure returned by gettimeofday(2) system call, + * and used in other calls. + */ +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; +#endif /* _TIMEVAL_DEFINED */ + +/* + * Skip define timespec for IAR version over 8.10.1 where __VER__ is 8010001. + */ +#if defined ( __ICCARM__ ) && (__VER__ >= 8010001) +#define _TIMESPEC_DEFINED +#endif + +#ifndef _TIMESPEC_DEFINED +#define _TIMESPEC_DEFINED +/* + * Structure defined by POSIX.1b to be like a timeval. + */ +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* and nanoseconds */ +}; +#endif /* _TIMESPEC_DEFINED */ + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +int gettimeofday(struct timeval *tp, void *ignore); + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_TIME_H_ */ diff --git a/rt-thread/components/libc/compilers/dlib/sys/types.h b/rt-thread/components/libc/compilers/dlib/sys/types.h new file mode 100644 index 0000000..b01d828 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/sys/types.h @@ -0,0 +1,12 @@ +#ifndef __TYPES_H__ +#define __TYPES_H__ + +#include +#include + +typedef rt_int32_t clockid_t; +typedef rt_int32_t key_t; /* Used for interprocess communication. */ +typedef rt_int32_t pid_t; /* Used for process IDs and process group IDs. */ +typedef signed long ssize_t; /* Used for a count of bytes or an error indication. */ + +#endif diff --git a/rt-thread/components/libc/compilers/dlib/sys/unistd.h b/rt-thread/components/libc/compilers/dlib/sys/unistd.h new file mode 100644 index 0000000..dbe4f30 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/sys/unistd.h @@ -0,0 +1,39 @@ +#ifndef _SYS_UNISTD_H +#define _SYS_UNISTD_H + +#ifdef RT_USING_DFS + +#define STDIN_FILENO 0 /* standard input file descriptor */ +#define STDOUT_FILENO 1 /* standard output file descriptor */ +#define STDERR_FILENO 2 /* standard error file descriptor */ + +#include +#else +#define _FREAD 0x0001 /* read enabled */ +#define _FWRITE 0x0002 /* write enabled */ +#define _FAPPEND 0x0008 /* append (writes guaranteed at the end) */ +#define _FMARK 0x0010 /* internal; mark during gc() */ +#define _FDEFER 0x0020 /* internal; defer for next gc pass */ +#define _FASYNC 0x0040 /* signal pgrp when data ready */ +#define _FSHLOCK 0x0080 /* BSD flock() shared lock present */ +#define _FEXLOCK 0x0100 /* BSD flock() exclusive lock present */ +#define _FCREAT 0x0200 /* open with file create */ +#define _FTRUNC 0x0400 /* open with truncation */ +#define _FEXCL 0x0800 /* error on open if file exists */ +#define _FNBIO 0x1000 /* non blocking I/O (sys5 style) */ +#define _FSYNC 0x2000 /* do all writes synchronously */ +#define _FNONBLOCK 0x4000 /* non blocking I/O (POSIX style) */ +#define _FNDELAY _FNONBLOCK /* non blocking I/O (4.2 style) */ +#define _FNOCTTY 0x8000 /* don't assign a ctty on this open */ + +#define O_RDONLY 0 /* +1 == FREAD */ +#define O_WRONLY 1 /* +1 == FWRITE */ +#define O_RDWR 2 /* +1 == FREAD|FWRITE */ +#define O_APPEND _FAPPEND +#define O_CREAT _FCREAT +#define O_TRUNC _FTRUNC +#define O_EXCL _FEXCL +#define O_SYNC _FSYNC +#endif + +#endif /* _SYS_UNISTD_H */ diff --git a/rt-thread/components/libc/compilers/dlib/syscall_close.c b/rt-thread/components/libc/compilers/dlib/syscall_close.c new file mode 100644 index 0000000..5792bb3 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/syscall_close.c @@ -0,0 +1,43 @@ +/* + * File : syscall_close.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-28 Bernard first version + */ +#include +#ifdef RT_USING_DFS +#include +#endif +#include + +#pragma module_name = "?__close" +int __close(int handle) +{ + if (handle == _LLIO_STDOUT || + handle == _LLIO_STDERR || + handle == _LLIO_STDIN) + return _LLIO_ERROR; + +#ifdef RT_USING_DFS + return close(handle); +#else + return 0; +#endif +} diff --git a/rt-thread/components/libc/compilers/dlib/syscall_lseek.c b/rt-thread/components/libc/compilers/dlib/syscall_lseek.c new file mode 100644 index 0000000..950ba52 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/syscall_lseek.c @@ -0,0 +1,43 @@ +/* + * File : syscall_lseek.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-28 Bernard first version + */ +#include +#ifdef RT_USING_DFS +#include +#endif +#include + +#pragma module_name = "?__lseek" +long __lseek(int handle, long offset, int whence) +{ + if (handle == _LLIO_STDOUT || + handle == _LLIO_STDERR || + handle == _LLIO_STDIN) + return _LLIO_ERROR; + +#ifdef RT_USING_DFS + return lseek(handle, offset, whence); +#else + return _LLIO_ERROR; +#endif +} diff --git a/rt-thread/components/libc/compilers/dlib/syscall_mem.c b/rt-thread/components/libc/compilers/dlib/syscall_mem.c new file mode 100644 index 0000000..b3933ba --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/syscall_mem.c @@ -0,0 +1,46 @@ +/* + * File : syscall_mem.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-28 Bernard first version + */ +#include + +#ifdef RT_USING_HEAP +void *malloc(rt_size_t n) +{ + return rt_malloc(n); +} + +void *realloc(void *rmem, rt_size_t newsize) +{ + return rt_realloc(rmem, newsize); +} + +void *calloc(rt_size_t nelem, rt_size_t elsize) +{ + return rt_calloc(nelem, elsize); +} + +void free(void *rmem) +{ + rt_free(rmem); +} +#endif diff --git a/rt-thread/components/libc/compilers/dlib/syscall_open.c b/rt-thread/components/libc/compilers/dlib/syscall_open.c new file mode 100644 index 0000000..6194707 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/syscall_open.c @@ -0,0 +1,88 @@ +/* +* File : syscall_open.c +* This file is part of RT-Thread RTOS +* COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License along +* with this program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +* +* Change Logs: +* Date Author Notes +* 2015-01-28 Bernard first version +*/ + +#include +#include +#ifdef RT_USING_DFS +#include +#endif + +#pragma module_name = "?__open" + +int __open(const char *filename, int mode) +{ +#ifndef RT_USING_DFS + return _LLIO_ERROR; +#else + int handle; + int open_mode = O_RDONLY; + + if (mode & _LLIO_CREAT) + { + open_mode |= O_CREAT; + + /* Check what we should do with it if it exists. */ + if (mode & _LLIO_APPEND) + { + /* Append to the existing file. */ + open_mode |= O_APPEND; + } + + if (mode & _LLIO_TRUNC) + { + /* Truncate the existsing file. */ + open_mode |= O_TRUNC; + } + } + + if (mode & _LLIO_TEXT) + { + /* we didn't support text mode */ + } + + switch (mode & _LLIO_RDWRMASK) + { + case _LLIO_RDONLY: + break; + + case _LLIO_WRONLY: + open_mode |= O_WRONLY; + break; + + case _LLIO_RDWR: + /* The file should be opened for both reads and writes. */ + open_mode |= O_RDWR; + break; + + default: + return _LLIO_ERROR; + } + + handle = open(filename, open_mode, 0); + if (handle < 0) + return _LLIO_ERROR; + + return handle; +#endif +} diff --git a/rt-thread/components/libc/compilers/dlib/syscall_read.c b/rt-thread/components/libc/compilers/dlib/syscall_read.c new file mode 100644 index 0000000..e7e9962 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/syscall_read.c @@ -0,0 +1,57 @@ +/* + * File : syscall_read.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-28 Bernard first version + */ + +#include +#ifdef RT_USING_DFS +#include +#endif +#include +#include "libc.h" + +#pragma module_name = "?__read" +size_t __read(int handle, unsigned char *buf, size_t len) +{ +#ifdef RT_USING_DFS + int size; +#endif + + if (handle == _LLIO_STDIN) + { +#ifdef RT_USING_POSIX + return libc_stdio_read(buf, len); +#else + return _LLIO_ERROR; +#endif + } + + if ((handle == _LLIO_STDOUT) || (handle == _LLIO_STDERR)) + return _LLIO_ERROR; + +#ifndef RT_USING_DFS + return _LLIO_ERROR; +#else + size = read(handle, buf, len); + return size; +#endif +} diff --git a/rt-thread/components/libc/compilers/dlib/syscall_remove.c b/rt-thread/components/libc/compilers/dlib/syscall_remove.c new file mode 100644 index 0000000..b7dd947 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/syscall_remove.c @@ -0,0 +1,38 @@ +/* + * File : syscall_remove.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-28 Bernard first version + */ +#include +#ifdef RT_USING_DFS +#include +#endif +#include + +#pragma module_name = "?remove" +int remove(const char *val) +{ +#ifdef RT_USING_DFS + dfs_file_unlink(val); +#endif + + return 0; +} diff --git a/rt-thread/components/libc/compilers/dlib/syscall_write.c b/rt-thread/components/libc/compilers/dlib/syscall_write.c new file mode 100644 index 0000000..79d7023 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/syscall_write.c @@ -0,0 +1,68 @@ +/* + * File : syscall_write.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-28 Bernard first version + */ + +#include +#ifdef RT_USING_DFS +#include +#endif +#include +#include "libc.h" + +#pragma module_name = "?__write" + +size_t __write(int handle, const unsigned char *buf, size_t len) +{ +#ifdef RT_USING_DFS + int size; +#endif + + if ((handle == _LLIO_STDOUT) || (handle == _LLIO_STDERR)) + { +#ifndef RT_USING_CONSOLE + return _LLIO_ERROR; +#else + +#ifdef RT_USING_POSIX + return libc_stdio_write((void*)buf, len); +#else + rt_device_t console_device; + + console_device = rt_console_get_device(); + if (console_device != 0) rt_device_write(console_device, 0, buf, len); + + return len; +#endif +#endif + } + + if (handle == _LLIO_STDIN) return _LLIO_ERROR; + +#ifndef RT_USING_DFS + return _LLIO_ERROR; +#else + size = write(handle, buf, len); + return size; +#endif +} + diff --git a/rt-thread/components/libc/compilers/dlib/syscalls.h b/rt-thread/components/libc/compilers/dlib/syscalls.h new file mode 100644 index 0000000..2c38854 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/syscalls.h @@ -0,0 +1,23 @@ +/* File: syscalls.h + * this file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-01-28 Bernard first version + */ + diff --git a/rt-thread/components/libc/compilers/dlib/termios.h b/rt-thread/components/libc/compilers/dlib/termios.h new file mode 100644 index 0000000..0b54066 --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/termios.h @@ -0,0 +1,7 @@ +#ifndef _TERMIOS_H__ +#define _TERMIOS_H__ + +#include +#include + +#endif diff --git a/rt-thread/components/libc/compilers/dlib/time.c b/rt-thread/components/libc/compilers/dlib/time.c new file mode 100644 index 0000000..f61bd5c --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/time.c @@ -0,0 +1,76 @@ +#include +#include + +#ifdef RT_USING_DEVICE +int gettimeofday(struct timeval *tp, void *ignore) +{ + time_t time; + rt_device_t device; + + device = rt_device_find("rtc"); + if (device != RT_NULL) + { + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time); + if (tp != RT_NULL) + { + tp->tv_sec = time; + tp->tv_usec = 0; + } + + return time; + } + + return 0; +} +#endif + +/** + * Returns the current time. + * + * @param time_t * t the timestamp pointer, if not used, keep NULL. + * + * @return time_t return timestamp current. + * + */ +#pragma module_name = "?time" +#if _DLIB_TIME_ALLOW_64 +time_t __time64(time_t *t) +#else +time_t __time32(time_t *t) +#endif +{ + time_t time_now = 0; + +#ifdef RT_USING_RTC + static rt_device_t device = RT_NULL; + + /* optimization: find rtc device only first. */ + if (device == RT_NULL) + { + device = rt_device_find("rtc"); + } + + /* read timestamp from RTC device. */ + if (device != RT_NULL) + { + if (rt_device_open(device, 0) == RT_EOK) + { + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time_now); + rt_device_close(device); + } + } +#endif /* RT_USING_RTC */ + + /* if t is not NULL, write timestamp to *t */ + if (t != RT_NULL) + { + *t = time_now; + } + + return time_now; +} + +RT_WEAK clock_t clock(void) +{ + return rt_tick_get(); +} diff --git a/rt-thread/components/libc/compilers/dlib/unistd.h b/rt-thread/components/libc/compilers/dlib/unistd.h new file mode 100644 index 0000000..d67f8fb --- /dev/null +++ b/rt-thread/components/libc/compilers/dlib/unistd.h @@ -0,0 +1,6 @@ +#ifndef _UNISTD_H_ +#define _UNISTD_H_ + +# include "sys/unistd.h" + +#endif /* _UNISTD_H_ */ diff --git a/rt-thread/components/libc/compilers/minilibc/SConscript b/rt-thread/components/libc/compilers/minilibc/SConscript new file mode 100644 index 0000000..518d800 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/SConscript @@ -0,0 +1,15 @@ +from building import * +Import('rtconfig') + +src = Glob('*.c') + Glob('*.cpp') +cwd = GetCurrentDir() +group = [] + +CPPPATH = [cwd] +CPPDEFINES = ['RT_USING_MINILIBC'] + +if rtconfig.PLATFORM == 'gcc' and rtconfig.ARCH != 'sim' and not GetDepend('RT_USING_LIBC'): + group = DefineGroup('libc', src, depend = [''], + CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES) + +Return('group') diff --git a/rt-thread/components/libc/compilers/minilibc/ctype.c b/rt-thread/components/libc/compilers/minilibc/ctype.c new file mode 100644 index 0000000..fed8f58 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/ctype.c @@ -0,0 +1,53 @@ +/* + * File : ctype.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008, 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 + * 2008-08-14 Bernard the first version + */ + +#include +#include + +#if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) +#include "ctype.h" + +int isprint (int ch) +{ + ch&=0x7f; + return (ch>=32 && ch<127); +} + +int isalpha(int ch) +{ + return (unsigned int)((ch | 0x20) - 'a') < 26u; +} + +int isdigit (int ch) +{ + return (unsigned int)(ch - '0') < 10u; +} + +int isspace(int ch) +{ + switch(ch) + { + case ' ': + case '\n': + case '\f': + case '\r': + case '\t': + case '\v': + return 1; + default: + return 0; + } +} + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/ctype.h b/rt-thread/components/libc/compilers/minilibc/ctype.h new file mode 100644 index 0000000..6b93490 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/ctype.h @@ -0,0 +1,22 @@ +/* + * File : ctype.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008, 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 + * 2008-08-14 Bernard the first version + */ +#ifndef __CTYPE_H__ +#define __CTYPE_H__ + +int isprint(int c) __attribute__ ((__const__)); +int isalpha (int c) __attribute__ ((__const__)); +int isdigit (int ch) __attribute__ ((__const__)); +int isspace(int ch) __attribute__ ((__const__)); + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/errno.h b/rt-thread/components/libc/compilers/minilibc/errno.h new file mode 100644 index 0000000..751eef5 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/errno.h @@ -0,0 +1,8 @@ +#ifndef __ERRNO_H__ +#define __ERRNO_H__ + +#include "libc/libc_errno.h" +/* Others defined in libc/libc_errno.h */ +#define ENSRNOTFOUND 163 /* Domain name not found */ + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/inttypes.h b/rt-thread/components/libc/compilers/minilibc/inttypes.h new file mode 100644 index 0000000..84e036a --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/inttypes.h @@ -0,0 +1,6 @@ +#ifndef __INTTYPES_H__ +#define __INTTYPES_H__ + +#include "stdint.h" + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/math.c b/rt-thread/components/libc/compilers/minilibc/math.c new file mode 100644 index 0000000..27315a4 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/math.c @@ -0,0 +1,168 @@ +#include + +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS CRT + * FILE: lib/crt/math/cos.c + * PURPOSE: Generic C Implementation of cos + * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +#define PRECISION 9 + +static double cos_off_tbl[] = {0.0, -M_PI/2., 0, -M_PI/2.}; +static double cos_sign_tbl[] = {1,-1,-1,1}; + +static double sin_off_tbl[] = {0.0, -M_PI/2., 0, -M_PI/2.}; +static double sin_sign_tbl[] = {1,-1,-1,1}; + +double sin(double x) +{ + int quadrant; + double x2, result; + + /* Calculate the quadrant */ + quadrant = x * (2./M_PI); + + /* Get offset inside quadrant */ + x = x - quadrant * (M_PI/2.); + + /* Normalize quadrant to [0..3] */ + quadrant = (quadrant - 1) & 0x3; + + /* Fixup value for the generic function */ + x += sin_off_tbl[quadrant]; + + /* Calculate the negative of the square of x */ + x2 = - (x * x); + + /* This is an unrolled taylor series using iterations + * Example with 4 iterations: + * result = 1 - x^2/2! + x^4/4! - x^6/6! + x^8/8! + * To save multiplications and to keep the precision high, it's performed + * like this: + * result = 1 - x^2 * (1/2! - x^2 * (1/4! - x^2 * (1/6! - x^2 * (1/8!)))) + */ + + /* Start with 0, compiler will optimize this away */ + result = 0; + +#if (PRECISION >= 10) + result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20); + result *= x2; +#endif +#if (PRECISION >= 9) + result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18); + result *= x2; +#endif +#if (PRECISION >= 8) + result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16); + result *= x2; +#endif +#if (PRECISION >= 7) + result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14); + result *= x2; +#endif +#if (PRECISION >= 6) + result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12); + result *= x2; +#endif +#if (PRECISION >= 5) + result += 1./(1.*2*3*4*5*6*7*8*9*10); + result *= x2; +#endif + result += 1./(1.*2*3*4*5*6*7*8); + result *= x2; + + result += 1./(1.*2*3*4*5*6); + result *= x2; + + result += 1./(1.*2*3*4); + result *= x2; + + result += 1./(1.*2); + result *= x2; + + result += 1; + + /* Apply correct sign */ + result *= sin_sign_tbl[quadrant]; + + return result; +} + +double cos(double x) +{ + int quadrant; + double x2, result; + + /* Calculate the quadrant */ + quadrant = x * (2./M_PI); + + /* Get offset inside quadrant */ + x = x - quadrant * (M_PI/2.); + + /* Normalize quadrant to [0..3] */ + quadrant = quadrant & 0x3; + + /* Fixup value for the generic function */ + x += cos_off_tbl[quadrant]; + + /* Calculate the negative of the square of x */ + x2 = - (x * x); + + /* This is an unrolled taylor series using iterations + * Example with 4 iterations: + * result = 1 - x^2/2! + x^4/4! - x^6/6! + x^8/8! + * To save multiplications and to keep the precision high, it's performed + * like this: + * result = 1 - x^2 * (1/2! - x^2 * (1/4! - x^2 * (1/6! - x^2 * (1/8!)))) + */ + + /* Start with 0, compiler will optimize this away */ + result = 0; + +#if (PRECISION >= 10) + result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20); + result *= x2; +#endif +#if (PRECISION >= 9) + result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18); + result *= x2; +#endif +#if (PRECISION >= 8) + result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16); + result *= x2; +#endif +#if (PRECISION >= 7) + result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12*13*14); + result *= x2; +#endif +#if (PRECISION >= 6) + result += 1./(1.*2*3*4*5*6*7*8*9*10*11*12); + result *= x2; +#endif +#if (PRECISION >= 5) + result += 1./(1.*2*3*4*5*6*7*8*9*10); + result *= x2; +#endif + result += 1./(1.*2*3*4*5*6*7*8); + result *= x2; + + result += 1./(1.*2*3*4*5*6); + result *= x2; + + result += 1./(1.*2*3*4); + result *= x2; + + result += 1./(1.*2); + result *= x2; + + result += 1; + + /* Apply correct sign */ + result *= cos_sign_tbl[quadrant]; + + return result; +} + diff --git a/rt-thread/components/libc/compilers/minilibc/math.h b/rt-thread/components/libc/compilers/minilibc/math.h new file mode 100644 index 0000000..b436eb0 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/math.h @@ -0,0 +1,9 @@ +#ifndef __MATH_H__ +#define __MATH_H__ + +#define M_PI 3.141592653589793238462643 + +double sin(double x); +double cos(double x); + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/qsort.c b/rt-thread/components/libc/compilers/minilibc/qsort.c new file mode 100644 index 0000000..f412986 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/qsort.c @@ -0,0 +1,44 @@ +#include +#include + +static void exch(char* base,size_t size,size_t a,size_t b) { + char* x=base+a*size; + char* y=base+b*size; + while (size) { + char z=*x; + *x=*y; + *y=z; + --size; ++x; ++y; + } +} + +/* Quicksort with 3-way partitioning, ala Sedgewick */ +/* Blame him for the scary variable names */ +/* http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf */ +static void quicksort(char* base,size_t size,ssize_t l,ssize_t r, + int (*compar)(const void*,const void*)) { + ssize_t i=l-1, j=r, p=l-1, q=r, k; + char* v=base+r*size; + if (r<=l) return; + for (;;) { + while (++i != r && compar(base+i*size,v)<0) ; + while (compar(v,base+(--j)*size)<0) if (j == l) break; + if (i >= j) break; + exch(base,size,i,j); + if (compar(base+i*size,v)==0) exch(base,size,++p,i); + if (compar(v,base+j*size)==0) exch(base,size,j,--q); + } + exch(base,size,i,r); j = i-1; ++i; + for (k=l; kq; k--, i++) exch(base,size,i,k); + quicksort(base,size,l,j,compar); + quicksort(base,size,i,r,compar); +} + +void qsort(void* base,size_t nmemb,size_t size,int (*compar)(const void*,const void*)) { + /* check for integer overflows */ + if (nmemb >= (((size_t)-1)>>1) || + size >= (((size_t)-1)>>1)) return; + if (nmemb>1) + quicksort(base,size,0,nmemb-1,compar); +} diff --git a/rt-thread/components/libc/compilers/minilibc/rand.c b/rt-thread/components/libc/compilers/minilibc/rand.c new file mode 100644 index 0000000..387d605 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/rand.c @@ -0,0 +1,35 @@ +#include +#include +#include + +static unsigned int _seed=1; + +/* Knuth's TAOCP section 3.6 */ +#define M ((1U<<31) -1) +#define A 48271 +#define Q 44488 // M/A +#define R 3399 // M%A; R < Q !!! + +int rand_r(unsigned int* seed) +{ int32_t X; + + X = *seed; + X = A*(X%Q) - R * (int32_t) (X/Q); + if (X < 0) + X += M; + + *seed = X; + return X; +} + +int rand(void) { + return rand_r(&_seed); +} + +void srand(unsigned int i) +{ + _seed=i; +} + +int random(void) __attribute__((alias("rand"))); +void srandom(unsigned int i) __attribute__((alias("srand"))); diff --git a/rt-thread/components/libc/compilers/minilibc/stddef.h b/rt-thread/components/libc/compilers/minilibc/stddef.h new file mode 100644 index 0000000..8068277 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/stddef.h @@ -0,0 +1,7 @@ +#ifndef __STDDEF_H__ +#define __STDDEF_H__ + +#include +typedef signed long ptrdiff_t; + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/stdint.h b/rt-thread/components/libc/compilers/minilibc/stdint.h new file mode 100644 index 0000000..c865d43 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/stdint.h @@ -0,0 +1,258 @@ +/* + * ISO C Standard: 7.18 Integer types + */ + +#ifndef __STDINT_H__ +#define __STDINT_H__ + +/* 7.8.1.1 Exact-width integer types */ + +#ifdef __INT8_TYPE__ +typedef __INT8_TYPE__ int8_t; +#endif +#ifdef __INT16_TYPE__ +typedef __INT16_TYPE__ int16_t; +#endif +#ifdef __INT32_TYPE__ +typedef __INT32_TYPE__ int32_t; +#endif +#ifdef __INT64_TYPE__ +typedef __INT64_TYPE__ int64_t; +#endif +#ifdef __UINT8_TYPE__ +typedef __UINT8_TYPE__ uint8_t; +#endif +#ifdef __UINT16_TYPE__ +typedef __UINT16_TYPE__ uint16_t; +#endif +#ifdef __UINT32_TYPE__ +typedef __UINT32_TYPE__ uint32_t; +#endif +#ifdef __UINT64_TYPE__ +typedef __UINT64_TYPE__ uint64_t; +#endif + +/* 7.8.1.2 Minimum-width integer types */ + +typedef __INT_LEAST8_TYPE__ int_least8_t; +typedef __INT_LEAST16_TYPE__ int_least16_t; +typedef __INT_LEAST32_TYPE__ int_least32_t; +typedef __INT_LEAST64_TYPE__ int_least64_t; +typedef __UINT_LEAST8_TYPE__ uint_least8_t; +typedef __UINT_LEAST16_TYPE__ uint_least16_t; +typedef __UINT_LEAST32_TYPE__ uint_least32_t; +typedef __UINT_LEAST64_TYPE__ uint_least64_t; + +/* 7.8.1.3 Fastest minimum-width integer types */ + +typedef __INT_FAST8_TYPE__ int_fast8_t; +typedef __INT_FAST16_TYPE__ int_fast16_t; +typedef __INT_FAST32_TYPE__ int_fast32_t; +typedef __INT_FAST64_TYPE__ int_fast64_t; +typedef __UINT_FAST8_TYPE__ uint_fast8_t; +typedef __UINT_FAST16_TYPE__ uint_fast16_t; +typedef __UINT_FAST32_TYPE__ uint_fast32_t; +typedef __UINT_FAST64_TYPE__ uint_fast64_t; + +/* 7.8.1.4 Integer types capable of holding object pointers */ + +#ifdef __INTPTR_TYPE__ +typedef __INTPTR_TYPE__ intptr_t; +#endif +#ifdef __UINTPTR_TYPE__ +typedef __UINTPTR_TYPE__ uintptr_t; +#endif + +/* 7.8.1.5 Greatest-width integer types */ + +typedef __INTMAX_TYPE__ intmax_t; +typedef __UINTMAX_TYPE__ uintmax_t; + +#if (!defined __cplusplus || __cplusplus >= 201103L \ + || defined __STDC_LIMIT_MACROS) + +/* + * 7.18.2 Limits of specified-width integer types. + * + * The following object-like macros specify the minimum and maximum limits + * of integer types corresponding to the typedef names defined above. + */ + +/* 7.18.2.1 Limits of exact-width integer types */ + +#ifdef __INT8_MAX__ +# undef INT8_MAX +# define INT8_MAX __INT8_MAX__ +# undef INT8_MIN +# define INT8_MIN (-INT8_MAX - 1) +#endif +#ifdef __UINT8_MAX__ +# undef UINT8_MAX +# define UINT8_MAX __UINT8_MAX__ +#endif +#ifdef __INT16_MAX__ +# undef INT16_MAX +# define INT16_MAX __INT16_MAX__ +# undef INT16_MIN +# define INT16_MIN (-INT16_MAX - 1) +#endif +#ifdef __UINT16_MAX__ +# undef UINT16_MAX +# define UINT16_MAX __UINT16_MAX__ +#endif +#ifdef __INT32_MAX__ +# undef INT32_MAX +# define INT32_MAX __INT32_MAX__ +# undef INT32_MIN +# define INT32_MIN (-INT32_MAX - 1) +#endif +#ifdef __UINT32_MAX__ +# undef UINT32_MAX +# define UINT32_MAX __UINT32_MAX__ +#endif +#ifdef __INT64_MAX__ +# undef INT64_MAX +# define INT64_MAX __INT64_MAX__ +# undef INT64_MIN +# define INT64_MIN (-INT64_MAX - 1) +#endif +#ifdef __UINT64_MAX__ +# undef UINT64_MAX +# define UINT64_MAX __UINT64_MAX__ +#endif + +#undef INT_LEAST8_MAX +#define INT_LEAST8_MAX __INT_LEAST8_MAX__ +#undef INT_LEAST8_MIN +#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1) +#undef UINT_LEAST8_MAX +#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__ +#undef INT_LEAST16_MAX +#define INT_LEAST16_MAX __INT_LEAST16_MAX__ +#undef INT_LEAST16_MIN +#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1) +#undef UINT_LEAST16_MAX +#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__ +#undef INT_LEAST32_MAX +#define INT_LEAST32_MAX __INT_LEAST32_MAX__ +#undef INT_LEAST32_MIN +#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1) +#undef UINT_LEAST32_MAX +#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__ +#undef INT_LEAST64_MAX +#define INT_LEAST64_MAX __INT_LEAST64_MAX__ +#undef INT_LEAST64_MIN +#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1) +#undef UINT_LEAST64_MAX +#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__ + +#undef INT_FAST8_MAX +#define INT_FAST8_MAX __INT_FAST8_MAX__ +#undef INT_FAST8_MIN +#define INT_FAST8_MIN (-INT_FAST8_MAX - 1) +#undef UINT_FAST8_MAX +#define UINT_FAST8_MAX __UINT_FAST8_MAX__ +#undef INT_FAST16_MAX +#define INT_FAST16_MAX __INT_FAST16_MAX__ +#undef INT_FAST16_MIN +#define INT_FAST16_MIN (-INT_FAST16_MAX - 1) +#undef UINT_FAST16_MAX +#define UINT_FAST16_MAX __UINT_FAST16_MAX__ +#undef INT_FAST32_MAX +#define INT_FAST32_MAX __INT_FAST32_MAX__ +#undef INT_FAST32_MIN +#define INT_FAST32_MIN (-INT_FAST32_MAX - 1) +#undef UINT_FAST32_MAX +#define UINT_FAST32_MAX __UINT_FAST32_MAX__ +#undef INT_FAST64_MAX +#define INT_FAST64_MAX __INT_FAST64_MAX__ +#undef INT_FAST64_MIN +#define INT_FAST64_MIN (-INT_FAST64_MAX - 1) +#undef UINT_FAST64_MAX +#define UINT_FAST64_MAX __UINT_FAST64_MAX__ + +#ifdef __INTPTR_MAX__ +# undef INTPTR_MAX +# define INTPTR_MAX __INTPTR_MAX__ +# undef INTPTR_MIN +# define INTPTR_MIN (-INTPTR_MAX - 1) +#endif +#ifdef __UINTPTR_MAX__ +# undef UINTPTR_MAX +# define UINTPTR_MAX __UINTPTR_MAX__ +#endif + +#undef INTMAX_MAX +#define INTMAX_MAX __INTMAX_MAX__ +#undef INTMAX_MIN +#define INTMAX_MIN (-INTMAX_MAX - 1) +#undef UINTMAX_MAX +#define UINTMAX_MAX __UINTMAX_MAX__ + +/* 7.18.3 Limits of other integer types */ + +#undef PTRDIFF_MAX +#define PTRDIFF_MAX __PTRDIFF_MAX__ +#undef PTRDIFF_MIN +#define PTRDIFF_MIN (-PTRDIFF_MAX - 1) + +#undef SIG_ATOMIC_MAX +#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__ +#undef SIG_ATOMIC_MIN +#define SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__ + +#undef SIZE_MAX +#define SIZE_MAX __SIZE_MAX__ + +#undef WCHAR_MAX +#define WCHAR_MAX __WCHAR_MAX__ +#undef WCHAR_MIN +#define WCHAR_MIN __WCHAR_MIN__ + +#undef WINT_MAX +#define WINT_MAX __WINT_MAX__ +#undef WINT_MIN +#define WINT_MIN __WINT_MIN__ + +#endif /* (!defined __cplusplus || __cplusplus >= 201103L + || defined __STDC_LIMIT_MACROS) */ + +#if (!defined __cplusplus || __cplusplus >= 201103L \ + || defined __STDC_CONSTANT_MACROS) + +#undef INT8_C +#define INT8_C(c) __INT8_C(c) +#undef INT16_C +#define INT16_C(c) __INT16_C(c) +#undef INT32_C +#define INT32_C(c) __INT32_C(c) +#undef INT64_C +#define INT64_C(c) __INT64_C(c) +#undef UINT8_C +#define UINT8_C(c) __UINT8_C(c) +#undef UINT16_C +#define UINT16_C(c) __UINT16_C(c) +#undef UINT32_C +#define UINT32_C(c) __UINT32_C(c) +#undef UINT64_C +#define UINT64_C(c) __UINT64_C(c) +#undef INTMAX_C +#define INTMAX_C(c) __INTMAX_C(c) +#undef UINTMAX_C +#define UINTMAX_C(c) __UINTMAX_C(c) + +#endif /* (!defined __cplusplus || __cplusplus >= 201103L + || defined __STDC_CONSTANT_MACROS) */ + +#ifndef __INT_MAX__ +#define __INT_MAX__ 2147483647 +#endif +#define INT_MIN (-1 - INT_MAX) +#define INT_MAX (__INT_MAX__) +#define UINT_MAX (INT_MAX * 2U + 1U) + +#define LONG_MAX ((long)(~0UL>>1)) +#define LONG_MIN (-LONG_MAX - 1) +#define ULONG_MAX (~0UL) + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/stdio.h b/rt-thread/components/libc/compilers/minilibc/stdio.h new file mode 100644 index 0000000..a6ecb32 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/stdio.h @@ -0,0 +1,18 @@ +#ifndef __STDIO_H__ +#define __STDIO_H__ + +#define BUFSIZ 128 +#define EOF (-1) + +#ifndef SEEK_SET +#define SEEK_SET 0 /* set file offset to offset */ +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 /* set file offset to current plus offset */ +#endif +#ifndef SEEK_END +#define SEEK_END 2 /* set file offset to EOF plus offset */ +#endif + +#endif + diff --git a/rt-thread/components/libc/compilers/minilibc/stdlib.c b/rt-thread/components/libc/compilers/minilibc/stdlib.c new file mode 100644 index 0000000..e29ae9b --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/stdlib.c @@ -0,0 +1,79 @@ +/* + * File : stdlib.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008, 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 + * 2008-08-14 Bernard the first version + */ + +#include + +#if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) +#include "stdlib.h" + +int atoi(const char* s) +{ + long int v=0; + int sign=1; + while ( *s == ' ' || (unsigned int)(*s - 9) < 5u) s++; + switch (*s) + { + case '-': + sign=-1; + case '+': + ++s; + } + while ((unsigned int) (*s - '0') < 10u) + { + v=v*10+*s-'0'; + ++s; + } + return sign==-1?-v:v; +} + +long int atol(const char* s) +{ + long int v=0; + int sign=0; + while ( *s == ' ' || (unsigned int)(*s - 9) < 5u) ++s; + switch (*s) + { + case '-': sign=-1; + case '+': ++s; + } + while ((unsigned int) (*s - '0') < 10u) + { + v=v*10+*s-'0'; ++s; + } + return sign?-v:v; +} + +#ifdef RT_USING_HEAP +void *malloc(size_t size) +{ + return rt_malloc(size); +} + +void free(void *ptr) +{ + rt_free(ptr); +} + +void *realloc(void *ptr, size_t size) +{ + return rt_realloc(ptr, size); +} + +void *calloc(size_t nelem, size_t elsize) +{ + return rt_calloc(nelem, elsize); +} +#endif + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/stdlib.h b/rt-thread/components/libc/compilers/minilibc/stdlib.h new file mode 100644 index 0000000..4e87537 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/stdlib.h @@ -0,0 +1,37 @@ +/* + * File : stdlib.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008, 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 + * 2008-08-14 Bernard the first version + */ + +#ifndef __STDLIB_H__ +#define __STDLIB_H__ + +#include + +#if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) +int atoi(const char *nptr); +long int atol(const char *nptr); + +int rand(void); +int rand_r(unsigned int *seed); +void srand(unsigned int seed); + +void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); + +void *malloc(size_t size); +void free(void *ptr); +void *realloc(void *ptr, size_t size); +void *calloc(size_t nelem, size_t elsize); +void abort(void); +#endif + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/string.c b/rt-thread/components/libc/compilers/minilibc/string.c new file mode 100644 index 0000000..4e90da1 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/string.c @@ -0,0 +1,634 @@ +/* + * File : string.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008, 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 + * 2008-08-14 Bernard the first version + * 2010-02-15 Gary Lee add strlcpy + * 2010-03-17 Bernard add strlcpy implementation to this file. + * fix strlcpy declaration + * 2010-03-24 Bernard add strchr and strtok implementation. + */ + +#include +#include + +#if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) +#include "string.h" + +/* there is no strcpy and strcmp implementation in RT-Thread */ +char *strcpy(char *dest, const char *src) +{ + return (char *)rt_strncpy(dest, src, rt_strlen(src) + 1); +} + +char *strncpy(char *dest, const char *src, size_t siz) +{ + return (char *)rt_strncpy(dest, src, siz); +} + +size_t strlcpy(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) + { + do + { + if ((*d++ = *s++) == 0) break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) + { + if (siz != 0) *d = '\0'; /* NUL-terminate dst */ + while (*s++) ; + } + + return(s - src - 1); /* count does not include NUL */ +} + +int strcmp (const char *s1, const char *s2) +{ + while (*s1 && *s1 == *s2) + s1++, s2++; + return (*s1 - *s2); +} + +/** + * strncmp - Compare two length-limited strings + * @cs: One string + * @ct: Another string + * @count: The maximum number of bytes to compare + */ +int strncmp(const char *cs,const char *ct, size_t count) +{ + register signed char __res = 0; + + while (count) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + count--; + } + + return __res; +} + +char *strcat(char * dest, const char * src) +{ + char *tmp = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + ; + + return tmp; +} + +char *strncat(char *dest, const char *src, size_t count) +{ + char *tmp = dest; + + if (count) { + while (*dest) + dest++; + while ((*dest++ = *src++)) { + if (--count == 0) { + *dest = '\0'; + break; + } + } + } + + return tmp; +} + +char *strrchr(const char *t, int c) +{ + register char ch; + register const char *l=0; + + ch = c; + for (;;) + { + if (*t == ch) l=t; + if (!*t) return (char*)l; + ++t; + } + + return (char*)l; +} + + +int strncasecmp ( const char* s1, const char* s2, size_t len ) +{ + register unsigned int x2; + register unsigned int x1; + register const char* end = s1 + len; + + while (1) + { + if ((s1 >= end) ) + return 0; + + x2 = *s2 - 'A'; if ((x2 < 26u)) x2 += 32; + x1 = *s1 - 'A'; if ((x1 < 26u)) x1 += 32; + s1++; s2++; + + if (x2 != x1) + break; + + if (x1 == (unsigned int)-'A') + break; + } + + return x1 - x2; +} + +/* private function */ +#define isdigit(c) ((unsigned)((c) - '0') < 10) + +rt_inline int divide(int *n, int base) +{ + rt_int32_t res; + + /* optimized for processor which does not support divide instructions. */ + if (base == 10) + { + res = ((int)*n) % 10U; + *n = ((int)*n) / 10U; + } + else + { + res = ((int)*n) % 16U; + *n = ((int)*n) / 16U; + } + + return res; +} + +rt_inline int skip_atoi(const char **s) +{ + register int i=0; + while (isdigit(**s)) i = i*10 + *((*s)++) - '0'; + + return i; +} + +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 */ + +#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) + +#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) +#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) +#define iscntrl(c) ((__ismask(c)&(_C)) != 0) +#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) +#define islower(c) ((__ismask(c)&(_L)) != 0) +#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) +#define ispunct(c) ((__ismask(c)&(_P)) != 0) +#define isspace(c) ((__ismask(c)&(_S)) != 0) +#define isupper(c) ((__ismask(c)&(_U)) != 0) +#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) + +#define isascii(c) (((unsigned char)(c))<=0x7f) +#define toascii(c) (((unsigned char)(c))&0x7f) + +static inline unsigned char __tolower(unsigned char c) +{ + if (isupper(c)) + c -= 'A'-'a'; + return c; +} + +static inline unsigned char __toupper(unsigned char c) +{ + if (islower(c)) + c -= 'a'-'A'; + return c; +} + +int tolower(int c) +{ + return __tolower(c); +} + +int toupper(int c) +{ + return __toupper(c); +} + +/** + * simple_strtoul - convert a string to an unsigned long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) +{ + unsigned long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } else if (base == 16) { + if (cp[0] == '0' && toupper(cp[1]) == 'X') + cp += 2; + } + while (isxdigit(*cp) && + (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +/** + * simple_strtol - convert a string to a signed long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +long simple_strtol(const char *cp,char **endp,unsigned int base) +{ + if(*cp=='-') + return -simple_strtoul(cp+1,endp,base); + return simple_strtoul(cp,endp,base); +} + +/** + * simple_strtoull - convert a string to an unsigned long long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) +{ + unsigned long long result = 0, value; + + if (*cp == '0') { + cp++; + if ((toupper(*cp) == 'X') && isxdigit (cp[1])) { + base = 16; + cp++; + } + if (!base) { + base = 8; + } + } + if (!base) { + base = 10; + } + while (isxdigit (*cp) && (value = isdigit (*cp) + ? *cp - '0' + : (islower (*cp) ? toupper (*cp) : *cp) - 'A' + 10) < base) { + result = result * base + value; + cp++; + } + if (endp) + *endp = (char *) cp; + return result; +} + +/** + * simple_strtoll - convert a string to a signed long long + * @cp: The start of the string + * @endp: A pointer to the end of the parsed string will be placed here + * @base: The number base to use + */ +long long simple_strtoll(const char *cp,char **endp,unsigned int base) +{ + if(*cp=='-') + return -simple_strtoull(cp+1,endp,base); + return simple_strtoull(cp,endp,base); +} + +/** + * vsscanf - Unformat a buffer into a list of arguments + * @buf: input buffer + * @fmt: format of buffer + * @args: arguments + */ +int vsscanf(const char * buf, const char * fmt, va_list args) +{ + const char *str = buf; + char *next; + int num = 0; + int qualifier; + int base; + int field_width = -1; + int is_sign = 0; + + while(*fmt && *str) { + /* skip any white space in format */ + /* white space in format matchs any amount of + * white space, including none, in the input. + */ + if (isspace(*fmt)) { + while (isspace(*fmt)) + ++fmt; + while (isspace(*str)) + ++str; + } + + /* anything that is not a conversion must match exactly */ + if (*fmt != '%' && *fmt) { + if (*fmt++ != *str++) + break; + continue; + } + + if (!*fmt) + break; + ++fmt; + + /* skip this conversion. + * advance both strings to next white space + */ + if (*fmt == '*') { + while (!isspace(*fmt) && *fmt) + fmt++; + while (!isspace(*str) && *str) + str++; + continue; + } + + /* get field width */ + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + + /* get conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z') { + qualifier = *fmt; + fmt++; + } + base = 10; + is_sign = 0; + + if (!*fmt || !*str) + break; + + switch(*fmt++) { + case 'c': + { + char *s = (char *) va_arg(args,char*); + if (field_width == -1) + field_width = 1; + do { + *s++ = *str++; + } while(field_width-- > 0 && *str); + num++; + } + continue; + case 's': + { + char *s = (char *) va_arg(args, char *); + if(field_width == -1) + field_width = INT_MAX; + /* first, skip leading white space in buffer */ + while (isspace(*str)) + str++; + + /* now copy until next white space */ + while (*str && !isspace(*str) && field_width--) { + *s++ = *str++; + } + *s = '\0'; + num++; + } + continue; + case 'n': + /* return number of characters read so far */ + { + int *i = (int *)va_arg(args,int*); + *i = str - buf; + } + continue; + case 'o': + base = 8; + break; + case 'x': + case 'X': + base = 16; + break; + case 'd': + case 'i': + is_sign = 1; + case 'u': + break; + case '%': + /* looking for '%' in str */ + if (*str++ != '%') + return num; + continue; + default: + /* invalid format; stop here */ + return num; + } + + /* have some sort of integer conversion. + * first, skip white space in buffer. + */ + while (isspace(*str)) + str++; + + if (!*str || !isdigit(*str)) + break; + + switch(qualifier) { + case 'h': + if (is_sign) { + short *s = (short *) va_arg(args,short *); + *s = (short) simple_strtol(str,&next,base); + } else { + unsigned short *s = (unsigned short *) va_arg(args, unsigned short *); + *s = (unsigned short) simple_strtoul(str, &next, base); + } + break; + case 'l': + if (is_sign) { + long *l = (long *) va_arg(args,long *); + *l = simple_strtol(str,&next,base); + } else { + unsigned long *l = (unsigned long*) va_arg(args,unsigned long*); + *l = simple_strtoul(str,&next,base); + } + break; + case 'L': + if (is_sign) { + long long *l = (long long*) va_arg(args,long long *); + *l = simple_strtoll(str,&next,base); + } else { + unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*); + *l = simple_strtoull(str,&next,base); + } + break; + case 'Z': + { + unsigned long *s = (unsigned long*) va_arg(args,unsigned long*); + *s = (unsigned long) simple_strtoul(str,&next,base); + } + break; + default: + if (is_sign) { + int *i = (int *) va_arg(args, int*); + *i = (int) simple_strtol(str,&next,base); + } else { + unsigned int *i = (unsigned int*) va_arg(args, unsigned int*); + *i = (unsigned int) simple_strtoul(str,&next,base); + } + break; + } + num++; + + if (!next) + break; + str = next; + } + return num; +} + +/** + * sscanf - Unformat a buffer into a list of arguments + * @buf: input buffer + * @fmt: formatting of buffer + * @...: resulting arguments + */ +int sscanf(const char * buf, const char * fmt, ...) +{ + va_list args; + int i; + + va_start(args,fmt); + i = vsscanf(buf,fmt,args); + va_end(args); + + return i; +} + +size_t strspn(const char *s, const char *accept) +{ + size_t l=0; + int a=1,i, al=strlen(accept); + + while((a)&&(*s)) + { + for(a=i=0;(!a)&&(i terminate it */ + } + *ptrptr=s; + return tmp; +} + +char *strtok(char *s, const char *delim) +{ + static char *strtok_pos; + return strtok_r(s,delim,&strtok_pos); +} + +char *strchr(const char *s1, int i) +{ + const unsigned char *s = (const unsigned char *)s1; + unsigned char c = (unsigned int)i; + + while (*s && *s != c) + { + s++; + } + + if (*s != c) + { + s = NULL; + } + + return (char *) s; +} + +long strtol(const char *str, char **endptr, int base) +{ + return simple_strtol(str, endptr, base); +} + +long long strtoll(const char *str, char **endptr, int base) +{ + return simple_strtoll(str, endptr, base); +} + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/string.h b/rt-thread/components/libc/compilers/minilibc/string.h new file mode 100644 index 0000000..089903e --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/string.h @@ -0,0 +1,73 @@ +/* + * File : string.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2008, 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 + * 2008-08-14 Bernard the first version + */ +#ifndef __STRING_H__ +#define __STRING_H__ + +#include +#include + +/* replace for standard string library */ +#if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) + +#define ZEROPAD (1 << 0) /* pad with zero */ +#define SIGN (1 << 1) /* unsigned/signed long */ +#define PLUS (1 << 2) /* show plus */ +#define SPACE (1 << 3) /* space if plus */ +#define LEFT (1 << 4) /* left justified */ +#define SPECIAL (1 << 5) /* 0x */ +#define LARGE (1 << 6) /* use 'ABCDEF' instead of 'abcdef' */ + +#define _U 0x01 /* upper */ +#define _L 0x02 /* lower */ +#define _D 0x04 /* digit */ +#define _C 0x08 /* cntrl */ +#define _P 0x10 /* punct */ +#define _S 0x20 /* white space (space/lf/tab) */ +#define _X 0x40 /* hex digit */ +#define _SP 0x80 /* hard space (0x20) */ + +void* memset(void *s, int c, size_t n); +void* memcpy(void *dest, const void *src, size_t n); +void* memmove(void *dest, const void *src, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); + +int tolower(int c); +int toupper(int c); + +int strcmp (const char *s1, const char *s2); +int strncmp(const char *cs,const char *ct, size_t count); +int strcasecmp(const char *a, const char *b); +int strncasecmp(const char *cs, const char *ct, size_t count); +int sscanf(const char * buf, const char * fmt, ...); +size_t strlen(const char *s); +char *strstr(const char * s1,const char * s2); +char *strcpy(char *dest, const char *src); +char *strncpy(char *dest, const char *src, size_t n); +size_t strlcpy(char *dst, const char *src, size_t siz); +char *strncat(char *dest, const char *src, size_t count); +char *strcat(char * dest, const char * src); +char *strchr(const char *s1, int i); +char *strrchr(const char *t, int c); +char *strdup(const char *s); +char *strtok(char *s, const char *delim); +char*strtok_r(char*s, const char*delim, char**ptrptr); + +size_t strcspn(const char *s, const char *reject); +size_t strspn (const char *s, const char *accept); + +long strtol(const char *str, char **endptr, int base); +long long strtoll(const char *str, char **endptr, int base); +#endif + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/sys/mman.h b/rt-thread/components/libc/compilers/minilibc/sys/mman.h new file mode 100644 index 0000000..024a64e --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/sys/mman.h @@ -0,0 +1,72 @@ +/* + * File : mman.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/11/30 Bernard The first version. + */ + +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAP_FAILED ((void *) -1) + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_TYPE 0x0f +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS MAP_ANON +#define MAP_NORESERVE 0x4000 +#define MAP_GROWSDOWN 0x0100 +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_FILE 0 + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 + +#define MS_ASYNC 1 +#define MS_INVALIDATE 2 +#define MS_SYNC 4 + +#define MCL_CURRENT 1 +#define MCL_FUTURE 2 +#define MCL_ONFAULT 4 + +void *mmap (void *start, size_t len, int prot, int flags, int fd, off_t off); +int munmap (void *start, size_t len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/sys/stat.h b/rt-thread/components/libc/compilers/minilibc/sys/stat.h new file mode 100644 index 0000000..7826cba --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/sys/stat.h @@ -0,0 +1,36 @@ +#ifndef __STAT_H__ +#define __STAT_H__ + +#include + +#ifdef RT_USING_DFS +#include +#else +#define _FREAD 0x0001 /* read enabled */ +#define _FWRITE 0x0002 /* write enabled */ +#define _FAPPEND 0x0008 /* append (writes guaranteed at the end) */ +#define _FMARK 0x0010 /* internal; mark during gc() */ +#define _FDEFER 0x0020 /* internal; defer for next gc pass */ +#define _FASYNC 0x0040 /* signal pgrp when data ready */ +#define _FSHLOCK 0x0080 /* BSD flock() shared lock present */ +#define _FEXLOCK 0x0100 /* BSD flock() exclusive lock present */ +#define _FCREAT 0x0200 /* open with file create */ +#define _FTRUNC 0x0400 /* open with truncation */ +#define _FEXCL 0x0800 /* error on open if file exists */ +#define _FNBIO 0x1000 /* non blocking I/O (sys5 style) */ +#define _FSYNC 0x2000 /* do all writes synchronously */ +#define _FNONBLOCK 0x4000 /* non blocking I/O (POSIX style) */ +#define _FNDELAY _FNONBLOCK /* non blocking I/O (4.2 style) */ +#define _FNOCTTY 0x8000 /* don't assign a ctty on this open */ + +#define O_RDONLY 0 /* +1 == FREAD */ +#define O_WRONLY 1 /* +1 == FWRITE */ +#define O_RDWR 2 /* +1 == FREAD|FWRITE */ +#define O_APPEND _FAPPEND +#define O_CREAT _FCREAT +#define O_TRUNC _FTRUNC +#define O_EXCL _FEXCL +#define O_SYNC _FSYNC +#endif + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/sys/time.h b/rt-thread/components/libc/compilers/minilibc/sys/time.h new file mode 100644 index 0000000..9cb330d --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/sys/time.h @@ -0,0 +1,46 @@ +#ifndef _SYS_TIME_H_ +#define _SYS_TIME_H_ + +#include +typedef long time_t; + +/* + * Structure returned by gettimeofday(2) system call, + * and used in other calls. + */ +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* and microseconds */ +}; + +/* + * Structure defined by POSIX.1b to be like a timeval. + */ +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* and nanoseconds */ +}; + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +struct tm { + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ + int tm_isdst; /* DST. [-1/0/1]*/ + + long int tm_gmtoff; /* Seconds east of UTC. */ + const char *tm_zone; /* Timezone abbreviation. */ +}; + +int gettimeofday(struct timeval *tp, void *ignore); + +#endif diff --git a/rt-thread/components/libc/compilers/minilibc/sys/types.h b/rt-thread/components/libc/compilers/minilibc/sys/types.h new file mode 100644 index 0000000..850bafe --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/sys/types.h @@ -0,0 +1,37 @@ +#ifndef __TYPES_H__ +#define __TYPES_H__ + +typedef long off_t; +typedef unsigned long size_t; +typedef signed long ssize_t; /* Used for a count of bytes or an error indication. */ + +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +typedef int mode_t; + +typedef unsigned long clockid_t; +typedef int pid_t; + +typedef int gid_t; +typedef int uid_t; +typedef int dev_t; +typedef int ino_t; +typedef int mode_t; +typedef int caddr_t; + +typedef unsigned int wint_t; +typedef unsigned long useconds_t; + +typedef unsigned long clock_t; /* clock() */ + +#ifndef NULL +#define NULL (0) +#endif + +#define __u_char_defined + +#endif + diff --git a/rt-thread/components/libc/compilers/minilibc/time.c b/rt-thread/components/libc/compilers/minilibc/time.c new file mode 100644 index 0000000..605f6f5 --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/time.c @@ -0,0 +1,282 @@ +#include +#include + +/* days per month -- nonleap! */ +const short __spm[13] = + { 0, + (31), + (31+28), + (31+28+31), + (31+28+31+30), + (31+28+31+30+31), + (31+28+31+30+31+30), + (31+28+31+30+31+30+31), + (31+28+31+30+31+30+31+31), + (31+28+31+30+31+30+31+31+30), + (31+28+31+30+31+30+31+31+30+31), + (31+28+31+30+31+30+31+31+30+31+30), + (31+28+31+30+31+30+31+31+30+31+30+31), + }; +static long int timezone; +static const char days[] = "Sun Mon Tue Wed Thu Fri Sat "; +static const char months[] = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec "; + +/* seconds per day */ +#define SPD 24*60*60 + +int __isleap(int year) +{ + /* every fourth year is a leap year except for century years that are + * not divisible by 400. */ + /* return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); */ + return (!(year % 4) && ((year % 100) || !(year % 400))); +} + +struct tm *gmtime_r(const time_t *timep, struct tm *r) +{ + time_t i; + register time_t work = *timep % (SPD); + r->tm_sec = work % 60; + work /= 60; + r->tm_min = work % 60; + r->tm_hour = work / 60; + work = *timep / (SPD); + r->tm_wday = (4 + work) % 7; + for (i = 1970;; ++i) + { + register time_t k = __isleap(i) ? 366 : 365; + if (work >= k) + work -= k; + else + break; + } + r->tm_year = i - 1900; + r->tm_yday = work; + + r->tm_mday = 1; + if (__isleap(i) && (work > 58)) + { + if (work == 59) + r->tm_mday = 2; /* 29.2. */ + work -= 1; + } + + for (i = 11; i && (__spm[i] > work); --i) + ; + r->tm_mon = i; + r->tm_mday += work - __spm[i]; + return r; +} + +struct tm* localtime_r(const time_t* t, struct tm* r) +{ + time_t tmp; + struct timezone tz = {0}; + gettimeofday(0, &tz); + timezone = tz.tz_minuteswest * 60L; + tmp = *t + timezone; + return gmtime_r(&tmp, r); +} + +struct tm* localtime(const time_t* t) +{ + static struct tm tmp; + return localtime_r(t, &tmp); +} + +time_t mktime(struct tm * const t) +{ + register time_t day; + register time_t i; + register time_t years = t->tm_year - 70; + + if (t->tm_sec > 60) + { + t->tm_min += t->tm_sec / 60; + t->tm_sec %= 60; + } + if (t->tm_min > 60) + { + t->tm_hour += t->tm_min / 60; + t->tm_min %= 60; + } + if (t->tm_hour > 24) + { + t->tm_mday += t->tm_hour / 24; + t->tm_hour %= 24; + } + if (t->tm_mon > 12) + { + t->tm_year += t->tm_mon / 12; + t->tm_mon %= 12; + } + while (t->tm_mday > __spm[1 + t->tm_mon]) + { + if (t->tm_mon == 1 && __isleap(t->tm_year + 1900)) + { + --t->tm_mday; + } + t->tm_mday -= __spm[t->tm_mon]; + ++t->tm_mon; + if (t->tm_mon > 11) + { + t->tm_mon = 0; + ++t->tm_year; + } + } + + if (t->tm_year < 70) + return (time_t) -1; + + /* Days since 1970 is 365 * number of years + number of leap years since 1970 */ + day = years * 365 + (years + 1) / 4; + + /* After 2100 we have to substract 3 leap years for every 400 years + This is not intuitive. Most mktime implementations do not support + dates after 2059, anyway, so we might leave this out for it's + bloat. */ + if (years >= 131) + { + years -= 131; + years /= 100; + day -= (years >> 2) * 3 + 1; + if ((years &= 3) == 3) + years--; + day -= years; + } + + day += t->tm_yday = __spm[t->tm_mon] + t->tm_mday - 1 + + (__isleap(t->tm_year + 1900) & (t->tm_mon > 1)); + + /* day is now the number of days since 'Jan 1 1970' */ + i = 7; + t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */ + + i = 24; + day *= i; + i = 60; + return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec; +} + +static void num2str(char *c, int i) +{ + c[0] = i / 10 + '0'; + c[1] = i % 10 + '0'; +} + +char *asctime_r(const struct tm *t, char *buf) +{ + /* "Wed Jun 30 21:49:08 1993\n" */ + *(int*) buf = *(int*) (days + (t->tm_wday << 2)); + *(int*) (buf + 4) = *(int*) (months + (t->tm_mon << 2)); + num2str(buf + 8, t->tm_mday); + if (buf[8] == '0') + buf[8] = ' '; + buf[10] = ' '; + num2str(buf + 11, t->tm_hour); + buf[13] = ':'; + num2str(buf + 14, t->tm_min); + buf[16] = ':'; + num2str(buf + 17, t->tm_sec); + buf[19] = ' '; + num2str(buf + 20, (t->tm_year + 1900) / 100); + num2str(buf + 22, (t->tm_year + 1900) % 100); + buf[24] = '\n'; + return buf; +} + +char *asctime(const struct tm *timeptr) +{ + static char buf[25]; + return asctime_r(timeptr, buf); +} + +char *ctime(const time_t *timep) +{ + return asctime(localtime(timep)); +} + +#ifdef RT_USING_DEVICE +int gettimeofday(struct timeval *tp, void *ignore) +{ + time_t time; + rt_device_t device; + + device = rt_device_find("rtc"); + if (device != RT_NULL) + { + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time); + if (tp != RT_NULL) + { + tp->tv_sec = time; + tp->tv_usec = 0; + } + + return time; + } + + return 0; +} +#endif + +#ifndef _gettimeofday +/* Dummy function when hardware do not have RTC */ +int _gettimeofday( struct timeval *tv, void *ignore) +{ + tv->tv_sec = 0; // convert to seconds + tv->tv_usec = 0; // get remaining microseconds + return 0; // return non-zero for error +} +#endif + +/** + * Returns the current time. + * + * @param time_t * t the timestamp pointer, if not used, keep NULL. + * + * @return time_t return timestamp current. + * + */ +/* for IAR 6.2 later Compiler */ +#if defined (__IAR_SYSTEMS_ICC__) && (__VER__) >= 6020000 +#pragma module_name = "?time" +time_t (__time32)(time_t *t) /* Only supports 32-bit timestamp */ +#else +time_t time(time_t *t) +#endif +{ + time_t time_now = 0; + +#ifdef RT_USING_RTC + static rt_device_t device = RT_NULL; + + /* optimization: find rtc device only first. */ + if (device == RT_NULL) + { + device = rt_device_find("rtc"); + } + + /* read timestamp from RTC device. */ + if (device != RT_NULL) + { + if (rt_device_open(device, 0) == RT_EOK) + { + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time_now); + rt_device_close(device); + } + } +#endif /* RT_USING_RTC */ + + /* if t is not NULL, write timestamp to *t */ + if (t != RT_NULL) + { + *t = time_now; + } + + return time_now; +} + +RT_WEAK clock_t clock(void) +{ + return rt_tick_get(); +} diff --git a/rt-thread/components/libc/compilers/minilibc/time.h b/rt-thread/components/libc/compilers/minilibc/time.h new file mode 100644 index 0000000..d64feba --- /dev/null +++ b/rt-thread/components/libc/compilers/minilibc/time.h @@ -0,0 +1,16 @@ +#ifndef __TIME_H__ +#define __TIME_H__ + +#include + +time_t mktime(struct tm * const t); + +char *asctime(const struct tm *timeptr); +char *ctime(const time_t *timep); +struct tm* localtime(const time_t* t); + +char *asctime_r(const struct tm *t, char *buf); +struct tm *gmtime_r(const time_t *timep, struct tm *r); +struct tm* localtime_r(const time_t* t, struct tm* r); + +#endif diff --git a/rt-thread/components/libc/compilers/newlib/SConscript b/rt-thread/components/libc/compilers/newlib/SConscript new file mode 100644 index 0000000..06e5faa --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/SConscript @@ -0,0 +1,21 @@ +from building import * +Import('rtconfig') + +src = Glob('*.c') +cwd = GetCurrentDir() +group = [] + +CPPPATH = [cwd] +CPPDEFINES = ['RT_USING_NEWLIB'] + +# link with libc and libm: +# libm is a frequently used lib. Newlib is compiled with -ffunction-sections in +# recent GCC tool chains. The linker would just link in the functions that have +# been referenced. So setting this won't result in bigger text size. +LIBS = ['c', 'm'] + +if rtconfig.PLATFORM == 'gcc': + group = DefineGroup('newlib', src, depend = ['RT_USING_LIBC'], + CPPPATH = CPPPATH, CPPDEFINES = CPPDEFINES, LIBS = LIBS) + +Return('group') diff --git a/rt-thread/components/libc/compilers/newlib/libc.c b/rt-thread/components/libc/compilers/newlib/libc.c new file mode 100644 index 0000000..495ecf4 --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/libc.c @@ -0,0 +1,66 @@ +/* + * File : libc.c + * Brief : gcc libc header file + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/10/15 bernard the first version + */ +#include +#include +#include +#include +#include + +#include "libc.h" + +#ifdef RT_USING_PTHREADS +#include +#endif + +int _EXFUN(putenv,(char *__string)); + +int libc_system_init(void) +{ +#if defined(RT_USING_DFS) & defined(RT_USING_DFS_DEVFS) & defined(RT_USING_CONSOLE) + rt_device_t dev_console; + + dev_console = rt_console_get_device(); + if (dev_console) + { + #if defined(RT_USING_POSIX) + libc_stdio_set_console(dev_console->parent.name, O_RDWR); + #else + libc_stdio_set_console(dev_console->parent.name, O_WRONLY); + #endif + } +#endif + + /* set PATH and HOME */ + putenv("PATH=/bin"); + putenv("HOME=/home"); + +#if defined RT_USING_PTHREADS && !defined RT_USING_COMPONENTS_INIT + pthread_system_init(); +#endif + + return 0; +} +INIT_COMPONENT_EXPORT(libc_system_init); diff --git a/rt-thread/components/libc/compilers/newlib/libc.h b/rt-thread/components/libc/compilers/newlib/libc.h new file mode 100644 index 0000000..e0a9f05 --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/libc.h @@ -0,0 +1,55 @@ +/* + * File : libc.h + * Brief : gcc libc header file + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/10/15 bernard the first version + */ +#ifndef __RTT_LIBC_H__ +#define __RTT_LIBC_H__ + +#include +#include +#include +#include + +#ifndef _EXFUN +#define _EXFUN(name, proto) name proto +#endif + +#define MILLISECOND_PER_SECOND 1000UL +#define MICROSECOND_PER_SECOND 1000000UL +#define NANOSECOND_PER_SECOND 1000000000UL + +#define MILLISECOND_PER_TICK (MILLISECOND_PER_SECOND / RT_TICK_PER_SECOND) +#define MICROSECOND_PER_TICK (MICROSECOND_PER_SECOND / RT_TICK_PER_SECOND) +#define NANOSECOND_PER_TICK (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND) + +int libc_system_init(void); +int libc_stdio_set_console(const char* device_name, int mode); +int libc_stdio_get_console(void); + +/* some time related function */ +int libc_set_time(const struct timespec *time); +int libc_get_time(struct timespec *time); +int libc_time_to_tick(const struct timespec *time); + +#endif diff --git a/rt-thread/components/libc/compilers/newlib/libc_syms.c b/rt-thread/components/libc/compilers/newlib/libc_syms.c new file mode 100644 index 0000000..ed8686e --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/libc_syms.c @@ -0,0 +1,72 @@ +/* + * File : libc_syms.c + * Brief : exported symbols for libc. + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/10/15 bernard the first version + */ +#include +#include + +#include +#include +#include + +RTM_EXPORT(strcpy); +RTM_EXPORT(strncpy); +RTM_EXPORT(strlen); +RTM_EXPORT(strcat); +RTM_EXPORT(strstr); +RTM_EXPORT(strchr); +RTM_EXPORT(strcmp); +RTM_EXPORT(strtol); +RTM_EXPORT(strtoul); +RTM_EXPORT(strncmp); + +RTM_EXPORT(memcpy); +RTM_EXPORT(memcmp); +RTM_EXPORT(memmove); +RTM_EXPORT(memset); +RTM_EXPORT(memchr); + +RTM_EXPORT(putchar); +RTM_EXPORT(puts); +RTM_EXPORT(printf); +RTM_EXPORT(sprintf); +RTM_EXPORT(snprintf); + +RTM_EXPORT(fwrite); + +#include +RTM_EXPORT(localtime); +RTM_EXPORT(time); + +#include +RTM_EXPORT(longjmp); +RTM_EXPORT(setjmp); + +RTM_EXPORT(exit); +RTM_EXPORT(abort); + +RTM_EXPORT(rand); + +#include +RTM_EXPORT(__assert_func); diff --git a/rt-thread/components/libc/compilers/newlib/stdio.c b/rt-thread/components/libc/compilers/newlib/stdio.c new file mode 100644 index 0000000..9f30106 --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/stdio.c @@ -0,0 +1,96 @@ +/* + * File : stdio.c + * Brief : stdio for newlib + * + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/10/15 bernard the first version + */ +#include +#include + +#include +#include "libc.h" + +#define STDIO_DEVICE_NAME_MAX 32 + +int _EXFUN(fileno, (FILE *)); + +static FILE* std_console = NULL; + +int libc_stdio_set_console(const char* device_name, int mode) +{ + FILE *fp; + char name[STDIO_DEVICE_NAME_MAX]; + char *file_mode; + + snprintf(name, sizeof(name) - 1, "/dev/%s", device_name); + name[STDIO_DEVICE_NAME_MAX - 1] = '\0'; + + if (mode == O_RDWR) file_mode = "r+"; + else if (mode == O_WRONLY) file_mode = "wb"; + else file_mode = "rb"; + + fp = fopen(name, file_mode); + if (fp) + { + setvbuf(fp, NULL, _IONBF, 0); + + if (std_console) + { + fclose(std_console); + std_console = NULL; + } + std_console = fp; + + if (mode == O_RDWR) + { + _GLOBAL_REENT->_stdin = std_console; + } + else + { + _GLOBAL_REENT->_stdin = NULL; + } + + if (mode == O_RDONLY) + { + _GLOBAL_REENT->_stdout = NULL; + _GLOBAL_REENT->_stderr = NULL; + } + else + { + _GLOBAL_REENT->_stdout = std_console; + _GLOBAL_REENT->_stderr = std_console; + } + + _GLOBAL_REENT->__sdidinit = 1; + } + + if (std_console) return fileno(std_console); + + return -1; +} + +int libc_stdio_get_console(void) { + if (std_console) + return fileno(std_console); + else + return -1; +} diff --git a/rt-thread/components/libc/compilers/newlib/sys/dirent.h b/rt-thread/components/libc/compilers/newlib/sys/dirent.h new file mode 100644 index 0000000..2efc683 --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/sys/dirent.h @@ -0,0 +1,57 @@ +#ifndef __RTT_DIRENT_H__ +#define __RTT_DIRENT_H__ + +#include + +/* +* dirent.h - format of directory entries + * Ref: http://www.opengroup.org/onlinepubs/009695399/basedefs/dirent.h.html + */ + +/* File types */ +#define FT_REGULAR 0 /* regular file */ +#define FT_SOCKET 1 /* socket file */ +#define FT_DIRECTORY 2 /* directory */ +#define FT_USER 3 /* user defined */ + +#define DT_UNKNOWN 0x00 +#define DT_REG 0x01 +#define DT_DIR 0x02 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef HAVE_DIR_STRUCTURE +typedef struct +{ + int fd; /* directory file */ + char buf[512]; + int num; + int cur; +} DIR; +#endif + +#ifndef HAVE_DIRENT_STRUCTURE +struct dirent +{ + rt_uint8_t d_type; /* The type of the file */ + rt_uint8_t d_namlen; /* The length of the not including the terminating null file name */ + rt_uint16_t d_reclen; /* length of this record */ + char d_name[256]; /* The null-terminated file name */ +}; +#endif + +int closedir(DIR *); +DIR *opendir(const char *); +struct dirent *readdir(DIR *); +int readdir_r(DIR *, struct dirent *, struct dirent **); +void rewinddir(DIR *); +void seekdir(DIR *, long int); +long telldir(DIR *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/components/libc/compilers/newlib/sys/mman.h b/rt-thread/components/libc/compilers/newlib/sys/mman.h new file mode 100644 index 0000000..024a64e --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/sys/mman.h @@ -0,0 +1,72 @@ +/* + * File : mman.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2017, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017/11/30 Bernard The first version. + */ + +#ifndef _SYS_MMAN_H +#define _SYS_MMAN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAP_FAILED ((void *) -1) + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_TYPE 0x0f +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS MAP_ANON +#define MAP_NORESERVE 0x4000 +#define MAP_GROWSDOWN 0x0100 +#define MAP_DENYWRITE 0x0800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_FILE 0 + +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +#define PROT_GROWSDOWN 0x01000000 +#define PROT_GROWSUP 0x02000000 + +#define MS_ASYNC 1 +#define MS_INVALIDATE 2 +#define MS_SYNC 4 + +#define MCL_CURRENT 1 +#define MCL_FUTURE 2 +#define MCL_ONFAULT 4 + +void *mmap (void *start, size_t len, int prot, int flags, int fd, off_t off); +int munmap (void *start, size_t len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/rt-thread/components/libc/compilers/newlib/sys/statfs.h b/rt-thread/components/libc/compilers/newlib/sys/statfs.h new file mode 100644 index 0000000..95772b5 --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/sys/statfs.h @@ -0,0 +1,13 @@ +#ifndef __RTT_STATFS_H__ +#define __RTT_STATFS_H__ + +#include + +struct statfs +{ + rt_size_t f_bsize; /* block size */ + rt_size_t f_blocks; /* total data blocks in file system */ + rt_size_t f_bfree; /* free blocks in file system */ +}; + +#endif diff --git a/rt-thread/components/libc/compilers/newlib/sys/termios.h b/rt-thread/components/libc/compilers/newlib/sys/termios.h new file mode 100644 index 0000000..e69de29 diff --git a/rt-thread/components/libc/compilers/newlib/syscalls.c b/rt-thread/components/libc/compilers/newlib/syscalls.c new file mode 100644 index 0000000..cc72efe --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/syscalls.c @@ -0,0 +1,426 @@ +#include +#include +#include +#include + +#ifdef RT_USING_DFS +#include +#endif + +#ifdef RT_USING_PTHREADS +#include +#endif + +#ifdef RT_USING_MODULE +#include +#endif + +/* Reentrant versions of system calls. */ + +int +_close_r(struct _reent *ptr, int fd) +{ +#ifndef RT_USING_DFS + return 0; +#else + return close(fd); +#endif +} + +int +_execve_r(struct _reent *ptr, const char * name, char *const *argv, char *const *env) +{ + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} + +int +_fcntl_r(struct _reent *ptr, int fd, int cmd, int arg) +{ + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} + +int +_fork_r(struct _reent *ptr) +{ + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} + +int +_fstat_r(struct _reent *ptr, int fd, struct stat *pstat) +{ + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} + +int +_getpid_r(struct _reent *ptr) +{ + return 0; +} + +int +_isatty_r(struct _reent *ptr, int fd) +{ + if (fd >=0 && fd < 3) return 1; + + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} + +int +_kill_r(struct _reent *ptr, int pid, int sig) +{ + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} + +int +_link_r(struct _reent *ptr, const char *old, const char *new) +{ + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} + +_off_t +_lseek_r(struct _reent *ptr, int fd, _off_t pos, int whence) +{ +#ifndef RT_USING_DFS + return 0; +#else + _off_t rc; + + rc = lseek(fd, pos, whence); + return rc; +#endif +} + +int +_mkdir_r(struct _reent *ptr, const char *name, int mode) +{ +#ifndef RT_USING_DFS + return 0; +#else + int rc; + + rc = mkdir(name, mode); + return rc; +#endif +} + +int +_open_r(struct _reent *ptr, const char *file, int flags, int mode) +{ +#ifndef RT_USING_DFS + return 0; +#else + int rc; + + rc = open(file, flags, mode); + return rc; +#endif +} + +_ssize_t +_read_r(struct _reent *ptr, int fd, void *buf, size_t nbytes) +{ +#ifndef RT_USING_DFS + return 0; +#else + _ssize_t rc; + + rc = read(fd, buf, nbytes); + return rc; +#endif +} + +int +_rename_r(struct _reent *ptr, const char *old, const char *new) +{ +#ifndef RT_USING_DFS + return 0; +#else + int rc; + + rc = rename(old, new); + return rc; +#endif +} + +void * +_sbrk_r(struct _reent *ptr, ptrdiff_t incr) +{ + /* no use this routine to get memory */ + return RT_NULL; +} + +int +_stat_r(struct _reent *ptr, const char *file, struct stat *pstat) +{ +#ifndef RT_USING_DFS + return 0; +#else + int rc; + + rc = stat(file, pstat); + return rc; +#endif +} + +_CLOCK_T_ +_times_r(struct _reent *ptr, struct tms *ptms) +{ + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} + +int +_unlink_r(struct _reent *ptr, const char *file) +{ +#ifndef RT_USING_DFS + return 0; +#else + int rc; + + rc = unlink(file); + return rc; +#endif +} + +int +_wait_r(struct _reent *ptr, int *status) +{ + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} + +#ifdef RT_USING_DEVICE +_ssize_t +_write_r(struct _reent *ptr, int fd, const void *buf, size_t nbytes) +{ +#ifndef RT_USING_DFS + if (fd == 0) + { + rt_device_t console; + + console = rt_console_get_device(); + if (console) return rt_device_write(console, -1, buf, nbytes); + } + + return 0; + +#else + _ssize_t rc; + + rc = write(fd, buf, nbytes); + return rc; +#endif +} +#endif + +#ifdef RT_USING_PTHREADS + +#include +/* POSIX timer provides clock_gettime function */ +#include +int +_gettimeofday_r(struct _reent *ptr, struct timeval *__tp, void *__tzp) +{ + struct timespec tp; + + if (clock_gettime(CLOCK_REALTIME, &tp) == 0) + { + if (__tp != RT_NULL) + { + __tp->tv_sec = tp.tv_sec; + __tp->tv_usec = tp.tv_nsec / 1000UL; + } + + return tp.tv_sec; + } + + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} + +#else + +#define MILLISECOND_PER_SECOND 1000UL +#define MICROSECOND_PER_SECOND 1000000UL +#define NANOSECOND_PER_SECOND 1000000000UL + +#define MILLISECOND_PER_TICK (MILLISECOND_PER_SECOND / RT_TICK_PER_SECOND) +#define MICROSECOND_PER_TICK (MICROSECOND_PER_SECOND / RT_TICK_PER_SECOND) +#define NANOSECOND_PER_TICK (NANOSECOND_PER_SECOND / RT_TICK_PER_SECOND) + +struct timeval _timevalue = {0}; +#ifdef RT_USING_DEVICE +static void libc_system_time_init(void) +{ + time_t time; + rt_tick_t tick; + rt_device_t device; + + time = 0; + device = rt_device_find("rtc"); + if (device != RT_NULL) + { + /* get realtime seconds */ + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time); + } + + /* get tick */ + tick = rt_tick_get(); + + _timevalue.tv_usec = MICROSECOND_PER_SECOND - (tick%RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK; + _timevalue.tv_sec = time - tick/RT_TICK_PER_SECOND - 1; +} +#endif + +int libc_get_time(struct timespec *time) +{ + rt_tick_t tick; + static rt_bool_t inited = 0; + + RT_ASSERT(time != RT_NULL); + + /* initialize system time */ + if (inited == 0) + { + libc_system_time_init(); + inited = 1; + } + + /* get tick */ + tick = rt_tick_get(); + + time->tv_sec = _timevalue.tv_sec + tick / RT_TICK_PER_SECOND; + time->tv_nsec = (_timevalue.tv_usec + (tick % RT_TICK_PER_SECOND) * MICROSECOND_PER_TICK) * 1000; + + return 0; +} + +int +_gettimeofday_r(struct _reent *ptr, struct timeval *__tp, void *__tzp) +{ + struct timespec tp; + + if (libc_get_time(&tp) == 0) + { + if (__tp != RT_NULL) + { + __tp->tv_sec = tp.tv_sec; + __tp->tv_usec = tp.tv_nsec / 1000UL; + } + + return tp.tv_sec; + } + + /* return "not supported" */ + ptr->_errno = ENOTSUP; + return -1; +} +#endif + +/* Memory routine */ +void * +_malloc_r (struct _reent *ptr, size_t size) +{ + void* result; + + result = (void*)rt_malloc (size); + if (result == RT_NULL) + { + ptr->_errno = ENOMEM; + } + + return result; +} + +void * +_realloc_r (struct _reent *ptr, void *old, size_t newlen) +{ + void* result; + + result = (void*)rt_realloc (old, newlen); + if (result == RT_NULL) + { + ptr->_errno = ENOMEM; + } + + return result; +} + +void *_calloc_r (struct _reent *ptr, size_t size, size_t len) +{ + void* result; + + result = (void*)rt_calloc (size, len); + if (result == RT_NULL) + { + ptr->_errno = ENOMEM; + } + + return result; +} + +void +_free_r (struct _reent *ptr, void *addr) +{ + rt_free (addr); +} + +void +exit (int status) +{ +#ifdef RT_USING_MODULE + if (dlmodule_self()) + { + dlmodule_exit(status); + } +#endif + + rt_kprintf("thread:%s exit with %d\n", rt_thread_self()->name, status); + RT_ASSERT(0); + + while (1); +} + +void +_system(const char *s) +{ + /* not support this call */ + return; +} + +void __libc_init_array(void) +{ + /* we not use __libc init_aray to initialize C++ objects */ +} + +void abort(void) +{ + if (rt_thread_self()) + { + rt_thread_t self = rt_thread_self(); + + rt_kprintf("thread:%-8.*s abort!\n", RT_NAME_MAX, self->name); + rt_thread_suspend(self); + + rt_schedule(); + } + + while (1); +} diff --git a/rt-thread/components/libc/compilers/newlib/termios.h b/rt-thread/components/libc/compilers/newlib/termios.h new file mode 100644 index 0000000..0b54066 --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/termios.h @@ -0,0 +1,7 @@ +#ifndef _TERMIOS_H__ +#define _TERMIOS_H__ + +#include +#include + +#endif diff --git a/rt-thread/components/libc/compilers/newlib/time.c b/rt-thread/components/libc/compilers/newlib/time.c new file mode 100644 index 0000000..e7ad19a --- /dev/null +++ b/rt-thread/components/libc/compilers/newlib/time.c @@ -0,0 +1,77 @@ +#include +#include + +#ifdef RT_USING_DEVICE +int gettimeofday(struct timeval *tp, void *ignore) +{ + time_t time; + rt_device_t device; + + device = rt_device_find("rtc"); + if (device != RT_NULL) + { + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time); + if (tp != RT_NULL) + { + tp->tv_sec = time; + tp->tv_usec = 0; + } + + return time; + } + + return 0; +} +#endif + +/** + * Returns the current time. + * + * @param time_t * t the timestamp pointer, if not used, keep NULL. + * + * @return time_t return timestamp current. + * + */ +/* for IAR 6.2 later Compiler */ +#if defined (__IAR_SYSTEMS_ICC__) && (__VER__) >= 6020000 +#pragma module_name = "?time" +time_t (__time32)(time_t *t) /* Only supports 32-bit timestamp */ +#else +time_t time(time_t *t) +#endif +{ + time_t time_now = 0; + +#ifdef RT_USING_RTC + static rt_device_t device = RT_NULL; + + /* optimization: find rtc device only first. */ + if (device == RT_NULL) + { + device = rt_device_find("rtc"); + } + + /* read timestamp from RTC device. */ + if (device != RT_NULL) + { + if (rt_device_open(device, 0) == RT_EOK) + { + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time_now); + rt_device_close(device); + } + } +#endif /* RT_USING_RTC */ + + /* if t is not NULL, write timestamp to *t */ + if (t != RT_NULL) + { + *t = time_now; + } + + return time_now; +} + +RT_WEAK clock_t clock(void) +{ + return rt_tick_get(); +} diff --git a/rt-thread/include/libc/libc_dirent.h b/rt-thread/include/libc/libc_dirent.h new file mode 100644 index 0000000..c3a1987 --- /dev/null +++ b/rt-thread/include/libc/libc_dirent.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LIBC_DIRENT_H__ +#define LIBC_DIRENT_H__ + +#define DT_UNKNOWN 0x00 +#define DT_REG 0x01 +#define DT_DIR 0x02 + +#endif diff --git a/rt-thread/include/libc/libc_errno.h b/rt-thread/include/libc/libc_errno.h new file mode 100644 index 0000000..82ae8cf --- /dev/null +++ b/rt-thread/include/libc/libc_errno.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : libc_errno.h + * + * Change Logs: + * Date Author Notes + * 2016-11-12 Bernard The first version + */ + +#ifndef LIBC_ERRNO_H__ +#define LIBC_ERRNO_H__ + +#include + +#if defined(RT_USING_NEWLIB) || defined(_WIN32) +/* use errno.h file in newlib */ +#include +#else +/* define errno self. */ +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define ENOTBLK 15 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define ETXTBSY 26 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 35 +#define ENAMETOOLONG 36 +#define ENOLCK 37 +#define ENOSYS 38 +#define ENOTEMPTY 39 +#define ELOOP 40 +#define EWOULDBLOCK EAGAIN +#define ENOMSG 42 +#define EIDRM 43 +#define ECHRNG 44 +#define EL2NSYNC 45 +#define EL3HLT 46 +#define EL3RST 47 +#define ELNRNG 48 +#define EUNATCH 49 +#define ENOCSI 50 +#define EL2HLT 51 +#define EBADE 52 +#define EBADR 53 +#define EXFULL 54 +#define ENOANO 55 +#define EBADRQC 56 +#define EBADSLT 57 +#define EDEADLOCK EDEADLK +#define EBFONT 59 +#define ENOSTR 60 +#define ENODATA 61 +#define ETIME 62 +#define ENOSR 63 +#define ENONET 64 +#define ENOPKG 65 +#define EREMOTE 66 +#define ENOLINK 67 +#define EADV 68 +#define ESRMNT 69 +#define ECOMM 70 +#define EPROTO 71 +#define EMULTIHOP 72 +#define EDOTDOT 73 +#define EBADMSG 74 +#define EOVERFLOW 75 +#define ENOTUNIQ 76 +#define EBADFD 77 +#define EREMCHG 78 +#define ELIBACC 79 +#define ELIBBAD 80 +#define ELIBSCN 81 +#define ELIBMAX 82 +#define ELIBEXEC 83 +#define EILSEQ 84 +#define ERESTART 85 +#define ESTRPIPE 86 +#define EUSERS 87 +#define ENOTSOCK 88 +#define EDESTADDRREQ 89 +#define EMSGSIZE 90 +#define EPROTOTYPE 91 +#define ENOPROTOOPT 92 +#define EPROTONOSUPPORT 93 +#define ESOCKTNOSUPPORT 94 +#define EOPNOTSUPP 95 +#define ENOTSUP EOPNOTSUPP +#define EPFNOSUPPORT 96 +#define EAFNOSUPPORT 97 +#define EADDRINUSE 98 +#define EADDRNOTAVAIL 99 +#define ENETDOWN 100 +#define ENETUNREACH 101 +#define ENETRESET 102 +#define ECONNABORTED 103 +#define ECONNRESET 104 +#define ENOBUFS 105 +#define EISCONN 106 +#define ENOTCONN 107 +#define ESHUTDOWN 108 +#define ETOOMANYREFS 109 +#define ETIMEDOUT 110 +#define ECONNREFUSED 111 +#define EHOSTDOWN 112 +#define EHOSTUNREACH 113 +#define EALREADY 114 +#define EINPROGRESS 115 +#define ESTALE 116 +#define EUCLEAN 117 +#define ENOTNAM 118 +#define ENAVAIL 119 +#define EISNAM 120 +#define EREMOTEIO 121 +#define EDQUOT 122 +#define ENOMEDIUM 123 +#define EMEDIUMTYPE 124 +#define ECANCELED 125 +#define ENOKEY 126 +#define EKEYEXPIRED 127 +#define EKEYREVOKED 128 +#define EKEYREJECTED 129 +#define EOWNERDEAD 130 +#define ENOTRECOVERABLE 131 +#define ERFKILL 132 +#define EHWPOISON 133 +#endif + +#endif diff --git a/rt-thread/include/libc/libc_fcntl.h b/rt-thread/include/libc/libc_fcntl.h new file mode 100644 index 0000000..1b7c69b --- /dev/null +++ b/rt-thread/include/libc/libc_fcntl.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : libc_fcntl.h + * + * Change Logs: + * Date Author Notes + * 2018-02-07 Bernard Add O_DIRECTORY definition in NEWLIB mode. + * 2018-02-09 Bernard Add O_BINARY definition + */ + +#ifndef LIBC_FCNTL_H__ +#define LIBC_FCNTL_H__ + +#if defined(RT_USING_NEWLIB) || defined(_WIN32) +#include + +#ifndef O_NONBLOCK +#define O_NONBLOCK 0x4000 +#endif + +#if defined(_WIN32) +#define O_ACCMODE (_O_RDONLY | _O_WRONLY | _O_RDWR) +#endif + +#ifndef F_GETFL +#define F_GETFL 3 +#endif +#ifndef F_SETFL +#define F_SETFL 4 +#endif + +#ifndef O_DIRECTORY +#define O_DIRECTORY 0x200000 +#endif + +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#else +#define O_BINARY 0 +#endif +#endif + +#else +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_BINARY 0100000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 + +#define O_ASYNC 020000 +#define O_DIRECT 040000 +#define O_LARGEFILE 0100000 +#define O_NOATIME 01000000 +#define O_PATH 010000000 +#define O_TMPFILE 020200000 +#define O_NDELAY O_NONBLOCK + +#define O_SEARCH O_PATH +#define O_EXEC O_PATH + +#define O_ACCMODE (03|O_SEARCH) + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_GETLK 12 +#define F_SETLK 13 +#define F_SETLKW 14 + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 +#endif + +#endif diff --git a/rt-thread/include/libc/libc_fdset.h b/rt-thread/include/libc/libc_fdset.h new file mode 100644 index 0000000..ecd965c --- /dev/null +++ b/rt-thread/include/libc/libc_fdset.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : libc_errno.h + * + * Change Logs: + * Date Author Notes + * 2017-10-30 Bernard The first version + */ + +#ifndef LIBC_FDSET_H__ +#define LIBC_FDSET_H__ + +#include + +#if defined(RT_USING_NEWLIB) || defined(_WIN32) +#include +#if defined(HAVE_SYS_SELECT_H) +#include +#endif + +#else + +#ifdef SAL_USING_POSIX + +#ifdef FD_SETSIZE +#undef FD_SETSIZE +#endif + +#define FD_SETSIZE DFS_FD_MAX +#endif + +# ifndef FD_SETSIZE +# define FD_SETSIZE 32 +# endif + +# define NBBY 8 /* number of bits in a byte */ + +typedef long fd_mask; +# define NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */ +# ifndef howmany +# define howmany(x,y) (((x)+((y)-1))/(y)) +# endif + +/* We use a macro for fd_set so that including Sockets.h afterwards + can work. */ +typedef struct _types_fd_set { + fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; +} _types_fd_set; + +#define fd_set _types_fd_set + +# define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS))) +# define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS))) +# define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS))) +# define FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p))) + +#endif + +#endif diff --git a/rt-thread/include/libc/libc_ioctl.h b/rt-thread/include/libc/libc_ioctl.h new file mode 100644 index 0000000..ef5a525 --- /dev/null +++ b/rt-thread/include/libc/libc_ioctl.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : libc_ioctl.h + * + * Change Logs: + * Date Author Notes + * 2017-01-21 Bernard the first version + */ + +#ifndef LIBC_IOCTL_H__ +#define LIBC_IOCTL_H__ + +#define _IOC(a,b,c,d) ( ((a)<<30) | ((b)<<8) | (c) | ((d)<<16) ) +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#ifndef _WIN32 +#define _IO(a,b) _IOC(_IOC_NONE,(a),(b),0) +#define _IOW(a,b,c) _IOC(_IOC_WRITE,(a),(b),sizeof(c)) +#define _IOR(a,b,c) _IOC(_IOC_READ,(a),(b),sizeof(c)) +#define _IOWR(a,b,c) _IOC(_IOC_READ|_IOC_WRITE,(a),(b),sizeof(c)) + +#define FIONREAD _IOR('f', 127, int) /* get # bytes to read */ +#define FIONBIO _IOW('f', 126, int) /* set/clear non-blocking i/o */ +#define FIONWRITE _IOR('f', 121, int) /* get # bytes outstanding + * in send queue. */ +#endif + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +// #define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +// #define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 +#define TIOCSBRK 0x5427 +#define TIOCCBRK 0x5428 +#define TIOCGSID 0x5429 +#define TIOCGRS485 0x542E +#define TIOCSRS485 0x542F +#define TIOCGPTN 0x80045430 +#define TIOCSPTLCK 0x40045431 +#define TIOCGDEV 0x80045432 +#define TCGETX 0x5432 +#define TCSETX 0x5433 +#define TCSETXF 0x5434 +#define TCSETXW 0x5435 +#define TIOCSIG 0x40045436 +#define TIOCVHANGUP 0x5437 +#define TIOCGPKT 0x80045438 +#define TIOCGPTLCK 0x80045439 +#define TIOCGEXCL 0x80045440 + +#define FIONCLEX 0x5450 +#define FIOCLEX 0x5451 + +#ifndef _WIN32 +#define FIOASYNC 0x5452 +#endif + +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 +#define TIOCSERGETLSR 0x5459 +#define TIOCSERGETMULTI 0x545A +#define TIOCSERSETMULTI 0x545B + +#define TIOCMIWAIT 0x545C +#define TIOCGICOUNT 0x545D +#define FIOQSIZE 0x5460 + +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 +#define TIOCPKT_IOCTL 64 + +#define TIOCSER_TEMT 0x01 + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 + +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 +#define N_AX25 5 +#define N_X25 6 +#define N_6PACK 7 +#define N_MASC 8 +#define N_R3964 9 +#define N_PROFIBUS_FDL 10 +#define N_IRDA 11 +#define N_SMSBLOCK 12 +#define N_HDLC 13 +#define N_SYNC_PPP 14 +#define N_HCI 15 + +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +// #define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 +#define SIOCGSTAMPNS 0x8907 + +#define SIOCADDRT 0x890B +#define SIOCDELRT 0x890C +#define SIOCRTMSG 0x890D + +#define SIOCGIFNAME 0x8910 +#define SIOCSIFLINK 0x8911 +#define SIOCGIFCONF 0x8912 +#define SIOCGIFFLAGS 0x8913 +#define SIOCSIFFLAGS 0x8914 +#define SIOCGIFADDR 0x8915 +#define SIOCSIFADDR 0x8916 +#define SIOCGIFDSTADDR 0x8917 +#define SIOCSIFDSTADDR 0x8918 +#define SIOCGIFBRDADDR 0x8919 +#define SIOCSIFBRDADDR 0x891a +#define SIOCGIFNETMASK 0x891b +#define SIOCSIFNETMASK 0x891c +#define SIOCGIFMETRIC 0x891d +#define SIOCSIFMETRIC 0x891e +#define SIOCGIFMEM 0x891f +#define SIOCSIFMEM 0x8920 +#define SIOCGIFMTU 0x8921 +#define SIOCSIFMTU 0x8922 +#define SIOCSIFNAME 0x8923 +#define SIOCSIFHWADDR 0x8924 +#define SIOCGIFENCAP 0x8925 +#define SIOCSIFENCAP 0x8926 +#define SIOCGIFHWADDR 0x8927 +#define SIOCGIFSLAVE 0x8929 +#define SIOCSIFSLAVE 0x8930 +#define SIOCADDMULTI 0x8931 +#define SIOCDELMULTI 0x8932 +#define SIOCGIFINDEX 0x8933 +#define SIOGIFINDEX SIOCGIFINDEX +#define SIOCSIFPFLAGS 0x8934 +#define SIOCGIFPFLAGS 0x8935 +#define SIOCDIFADDR 0x8936 +#define SIOCSIFHWBROADCAST 0x8937 +#define SIOCGIFCOUNT 0x8938 + +#define SIOCGIFBR 0x8940 +#define SIOCSIFBR 0x8941 + +#define SIOCGIFTXQLEN 0x8942 +#define SIOCSIFTXQLEN 0x8943 + +#define SIOCDARP 0x8953 +#define SIOCGARP 0x8954 +#define SIOCSARP 0x8955 + +#define SIOCDRARP 0x8960 +#define SIOCGRARP 0x8961 +#define SIOCSRARP 0x8962 + +#define SIOCGIFMAP 0x8970 +#define SIOCSIFMAP 0x8971 + +#define SIOCADDDLCI 0x8980 +#define SIOCDELDLCI 0x8981 + +#define SIOCDEVPRIVATE 0x89F0 +#define SIOCPROTOPRIVATE 0x89E0 + +#endif + diff --git a/rt-thread/include/libc/libc_signal.h b/rt-thread/include/libc/libc_signal.h new file mode 100644 index 0000000..b592b82 --- /dev/null +++ b/rt-thread/include/libc/libc_signal.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : libc_signal.h + * + * Change Logs: + * Date Author Notes + * 2017-09-12 Bernard The first version + */ + +#ifndef LIBC_SIGNAL_H__ +#define LIBC_SIGNAL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_CCONFIG_H +#include +#endif + +#ifndef HAVE_SIGVAL +/* Signal Generation and Delivery, P1003.1b-1993, p. 63 + NOTE: P1003.1c/D10, p. 34 adds sigev_notify_function and + sigev_notify_attributes to the sigevent structure. */ + +union sigval +{ + int sival_int; /* Integer signal value */ + void *sival_ptr; /* Pointer signal value */ +}; +#endif + +#ifndef HAVE_SIGEVENT +struct sigevent +{ + int sigev_notify; /* Notification type */ + int sigev_signo; /* Signal number */ + union sigval sigev_value; /* Signal value */ + void (*sigev_notify_function)( union sigval ); + /* Notification function */ + void *sigev_notify_attributes; /* Notification Attributes, really pthread_attr_t */ +}; +#endif + +#ifndef HAVE_SIGINFO +struct siginfo +{ + rt_uint16_t si_signo; + rt_uint16_t si_code; + + union sigval si_value; +}; +typedef struct siginfo siginfo_t; +#endif + +#define SI_USER 0x01 /* Signal sent by kill(). */ +#define SI_QUEUE 0x02 /* Signal sent by sigqueue(). */ +#define SI_TIMER 0x03 /* Signal generated by expiration of a + timer set by timer_settime(). */ +#define SI_ASYNCIO 0x04 /* Signal generated by completion of an + asynchronous I/O request. */ +#define SI_MESGQ 0x05 /* Signal generated by arrival of a + message on an empty message queue. */ + +#ifdef RT_USING_NEWLIB +#include +#endif + +#if defined(__CC_ARM) || defined(__CLANG_ARM) +#include +typedef unsigned long sigset_t; + +#define SIGHUP 1 +// #define SIGINT 2 +#define SIGQUIT 3 +// #define SIGILL 4 +#define SIGTRAP 5 +// #define SIGABRT 6 +#define SIGEMT 7 +// #define SIGFPE 8 +#define SIGKILL 9 +#define SIGBUS 10 +// #define SIGSEGV 11 +#define SIGSYS 12 +#define SIGPIPE 13 +#define SIGALRM 14 +// #define SIGTERM 15 +#define SIGURG 16 +#define SIGSTOP 17 +#define SIGTSTP 18 +#define SIGCONT 19 +#define SIGCHLD 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGPOLL 23 +#define SIGWINCH 24 +// #define SIGUSR1 25 +// #define SIGUSR2 26 +#define SIGRTMIN 27 +#define SIGRTMAX 31 +#define NSIG 32 + +#define SIG_SETMASK 0 /* set mask with sigprocmask() */ +#define SIG_BLOCK 1 /* set of signals to block */ +#define SIG_UNBLOCK 2 /* set of signals to, well, unblock */ + +typedef void (*_sig_func_ptr)(int); + +struct sigaction +{ + _sig_func_ptr sa_handler; + sigset_t sa_mask; + int sa_flags; +}; + +#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0) +#define sigdelset(what,sig) (*(what) &= ~(1<<(sig)), 0) +#define sigemptyset(what) (*(what) = 0, 0) +#define sigfillset(what) (*(what) = ~(0), 0) +#define sigismember(what,sig) (((*(what)) & (1<<(sig))) != 0) + +int sigprocmask (int how, const sigset_t *set, sigset_t *oset); +int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); + +#elif defined(__IAR_SYSTEMS_ICC__) +#include +typedef unsigned long sigset_t; + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +// #define SIGABRT 6 +#define SIGEMT 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGBUS 10 +#define SIGSEGV 11 +#define SIGSYS 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGURG 16 +#define SIGSTOP 17 +#define SIGTSTP 18 +#define SIGCONT 19 +#define SIGCHLD 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGPOLL 23 +#define SIGWINCH 24 +#define SIGUSR1 25 +#define SIGUSR2 26 +#define SIGRTMIN 27 +#define SIGRTMAX 31 +#define NSIG 32 + +#define SIG_SETMASK 0 /* set mask with sigprocmask() */ +#define SIG_BLOCK 1 /* set of signals to block */ +#define SIG_UNBLOCK 2 /* set of signals to, well, unblock */ + +typedef void (*_sig_func_ptr)(int); + +struct sigaction +{ + _sig_func_ptr sa_handler; + sigset_t sa_mask; + int sa_flags; +}; + +#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0) +#define sigdelset(what,sig) (*(what) &= ~(1<<(sig)), 0) +#define sigemptyset(what) (*(what) = 0, 0) +#define sigfillset(what) (*(what) = ~(0), 0) +#define sigismember(what,sig) (((*(what)) & (1<<(sig))) != 0) + +int sigprocmask (int how, const sigset_t *set, sigset_t *oset); +int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/rt-thread/include/libc/libc_stat.h b/rt-thread/include/libc/libc_stat.h new file mode 100644 index 0000000..9079d1e --- /dev/null +++ b/rt-thread/include/libc/libc_stat.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef LIBC_STAT_H__ +#define LIBC_STAT_H__ + +#include + +#if defined(RT_USING_NEWLIB) +/* use header file of newlib */ +#include + +#elif defined(_WIN32) +#include + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFBLK 0060000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) + +#else +#define S_IFMT 00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +/* stat structure */ +#include +#include + +struct stat +{ + struct rt_device *st_dev; + uint16_t st_ino; + uint16_t st_mode; + uint16_t st_nlink; + uint16_t st_uid; + uint16_t st_gid; + struct rt_device *st_rdev; + uint32_t st_size; + time_t st_atime; + long st_spare1; + time_t st_mtime; + long st_spare2; + time_t st_ctime; + long st_spare3; + uint32_t st_blksize; + uint32_t st_blocks; + long st_spare4[2]; +}; + +#endif + +#endif diff --git a/rt-thread/include/rtdbg.h b/rt-thread/include/rtdbg.h new file mode 100644 index 0000000..da4eb48 --- /dev/null +++ b/rt-thread/include/rtdbg.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : rtdbg.h + * + * Change Logs: + * Date Author Notes + * 2016-11-12 Bernard The first version + * 2018-05-25 armink Add simple API, such as LOG_D, LOG_E + */ + +/* + * The macro definitions for debug + * + * These macros are defined in static. If you want to use debug macro, you can + * use as following code: + * + * In your C/C++ file, enable/disable DEBUG_ENABLE macro, and then include this + * header file. + * + * #define DBG_SECTION_NAME "MOD" + * #define DBG_ENABLE // enable debug macro + * #define DBG_LEVEL DBG_INFO + * #include // must after of DEBUG_ENABLE or some other options + * + * Then in your C/C++ file, you can use dbg_log macro to print out logs: + * dbg_log(DBG_INFO, "this is a log!\n"); + * + * Or if you want to using the simple API, you can + * LOG_D("this is a debug log!"); + * LOG_E("this is a error log!"); + * + * If you want to use different color for different kinds log, you can + * #define DBG_COLOR + */ + +#ifndef RT_DBG_H__ +#define RT_DBG_H__ + +#include + +/* DEBUG level */ +#define DBG_ERROR 0 +#define DBG_WARNING 1 +#define DBG_INFO 2 +#define DBG_LOG 3 + +#ifndef DBG_SECTION_NAME +#define DBG_SECTION_NAME "DBG" +#endif + +#ifdef DBG_ENABLE + +#ifndef DBG_LEVEL +#define DBG_LEVEL DBG_WARNING +#endif + +/* + * The color for terminal (foreground) + * BLACK 30 + * RED 31 + * GREEN 32 + * YELLOW 33 + * BLUE 34 + * PURPLE 35 + * CYAN 36 + * WHITE 37 + */ +#ifdef DBG_COLOR +#define _DBG_COLOR(n) rt_kprintf("\033["#n"m") +#define _DBG_LOG_HDR(lvl_name, color_n) \ + rt_kprintf("\033["#color_n"m["lvl_name"/"DBG_SECTION_NAME"] ") +#define _DBG_LOG_X_END \ + rt_kprintf("\033[0m\n") +#else +#define _DBG_COLOR(n) +#define _DBG_LOG_HDR(lvl_name, color_n) \ + rt_kprintf("["lvl_name"/"DBG_SECTION_NAME"] ") +#define _DBG_LOG_X_END \ + rt_kprintf("\n") +#endif /* DBG_COLOR */ + +/* + * static debug routine + */ +#define dbg_log(level, fmt, ...) \ + if ((level) <= DBG_LEVEL) \ + { \ + switch(level) \ + { \ + case DBG_ERROR: _DBG_LOG_HDR("E", 31); break; \ + case DBG_WARNING: _DBG_LOG_HDR("W", 33); break; \ + case DBG_INFO: _DBG_LOG_HDR("I", 32); break; \ + case DBG_LOG: _DBG_LOG_HDR("D", 0); break; \ + default: break; \ + } \ + rt_kprintf(fmt, ##__VA_ARGS__); \ + _DBG_COLOR(0); \ + } + +#define dbg_here \ + if ((DBG_LEVEL) <= DBG_LOG){ \ + rt_kprintf(DBG_SECTION_NAME " Here %s:%d\n", \ + __FUNCTION__, __LINE__); \ + } + +#define dbg_enter \ + if ((DBG_LEVEL) <= DBG_LOG){ \ + _DBG_COLOR(32); \ + rt_kprintf(DBG_SECTION_NAME " Enter %s\n", \ + __FUNCTION__); \ + _DBG_COLOR(0); \ + } + +#define dbg_exit \ + if ((DBG_LEVEL) <= DBG_LOG){ \ + _DBG_COLOR(32); \ + rt_kprintf(DBG_SECTION_NAME " Exit %s:%d\n", \ + __FUNCTION__); \ + _DBG_COLOR(0); \ + } + + +#define dbg_log_line(lvl, color_n, fmt, ...) \ + do \ + { \ + _DBG_LOG_HDR(lvl, color_n); \ + rt_kprintf(fmt, ##__VA_ARGS__); \ + _DBG_LOG_X_END; \ + } \ + while (0) + +#define dbg_raw(...) rt_kprintf(__VA_ARGS__); + +#else +#define dbg_log(level, fmt, ...) +#define dbg_here +#define dbg_enter +#define dbg_exit +#define dbg_log_line(lvl, color_n, fmt, ...) +#define dbg_raw(...) +#endif /* DBG_ENABLE */ + +#if (DBG_LEVEL >= DBG_LOG) +#define LOG_D(fmt, ...) dbg_log_line("D", 0, fmt, ##__VA_ARGS__) +#else +#define LOG_D(...) +#endif + +#if (DBG_LEVEL >= DBG_INFO) +#define LOG_I(fmt, ...) dbg_log_line("I", 32, fmt, ##__VA_ARGS__) +#else +#define LOG_I(...) +#endif + +#if (DBG_LEVEL >= DBG_WARNING) +#define LOG_W(fmt, ...) dbg_log_line("W", 33, fmt, ##__VA_ARGS__) +#else +#define LOG_W(...) +#endif + +#if (DBG_LEVEL >= DBG_ERROR) +#define LOG_E(fmt, ...) dbg_log_line("E", 31, fmt, ##__VA_ARGS__) +#else +#define LOG_E(...) +#endif + +#define LOG_RAW(...) dbg_raw(__VA_ARGS__) + +#endif /* RT_DBG_H__ */ diff --git a/rt-thread/include/rtdebug.h b/rt-thread/include/rtdebug.h new file mode 100644 index 0000000..48f8d23 --- /dev/null +++ b/rt-thread/include/rtdebug.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : rtdebug.h + */ + +#ifndef __RTDEBUG_H__ +#define __RTDEBUG_H__ + +#include + +/* settings depend check */ +#ifdef RT_USING_POSIX +#if !defined(RT_USING_DFS) || !defined(RT_USING_DFS_DEVFS) +#error "POSIX poll/select, stdin need file system(RT_USING_DFS) and device file system(RT_USING_DFS_DEVFS)" +#endif + +#if !defined(RT_USING_LIBC) +#error "POSIX layer need standard C library(RT_USING_LIBC)" +#endif + +#endif + +#ifdef RT_USING_POSIX_TERMIOS +#if !defined(RT_USING_POSIX) +#error "termios need POSIX layer(RT_USING_POSIX)" +#endif +#endif + +/* Using this macro to control all kernel debug features. */ +#ifdef RT_DEBUG + +/* Turn on some of these (set to non-zero) to debug kernel */ +#ifndef RT_DEBUG_MEM +#define RT_DEBUG_MEM 0 +#endif + +#ifndef RT_DEBUG_MEMHEAP +#define RT_DEBUG_MEMHEAP 0 +#endif + +#ifndef RT_DEBUG_MODULE +#define RT_DEBUG_MODULE 0 +#endif + +#ifndef RT_DEBUG_SCHEDULER +#define RT_DEBUG_SCHEDULER 0 +#endif + +#ifndef RT_DEBUG_SLAB +#define RT_DEBUG_SLAB 0 +#endif + +#ifndef RT_DEBUG_THREAD +#define RT_DEBUG_THREAD 0 +#endif + +#ifndef RT_DEBUG_TIMER +#define RT_DEBUG_TIMER 0 +#endif + +#ifndef RT_DEBUG_IRQ +#define RT_DEBUG_IRQ 0 +#endif + +#ifndef RT_DEBUG_IPC +#define RT_DEBUG_IPC 0 +#endif + +#ifndef RT_DEBUG_INIT +#define RT_DEBUG_INIT 0 +#endif + +/* Turn on this to enable context check */ +#ifndef RT_DEBUG_CONTEXT_CHECK +#define RT_DEBUG_CONTEXT_CHECK 1 +#endif + +#define RT_DEBUG_LOG(type, message) \ +do \ +{ \ + if (type) \ + rt_kprintf message; \ +} \ +while (0) + +#define RT_ASSERT(EX) \ +if (!(EX)) \ +{ \ + rt_assert_handler(#EX, __FUNCTION__, __LINE__); \ +} + +/* Macro to check current context */ +#if RT_DEBUG_CONTEXT_CHECK +#define RT_DEBUG_NOT_IN_INTERRUPT \ +do \ +{ \ + rt_base_t level; \ + level = rt_hw_interrupt_disable(); \ + if (rt_interrupt_get_nest() != 0) \ + { \ + rt_kprintf("Function[%s] shall not be used in ISR\n", __FUNCTION__); \ + RT_ASSERT(0) \ + } \ + rt_hw_interrupt_enable(level); \ +} \ +while (0) + +/* "In thread context" means: + * 1) the scheduler has been started + * 2) not in interrupt context. + */ +#define RT_DEBUG_IN_THREAD_CONTEXT \ +do \ +{ \ + rt_base_t level; \ + level = rt_hw_interrupt_disable(); \ + if (rt_thread_self() == RT_NULL) \ + { \ + rt_kprintf("Function[%s] shall not be used before scheduler start\n", \ + __FUNCTION__); \ + RT_ASSERT(0) \ + } \ + RT_DEBUG_NOT_IN_INTERRUPT; \ + rt_hw_interrupt_enable(level); \ +} \ +while (0) +#else +#define RT_DEBUG_NOT_IN_INTERRUPT +#define RT_DEBUG_IN_THREAD_CONTEXT +#endif + +#else /* RT_DEBUG */ + +#define RT_ASSERT(EX) +#define RT_DEBUG_LOG(type, message) +#define RT_DEBUG_NOT_IN_INTERRUPT +#define RT_DEBUG_IN_THREAD_CONTEXT + +#endif /* RT_DEBUG */ + +#endif /* __RTDEBUG_H__ */ diff --git a/rt-thread/include/rtdef.h b/rt-thread/include/rtdef.h new file mode 100644 index 0000000..92b9971 --- /dev/null +++ b/rt-thread/include/rtdef.h @@ -0,0 +1,1038 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : rtdef.h + * + * Change Logs: + * Date Author Notes + * 2007-01-10 Bernard the first version + * 2008-07-12 Bernard remove all rt_int8, rt_uint32_t etc typedef + * 2010-10-26 yi.qiu add module support + * 2010-11-10 Bernard add cleanup callback function in thread exit. + * 2011-05-09 Bernard use builtin va_arg in GCC 4.x + * 2012-11-16 Bernard change RT_NULL from ((void*)0) to 0. + * 2012-12-29 Bernard change the RT_USING_MEMPOOL location and add + * RT_USING_MEMHEAP condition. + * 2012-12-30 Bernard add more control command for graphic. + * 2013-01-09 Bernard change version number. + * 2015-02-01 Bernard change version number to v2.1.0 + * 2017-08-31 Bernard change version number to v3.0.0 + * 2017-11-30 Bernard change version number to v3.0.1 + * 2017-12-27 Bernard change version number to v3.0.2 + * 2018-02-24 Bernard change version number to v3.0.3 + * 2018-04-25 Bernard change version number to v3.0.4 + * 2018-05-31 Bernard change version number to v3.1.0 + * 2018-09-04 Bernard change version number to v3.1.1 + * 2018-09-14 Bernard apply Apache License v2.0 to RT-Thread Kernel + */ + +#ifndef __RT_DEF_H__ +#define __RT_DEF_H__ + +/* include rtconfig header to import configuration */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup BasicDef + */ + +/*@{*/ + +/* RT-Thread version information */ +#define RT_VERSION 3L /**< major version number */ +#define RT_SUBVERSION 1L /**< minor version number */ +#define RT_REVISION 1L /**< revise version number */ + +/* RT-Thread version */ +#define RTTHREAD_VERSION ((RT_VERSION * 10000) + \ + (RT_SUBVERSION * 100) + RT_REVISION) + +/* RT-Thread basic data type definitions */ +typedef signed char rt_int8_t; /**< 8bit integer type */ +typedef signed short rt_int16_t; /**< 16bit integer type */ +typedef signed long rt_int32_t; /**< 32bit integer type */ +typedef unsigned char rt_uint8_t; /**< 8bit unsigned integer type */ +typedef unsigned short rt_uint16_t; /**< 16bit unsigned integer type */ +typedef unsigned long rt_uint32_t; /**< 32bit unsigned integer type */ +typedef int rt_bool_t; /**< boolean type */ + +/* 32bit CPU */ +typedef long rt_base_t; /**< Nbit CPU related date type */ +typedef unsigned long rt_ubase_t; /**< Nbit unsigned CPU related data type */ + +typedef rt_base_t rt_err_t; /**< Type for error number */ +typedef rt_uint32_t rt_time_t; /**< Type for time stamp */ +typedef rt_uint32_t rt_tick_t; /**< Type for tick count */ +typedef rt_base_t rt_flag_t; /**< Type for flags */ +typedef rt_ubase_t rt_size_t; /**< Type for size number */ +typedef rt_ubase_t rt_dev_t; /**< Type for device */ +typedef rt_base_t rt_off_t; /**< Type for offset */ + +/* boolean type definitions */ +#define RT_TRUE 1 /**< boolean true */ +#define RT_FALSE 0 /**< boolean fails */ + +/*@}*/ + +/* maximum value of base type */ +#define RT_UINT8_MAX 0xff /**< Maxium number of UINT8 */ +#define RT_UINT16_MAX 0xffff /**< Maxium number of UINT16 */ +#define RT_UINT32_MAX 0xffffffff /**< Maxium number of UINT32 */ +#define RT_TICK_MAX RT_UINT32_MAX /**< Maxium number of tick */ + +#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) +#define __CLANG_ARM +#endif + +/* Compiler Related Definitions */ +#if defined(__CC_ARM) || defined(__CLANG_ARM) /* ARM Compiler */ + #include + #define SECTION(x) __attribute__((section(x))) + #define RT_UNUSED __attribute__((unused)) + #define RT_USED __attribute__((used)) + #define ALIGN(n) __attribute__((aligned(n))) + + #define RT_WEAK __attribute__((weak)) + #define rt_inline static __inline + /* module compiling */ + #ifdef RT_USING_MODULE + #define RTT_API __declspec(dllimport) + #else + #define RTT_API __declspec(dllexport) + #endif + +#elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */ + #include + #define SECTION(x) @ x + #define RT_UNUSED + #define RT_USED __root + #define PRAGMA(x) _Pragma(#x) + #define ALIGN(n) PRAGMA(data_alignment=n) + #define RT_WEAK __weak + #define rt_inline static inline + #define RTT_API + +#elif defined (__GNUC__) /* GNU GCC Compiler */ + #ifdef RT_USING_NEWLIB + #include + #else + /* the version of GNU GCC must be greater than 4.x */ + typedef __builtin_va_list __gnuc_va_list; + typedef __gnuc_va_list va_list; + #define va_start(v,l) __builtin_va_start(v,l) + #define va_end(v) __builtin_va_end(v) + #define va_arg(v,l) __builtin_va_arg(v,l) + #endif + + #define SECTION(x) __attribute__((section(x))) + #define RT_UNUSED __attribute__((unused)) + #define RT_USED __attribute__((used)) + #define ALIGN(n) __attribute__((aligned(n))) + #define RT_WEAK __attribute__((weak)) + #define rt_inline static __inline + #define RTT_API +#elif defined (__ADSPBLACKFIN__) /* for VisualDSP++ Compiler */ + #include + #define SECTION(x) __attribute__((section(x))) + #define RT_UNUSED __attribute__((unused)) + #define RT_USED __attribute__((used)) + #define ALIGN(n) __attribute__((aligned(n))) + #define RT_WEAK __attribute__((weak)) + #define rt_inline static inline + #define RTT_API +#elif defined (_MSC_VER) + #include + #define SECTION(x) + #define RT_UNUSED + #define RT_USED + #define ALIGN(n) __declspec(align(n)) + #define RT_WEAK + #define rt_inline static __inline + #define RTT_API +#elif defined (__TI_COMPILER_VERSION__) + #include + /* The way that TI compiler set section is different from other(at least + * GCC and MDK) compilers. See ARM Optimizing C/C++ Compiler 5.9.3 for more + * details. */ + #define SECTION(x) + #define RT_UNUSED + #define RT_USED + #define PRAGMA(x) _Pragma(#x) + #define ALIGN(n) + #define RT_WEAK + #define rt_inline static inline + #define RTT_API +#else + #error not supported tool chain +#endif + +/* initialization export */ +#ifdef RT_USING_COMPONENTS_INIT +typedef int (*init_fn_t)(void); +#ifdef _MSC_VER /* we do not support MS VC++ compiler */ + #define INIT_EXPORT(fn, level) +#else + #if RT_DEBUG_INIT + struct rt_init_desc + { + const char* fn_name; + const init_fn_t fn; + }; + #define INIT_EXPORT(fn, level) \ + const char __rti_##fn##_name[] = #fn; \ + RT_USED const struct rt_init_desc __rt_init_desc_##fn SECTION(".rti_fn."level) = \ + { __rti_##fn##_name, fn}; + #else + #define INIT_EXPORT(fn, level) \ + RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn."level) = fn + #endif +#endif +#else +#define INIT_EXPORT(fn, level) +#endif + +/* board init routines will be called in board_init() function */ +#define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1") + +/* pre/device/component/env/app init routines will be called in init_thread */ +/* components pre-initialization (pure software initilization) */ +#define INIT_PREV_EXPORT(fn) INIT_EXPORT(fn, "2") +/* device initialization */ +#define INIT_DEVICE_EXPORT(fn) INIT_EXPORT(fn, "3") +/* components initialization (dfs, lwip, ...) */ +#define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT(fn, "4") +/* environment initialization (mount disk, ...) */ +#define INIT_ENV_EXPORT(fn) INIT_EXPORT(fn, "5") +/* appliation initialization (rtgui application etc ...) */ +#define INIT_APP_EXPORT(fn) INIT_EXPORT(fn, "6") + +#if !defined(RT_USING_FINSH) +/* define these to empty, even if not include finsh.h file */ +#define FINSH_FUNCTION_EXPORT(name, desc) +#define FINSH_FUNCTION_EXPORT_ALIAS(name, alias, desc) +#define FINSH_VAR_EXPORT(name, type, desc) + +#define MSH_CMD_EXPORT(command, desc) +#define MSH_CMD_EXPORT_ALIAS(command, alias, desc) +#elif !defined(FINSH_USING_SYMTAB) +#define FINSH_FUNCTION_EXPORT_CMD(name, cmd, desc) +#endif + +/* event length */ +#define RT_EVENT_LENGTH 32 + +/* memory management option */ +#define RT_MM_PAGE_SIZE 4096 +#define RT_MM_PAGE_MASK (RT_MM_PAGE_SIZE - 1) +#define RT_MM_PAGE_BITS 12 + +/* kernel malloc definitions */ +#ifndef RT_KERNEL_MALLOC +#define RT_KERNEL_MALLOC(sz) rt_malloc(sz) +#endif + +#ifndef RT_KERNEL_FREE +#define RT_KERNEL_FREE(ptr) rt_free(ptr) +#endif + +#ifndef RT_KERNEL_REALLOC +#define RT_KERNEL_REALLOC(ptr, size) rt_realloc(ptr, size) +#endif + +/** + * @addtogroup Error + */ + +/*@{*/ + +/* RT-Thread error code definitions */ +#define RT_EOK 0 /**< There is no error */ +#define RT_ERROR 1 /**< A generic error happens */ +#define RT_ETIMEOUT 2 /**< Timed out */ +#define RT_EFULL 3 /**< The resource is full */ +#define RT_EEMPTY 4 /**< The resource is empty */ +#define RT_ENOMEM 5 /**< No memory */ +#define RT_ENOSYS 6 /**< No system */ +#define RT_EBUSY 7 /**< Busy */ +#define RT_EIO 8 /**< IO error */ +#define RT_EINTR 9 /**< Interrupted system call */ +#define RT_EINVAL 10 /**< Invalid argument */ + +/*@}*/ + +/** + * @ingroup BasicDef + * + * @def RT_ALIGN(size, align) + * Return the most contiguous size aligned at specified width. RT_ALIGN(13, 4) + * would return 16. + */ +#define RT_ALIGN(size, align) (((size) + (align) - 1) & ~((align) - 1)) + +/** + * @ingroup BasicDef + * + * @def RT_ALIGN_DOWN(size, align) + * Return the down number of aligned at specified width. RT_ALIGN_DOWN(13, 4) + * would return 12. + */ +#define RT_ALIGN_DOWN(size, align) ((size) & ~((align) - 1)) + +/** + * @ingroup BasicDef + * + * @def RT_NULL + * Similar as the \c NULL in C library. + */ +#define RT_NULL (0) + +/** + * Double List structure + */ +struct rt_list_node +{ + struct rt_list_node *next; /**< point to next node. */ + struct rt_list_node *prev; /**< point to prev node. */ +}; +typedef struct rt_list_node rt_list_t; /**< Type for lists. */ + +/** + * Single List structure + */ +struct rt_slist_node +{ + struct rt_slist_node *next; /**< point to next node. */ +}; +typedef struct rt_slist_node rt_slist_t; /**< Type for single list. */ + +/** + * @addtogroup KernelObject + */ + +/*@{*/ + +/* + * kernel object macros + */ +#define RT_OBJECT_FLAG_MODULE 0x80 /**< is module object. */ + +/** + * Base structure of Kernel object + */ +struct rt_object +{ + char name[RT_NAME_MAX]; /**< name of kernel object */ + rt_uint8_t type; /**< type of kernel object */ + rt_uint8_t flag; /**< flag of kernel object */ + +#ifdef RT_USING_MODULE + void *module_id; /**< id of application module */ +#endif + rt_list_t list; /**< list node of kernel object */ +}; +typedef struct rt_object *rt_object_t; /**< Type for kernel objects. */ + +/** + * The object type can be one of the follows with specific + * macros enabled: + * - Thread + * - Semaphore + * - Mutex + * - Event + * - MailBox + * - MessageQueue + * - MemHeap + * - MemPool + * - Device + * - Timer + * - Module + * - Unknown + * - Static + */ +enum rt_object_class_type +{ + RT_Object_Class_Thread = 0, /**< The object is a thread. */ + RT_Object_Class_Semaphore, /**< The object is a semaphore. */ + RT_Object_Class_Mutex, /**< The object is a mutex. */ + RT_Object_Class_Event, /**< The object is a event. */ + RT_Object_Class_MailBox, /**< The object is a mail box. */ + RT_Object_Class_MessageQueue, /**< The object is a message queue. */ + RT_Object_Class_MemHeap, /**< The object is a memory heap */ + RT_Object_Class_MemPool, /**< The object is a memory pool. */ + RT_Object_Class_Device, /**< The object is a device */ + RT_Object_Class_Timer, /**< The object is a timer. */ + RT_Object_Class_Module, /**< The object is a module. */ + RT_Object_Class_Unknown, /**< The object is unknown. */ + RT_Object_Class_Static = 0x80 /**< The object is a static object. */ +}; + +/** + * The information of the kernel object + */ +struct rt_object_information +{ + enum rt_object_class_type type; /**< object class type */ + rt_list_t object_list; /**< object list */ + rt_size_t object_size; /**< object size */ +}; + +/** + * The hook function call macro + */ +#ifdef RT_USING_HOOK +#define RT_OBJECT_HOOK_CALL(func, argv) \ + do { if ((func) != RT_NULL) func argv; } while (0) +#else +#define RT_OBJECT_HOOK_CALL(func, argv) +#endif + +/*@}*/ + +/** + * @addtogroup Clock + */ + +/*@{*/ + +/** + * clock & timer macros + */ +#define RT_TIMER_FLAG_DEACTIVATED 0x0 /**< timer is deactive */ +#define RT_TIMER_FLAG_ACTIVATED 0x1 /**< timer is active */ +#define RT_TIMER_FLAG_ONE_SHOT 0x0 /**< one shot timer */ +#define RT_TIMER_FLAG_PERIODIC 0x2 /**< periodic timer */ + +#define RT_TIMER_FLAG_HARD_TIMER 0x0 /**< hard timer,the timer's callback function will be called in tick isr. */ +#define RT_TIMER_FLAG_SOFT_TIMER 0x4 /**< soft timer,the timer's callback function will be called in timer thread. */ + +#define RT_TIMER_CTRL_SET_TIME 0x0 /**< set timer control command */ +#define RT_TIMER_CTRL_GET_TIME 0x1 /**< get timer control command */ +#define RT_TIMER_CTRL_SET_ONESHOT 0x2 /**< change timer to one shot */ +#define RT_TIMER_CTRL_SET_PERIODIC 0x3 /**< change timer to periodic */ + +#ifndef RT_TIMER_SKIP_LIST_LEVEL +#define RT_TIMER_SKIP_LIST_LEVEL 1 +#endif + +/* 1 or 3 */ +#ifndef RT_TIMER_SKIP_LIST_MASK +#define RT_TIMER_SKIP_LIST_MASK 0x3 +#endif + +/** + * timer structure + */ +struct rt_timer +{ + struct rt_object parent; /**< inherit from rt_object */ + + rt_list_t row[RT_TIMER_SKIP_LIST_LEVEL]; + + void (*timeout_func)(void *parameter); /**< timeout function */ + void *parameter; /**< timeout function's parameter */ + + rt_tick_t init_tick; /**< timer timeout tick */ + rt_tick_t timeout_tick; /**< timeout tick */ +}; +typedef struct rt_timer *rt_timer_t; + +/*@}*/ + +/** + * @addtogroup Signal + */ +#ifdef RT_USING_SIGNALS +#include +typedef unsigned long rt_sigset_t; +typedef void (*rt_sighandler_t)(int signo); +typedef siginfo_t rt_siginfo_t; + +#define RT_SIG_MAX 32 +#endif +/*@}*/ + +/** + * @addtogroup Thread + */ + +/*@{*/ + +/* + * Thread + */ + +/* + * thread state definitions + */ +#define RT_THREAD_INIT 0x00 /**< Initialized status */ +#define RT_THREAD_READY 0x01 /**< Ready status */ +#define RT_THREAD_SUSPEND 0x02 /**< Suspend status */ +#define RT_THREAD_RUNNING 0x03 /**< Running status */ +#define RT_THREAD_BLOCK RT_THREAD_SUSPEND /**< Blocked status */ +#define RT_THREAD_CLOSE 0x04 /**< Closed status */ +#define RT_THREAD_STAT_MASK 0x0f + +#define RT_THREAD_STAT_SIGNAL 0x10 +#define RT_THREAD_STAT_SIGNAL_READY (RT_THREAD_STAT_SIGNAL | RT_THREAD_READY) +#define RT_THREAD_STAT_SIGNAL_WAIT 0x20 +#define RT_THREAD_STAT_SIGNAL_MASK 0xf0 + +/** + * thread control command definitions + */ +#define RT_THREAD_CTRL_STARTUP 0x00 /**< Startup thread. */ +#define RT_THREAD_CTRL_CLOSE 0x01 /**< Close thread. */ +#define RT_THREAD_CTRL_CHANGE_PRIORITY 0x02 /**< Change thread priority. */ +#define RT_THREAD_CTRL_INFO 0x03 /**< Get thread information. */ + +/** + * Thread structure + */ +struct rt_thread +{ + /* rt object */ + char name[RT_NAME_MAX]; /**< the name of thread */ + rt_uint8_t type; /**< type of object */ + rt_uint8_t flags; /**< thread's flags */ + +#ifdef RT_USING_MODULE + void *module_id; /**< id of application module */ +#endif + + rt_list_t list; /**< the object list */ + rt_list_t tlist; /**< the thread list */ + + /* stack point and entry */ + void *sp; /**< stack point */ + void *entry; /**< entry */ + void *parameter; /**< parameter */ + void *stack_addr; /**< stack address */ + rt_uint32_t stack_size; /**< stack size */ + + /* error code */ + rt_err_t error; /**< error code */ + + rt_uint8_t stat; /**< thread status */ + + /* priority */ + rt_uint8_t current_priority; /**< current priority */ + rt_uint8_t init_priority; /**< initialized priority */ +#if RT_THREAD_PRIORITY_MAX > 32 + rt_uint8_t number; + rt_uint8_t high_mask; +#endif + rt_uint32_t number_mask; + +#if defined(RT_USING_EVENT) + /* thread event */ + rt_uint32_t event_set; + rt_uint8_t event_info; +#endif + +#if defined(RT_USING_SIGNALS) + rt_sigset_t sig_pending; /**< the pending signals */ + rt_sigset_t sig_mask; /**< the mask bits of signal */ + + void *sig_ret; /**< the return stack pointer from signal */ + rt_sighandler_t *sig_vectors; /**< vectors of signal handler */ + void *si_list; /**< the signal infor list */ +#endif + + rt_ubase_t init_tick; /**< thread's initialized tick */ + rt_ubase_t remaining_tick; /**< remaining tick */ + + struct rt_timer thread_timer; /**< built-in thread timer */ + + void (*cleanup)(struct rt_thread *tid); /**< cleanup function when thread exit */ + + /* light weight process if present */ +#ifdef RT_USING_LWP + void *lwp; +#endif + + rt_uint32_t user_data; /**< private user data beyond this thread */ +}; +typedef struct rt_thread *rt_thread_t; + +/*@}*/ + +/** + * @addtogroup IPC + */ + +/*@{*/ + +/** + * IPC flags and control command definitions + */ +#define RT_IPC_FLAG_FIFO 0x00 /**< FIFOed IPC. @ref IPC. */ +#define RT_IPC_FLAG_PRIO 0x01 /**< PRIOed IPC. @ref IPC. */ + +#define RT_IPC_CMD_UNKNOWN 0x00 /**< unknown IPC command */ +#define RT_IPC_CMD_RESET 0x01 /**< reset IPC object */ + +#define RT_WAITING_FOREVER -1 /**< Block forever until get resource. */ +#define RT_WAITING_NO 0 /**< Non-block. */ + +/** + * Base structure of IPC object + */ +struct rt_ipc_object +{ + struct rt_object parent; /**< inherit from rt_object */ + + rt_list_t suspend_thread; /**< threads pended on this resource */ +}; + +#ifdef RT_USING_SEMAPHORE +/** + * Semaphore structure + */ +struct rt_semaphore +{ + struct rt_ipc_object parent; /**< inherit from ipc_object */ + + rt_uint16_t value; /**< value of semaphore. */ +}; +typedef struct rt_semaphore *rt_sem_t; +#endif + +#ifdef RT_USING_MUTEX +/** + * Mutual exclusion (mutex) structure + */ +struct rt_mutex +{ + struct rt_ipc_object parent; /**< inherit from ipc_object */ + + rt_uint16_t value; /**< value of mutex */ + + rt_uint8_t original_priority; /**< priority of last thread hold the mutex */ + rt_uint8_t hold; /**< numbers of thread hold the mutex */ + + struct rt_thread *owner; /**< current owner of mutex */ +}; +typedef struct rt_mutex *rt_mutex_t; +#endif + +#ifdef RT_USING_EVENT +/** + * flag defintions in event + */ +#define RT_EVENT_FLAG_AND 0x01 /**< logic and */ +#define RT_EVENT_FLAG_OR 0x02 /**< logic or */ +#define RT_EVENT_FLAG_CLEAR 0x04 /**< clear flag */ + +/* + * event structure + */ +struct rt_event +{ + struct rt_ipc_object parent; /**< inherit from ipc_object */ + + rt_uint32_t set; /**< event set */ +}; +typedef struct rt_event *rt_event_t; +#endif + +#ifdef RT_USING_MAILBOX +/** + * mailbox structure + */ +struct rt_mailbox +{ + struct rt_ipc_object parent; /**< inherit from ipc_object */ + + rt_uint32_t *msg_pool; /**< start address of message buffer */ + + rt_uint16_t size; /**< size of message pool */ + + rt_uint16_t entry; /**< index of messages in msg_pool */ + rt_uint16_t in_offset; /**< input offset of the message buffer */ + rt_uint16_t out_offset; /**< output offset of the message buffer */ + + rt_list_t suspend_sender_thread; /**< sender thread suspended on this mailbox */ +}; +typedef struct rt_mailbox *rt_mailbox_t; +#endif + +#ifdef RT_USING_MESSAGEQUEUE +/** + * message queue structure + */ +struct rt_messagequeue +{ + struct rt_ipc_object parent; /**< inherit from ipc_object */ + + void *msg_pool; /**< start address of message queue */ + + rt_uint16_t msg_size; /**< message size of each message */ + rt_uint16_t max_msgs; /**< max number of messages */ + + rt_uint16_t entry; /**< index of messages in the queue */ + + void *msg_queue_head; /**< list head */ + void *msg_queue_tail; /**< list tail */ + void *msg_queue_free; /**< pointer indicated the free node of queue */ +}; +typedef struct rt_messagequeue *rt_mq_t; +#endif + +/*@}*/ + +/** + * @addtogroup MM + */ + +/*@{*/ + +/* + * memory management + * heap & partition + */ + +#ifdef RT_USING_MEMHEAP +/** + * memory item on the heap + */ +struct rt_memheap_item +{ + rt_uint32_t magic; /**< magic number for memheap */ + struct rt_memheap *pool_ptr; /**< point of pool */ + + struct rt_memheap_item *next; /**< next memheap item */ + struct rt_memheap_item *prev; /**< prev memheap item */ + + struct rt_memheap_item *next_free; /**< next free memheap item */ + struct rt_memheap_item *prev_free; /**< prev free memheap item */ +}; + +/** + * Base structure of memory heap object + */ +struct rt_memheap +{ + struct rt_object parent; /**< inherit from rt_object */ + + void *start_addr; /**< pool start address and size */ + + rt_uint32_t pool_size; /**< pool size */ + rt_uint32_t available_size; /**< available size */ + rt_uint32_t max_used_size; /**< maximum allocated size */ + + struct rt_memheap_item *block_list; /**< used block list */ + + struct rt_memheap_item *free_list; /**< free block list */ + struct rt_memheap_item free_header; /**< free block list header */ + + struct rt_semaphore lock; /**< semaphore lock */ +}; +#endif + +#ifdef RT_USING_MEMPOOL +/** + * Base structure of Memory pool object + */ +struct rt_mempool +{ + struct rt_object parent; /**< inherit from rt_object */ + + void *start_address; /**< memory pool start */ + rt_size_t size; /**< size of memory pool */ + + rt_size_t block_size; /**< size of memory blocks */ + rt_uint8_t *block_list; /**< memory blocks list */ + + rt_size_t block_total_count; /**< numbers of memory block */ + rt_size_t block_free_count; /**< numbers of free memory block */ + + rt_list_t suspend_thread; /**< threads pended on this resource */ + rt_size_t suspend_thread_count; /**< numbers of thread pended on this resource */ +}; +typedef struct rt_mempool *rt_mp_t; +#endif + +/*@}*/ + +#ifdef RT_USING_DEVICE +/** + * @addtogroup Device + */ + +/*@{*/ + +/** + * device (I/O) class type + */ +enum rt_device_class_type +{ + RT_Device_Class_Char = 0, /**< character device */ + RT_Device_Class_Block, /**< block device */ + RT_Device_Class_NetIf, /**< net interface */ + RT_Device_Class_MTD, /**< memory device */ + RT_Device_Class_CAN, /**< CAN device */ + RT_Device_Class_RTC, /**< RTC device */ + RT_Device_Class_Sound, /**< Sound device */ + RT_Device_Class_Graphic, /**< Graphic device */ + RT_Device_Class_I2CBUS, /**< I2C bus device */ + RT_Device_Class_USBDevice, /**< USB slave device */ + RT_Device_Class_USBHost, /**< USB host bus */ + RT_Device_Class_SPIBUS, /**< SPI bus device */ + RT_Device_Class_SPIDevice, /**< SPI device */ + RT_Device_Class_SDIO, /**< SDIO bus device */ + RT_Device_Class_PM, /**< PM pseudo device */ + RT_Device_Class_Pipe, /**< Pipe device */ + RT_Device_Class_Portal, /**< Portal device */ + RT_Device_Class_Timer, /**< Timer device */ + RT_Device_Class_Miscellaneous, /**< Miscellaneous device */ + RT_Device_Class_Unknown /**< unknown device */ +}; + +/** + * device flags defitions + */ +#define RT_DEVICE_FLAG_DEACTIVATE 0x000 /**< device is not not initialized */ + +#define RT_DEVICE_FLAG_RDONLY 0x001 /**< read only */ +#define RT_DEVICE_FLAG_WRONLY 0x002 /**< write only */ +#define RT_DEVICE_FLAG_RDWR 0x003 /**< read and write */ + +#define RT_DEVICE_FLAG_REMOVABLE 0x004 /**< removable device */ +#define RT_DEVICE_FLAG_STANDALONE 0x008 /**< standalone device */ +#define RT_DEVICE_FLAG_ACTIVATED 0x010 /**< device is activated */ +#define RT_DEVICE_FLAG_SUSPENDED 0x020 /**< device is suspended */ +#define RT_DEVICE_FLAG_STREAM 0x040 /**< stream mode */ + +#define RT_DEVICE_FLAG_INT_RX 0x100 /**< INT mode on Rx */ +#define RT_DEVICE_FLAG_DMA_RX 0x200 /**< DMA mode on Rx */ +#define RT_DEVICE_FLAG_INT_TX 0x400 /**< INT mode on Tx */ +#define RT_DEVICE_FLAG_DMA_TX 0x800 /**< DMA mode on Tx */ + +#define RT_DEVICE_OFLAG_CLOSE 0x000 /**< device is closed */ +#define RT_DEVICE_OFLAG_RDONLY 0x001 /**< read only access */ +#define RT_DEVICE_OFLAG_WRONLY 0x002 /**< write only access */ +#define RT_DEVICE_OFLAG_RDWR 0x003 /**< read and write */ +#define RT_DEVICE_OFLAG_OPEN 0x008 /**< device is opened */ +#define RT_DEVICE_OFLAG_MASK 0xf0f /**< mask of open flag */ + +/** + * general device commands + */ +#define RT_DEVICE_CTRL_RESUME 0x01 /**< resume device */ +#define RT_DEVICE_CTRL_SUSPEND 0x02 /**< suspend device */ +#define RT_DEVICE_CTRL_CONFIG 0x03 /**< configure device */ + +#define RT_DEVICE_CTRL_SET_INT 0x10 /**< set interrupt */ +#define RT_DEVICE_CTRL_CLR_INT 0x11 /**< clear interrupt */ +#define RT_DEVICE_CTRL_GET_INT 0x12 /**< get interrupt status */ + +/** + * special device commands + */ +#define RT_DEVICE_CTRL_CHAR_STREAM 0x10 /**< stream mode on char device */ +#define RT_DEVICE_CTRL_BLK_GETGEOME 0x10 /**< get geometry information */ +#define RT_DEVICE_CTRL_BLK_SYNC 0x11 /**< flush data to block device */ +#define RT_DEVICE_CTRL_BLK_ERASE 0x12 /**< erase block on block device */ +#define RT_DEVICE_CTRL_BLK_AUTOREFRESH 0x13 /**< block device : enter/exit auto refresh mode */ +#define RT_DEVICE_CTRL_NETIF_GETMAC 0x10 /**< get mac address */ +#define RT_DEVICE_CTRL_MTD_FORMAT 0x10 /**< format a MTD device */ +#define RT_DEVICE_CTRL_RTC_GET_TIME 0x10 /**< get time */ +#define RT_DEVICE_CTRL_RTC_SET_TIME 0x11 /**< set time */ +#define RT_DEVICE_CTRL_RTC_GET_ALARM 0x12 /**< get alarm */ +#define RT_DEVICE_CTRL_RTC_SET_ALARM 0x13 /**< set alarm */ + +typedef struct rt_device *rt_device_t; +/** + * operations set for device object + */ +struct rt_device_ops +{ + /* common device interface */ + rt_err_t (*init) (rt_device_t dev); + rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag); + rt_err_t (*close) (rt_device_t dev); + rt_size_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); + rt_size_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); + rt_err_t (*control)(rt_device_t dev, int cmd, void *args); +}; + +/** + * WaitQueue structure + */ +struct rt_wqueue +{ + rt_uint32_t flag; + rt_list_t waiting_list; +}; +typedef struct rt_wqueue rt_wqueue_t; + +/** + * Device structure + */ +struct rt_device +{ + struct rt_object parent; /**< inherit from rt_object */ + + enum rt_device_class_type type; /**< device type */ + rt_uint16_t flag; /**< device flag */ + rt_uint16_t open_flag; /**< device open flag */ + + rt_uint8_t ref_count; /**< reference count */ + rt_uint8_t device_id; /**< 0 - 255 */ + + /* device call back */ + rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size); + rt_err_t (*tx_complete)(rt_device_t dev, void *buffer); + +#ifdef RT_USING_DEVICE_OPS + const struct rt_device_ops *ops; +#else + /* common device interface */ + rt_err_t (*init) (rt_device_t dev); + rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag); + rt_err_t (*close) (rt_device_t dev); + rt_size_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size); + rt_size_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size); + rt_err_t (*control)(rt_device_t dev, int cmd, void *args); +#endif + +#if defined(RT_USING_POSIX) + const struct dfs_file_ops *fops; + struct rt_wqueue wait_queue; +#endif + + void *user_data; /**< device private data */ +}; + +/** + * block device geometry structure + */ +struct rt_device_blk_geometry +{ + rt_uint32_t sector_count; /**< count of sectors */ + rt_uint32_t bytes_per_sector; /**< number of bytes per sector */ + rt_uint32_t block_size; /**< number of bytes to erase one block */ +}; + +/** + * sector arrange struct on block device + */ +struct rt_device_blk_sectors +{ + rt_uint32_t sector_begin; /**< begin sector */ + rt_uint32_t sector_end; /**< end sector */ +}; + +/** + * cursor control command + */ +#define RT_DEVICE_CTRL_CURSOR_SET_POSITION 0x10 +#define RT_DEVICE_CTRL_CURSOR_SET_TYPE 0x11 + +/** + * graphic device control command + */ +#define RTGRAPHIC_CTRL_RECT_UPDATE 0 +#define RTGRAPHIC_CTRL_POWERON 1 +#define RTGRAPHIC_CTRL_POWEROFF 2 +#define RTGRAPHIC_CTRL_GET_INFO 3 +#define RTGRAPHIC_CTRL_SET_MODE 4 +#define RTGRAPHIC_CTRL_GET_EXT 5 + +/* graphic deice */ +enum +{ + RTGRAPHIC_PIXEL_FORMAT_MONO = 0, + RTGRAPHIC_PIXEL_FORMAT_GRAY4, + RTGRAPHIC_PIXEL_FORMAT_GRAY16, + RTGRAPHIC_PIXEL_FORMAT_RGB332, + RTGRAPHIC_PIXEL_FORMAT_RGB444, + RTGRAPHIC_PIXEL_FORMAT_RGB565, + RTGRAPHIC_PIXEL_FORMAT_RGB565P, + RTGRAPHIC_PIXEL_FORMAT_BGR565 = RTGRAPHIC_PIXEL_FORMAT_RGB565P, + RTGRAPHIC_PIXEL_FORMAT_RGB666, + RTGRAPHIC_PIXEL_FORMAT_RGB888, + RTGRAPHIC_PIXEL_FORMAT_ARGB888, + RTGRAPHIC_PIXEL_FORMAT_ABGR888, + RTGRAPHIC_PIXEL_FORMAT_ARGB565, + RTGRAPHIC_PIXEL_FORMAT_ALPHA, +}; + +/** + * build a pixel position according to (x, y) coordinates. + */ +#define RTGRAPHIC_PIXEL_POSITION(x, y) ((x << 16) | y) + +/** + * graphic device information structure + */ +struct rt_device_graphic_info +{ + rt_uint8_t pixel_format; /**< graphic format */ + rt_uint8_t bits_per_pixel; /**< bits per pixel */ + rt_uint16_t reserved; /**< reserved field */ + + rt_uint16_t width; /**< width of graphic device */ + rt_uint16_t height; /**< height of graphic device */ + + rt_uint8_t *framebuffer; /**< frame buffer */ +}; + +/** + * rectangle information structure + */ +struct rt_device_rect_info +{ + rt_uint16_t x; /**< x coordinate */ + rt_uint16_t y; /**< y coordinate */ + rt_uint16_t width; /**< width */ + rt_uint16_t height; /**< height */ +}; + +/** + * graphic operations + */ +struct rt_device_graphic_ops +{ + void (*set_pixel) (const char *pixel, int x, int y); + void (*get_pixel) (char *pixel, int x, int y); + + void (*draw_hline)(const char *pixel, int x1, int x2, int y); + void (*draw_vline)(const char *pixel, int x, int y1, int y2); + + void (*blit_line) (const char *pixel, int x, int y, rt_size_t size); +}; +#define rt_graphix_ops(device) ((struct rt_device_graphic_ops *)(device->user_data)) + +/*@}*/ +#endif + +/* definitions for libc */ +#include "rtlibc.h" + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +/* RT-Thread definitions for C++ */ +namespace rtthread { + +enum TICK_WAIT { + WAIT_NONE = 0, + WAIT_FOREVER = -1, +}; + +} + +#endif /* end of __cplusplus */ + +#endif diff --git a/rt-thread/include/rthw.h b/rt-thread/include/rthw.h new file mode 100644 index 0000000..8473854 --- /dev/null +++ b/rt-thread/include/rthw.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : rthw.h + * + * Change Logs: + * Date Author Notes + * 2006-03-18 Bernard the first version + * 2006-04-25 Bernard add rt_hw_context_switch_interrupt declaration + * 2006-09-24 Bernard add rt_hw_context_switch_to declaration + * 2012-12-29 Bernard add rt_hw_exception_install declaration + * 2017-10-17 Hichard add some micros + */ + +#ifndef __RT_HW_H__ +#define __RT_HW_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Some macros define + */ +#ifndef HWREG32 +#define HWREG32(x) (*((volatile rt_uint32_t *)(x))) +#endif +#ifndef HWREG16 +#define HWREG16(x) (*((volatile rt_uint16_t *)(x))) +#endif +#ifndef HWREG8 +#define HWREG8(x) (*((volatile rt_uint8_t *)(x))) +#endif + +#ifndef RT_CPU_CACHE_LINE_SZ +#define RT_CPU_CACHE_LINE_SZ 32 +#endif + +enum RT_HW_CACHE_OPS +{ + RT_HW_CACHE_FLUSH = 0x01, + RT_HW_CACHE_INVALIDATE = 0x02, +}; + +/* + * CPU interfaces + */ +void rt_hw_cpu_icache_enable(void); +void rt_hw_cpu_icache_disable(void); +rt_base_t rt_hw_cpu_icache_status(void); +void rt_hw_cpu_icache_ops(int ops, void* addr, int size); + +void rt_hw_cpu_dcache_enable(void); +void rt_hw_cpu_dcache_disable(void); +rt_base_t rt_hw_cpu_dcache_status(void); +void rt_hw_cpu_dcache_ops(int ops, void* addr, int size); + +void rt_hw_cpu_reset(void); +void rt_hw_cpu_shutdown(void); + +rt_uint8_t *rt_hw_stack_init(void *entry, + void *parameter, + rt_uint8_t *stack_addr, + void *exit); + +/* + * Interrupt handler definition + */ +typedef void (*rt_isr_handler_t)(int vector, void *param); + +struct rt_irq_desc +{ + rt_isr_handler_t handler; + void *param; + +#ifdef RT_USING_INTERRUPT_INFO + char name[RT_NAME_MAX]; + rt_uint32_t counter; +#endif +}; + +/* + * Interrupt interfaces + */ +void rt_hw_interrupt_init(void); +void rt_hw_interrupt_mask(int vector); +void rt_hw_interrupt_umask(int vector); +rt_isr_handler_t rt_hw_interrupt_install(int vector, + rt_isr_handler_t handler, + void *param, + char *name); + +rt_base_t rt_hw_interrupt_disable(void); +void rt_hw_interrupt_enable(rt_base_t level); + +/* + * Context interfaces + */ +void rt_hw_context_switch(rt_uint32_t from, rt_uint32_t to); +void rt_hw_context_switch_to(rt_uint32_t to); +void rt_hw_context_switch_interrupt(rt_uint32_t from, rt_uint32_t to); + +void rt_hw_console_output(const char *str); + +void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry); +void rt_hw_show_memory(rt_uint32_t addr, rt_uint32_t size); + +/* + * Exception interfaces + */ +void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context)); + +/* + * delay interfaces + */ +void rt_hw_us_delay(rt_uint32_t us); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/include/rtlibc.h b/rt-thread/include/rtlibc.h new file mode 100644 index 0000000..020c347 --- /dev/null +++ b/rt-thread/include/rtlibc.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : rtlibc.h + * + * Change Logs: + * Date Author Notes + * 2017-01-21 Bernard the first version + */ + +#ifndef RTLIBC_H__ +#define RTLIBC_H__ + +/* definitions for libc if toolchain has no these definitions */ +#include "libc/libc_stat.h" +#include "libc/libc_errno.h" + +#include "libc/libc_fcntl.h" +#include "libc/libc_ioctl.h" +#include "libc/libc_dirent.h" +#include "libc/libc_signal.h" +#include "libc/libc_fdset.h" + +#if defined(__CC_ARM) || defined(__CLANG_ARM) || defined(__IAR_SYSTEMS_ICC__) +typedef signed long off_t; +typedef int mode_t; +#endif + +#if defined(__MINGW32__) || defined(_WIN32) +typedef signed long off_t; +typedef int mode_t; +#endif + +#endif + diff --git a/rt-thread/include/rtm.h b/rt-thread/include/rtm.h new file mode 100644 index 0000000..08ad721 --- /dev/null +++ b/rt-thread/include/rtm.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : rtm.h + */ + +#ifndef __RTM_H__ +#define __RTM_H__ + +#include +#include + +#ifdef RT_USING_MODULE +struct rt_module_symtab +{ + void *addr; + const char *name; +}; + +#if defined(_MSC_VER) +#pragma section("RTMSymTab$f",read) +#define RTM_EXPORT(symbol) \ +__declspec(allocate("RTMSymTab$f"))const char __rtmsym_##symbol##_name[] = "__vs_rtm_"#symbol; +#pragma comment(linker, "/merge:RTMSymTab=mytext") + +#elif defined(__MINGW32__) +#define RTM_EXPORT(symbol) + +#else +#define RTM_EXPORT(symbol) \ +const char __rtmsym_##symbol##_name[] SECTION(".rodata.name") = #symbol; \ +const struct rt_module_symtab __rtmsym_##symbol SECTION("RTMSymTab")= \ +{ \ + (void *)&symbol, \ + __rtmsym_##symbol##_name \ +}; +#endif + +#else +#define RTM_EXPORT(symbol) +#endif + +#endif diff --git a/rt-thread/include/rtservice.h b/rt-thread/include/rtservice.h new file mode 100644 index 0000000..145a225 --- /dev/null +++ b/rt-thread/include/rtservice.h @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : rtservice.h + * + * Change Logs: + * Date Author Notes + * 2006-03-16 Bernard the first version + * 2006-09-07 Bernard move the kservice APIs to rtthread.h + * 2007-06-27 Bernard fix the rt_list_remove bug + * 2012-03-22 Bernard rename kservice.h to rtservice.h + * 2017-11-15 JasonJia Modify rt_slist_foreach to rt_slist_for_each_entry. + * Make code cleanup. + */ + +#ifndef __RT_SERVICE_H__ +#define __RT_SERVICE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup KernelService + */ + +/*@{*/ + +/** + * rt_container_of - return the member address of ptr, if the type of ptr is the + * struct type. + */ +#define rt_container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) + + +/** + * @brief initialize a list object + */ +#define RT_LIST_OBJECT_INIT(object) { &(object), &(object) } + +/** + * @brief initialize a list + * + * @param l list to be initialized + */ +rt_inline void rt_list_init(rt_list_t *l) +{ + l->next = l->prev = l; +} + +/** + * @brief insert a node after a list + * + * @param l list to insert it + * @param n new node to be inserted + */ +rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n) +{ + l->next->prev = n; + n->next = l->next; + + l->next = n; + n->prev = l; +} + +/** + * @brief insert a node before a list + * + * @param n new node to be inserted + * @param l list to insert it + */ +rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n) +{ + l->prev->next = n; + n->prev = l->prev; + + l->prev = n; + n->next = l; +} + +/** + * @brief remove node from list. + * @param n the node to remove from the list. + */ +rt_inline void rt_list_remove(rt_list_t *n) +{ + n->next->prev = n->prev; + n->prev->next = n->next; + + n->next = n->prev = n; +} + +/** + * @brief tests whether a list is empty + * @param l the list to test. + */ +rt_inline int rt_list_isempty(const rt_list_t *l) +{ + return l->next == l; +} + +/** + * @brief get the list length + * @param l the list to get. + */ +rt_inline unsigned int rt_list_len(const rt_list_t *l) +{ + unsigned int len = 0; + const rt_list_t *p = l; + while (p->next != l) + { + p = p->next; + len ++; + } + + return len; +} + +/** + * @brief get the struct for this entry + * @param node the entry point + * @param type the type of structure + * @param member the name of list in structure + */ +#define rt_list_entry(node, type, member) \ + rt_container_of(node, type, member) + +/** + * rt_list_for_each - iterate over a list + * @pos: the rt_list_t * to use as a loop cursor. + * @head: the head for your list. + */ +#define rt_list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * rt_list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the rt_list_t * to use as a loop cursor. + * @n: another rt_list_t * to use as temporary storage + * @head: the head for your list. + */ +#define rt_list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * rt_list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define rt_list_for_each_entry(pos, head, member) \ + for (pos = rt_list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = rt_list_entry(pos->member.next, typeof(*pos), member)) + +/** + * rt_list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define rt_list_for_each_entry_safe(pos, n, head, member) \ + for (pos = rt_list_entry((head)->next, typeof(*pos), member), \ + n = rt_list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = rt_list_entry(n->member.next, typeof(*n), member)) + +/** + * rt_list_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + * + * Note, that list is expected to be not empty. + */ +#define rt_list_first_entry(ptr, type, member) \ + rt_list_entry((ptr)->next, type, member) + +#define RT_SLIST_OBJECT_INIT(object) { RT_NULL } + +/** + * @brief initialize a single list + * + * @param l the single list to be initialized + */ +rt_inline void rt_slist_init(rt_slist_t *l) +{ + l->next = RT_NULL; +} + +rt_inline void rt_slist_append(rt_slist_t *l, rt_slist_t *n) +{ + struct rt_slist_node *node; + + node = l; + while (node->next) node = node->next; + + /* append the node to the tail */ + node->next = n; + n->next = RT_NULL; +} + +rt_inline void rt_slist_insert(rt_slist_t *l, rt_slist_t *n) +{ + n->next = l->next; + l->next = n; +} + +rt_inline unsigned int rt_slist_len(const rt_slist_t *l) +{ + unsigned int len = 0; + const rt_slist_t *list = l->next; + while (list != RT_NULL) + { + list = list->next; + len ++; + } + + return len; +} + +rt_inline rt_slist_t *rt_slist_remove(rt_slist_t *l, rt_slist_t *n) +{ + /* remove slist head */ + struct rt_slist_node *node = l; + while (node->next && node->next != n) node = node->next; + + /* remove node */ + if (node->next != (rt_slist_t *)0) node->next = node->next->next; + + return l; +} + +rt_inline rt_slist_t *rt_slist_first(rt_slist_t *l) +{ + return l->next; +} + +rt_inline rt_slist_t *rt_slist_tail(rt_slist_t *l) +{ + while (l->next) l = l->next; + + return l; +} + +rt_inline rt_slist_t *rt_slist_next(rt_slist_t *n) +{ + return n->next; +} + +rt_inline int rt_slist_isempty(rt_slist_t *l) +{ + return l->next == RT_NULL; +} + +/** + * @brief get the struct for this single list node + * @param node the entry point + * @param type the type of structure + * @param member the name of list in structure + */ +#define rt_slist_entry(node, type, member) \ + rt_container_of(node, type, member) + +/** + * rt_slist_for_each - iterate over a single list + * @pos: the rt_slist_t * to use as a loop cursor. + * @head: the head for your single list. + */ +#define rt_slist_for_each(pos, head) \ + for (pos = (head)->next; pos != RT_NULL; pos = pos->next) + +/** + * rt_slist_for_each_entry - iterate over single list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your single list. + * @member: the name of the list_struct within the struct. + */ +#define rt_slist_for_each_entry(pos, head, member) \ + for (pos = rt_slist_entry((head)->next, typeof(*pos), member); \ + &pos->member != (RT_NULL); \ + pos = rt_slist_entry(pos->member.next, typeof(*pos), member)) + +/** + * rt_slist_first_entry - get the first element from a slist + * @ptr: the slist head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the slist_struct within the struct. + * + * Note, that slist is expected to be not empty. + */ +#define rt_slist_first_entry(ptr, type, member) \ + rt_slist_entry((ptr)->next, type, member) + +/** + * rt_slist_tail_entry - get the tail element from a slist + * @ptr: the slist head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the slist_struct within the struct. + * + * Note, that slist is expected to be not empty. + */ +#define rt_slist_tail_entry(ptr, type, member) \ + rt_slist_entry(rt_slist_tail(ptr), type, member) + +/*@}*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/include/rtthread.h b/rt-thread/include/rtthread.h new file mode 100644 index 0000000..f8da2d4 --- /dev/null +++ b/rt-thread/include/rtthread.h @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : rtthread.h + * + * Change Logs: + * Date Author Notes + * 2006-03-18 Bernard the first version + * 2006-04-26 Bernard add semaphore APIs + * 2006-08-10 Bernard add version information + * 2007-01-28 Bernard rename RT_OBJECT_Class_Static to RT_Object_Class_Static + * 2007-03-03 Bernard clean up the definitions to rtdef.h + * 2010-04-11 yi.qiu add module feature + * 2013-06-24 Bernard add rt_kprintf re-define when not use RT_USING_CONSOLE. + * 2016-08-09 ArdaFu add new thread and interrupt hook. + */ + +#ifndef __RT_THREAD_H__ +#define __RT_THREAD_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup KernelObject + */ + +/**@{*/ + +/* + * kernel object interface + */ +void rt_system_object_init(void); +struct rt_object_information * +rt_object_get_information(enum rt_object_class_type type); +void rt_object_init(struct rt_object *object, + enum rt_object_class_type type, + const char *name); +void rt_object_detach(rt_object_t object); +rt_object_t rt_object_allocate(enum rt_object_class_type type, + const char *name); +void rt_object_delete(rt_object_t object); +rt_bool_t rt_object_is_systemobject(rt_object_t object); +rt_uint8_t rt_object_get_type(rt_object_t object); +rt_object_t rt_object_find(const char *name, rt_uint8_t type); + +#ifdef RT_USING_HOOK +void rt_object_attach_sethook(void (*hook)(struct rt_object *object)); +void rt_object_detach_sethook(void (*hook)(struct rt_object *object)); +void rt_object_trytake_sethook(void (*hook)(struct rt_object *object)); +void rt_object_take_sethook(void (*hook)(struct rt_object *object)); +void rt_object_put_sethook(void (*hook)(struct rt_object *object)); +#endif + +/**@}*/ + +/** + * @addtogroup Clock + */ + +/**@{*/ + +/* + * clock & timer interface + */ +void rt_system_tick_init(void); +rt_tick_t rt_tick_get(void); +void rt_tick_set(rt_tick_t tick); +void rt_tick_increase(void); +int rt_tick_from_millisecond(rt_int32_t ms); + +void rt_system_timer_init(void); +void rt_system_timer_thread_init(void); + +void rt_timer_init(rt_timer_t timer, + const char *name, + void (*timeout)(void *parameter), + void *parameter, + rt_tick_t time, + rt_uint8_t flag); +rt_err_t rt_timer_detach(rt_timer_t timer); +rt_timer_t rt_timer_create(const char *name, + void (*timeout)(void *parameter), + void *parameter, + rt_tick_t time, + rt_uint8_t flag); +rt_err_t rt_timer_delete(rt_timer_t timer); +rt_err_t rt_timer_start(rt_timer_t timer); +rt_err_t rt_timer_stop(rt_timer_t timer); +rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg); + +rt_tick_t rt_timer_next_timeout_tick(void); +void rt_timer_check(void); + +#ifdef RT_USING_HOOK +void rt_timer_timeout_sethook(void (*hook)(struct rt_timer *timer)); +#endif + +/**@}*/ + +/** + * @addtogroup Thread + */ + +/**@{*/ + +/* + * thread interface + */ +rt_err_t rt_thread_init(struct rt_thread *thread, + const char *name, + void (*entry)(void *parameter), + void *parameter, + void *stack_start, + rt_uint32_t stack_size, + rt_uint8_t priority, + rt_uint32_t tick); +rt_err_t rt_thread_detach(rt_thread_t thread); +rt_thread_t rt_thread_create(const char *name, + void (*entry)(void *parameter), + void *parameter, + rt_uint32_t stack_size, + rt_uint8_t priority, + rt_uint32_t tick); +rt_thread_t rt_thread_self(void); +rt_thread_t rt_thread_find(char *name); +rt_err_t rt_thread_startup(rt_thread_t thread); +rt_err_t rt_thread_delete(rt_thread_t thread); + +rt_err_t rt_thread_yield(void); +rt_err_t rt_thread_delay(rt_tick_t tick); +rt_err_t rt_thread_mdelay(rt_int32_t ms); +rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg); +rt_err_t rt_thread_suspend(rt_thread_t thread); +rt_err_t rt_thread_resume(rt_thread_t thread); +void rt_thread_timeout(void *parameter); + +#ifdef RT_USING_SIGNALS +void rt_thread_alloc_sig(rt_thread_t tid); +void rt_thread_free_sig(rt_thread_t tid); +int rt_thread_kill(rt_thread_t tid, int sig); +#endif + +#ifdef RT_USING_HOOK +void rt_thread_suspend_sethook(void (*hook)(rt_thread_t thread)); +void rt_thread_resume_sethook (void (*hook)(rt_thread_t thread)); +void rt_thread_inited_sethook (void (*hook)(rt_thread_t thread)); +#endif + +/* + * idle thread interface + */ +void rt_thread_idle_init(void); +#if defined(RT_USING_HOOK) || defined(RT_USING_IDLE_HOOK) +rt_err_t rt_thread_idle_sethook(void (*hook)(void)); +rt_err_t rt_thread_idle_delhook(void (*hook)(void)); +#endif +void rt_thread_idle_excute(void); +rt_thread_t rt_thread_idle_gethandler(void); + +/* + * schedule service + */ +void rt_system_scheduler_init(void); +void rt_system_scheduler_start(void); + +void rt_schedule(void); +void rt_schedule_insert_thread(struct rt_thread *thread); +void rt_schedule_remove_thread(struct rt_thread *thread); + +void rt_enter_critical(void); +void rt_exit_critical(void); +rt_uint16_t rt_critical_level(void); + +#ifdef RT_USING_HOOK +void rt_scheduler_sethook(void (*hook)(rt_thread_t from, rt_thread_t to)); +#endif + +/**@}*/ + +/** + * @addtogroup Signals + * @{ + */ +#ifdef RT_USING_SIGNALS +void rt_signal_mask(int signo); +void rt_signal_unmask(int signo); +rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler); +int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout); + +int rt_system_signal_init(void); +#endif +/*@}*/ + +/** + * @addtogroup MM + */ + +/**@{*/ + +/* + * memory management interface + */ +#ifdef RT_USING_MEMPOOL +/* + * memory pool interface + */ +rt_err_t rt_mp_init(struct rt_mempool *mp, + const char *name, + void *start, + rt_size_t size, + rt_size_t block_size); +rt_err_t rt_mp_detach(struct rt_mempool *mp); +rt_mp_t rt_mp_create(const char *name, + rt_size_t block_count, + rt_size_t block_size); +rt_err_t rt_mp_delete(rt_mp_t mp); + +void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time); +void rt_mp_free(void *block); + +#ifdef RT_USING_HOOK +void rt_mp_alloc_sethook(void (*hook)(struct rt_mempool *mp, void *block)); +void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block)); +#endif + +#endif + +#ifdef RT_USING_HEAP +/* + * heap memory interface + */ +void rt_system_heap_init(void *begin_addr, void *end_addr); + +void *rt_malloc(rt_size_t nbytes); +void rt_free(void *ptr); +void *rt_realloc(void *ptr, rt_size_t nbytes); +void *rt_calloc(rt_size_t count, rt_size_t size); +void *rt_malloc_align(rt_size_t size, rt_size_t align); +void rt_free_align(void *ptr); + +void rt_memory_info(rt_uint32_t *total, + rt_uint32_t *used, + rt_uint32_t *max_used); + +#ifdef RT_USING_SLAB +void *rt_page_alloc(rt_size_t npages); +void rt_page_free(void *addr, rt_size_t npages); +#endif + +#ifdef RT_USING_HOOK +void rt_malloc_sethook(void (*hook)(void *ptr, rt_uint32_t size)); +void rt_free_sethook(void (*hook)(void *ptr)); +#endif + +#endif + +#ifdef RT_USING_MEMHEAP +/** + * memory heap object interface + */ +rt_err_t rt_memheap_init(struct rt_memheap *memheap, + const char *name, + void *start_addr, + rt_uint32_t size); +rt_err_t rt_memheap_detach(struct rt_memheap *heap); +void *rt_memheap_alloc(struct rt_memheap *heap, rt_uint32_t size); +void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize); +void rt_memheap_free(void *ptr); +#endif + +/**@}*/ + +/** + * @addtogroup IPC + */ + +/**@{*/ + +#ifdef RT_USING_SEMAPHORE +/* + * semaphore interface + */ +rt_err_t rt_sem_init(rt_sem_t sem, + const char *name, + rt_uint32_t value, + rt_uint8_t flag); +rt_err_t rt_sem_detach(rt_sem_t sem); +rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag); +rt_err_t rt_sem_delete(rt_sem_t sem); + +rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time); +rt_err_t rt_sem_trytake(rt_sem_t sem); +rt_err_t rt_sem_release(rt_sem_t sem); +rt_err_t rt_sem_control(rt_sem_t sem, int cmd, void *arg); +#endif + +#ifdef RT_USING_MUTEX +/* + * mutex interface + */ +rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag); +rt_err_t rt_mutex_detach(rt_mutex_t mutex); +rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag); +rt_err_t rt_mutex_delete(rt_mutex_t mutex); + +rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time); +rt_err_t rt_mutex_release(rt_mutex_t mutex); +rt_err_t rt_mutex_control(rt_mutex_t mutex, int cmd, void *arg); +#endif + +#ifdef RT_USING_EVENT +/* + * event interface + */ +rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag); +rt_err_t rt_event_detach(rt_event_t event); +rt_event_t rt_event_create(const char *name, rt_uint8_t flag); +rt_err_t rt_event_delete(rt_event_t event); + +rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set); +rt_err_t rt_event_recv(rt_event_t event, + rt_uint32_t set, + rt_uint8_t opt, + rt_int32_t timeout, + rt_uint32_t *recved); +rt_err_t rt_event_control(rt_event_t event, int cmd, void *arg); +#endif + +#ifdef RT_USING_MAILBOX +/* + * mailbox interface + */ +rt_err_t rt_mb_init(rt_mailbox_t mb, + const char *name, + void *msgpool, + rt_size_t size, + rt_uint8_t flag); +rt_err_t rt_mb_detach(rt_mailbox_t mb); +rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag); +rt_err_t rt_mb_delete(rt_mailbox_t mb); + +rt_err_t rt_mb_send(rt_mailbox_t mb, rt_uint32_t value); +rt_err_t rt_mb_send_wait(rt_mailbox_t mb, + rt_uint32_t value, + rt_int32_t timeout); +rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_uint32_t *value, rt_int32_t timeout); +rt_err_t rt_mb_control(rt_mailbox_t mb, int cmd, void *arg); +#endif + +#ifdef RT_USING_MESSAGEQUEUE +/* + * message queue interface + */ +rt_err_t rt_mq_init(rt_mq_t mq, + const char *name, + void *msgpool, + rt_size_t msg_size, + rt_size_t pool_size, + rt_uint8_t flag); +rt_err_t rt_mq_detach(rt_mq_t mq); +rt_mq_t rt_mq_create(const char *name, + rt_size_t msg_size, + rt_size_t max_msgs, + rt_uint8_t flag); +rt_err_t rt_mq_delete(rt_mq_t mq); + +rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size); +rt_err_t rt_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size); +rt_err_t rt_mq_recv(rt_mq_t mq, + void *buffer, + rt_size_t size, + rt_int32_t timeout); +rt_err_t rt_mq_control(rt_mq_t mq, int cmd, void *arg); +#endif + +/**@}*/ + +#ifdef RT_USING_DEVICE +/** + * @addtogroup Device + */ + +/**@{*/ + +/* + * device (I/O) system interface + */ +rt_device_t rt_device_find(const char *name); + +rt_err_t rt_device_register(rt_device_t dev, + const char *name, + rt_uint16_t flags); +rt_err_t rt_device_unregister(rt_device_t dev); + +rt_device_t rt_device_create(int type, int attach_size); +void rt_device_destroy(rt_device_t device); + +rt_err_t rt_device_init_all(void); + +rt_err_t +rt_device_set_rx_indicate(rt_device_t dev, + rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size)); +rt_err_t +rt_device_set_tx_complete(rt_device_t dev, + rt_err_t (*tx_done)(rt_device_t dev, void *buffer)); + +rt_err_t rt_device_init (rt_device_t dev); +rt_err_t rt_device_open (rt_device_t dev, rt_uint16_t oflag); +rt_err_t rt_device_close(rt_device_t dev); +rt_size_t rt_device_read (rt_device_t dev, + rt_off_t pos, + void *buffer, + rt_size_t size); +rt_size_t rt_device_write(rt_device_t dev, + rt_off_t pos, + const void *buffer, + rt_size_t size); +rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg); + +/**@}*/ +#endif + +/* + * interrupt service + */ + +/* + * rt_interrupt_enter and rt_interrupt_leave only can be called by BSP + */ +void rt_interrupt_enter(void); +void rt_interrupt_leave(void); + +/* + * the number of nested interrupts. + */ +rt_uint8_t rt_interrupt_get_nest(void); + +#ifdef RT_USING_HOOK +void rt_interrupt_enter_sethook(void (*hook)(void)); +void rt_interrupt_leave_sethook(void (*hook)(void)); +#endif + +#ifdef RT_USING_COMPONENTS_INIT +void rt_components_init(void); +void rt_components_board_init(void); +#endif + +/** + * @addtogroup KernelService + */ + +/**@{*/ + +/* + * general kernel service + */ +#ifndef RT_USING_CONSOLE +#define rt_kprintf(...) +#define rt_kputs(str) +#else +void rt_kprintf(const char *fmt, ...); +void rt_kputs(const char *str); +#endif +rt_int32_t rt_vsprintf(char *dest, const char *format, va_list arg_ptr); +rt_int32_t rt_vsnprintf(char *buf, rt_size_t size, const char *fmt, va_list args); +rt_int32_t rt_sprintf(char *buf, const char *format, ...); +rt_int32_t rt_snprintf(char *buf, rt_size_t size, const char *format, ...); + +#if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE) +rt_device_t rt_console_set_device(const char *name); +rt_device_t rt_console_get_device(void); +#endif + +rt_err_t rt_get_errno(void); +void rt_set_errno(rt_err_t no); +int *_rt_errno(void); +#if !defined(RT_USING_NEWLIB) && !defined(_WIN32) +#ifndef errno +#define errno *_rt_errno() +#endif +#endif + +int __rt_ffs(int value); + +void *rt_memset(void *src, int c, rt_ubase_t n); +void *rt_memcpy(void *dest, const void *src, rt_ubase_t n); + +rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_ubase_t count); +rt_int32_t rt_strcmp(const char *cs, const char *ct); +rt_size_t rt_strlen(const char *src); +char *rt_strdup(const char *s); +#if defined(__CC_ARM) || defined(__CLANG_ARM) +/* leak strdup interface */ +char* strdup(const char* str); +#endif + +char *rt_strstr(const char *str1, const char *str2); +rt_int32_t rt_sscanf(const char *buf, const char *fmt, ...); +char *rt_strncpy(char *dest, const char *src, rt_ubase_t n); +void *rt_memmove(void *dest, const void *src, rt_ubase_t n); +rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_ubase_t count); +rt_uint32_t rt_strcasecmp(const char *a, const char *b); + +void rt_show_version(void); + +#ifdef RT_DEBUG +extern void (*rt_assert_hook)(const char *ex, const char *func, rt_size_t line); +void rt_assert_set_hook(void (*hook)(const char *ex, const char *func, rt_size_t line)); + +void rt_assert_handler(const char *ex, const char *func, rt_size_t line); +#endif /* RT_DEBUG */ + +#ifdef RT_USING_FINSH +#include +#endif + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/libcpu/Kconfig b/rt-thread/libcpu/Kconfig new file mode 100644 index 0000000..0a280d4 --- /dev/null +++ b/rt-thread/libcpu/Kconfig @@ -0,0 +1,90 @@ +config ARCH_ARM + bool + +config ARCH_ARM_CORTEX_M + bool + select ARCH_ARM + +config ARCH_ARM_CORTEX_FPU + bool + +config ARCH_ARM_CORTEX_M0 + bool + select ARCH_ARM_CORTEX_M + +config ARCH_ARM_CORTEX_M3 + bool + select ARCH_ARM_CORTEX_M + +config ARCH_ARM_MPU + bool + depends on ARCH_ARM + +config ARCH_ARM_CORTEX_M4 + bool + select ARCH_ARM_CORTEX_M + +config ARCH_ARM_CORTEX_M7 + bool + select ARCH_ARM_CORTEX_M + +config ARCH_ARM_CORTEX_R + bool + select ARCH_ARM + +config ARCH_ARM_MMU + bool + depends on ARCH_ARM + +config ARCH_ARM_ARM9 + bool + select ARCH_ARM + +config ARCH_ARM_ARM11 + bool + select ARCH_ARM + +config ARCH_ARM_CORTEX_A + bool + select ARCH_ARM + +config ARCH_ARM_CORTEX_A5 + bool + select ARCH_ARM_CORTEX_A + +config ARCH_ARM_CORTEX_A7 + bool + select ARCH_ARM_CORTEX_A + +config ARCH_ARM_CORTEX_A8 + bool + select ARCH_ARM_CORTEX_A + +config ARCH_ARM_CORTEX_A9 + bool + select ARCH_ARM_CORTEX_A + +config ARCH_MIPS + bool + +config ARCH_MIPS_XBURST + bool + select ARCH_MIPS + +config ARCH_ANDES + bool + +config ARCH_CSKY + bool + +config ARCH_POWERPC + bool + +config ARCH_RISCV + bool + +config ARCH_IA32 + bool + +config ARCH_HOST_SIMULATOR + bool diff --git a/rt-thread/libcpu/SConscript b/rt-thread/libcpu/SConscript new file mode 100644 index 0000000..a42909e --- /dev/null +++ b/rt-thread/libcpu/SConscript @@ -0,0 +1,31 @@ +Import('RTT_ROOT') +Import('rtconfig') +from building import * + +comm = rtconfig.ARCH + '/common' +path = rtconfig.ARCH + '/' + rtconfig.CPU +ASFLAGS = '' + +# The set of source files associated with this SConscript file. +if rtconfig.PLATFORM == 'armcc': + src = Glob(path + '/*.c') + Glob(path + '/*_rvds.S') + Glob(comm + '/*.c') + +if rtconfig.PLATFORM == 'gcc': + src = Glob(path + '/*.c') + Glob(path + '/*_gcc.S') + Glob(comm + '/*.c') + Glob(path + '/*_init.S') + +if rtconfig.PLATFORM == 'iar': + src = Glob(path + '/*.c') + Glob(path + '/*_iar.S') + Glob(comm + '/*.c') + +if rtconfig.PLATFORM == 'cl': + src = Glob(path + '/*.c') + +if rtconfig.PLATFORM == 'mingw': + src = Glob(path + '/*.c') + +if rtconfig.PLATFORM == 'armcc' and rtconfig.ARCH == 'arm' and rtconfig.CPU == 'arm926': + ASFLAGS = ' --cpreproc' + +CPPPATH = [RTT_ROOT + '/libcpu/' + rtconfig.ARCH + '/' + rtconfig.CPU, RTT_ROOT + '/libcpu/' + rtconfig.ARCH + '/common'] +group = DefineGroup(rtconfig.CPU.upper(), src, depend = [''], CPPPATH = CPPPATH, ASFLAGS = ASFLAGS) + +Return('group') diff --git a/rt-thread/libcpu/arm/AT91SAM7S/AT91SAM7S.h b/rt-thread/libcpu/arm/AT91SAM7S/AT91SAM7S.h new file mode 100644 index 0000000..0c8d652 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/AT91SAM7S.h @@ -0,0 +1,297 @@ +/* + * File : at91sam7s.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-08-23 Bernard first version + */ + +#ifndef __AT91SAM7S_H__ +#define __AT91SAM7S_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define AT91_REG *(volatile unsigned int *) /* Hardware register definition */ + +/* ========== Register definition for TC0 peripheral ========== */ +#define AT91C_TC0_SR (AT91_REG(0xFFFA0020)) /* TC0 Status Register */ +#define AT91C_TC0_RC (AT91_REG(0xFFFA001C)) /* TC0 Register C */ +#define AT91C_TC0_RB (AT91_REG(0xFFFA0018)) /* TC0 Register B */ +#define AT91C_TC0_CCR (AT91_REG(0xFFFA0000)) /* TC0 Channel Control Register */ +#define AT91C_TC0_CMR (AT91_REG(0xFFFA0004)) /* TC0 Channel Mode Register (Capture Mode / Waveform Mode) */ +#define AT91C_TC0_IER (AT91_REG(0xFFFA0024)) /* TC0 Interrupt Enable Register */ +#define AT91C_TC0_RA (AT91_REG(0xFFFA0014)) /* TC0 Register A */ +#define AT91C_TC0_IDR (AT91_REG(0xFFFA0028)) /* TC0 Interrupt Disable Register */ +#define AT91C_TC0_CV (AT91_REG(0xFFFA0010)) /* TC0 Counter Value */ +#define AT91C_TC0_IMR (AT91_REG(0xFFFA002C)) /* TC0 Interrupt Mask Register */ + +/* ========== Register definition for TC1 peripheral ========== */ +#define AT91C_TC1_RB (AT91_REG(0xFFFA0058)) /* TC1 Register B */ +#define AT91C_TC1_CCR (AT91_REG(0xFFFA0040)) /* TC1 Channel Control Register */ +#define AT91C_TC1_IER (AT91_REG(0xFFFA0064)) /* TC1 Interrupt Enable Register */ +#define AT91C_TC1_IDR (AT91_REG(0xFFFA0068)) /* TC1 Interrupt Disable Register */ +#define AT91C_TC1_SR (AT91_REG(0xFFFA0060)) /* TC1 Status Register */ +#define AT91C_TC1_CMR (AT91_REG(0xFFFA0044)) /* TC1 Channel Mode Register (Capture Mode / Waveform Mode) */ +#define AT91C_TC1_RA (AT91_REG(0xFFFA0054)) /* TC1 Register A */ +#define AT91C_TC1_RC (AT91_REG(0xFFFA005C)) /* TC1 Register C */ +#define AT91C_TC1_IMR (AT91_REG(0xFFFA006C)) /* TC1 Interrupt Mask Register */ +#define AT91C_TC1_CV (AT91_REG(0xFFFA0050)) /* TC1 Counter Value */ + +/* ========== Register definition for TC2 peripheral ========== */ +#define AT91C_TC2_CMR (AT91_REG(0xFFFA0084)) /* TC2 Channel Mode Register (Capture Mode / Waveform Mode) */ +#define AT91C_TC2_CCR (AT91_REG(0xFFFA0080)) /* TC2 Channel Control Register */ +#define AT91C_TC2_CV (AT91_REG(0xFFFA0090)) /* TC2 Counter Value */ +#define AT91C_TC2_RA (AT91_REG(0xFFFA0094)) /* TC2 Register A */ +#define AT91C_TC2_RB (AT91_REG(0xFFFA0098)) /* TC2 Register B */ +#define AT91C_TC2_IDR (AT91_REG(0xFFFA00A8)) /* TC2 Interrupt Disable Register */ +#define AT91C_TC2_IMR (AT91_REG(0xFFFA00AC)) /* TC2 Interrupt Mask Register */ +#define AT91C_TC2_RC (AT91_REG(0xFFFA009C)) /* TC2 Register C */ +#define AT91C_TC2_IER (AT91_REG(0xFFFA00A4)) /* TC2 Interrupt Enable Register */ +#define AT91C_TC2_SR (AT91_REG(0xFFFA00A0)) /* TC2 Status Register */ + +/* ========== Register definition for PITC peripheral ========== */ +#define AT91C_PITC_PIVR (AT91_REG(0xFFFFFD38)) /* PITC Period Interval Value Register */ +#define AT91C_PITC_PISR (AT91_REG(0xFFFFFD34)) /* PITC Period Interval Status Register */ +#define AT91C_PITC_PIIR (AT91_REG(0xFFFFFD3C)) /* PITC Period Interval Image Register */ +#define AT91C_PITC_PIMR (AT91_REG(0xFFFFFD30)) /* PITC Period Interval Mode Register */ + +/* ========== Register definition for UDP peripheral ========== */ +#define AT91C_UDP_NUM (AT91_REG(0xFFFB0000)) /* UDP Frame Number Register */ +#define AT91C_UDP_STAT (AT91_REG(0xFFFB0004)) /* UDP Global State Register */ +#define AT91C_UDP_FADDR (AT91_REG(0xFFFB0008)) /* UDP Function Address Register */ +#define AT91C_UDP_IER (AT91_REG(0xFFFB0010)) /* UDP Interrupt Enable Register */ +#define AT91C_UDP_IDR (AT91_REG(0xFFFB0014)) /* UDP Interrupt Disable Register */ +#define AT91C_UDP_IMR (AT91_REG(0xFFFB0018)) /* UDP Interrupt Mask Register */ +#define AT91C_UDP_ISR (AT91_REG(0xFFFB001C)) /* UDP Interrupt Status Register */ +#define AT91C_UDP_ICR (AT91_REG(0xFFFB0020)) /* UDP Interrupt Clear Register */ +#define AT91C_UDP_RSTEP (AT91_REG(0xFFFB0028)) /* UDP Reset Endpoint Register */ +#define AT91C_UDP_CSR0 (AT91_REG(0xFFFB0030)) /* UDP Endpoint Control and Status Register */ +#define AT91C_UDP_CSR(n) (*(&AT91C_UDP_CSR0 + n)) +#define AT91C_UDP_FDR0 (AT91_REG(0xFFFB0050)) /* UDP Endpoint FIFO Data Register */ +#define AT91C_UDP_FDR(n) (*(&AT91C_UDP_FDR0 + n)) +#define AT91C_UDP_TXVC (AT91_REG(0xFFFB0074)) /* UDP Transceiver Control Register */ + +/* ========== Register definition for US0 peripheral ========== */ +#define AT91C_US0_CR (AT91_REG(0xFFFC0000)) /* US0 Control Register */ +#define AT91C_US0_MR (AT91_REG(0xFFFC0004)) /* US0 Mode Register */ +#define AT91C_US0_IER (AT91_REG(0xFFFC0008)) /* US0 Interrupt Enable Register */ +#define AT91C_US0_IDR (AT91_REG(0xFFFC000C)) /* US0 Interrupt Disable Register */ +#define AT91C_US0_IMR (AT91_REG(0xFFFC0010)) /* US0 Interrupt Mask Register */ +#define AT91C_US0_CSR (AT91_REG(0xFFFC0014)) /* US0 Channel Status Register */ +#define AT91C_US0_RHR (AT91_REG(0xFFFC0018)) /* US0 Receiver Holding Register */ +#define AT91C_US0_THR (AT91_REG(0xFFFC001C)) /* US0 Transmitter Holding Register */ +#define AT91C_US0_BRGR (AT91_REG(0xFFFC0020)) /* US0 Baud Rate Generator Register */ +#define AT91C_US0_RTOR (AT91_REG(0xFFFC0024)) /* US0 Receiver Time-out Register */ +#define AT91C_US0_TTGR (AT91_REG(0xFFFC0028)) /* US0 Transmitter Time-guard Register */ +#define AT91C_US0_NER (AT91_REG(0xFFFC0044)) /* US0 Nb Errors Register */ +#define AT91C_US0_FIDI (AT91_REG(0xFFFC0040)) /* US0 FI_DI_Ratio Register */ +#define AT91C_US0_IF (AT91_REG(0xFFFC004C)) /* US0 IRDA_FILTER Register */ + +/* ========== Register definition for AIC peripheral ========== */ +#define AT91C_AIC_SMR0 (AT91_REG(0xFFFFF000)) /* AIC Source Mode Register */ +#define AT91C_AIC_SMR(n) (*(&AT91C_AIC_SMR0 + n)) +#define AT91C_AIC_SVR0 (AT91_REG(0xFFFFF080)) /* AIC Source Vector Register */ +#define AT91C_AIC_SVR(n) (*(&AT91C_AIC_SVR0 + n)) +#define AT91C_AIC_IVR (AT91_REG(0xFFFFF100)) /* AIC Interrupt Vector Register */ +#define AT91C_AIC_FVR (AT91_REG(0xFFFFF104)) /* AIC FIQ Vector Register */ +#define AT91C_AIC_ISR (AT91_REG(0xFFFFF108)) /* AIC Interrupt Status Register */ +#define AT91C_AIC_IPR (AT91_REG(0xFFFFF10C)) /* AIC Interrupt Pending Register */ +#define AT91C_AIC_IMR (AT91_REG(0xFFFFF110)) /* AIC Interrupt Mask Register */ +#define AT91C_AIC_CISR (AT91_REG(0xFFFFF114)) /* AIC Core Interrupt Status Register */ +#define AT91C_AIC_IECR (AT91_REG(0xFFFFF120)) /* AIC Interrupt Enable Command Register */ +#define AT91C_AIC_IDCR (AT91_REG(0xFFFFF124)) /* AIC Interrupt Disable Command Register */ +#define AT91C_AIC_ICCR (AT91_REG(0xFFFFF128)) /* AIC Interrupt Clear Command Register */ +#define AT91C_AIC_ISCR (AT91_REG(0xFFFFF12C)) /* AIC Interrupt Set Command Register */ +#define AT91C_AIC_EOICR (AT91_REG(0xFFFFF130)) /* AIC End of Interrupt Command Register */ +#define AT91C_AIC_SPU (AT91_REG(0xFFFFF134)) /* AIC Spurious Vector Register */ +#define AT91C_AIC_DCR (AT91_REG(0xFFFFF138)) /* AIC Debug Control Register (Protect) */ +#define AT91C_AIC_FFER (AT91_REG(0xFFFFF140)) /* AIC Fast Forcing Enable Register */ +#define AT91C_AIC_FFDR (AT91_REG(0xFFFFF144)) /* AIC Fast Forcing Disable Register */ +#define AT91C_AIC_FFSR (AT91_REG(0xFFFFF148)) /* AIC Fast Forcing Status Register */ + + +/* ========== Register definition for DBGU peripheral ========== */ +#define AT91C_DBGU_EXID (AT91_REG(0xFFFFF244)) /* DBGU Chip ID Extension Register */ +#define AT91C_DBGU_BRGR (AT91_REG(0xFFFFF220)) /* DBGU Baud Rate Generator Register */ +#define AT91C_DBGU_IDR (AT91_REG(0xFFFFF20C)) /* DBGU Interrupt Disable Register */ +#define AT91C_DBGU_CSR (AT91_REG(0xFFFFF214)) /* DBGU Channel Status Register */ +#define AT91C_DBGU_CIDR (AT91_REG(0xFFFFF240)) /* DBGU Chip ID Register */ +#define AT91C_DBGU_MR (AT91_REG(0xFFFFF204)) /* DBGU Mode Register */ +#define AT91C_DBGU_IMR (AT91_REG(0xFFFFF210)) /* DBGU Interrupt Mask Register */ +#define AT91C_DBGU_CR (AT91_REG(0xFFFFF200)) /* DBGU Control Register */ +#define AT91C_DBGU_FNTR (AT91_REG(0xFFFFF248)) /* DBGU Force NTRST Register */ +#define AT91C_DBGU_THR (AT91_REG(0xFFFFF21C)) /* DBGU Transmitter Holding Register */ +#define AT91C_DBGU_RHR (AT91_REG(0xFFFFF218)) /* DBGU Receiver Holding Register */ +#define AT91C_DBGU_IER (AT91_REG(0xFFFFF208)) /* DBGU Interrupt Enable Register */ + +/* ========== Register definition for PIO peripheral ========== */ +#define AT91C_PIO_ODR (AT91_REG(0xFFFFF414)) /* PIOA Output Disable Registerr */ +#define AT91C_PIO_SODR (AT91_REG(0xFFFFF430)) /* PIOA Set Output Data Register */ +#define AT91C_PIO_ISR (AT91_REG(0xFFFFF44C)) /* PIOA Interrupt Status Register */ +#define AT91C_PIO_ABSR (AT91_REG(0xFFFFF478)) /* PIOA AB Select Status Register */ +#define AT91C_PIO_IER (AT91_REG(0xFFFFF440)) /* PIOA Interrupt Enable Register */ +#define AT91C_PIO_PPUDR (AT91_REG(0xFFFFF460)) /* PIOA Pull-up Disable Register */ +#define AT91C_PIO_IMR (AT91_REG(0xFFFFF448)) /* PIOA Interrupt Mask Register */ +#define AT91C_PIO_PER (AT91_REG(0xFFFFF400)) /* PIOA PIO Enable Register */ +#define AT91C_PIO_IFDR (AT91_REG(0xFFFFF424)) /* PIOA Input Filter Disable Register */ +#define AT91C_PIO_OWDR (AT91_REG(0xFFFFF4A4)) /* PIOA Output Write Disable Register */ +#define AT91C_PIO_MDSR (AT91_REG(0xFFFFF458)) /* PIOA Multi-driver Status Register */ +#define AT91C_PIO_IDR (AT91_REG(0xFFFFF444)) /* PIOA Interrupt Disable Register */ +#define AT91C_PIO_ODSR (AT91_REG(0xFFFFF438)) /* PIOA Output Data Status Register */ +#define AT91C_PIO_PPUSR (AT91_REG(0xFFFFF468)) /* PIOA Pull-up Status Register */ +#define AT91C_PIO_OWSR (AT91_REG(0xFFFFF4A8)) /* PIOA Output Write Status Register */ +#define AT91C_PIO_BSR (AT91_REG(0xFFFFF474)) /* PIOA Select B Register */ +#define AT91C_PIO_OWER (AT91_REG(0xFFFFF4A0)) /* PIOA Output Write Enable Register */ +#define AT91C_PIO_IFER (AT91_REG(0xFFFFF420)) /* PIOA Input Filter Enable Register */ +#define AT91C_PIO_PDSR (AT91_REG(0xFFFFF43C)) /* PIOA Pin Data Status Register */ +#define AT91C_PIO_PPUER (AT91_REG(0xFFFFF464)) /* PIOA Pull-up Enable Register */ +#define AT91C_PIO_OSR (AT91_REG(0xFFFFF418)) /* PIOA Output Status Register */ +#define AT91C_PIO_ASR (AT91_REG(0xFFFFF470)) /* PIOA Select A Register */ +#define AT91C_PIO_MDDR (AT91_REG(0xFFFFF454)) /* PIOA Multi-driver Disable Register */ +#define AT91C_PIO_CODR (AT91_REG(0xFFFFF434)) /* PIOA Clear Output Data Register */ +#define AT91C_PIO_MDER (AT91_REG(0xFFFFF450)) /* PIOA Multi-driver Enable Register */ +#define AT91C_PIO_PDR (AT91_REG(0xFFFFF404)) /* PIOA PIO Disable Register */ +#define AT91C_PIO_IFSR (AT91_REG(0xFFFFF428)) /* PIOA Input Filter Status Register */ +#define AT91C_PIO_OER (AT91_REG(0xFFFFF410)) /* PIOA Output Enable Register */ +#define AT91C_PIO_PSR (AT91_REG(0xFFFFF408)) /* PIOA PIO Status Register */ + +// ========== Register definition for PIOA peripheral ========== +#define AT91C_PIOA_IMR (AT91_REG(0xFFFFF448)) // (PIOA) Interrupt Mask Register +#define AT91C_PIOA_IER (AT91_REG(0xFFFFF440)) // (PIOA) Interrupt Enable Register +#define AT91C_PIOA_OWDR (AT91_REG(0xFFFFF4A4)) // (PIOA) Output Write Disable Register +#define AT91C_PIOA_ISR (AT91_REG(0xFFFFF44C)) // (PIOA) Interrupt Status Register +#define AT91C_PIOA_PPUDR (AT91_REG(0xFFFFF460)) // (PIOA) Pull-up Disable Register +#define AT91C_PIOA_MDSR (AT91_REG(0xFFFFF458)) // (PIOA) Multi-driver Status Register +#define AT91C_PIOA_MDER (AT91_REG(0xFFFFF450)) // (PIOA) Multi-driver Enable Register +#define AT91C_PIOA_PER (AT91_REG(0xFFFFF400)) // (PIOA) PIO Enable Register +#define AT91C_PIOA_PSR (AT91_REG(0xFFFFF408)) // (PIOA) PIO Status Register +#define AT91C_PIOA_OER (AT91_REG(0xFFFFF410)) // (PIOA) Output Enable Register +#define AT91C_PIOA_BSR (AT91_REG(0xFFFFF474)) // (PIOA) Select B Register +#define AT91C_PIOA_PPUER (AT91_REG(0xFFFFF464)) // (PIOA) Pull-up Enable Register +#define AT91C_PIOA_MDDR (AT91_REG(0xFFFFF454)) // (PIOA) Multi-driver Disable Register +#define AT91C_PIOA_PDR (AT91_REG(0xFFFFF404)) // (PIOA) PIO Disable Register +#define AT91C_PIOA_ODR (AT91_REG(0xFFFFF414)) // (PIOA) Output Disable Registerr +#define AT91C_PIOA_IFDR (AT91_REG(0xFFFFF424)) // (PIOA) Input Filter Disable Register +#define AT91C_PIOA_ABSR (AT91_REG(0xFFFFF478)) // (PIOA) AB Select Status Register +#define AT91C_PIOA_ASR (AT91_REG(0xFFFFF470)) // (PIOA) Select A Register +#define AT91C_PIOA_PPUSR (AT91_REG(0xFFFFF468)) // (PIOA) Pull-up Status Register +#define AT91C_PIOA_ODSR (AT91_REG(0xFFFFF438)) // (PIOA) Output Data Status Register +#define AT91C_PIOA_SODR (AT91_REG(0xFFFFF430)) // (PIOA) Set Output Data Register +#define AT91C_PIOA_IFSR (AT91_REG(0xFFFFF428)) // (PIOA) Input Filter Status Register +#define AT91C_PIOA_IFER (AT91_REG(0xFFFFF420)) // (PIOA) Input Filter Enable Register +#define AT91C_PIOA_OSR (AT91_REG(0xFFFFF418)) // (PIOA) Output Status Register +#define AT91C_PIOA_IDR (AT91_REG(0xFFFFF444)) // (PIOA) Interrupt Disable Register +#define AT91C_PIOA_PDSR (AT91_REG(0xFFFFF43C)) // (PIOA) Pin Data Status Register +#define AT91C_PIOA_CODR (AT91_REG(0xFFFFF434)) // (PIOA) Clear Output Data Register +#define AT91C_PIOA_OWSR (AT91_REG(0xFFFFF4A8)) // (PIOA) Output Write Status Register +#define AT91C_PIOA_OWER (AT91_REG(0xFFFFF4A0)) // (PIOA) Output Write Enable Register +// ========== Register definition for PIOB peripheral ========== +#define AT91C_PIOB_OWSR (AT91_REG(0xFFFFF6A8)) // (PIOB) Output Write Status Register +#define AT91C_PIOB_PPUSR (AT91_REG(0xFFFFF668)) // (PIOB) Pull-up Status Register +#define AT91C_PIOB_PPUDR (AT91_REG(0xFFFFF660)) // (PIOB) Pull-up Disable Register +#define AT91C_PIOB_MDSR (AT91_REG(0xFFFFF658)) // (PIOB) Multi-driver Status Register +#define AT91C_PIOB_MDER (AT91_REG(0xFFFFF650)) // (PIOB) Multi-driver Enable Register +#define AT91C_PIOB_IMR (AT91_REG(0xFFFFF648)) // (PIOB) Interrupt Mask Register +#define AT91C_PIOB_OSR (AT91_REG(0xFFFFF618)) // (PIOB) Output Status Register +#define AT91C_PIOB_OER (AT91_REG(0xFFFFF610)) // (PIOB) Output Enable Register +#define AT91C_PIOB_PSR (AT91_REG(0xFFFFF608)) // (PIOB) PIO Status Register +#define AT91C_PIOB_PER (AT91_REG(0xFFFFF600)) // (PIOB) PIO Enable Register +#define AT91C_PIOB_BSR (AT91_REG(0xFFFFF674)) // (PIOB) Select B Register +#define AT91C_PIOB_PPUER (AT91_REG(0xFFFFF664)) // (PIOB) Pull-up Enable Register +#define AT91C_PIOB_IFDR (AT91_REG(0xFFFFF624)) // (PIOB) Input Filter Disable Register +#define AT91C_PIOB_ODR (AT91_REG(0xFFFFF614)) // (PIOB) Output Disable Registerr +#define AT91C_PIOB_ABSR (AT91_REG(0xFFFFF678)) // (PIOB) AB Select Status Register +#define AT91C_PIOB_ASR (AT91_REG(0xFFFFF670)) // (PIOB) Select A Register +#define AT91C_PIOB_IFER (AT91_REG(0xFFFFF620)) // (PIOB) Input Filter Enable Register +#define AT91C_PIOB_IFSR (AT91_REG(0xFFFFF628)) // (PIOB) Input Filter Status Register +#define AT91C_PIOB_SODR (AT91_REG(0xFFFFF630)) // (PIOB) Set Output Data Register +#define AT91C_PIOB_ODSR (AT91_REG(0xFFFFF638)) // (PIOB) Output Data Status Register +#define AT91C_PIOB_CODR (AT91_REG(0xFFFFF634)) // (PIOB) Clear Output Data Register +#define AT91C_PIOB_PDSR (AT91_REG(0xFFFFF63C)) // (PIOB) Pin Data Status Register +#define AT91C_PIOB_OWER (AT91_REG(0xFFFFF6A0)) // (PIOB) Output Write Enable Register +#define AT91C_PIOB_IER (AT91_REG(0xFFFFF640)) // (PIOB) Interrupt Enable Register +#define AT91C_PIOB_OWDR (AT91_REG(0xFFFFF6A4)) // (PIOB) Output Write Disable Register +#define AT91C_PIOB_MDDR (AT91_REG(0xFFFFF654)) // (PIOB) Multi-driver Disable Register +#define AT91C_PIOB_ISR (AT91_REG(0xFFFFF64C)) // (PIOB) Interrupt Status Register +#define AT91C_PIOB_IDR (AT91_REG(0xFFFFF644)) // (PIOB) Interrupt Disable Register +#define AT91C_PIOB_PDR (AT91_REG(0xFFFFF604)) // (PIOB) PIO Disable Register + +/* ========== Register definition for PMC peripheral ========== */ +#define AT91C_PMC_SCER (AT91_REG(0xFFFFFC00)) /* PMC System Clock Enable Register */ +#define AT91C_PMC_SCDR (AT91_REG(0xFFFFFC04)) /* PMC System Clock Disable Register */ +#define AT91C_PMC_SCSR (AT91_REG(0xFFFFFC08)) /* PMC System Clock Status Register */ +#define AT91C_PMC_PCER (AT91_REG(0xFFFFFC10)) /* PMC Peripheral Clock Enable Register */ +#define AT91C_PMC_PCDR (AT91_REG(0xFFFFFC14)) /* PMC Peripheral Clock Disable Register */ +#define AT91C_PMC_PCSR (AT91_REG(0xFFFFFC18)) /* PMC Peripheral Clock Status Register */ +#define AT91C_PMC_MOR (AT91_REG(0xFFFFFC20)) /* PMC Main Oscillator Register */ +#define AT91C_PMC_MCFR (AT91_REG(0xFFFFFC24)) /* PMC Main Clock Frequency Register */ +#define AT91C_PMC_PLLR (AT91_REG(0xFFFFFC2C)) /* PMC PLL Register */ +#define AT91C_PMC_MCKR (AT91_REG(0xFFFFFC30)) /* PMC Master Clock Register */ +#define AT91C_PMC_PCKR (AT91_REG(0xFFFFFC40)) /* PMC Programmable Clock Register */ +#define AT91C_PMC_IER (AT91_REG(0xFFFFFC60)) /* PMC Interrupt Enable Register */ +#define AT91C_PMC_IDR (AT91_REG(0xFFFFFC64)) /* PMC Interrupt Disable Register */ +#define AT91C_PMC_SR (AT91_REG(0xFFFFFC68)) /* PMC Status Register */ +#define AT91C_PMC_IMR (AT91_REG(0xFFFFFC6C)) /* PMC Interrupt Mask Register */ + +/******************************************************************************/ +/* PERIPHERAL ID DEFINITIONS FOR AT91SAM7S64 */ +/******************************************************************************/ +#define AT91C_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */ +#define AT91C_ID_SYS 1 /* System Peripheral */ +#define AT91C_ID_PIOA 2 /* Parallel IO Controller A */ +#define AT91C_ID_PIOB 3 /* Parallel IO Controller B */ +#define AT91C_ID_ADC 4 /* Analog-to-Digital Converter */ +#define AT91C_ID_SPI 5 /* Serial Peripheral Interface */ +#define AT91C_ID_US0 6 /* USART 0 */ +#define AT91C_ID_US1 7 /* USART 1 */ +#define AT91C_ID_SSC 8 /* Serial Synchronous Controller */ +#define AT91C_ID_TWI 9 /* Two-Wire Interface */ +#define AT91C_ID_PWMC 10 /* PWM Controller */ +#define AT91C_ID_UDP 11 /* USB Device Port */ +#define AT91C_ID_TC0 12 /* Timer Counter 0 */ +#define AT91C_ID_TC1 13 /* Timer Counter 1 */ +#define AT91C_ID_TC2 14 /* Timer Counter 2 */ +#define AT91C_ID_15 15 /* Reserved */ +#define AT91C_ID_16 16 /* Reserved */ +#define AT91C_ID_17 17 /* Reserved */ +#define AT91C_ID_18 18 /* Reserved */ +#define AT91C_ID_19 19 /* Reserved */ +#define AT91C_ID_20 20 /* Reserved */ +#define AT91C_ID_21 21 /* Reserved */ +#define AT91C_ID_22 22 /* Reserved */ +#define AT91C_ID_23 23 /* Reserved */ +#define AT91C_ID_24 24 /* Reserved */ +#define AT91C_ID_25 25 /* Reserved */ +#define AT91C_ID_26 26 /* Reserved */ +#define AT91C_ID_27 27 /* Reserved */ +#define AT91C_ID_28 28 /* Reserved */ +#define AT91C_ID_29 29 /* Reserved */ +#define AT91C_ID_IRQ0 30 /* Advanced Interrupt Controller (IRQ0) */ +#define AT91C_ID_IRQ1 31 /* Advanced Interrupt Controller (IRQ1) */ +#define AT91C_ALL_INT 0xC0007FF7 /* ALL VALID INTERRUPTS */ + +/*****************************/ +/* CPU Mode */ +/*****************************/ +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define ABORTMODE 0x17 +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/rt-thread/libcpu/arm/AT91SAM7S/context_gcc.S b/rt-thread/libcpu/arm/AT91SAM7S/context_gcc.S new file mode 100644 index 0000000..e76093f --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/context_gcc.S @@ -0,0 +1,94 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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-03-13 Bernard first version + */ + +#define NOINT 0xc0 + +/* + * rt_base_t rt_hw_interrupt_disable()/* + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + orr r1, r0, #NOINT + msr cpsr_c, r1 + mov pc, lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level)/* + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + mov pc, lr + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to)/* + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} /* push pc (lr should be pushed in place of PC) */ + stmfd sp!, {r0-r12, lr} /* push lr & register file */ + + mrs r4, cpsr + stmfd sp!, {r4} /* push cpsr */ + mrs r4, spsr + stmfd sp!, {r4} /* push spsr */ + + str sp, [r0] /* store sp in preempted tasks TCB */ + ldr sp, [r1] /* get new task stack pointer */ + + ldmfd sp!, {r4} /* pop new task spsr */ + msr spsr_cxsf, r4 + ldmfd sp!, {r4} /* pop new task cpsr */ + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc} /* pop new task r0-r12, lr & pc */ + +/* + * void rt_hw_context_switch_to(rt_uint32 to)/* + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] /* get new task stack pointer */ + + ldmfd sp!, {r4} /* pop new task spsr */ + msr spsr_cxsf, r4 + ldmfd sp!, {r4} /* pop new task cpsr */ + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc} /* pop new task r0-r12, lr & pc */ + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to)/* + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + mov r3, #1 /* set rt_thread_switch_interrupt_flag to 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] + mov pc, lr diff --git a/rt-thread/libcpu/arm/AT91SAM7S/context_rvds.S b/rt-thread/libcpu/arm/AT91SAM7S/context_rvds.S new file mode 100644 index 0000000..641ec7a --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/context_rvds.S @@ -0,0 +1,107 @@ +;/* +; * File : context_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, 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-20 Bernard first version +; */ + +NOINT EQU 0xc0 ; disable interrupt in psr + + AREA |.text|, CODE, READONLY, ALIGN=2 + ARM + REQUIRE8 + PRESERVE8 + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ +rt_hw_interrupt_disable PROC + EXPORT rt_hw_interrupt_disable + MRS r0, cpsr + ORR r1, r0, #NOINT + MSR cpsr_c, r1 + BX lr + ENDP + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ +rt_hw_interrupt_enable PROC + EXPORT rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + ENDP + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ +rt_hw_context_switch PROC + EXPORT rt_hw_context_switch + STMFD sp!, {lr} ; push pc (lr should be pushed in place of PC) + STMFD sp!, {r0-r12, lr} ; push lr & register file + + MRS r4, cpsr + STMFD sp!, {r4} ; push cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push spsr + + STR sp, [r0] ; store sp in preempted tasks TCB + LDR sp, [r1] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ +rt_hw_context_switch_to PROC + EXPORT rt_hw_context_switch_to + LDR sp, [r0] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +rt_hw_context_switch_interrupt PROC + EXPORT rt_hw_context_switch_interrupt + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 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] + BX lr + ENDP + + END \ No newline at end of file diff --git a/rt-thread/libcpu/arm/AT91SAM7S/cpu.c b/rt-thread/libcpu/arm/AT91SAM7S/cpu.c new file mode 100644 index 0000000..57db2b7 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/cpu.c @@ -0,0 +1,42 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop 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 first version + */ + +#include +#include "AT91SAM7S.h" + +/** + * @addtogroup AT91SAM7 + */ +/*@{*/ + +/** + * this function will reset CPU + * + */ +void rt_hw_cpu_reset() +{ +} + +/** + * this function will shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_kprintf("shutdown...\n"); + + while (1); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/AT91SAM7S/interrupt.c b/rt-thread/libcpu/arm/AT91SAM7S/interrupt.c new file mode 100644 index 0000000..fd84a72 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/interrupt.c @@ -0,0 +1,91 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-08-23 Bernard first version + */ + +#include +#include "AT91SAM7S.h" + +#define MAX_HANDLERS 32 + +extern rt_uint32_t rt_interrupt_nest; + +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +/** + * @addtogroup AT91SAM7 + */ +/*@{*/ + +void rt_hw_interrupt_handler(int vector) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init() +{ + rt_base_t index; + + for (index = 0; index < MAX_HANDLERS; index ++) + { + AT91C_AIC_SVR(index) = (rt_uint32_t)rt_hw_interrupt_handler; + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + /* disable interrupt */ + AT91C_AIC_IDCR = 1 << vector; + + /* clear interrupt */ + AT91C_AIC_ICCR = 1 << vector; +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + AT91C_AIC_IECR = 1 << vector; +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +void rt_hw_interrupt_install(int vector, rt_isr_handler_t new_handler, rt_isr_handler_t *old_handler) +{ + if(vector >= 0 && vector < MAX_HANDLERS) + { + if (*old_handler != RT_NULL) *old_handler = (rt_isr_handler_t)AT91C_AIC_SVR(vector); + if (new_handler != RT_NULL) AT91C_AIC_SVR(vector) = (rt_uint32_t)new_handler; + } +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/AT91SAM7S/serial.c b/rt-thread/libcpu/arm/AT91SAM7S/serial.c new file mode 100644 index 0000000..ede8683 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/serial.c @@ -0,0 +1,387 @@ +/* + * File : serial.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-08-23 Bernard first version + * 2009-05-14 Bernard add RT-THread device interface + */ + +#include +#include + +#include "AT91SAM7S.h" +#include "serial.h" + +/** + * @addtogroup AT91SAM7 + */ +/*@{*/ +typedef volatile rt_uint32_t REG32; +struct rt_at91serial_hw +{ + REG32 US_CR; // Control Register + REG32 US_MR; // Mode Register + REG32 US_IER; // Interrupt Enable Register + REG32 US_IDR; // Interrupt Disable Register + REG32 US_IMR; // Interrupt Mask Register + REG32 US_CSR; // Channel Status Register + REG32 US_RHR; // Receiver Holding Register + REG32 US_THR; // Transmitter Holding Register + REG32 US_BRGR; // Baud Rate Generator Register + REG32 US_RTOR; // Receiver Time-out Register + REG32 US_TTGR; // Transmitter Time-guard Register + REG32 Reserved0[5]; // + REG32 US_FIDI; // FI_DI_Ratio Register + REG32 US_NER; // Nb Errors Register + REG32 Reserved1[1]; // + REG32 US_IF; // IRDA_FILTER Register + REG32 Reserved2[44]; // + REG32 US_RPR; // Receive Pointer Register + REG32 US_RCR; // Receive Counter Register + REG32 US_TPR; // Transmit Pointer Register + REG32 US_TCR; // Transmit Counter Register + REG32 US_RNPR; // Receive Next Pointer Register + REG32 US_RNCR; // Receive Next Counter Register + REG32 US_TNPR; // Transmit Next Pointer Register + REG32 US_TNCR; // Transmit Next Counter Register + REG32 US_PTCR; // PDC Transfer Control Register + REG32 US_PTSR; // PDC Transfer Status Register +}; + +struct rt_at91serial +{ + struct rt_device parent; + + struct rt_at91serial_hw* hw_base; + rt_uint16_t peripheral_id; + rt_uint32_t baudrate; + + /* reception field */ + rt_uint16_t save_index, read_index; + rt_uint8_t rx_buffer[RT_UART_RX_BUFFER_SIZE]; +}; +#ifdef RT_USING_UART1 +struct rt_at91serial serial1; +#endif +#ifdef RT_USING_UART2 +struct rt_at91serial serial2; +#endif + +static void rt_hw_serial_isr(int irqno) +{ + rt_base_t level; + struct rt_device* device; + struct rt_at91serial* serial = RT_NULL; + + if (irqno == AT91C_ID_US0) + { +#ifdef RT_USING_UART1 + /* serial 1 */ + serial = &serial1; +#endif + } + else if (irqno == AT91C_ID_US1) + { +#ifdef RT_USING_UART2 + /* serial 2 */ + serial = &serial2; +#endif + } + RT_ASSERT(serial != RT_NULL); + + /* get generic device object */ + device = (rt_device_t)serial; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* get received character */ + serial->rx_buffer[serial->save_index] = serial->hw_base->US_RHR; + + /* move to next position */ + serial->save_index ++; + if (serial->save_index >= RT_UART_RX_BUFFER_SIZE) + serial->save_index = 0; + + /* if the next position is read index, discard this 'read char' */ + if (serial->save_index == serial->read_index) + { + serial->read_index ++; + if (serial->read_index >= RT_UART_RX_BUFFER_SIZE) + serial->read_index = 0; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* indicate to upper layer application */ + if (device->rx_indicate != RT_NULL) + device->rx_indicate(device, 1); + + /* ack interrupt */ + AT91C_AIC_EOICR = 1; +} + +static rt_err_t rt_serial_init (rt_device_t dev) +{ + rt_uint32_t bd; + struct rt_at91serial* serial = (struct rt_at91serial*) dev; + + RT_ASSERT(serial != RT_NULL); + /* must be US0 or US1 */ + RT_ASSERT(((serial->peripheral_id == AT91C_ID_US0) || + (serial->peripheral_id == AT91C_ID_US1))); + + /* Enable Clock for USART */ + AT91C_PMC_PCER = 1 << serial->peripheral_id; + + /* Enable RxD0 and TxDO Pin */ + if (serial->peripheral_id == AT91C_ID_US0) + { + /* set pinmux */ + AT91C_PIO_PDR = (1 << 5) | (1 << 6); + } + else if (serial->peripheral_id == AT91C_ID_US1) + { + /* set pinmux */ + AT91C_PIO_PDR = (1 << 21) | (1 << 22); + } + + serial->hw_base->US_CR = AT91C_US_RSTRX | /* Reset Receiver */ + AT91C_US_RSTTX | /* Reset Transmitter */ + AT91C_US_RXDIS | /* Receiver Disable */ + AT91C_US_TXDIS; /* Transmitter Disable */ + + serial->hw_base->US_MR = AT91C_US_USMODE_NORMAL | /* Normal Mode */ + AT91C_US_CLKS_CLOCK | /* Clock = MCK */ + AT91C_US_CHRL_8_BITS | /* 8-bit Data */ + AT91C_US_PAR_NONE | /* No Parity */ + AT91C_US_NBSTOP_1_BIT; /* 1 Stop Bit */ + + /* set baud rate divisor */ + bd = ((MCK*10)/(serial->baudrate * 16)); + if ((bd % 10) >= 5) bd = (bd / 10) + 1; + else bd /= 10; + + serial->hw_base->US_BRGR = bd; + serial->hw_base->US_CR = AT91C_US_RXEN | /* Receiver Enable */ + AT91C_US_TXEN; /* Transmitter Enable */ + + /* reset rx index */ + serial->save_index = 0; + serial->read_index = 0; + + /* reset rx buffer */ + rt_memset(serial->rx_buffer, 0, RT_UART_RX_BUFFER_SIZE); + + return RT_EOK; +} + +static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag) +{ + struct rt_at91serial *serial = (struct rt_at91serial*)dev; + RT_ASSERT(serial != RT_NULL); + + if (dev->flag & RT_DEVICE_FLAG_INT_RX) + { + /* enable UART rx interrupt */ + serial->hw_base->US_IER = 1 << 0; /* RxReady interrupt */ + serial->hw_base->US_IMR |= 1 << 0; /* umask RxReady interrupt */ + + /* install UART handler */ + rt_hw_interrupt_install(serial->peripheral_id, rt_hw_serial_isr, RT_NULL); + AT91C_AIC_SMR(serial->peripheral_id) = 5 | (0x01 << 5); + rt_hw_interrupt_umask(serial->peripheral_id); + } + + return RT_EOK; +} + +static rt_err_t rt_serial_close(rt_device_t dev) +{ + struct rt_at91serial *serial = (struct rt_at91serial*)dev; + RT_ASSERT(serial != RT_NULL); + + if (dev->flag & RT_DEVICE_FLAG_INT_RX) + { + /* disable interrupt */ + serial->hw_base->US_IDR = 1 << 0; /* RxReady interrupt */ + serial->hw_base->US_IMR &= ~(1 << 0); /* mask RxReady interrupt */ + } + + return RT_EOK; +} + +static rt_size_t rt_serial_read (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + rt_uint8_t* ptr; + struct rt_at91serial *serial = (struct rt_at91serial*)dev; + RT_ASSERT(serial != RT_NULL); + + /* point to buffer */ + ptr = (rt_uint8_t*) buffer; + + if (dev->flag & RT_DEVICE_FLAG_INT_RX) + { + while (size) + { + /* interrupt receive */ + rt_base_t level; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + if (serial->read_index != serial->save_index) + { + *ptr = serial->rx_buffer[serial->read_index]; + + serial->read_index ++; + if (serial->read_index >= RT_UART_RX_BUFFER_SIZE) + serial->read_index = 0; + } + else + { + /* no data in rx buffer */ + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + break; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + ptr ++; size --; + } + + return (rt_uint32_t)ptr - (rt_uint32_t)buffer; + } + else if (dev->flag & RT_DEVICE_FLAG_DMA_RX) + { + /* not support right now */ + RT_ASSERT(0); + } + else + { + /* poll mode */ + while (size) + { + /* Wait for Full Rx Buffer */ + while (!(serial->hw_base->US_CSR & AT91C_US_RXRDY)); + + /* Read Character */ + *ptr = serial->hw_base->US_RHR; + ptr ++; + size --; + } + + return (rt_size_t)ptr - (rt_size_t)buffer; + } + + return 0; +} + +static rt_size_t rt_serial_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + rt_uint8_t* ptr; + struct rt_at91serial *serial = (struct rt_at91serial*)dev; + RT_ASSERT(serial != RT_NULL); + + ptr = (rt_uint8_t*) buffer; + if (dev->open_flag & RT_DEVICE_OFLAG_WRONLY) + { + if (dev->flag & RT_DEVICE_FLAG_STREAM) + { + /* it's a stream mode device */ + while (size) + { + /* stream mode */ + if (*ptr == '\n') + { + while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY)); + serial->hw_base->US_THR = '\r'; + } + + /* Wait for Empty Tx Buffer */ + while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY)); + + /* Transmit Character */ + serial->hw_base->US_THR = *ptr; + ptr ++; size --; + } + } + else + { + while (size) + { + /* Wait for Empty Tx Buffer */ + while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY)); + + /* Transmit Character */ + serial->hw_base->US_THR = *ptr; + ptr ++; size --; + } + } + } + + return (rt_size_t)ptr - (rt_size_t)buffer; +} + +static rt_err_t rt_serial_control (rt_device_t dev, int cmd, void *args) +{ + return RT_EOK; +} + +rt_err_t rt_hw_serial_init() +{ + rt_device_t device; + +#ifdef RT_USING_UART1 + device = (rt_device_t) &serial1; + + /* init serial device private data */ + serial1.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US0; + serial1.peripheral_id = AT91C_ID_US0; + serial1.baudrate = 115200; + + /* set device virtual interface */ + device->init = rt_serial_init; + device->open = rt_serial_open; + device->close = rt_serial_close; + device->read = rt_serial_read; + device->write = rt_serial_write; + device->control = rt_serial_control; + + /* register uart1 on device subsystem */ + rt_device_register(device, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX); +#endif + +#ifdef RT_USING_UART2 + device = (rt_device_t) &serial2; + + serial2.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US1; + serial2.peripheral_id = AT91C_ID_US1; + serial2.baudrate = 115200; + + /* set device virtual interface */ + device->init = rt_serial_init; + device->open = rt_serial_open; + device->close = rt_serial_close; + device->read = rt_serial_read; + device->write = rt_serial_write; + device->control = rt_serial_control; + + /* register uart2 on device subsystem */ + rt_device_register(device, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX); +#endif + + return RT_EOK; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/AT91SAM7S/serial.h b/rt-thread/libcpu/arm/AT91SAM7S/serial.h new file mode 100644 index 0000000..401b0c3 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/serial.h @@ -0,0 +1,56 @@ +#ifndef __RT_SERIAL_H__ +#define __RT_SERIAL_H__ + +#ifndef AT91C_BASE_US0 +#define AT91C_BASE_US0 (0xFFFC0000) // (US0) Base Address +#endif + +#ifndef AT91C_BASE_US1 +#define AT91C_BASE_US1 (0xFFFC4000) // (US1) Base Address +#endif + +#define AT91C_US_RXRDY ((unsigned int) 0x1 << 0) /* US RXRDY Interrupt */ +#define AT91C_US_TXRDY ((unsigned int) 0x1 << 1) /* US TXRDY Interrupt */ +#define AT91C_US_RSTRX ((unsigned int) 0x1 << 2) /* US Reset Receiver */ +#define AT91C_US_RSTTX ((unsigned int) 0x1 << 3) /* US Reset Transmitter */ +#define AT91C_US_RXEN ((unsigned int) 0x1 << 4) /* US Receiver Enable */ +#define AT91C_US_RXDIS ((unsigned int) 0x1 << 5) /* US Receiver Disable */ +#define AT91C_US_TXEN ((unsigned int) 0x1 << 6) /* US Transmitter Enable */ +#define AT91C_US_TXDIS ((unsigned int) 0x1 << 7) /* US Transmitter Disable */ +#define AT91C_US_RSTSTA ((unsigned int) 0x1 << 8) /* US Reset Status Bits */ + +#define AT91C_US_USMODE_NORMAL ((unsigned int) 0x0) /* USAR) Normal */ +#define AT91C_US_USMODE_RS485 ((unsigned int) 0x1) /* USAR) RS485 */ +#define AT91C_US_USMODE_HWHSH ((unsigned int) 0x2) /* USAR) Hardware Handshaking */ +#define AT91C_US_USMODE_MODEM ((unsigned int) 0x3) /* USAR) Modem */ +#define AT91C_US_USMODE_ISO7816_0 ((unsigned int) 0x4) /* USAR) ISO7816 protocol: T = 0 */ +#define AT91C_US_USMODE_ISO7816_1 ((unsigned int) 0x6) /* USAR) ISO7816 protocol: T = 1 */ +#define AT91C_US_USMODE_IRDA ((unsigned int) 0x8) /* USAR) IrDA */ +#define AT91C_US_USMODE_SWHSH ((unsigned int) 0xC) /* USAR) Software Handshaking */ + +#define AT91C_US_CLKS_CLOCK ((unsigned int) 0x0 << 4) /* USAR) Clock */ +#define AT91C_US_CLKS_FDIV1 ((unsigned int) 0x1 << 4) /* USAR) fdiv1 */ +#define AT91C_US_CLKS_SLOW ((unsigned int) 0x2 << 4) /* USAR) slow_clock (ARM) */ +#define AT91C_US_CLKS_EXT ((unsigned int) 0x3 << 4) /* USAR) External (SCK) */ + +#define AT91C_US_CHRL_5_BITS ((unsigned int) 0x0 << 6) /* USAR) Character Length: 5 bits */ +#define AT91C_US_CHRL_6_BITS ((unsigned int) 0x1 << 6) /* USAR) Character Length: 6 bits */ +#define AT91C_US_CHRL_7_BITS ((unsigned int) 0x2 << 6) /* USAR) Character Length: 7 bits */ +#define AT91C_US_CHRL_8_BITS ((unsigned int) 0x3 << 6) /* USAR) Character Length: 8 bits */ + +#define AT91C_US_PAR_EVEN ((unsigned int) 0x0 << 9) /* DBGU Even Parity */ +#define AT91C_US_PAR_ODD ((unsigned int) 0x1 << 9) /* DBGU Odd Parity */ +#define AT91C_US_PAR_SPACE ((unsigned int) 0x2 << 9) /* DBGU Parity forced to 0 (Space) */ +#define AT91C_US_PAR_MARK ((unsigned int) 0x3 << 9) /* DBGU Parity forced to 1 (Mark) */ +#define AT91C_US_PAR_NONE ((unsigned int) 0x4 << 9) /* DBGU No Parity */ +#define AT91C_US_PAR_MULTI_DROP ((unsigned int) 0x6 << 9) /* DBGU Multi-drop mode */ + +#define AT91C_US_NBSTOP_1_BIT ((unsigned int) 0x0 << 12) /* USART 1 stop bit */ +#define AT91C_US_NBSTOP_15_BIT ((unsigned int) 0x1 << 12) /* USART Asynchronous (SYNC=0) 2 stop bits Synchronous (SYNC=1) 2 stop bits */ +#define AT91C_US_NBSTOP_2_BIT ((unsigned int) 0x2 << 12) /* USART 2 stop bits */ + +#define MCK 48054857 +#define BR 115200 /* Baud Rate */ +#define BRD (MCK/16/BR) /* Baud Rate Divisor */ + +#endif diff --git a/rt-thread/libcpu/arm/AT91SAM7S/stack.c b/rt-thread/libcpu/arm/AT91SAM7S/stack.c new file mode 100644 index 0000000..14acc54 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/stack.c @@ -0,0 +1,63 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-08-23 Bernard the first version + */ +#include +#include "AT91SAM7S.h" + +/** + * @addtogroup AT91SAM7 + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + *(--stk) = SVCMODE; /* cpsr */ + *(--stk) = SVCMODE; /* spsr */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/AT91SAM7S/start_gcc.S b/rt-thread/libcpu/arm/AT91SAM7S/start_gcc.S new file mode 100644 index 0000000..17695e3 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/start_gcc.S @@ -0,0 +1,237 @@ +/* + * File : start_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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-31 Bernard first version + */ + + /* Internal Memory Base Addresses */ + .equ FLASH_BASE, 0x00100000 + .equ RAM_BASE, 0x00200000 + + /* Stack Configuration */ + .equ TOP_STACK, 0x00204000 + .equ UND_STACK_SIZE, 0x00000100 + .equ SVC_STACK_SIZE, 0x00000400 + .equ ABT_STACK_SIZE, 0x00000100 + .equ FIQ_STACK_SIZE, 0x00000100 + .equ IRQ_STACK_SIZE, 0x00000100 + .equ USR_STACK_SIZE, 0x00000004 + + /* ARM architecture definitions */ + .equ MODE_USR, 0x10 + .equ MODE_FIQ, 0x11 + .equ MODE_IRQ, 0x12 + .equ MODE_SVC, 0x13 + .equ MODE_ABT, 0x17 + .equ MODE_UND, 0x1B + .equ MODE_SYS, 0x1F + + .equ I_BIT, 0x80 /* when this bit is set, IRQ is disabled */ + .equ F_BIT, 0x40 /* when this bit is set, FIQ is disabled */ + +.section .init, "ax" +.code 32 +.align 0 +.globl _start +_start: + b reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + nop /* reserved vector */ + ldr pc, _vector_irq + ldr pc, _vector_fiq + +_vector_undef: .word vector_undef +_vector_swi: .word vector_swi +_vector_pabt: .word vector_pabt +_vector_dabt: .word vector_dabt +_vector_resv: .word vector_resv +_vector_irq: .word vector_irq +_vector_fiq: .word vector_fiq + +/* + * rtthread bss start and end + * which are defined in linker script + */ +.globl _bss_start +_bss_start: .word __bss_start +.globl _bss_end +_bss_end: .word __bss_end + +/* the system entry */ +reset: + /* disable watchdog */ + ldr r0, =0xFFFFFD40 + ldr r1, =0x00008000 + str r1, [r0, #0x04] + + /* enable the main oscillator */ + ldr r0, =0xFFFFFC00 + ldr r1, =0x00000601 + str r1, [r0, #0x20] + + /* wait for main oscillator to stabilize */ +moscs_loop: + ldr r2, [r0, #0x68] + ands r2, r2, #1 + beq moscs_loop + + /* set up the PLL */ + ldr r1, =0x00191C05 + str r1, [r0, #0x2C] + + /* wait for PLL to lock */ +pll_loop: + ldr r2, [r0, #0x68] + ands r2, r2, #0x04 + beq pll_loop + + /* select clock */ + ldr r1, =0x00000007 + str r1, [r0, #0x30] + + /* setup stack for each mode */ + ldr r0, =TOP_STACK + + /* set stack */ + /* undefined instruction mode */ + msr cpsr_c, #MODE_UND|I_BIT|F_BIT + mov sp, r0 + sub r0, r0, #UND_STACK_SIZE + + /* abort mode */ + msr cpsr_c, #MODE_ABT|I_BIT|F_BIT + mov sp, r0 + sub r0, r0, #ABT_STACK_SIZE + + /* FIQ mode */ + msr cpsr_c, #MODE_FIQ|I_BIT|F_BIT + mov sp, r0 + sub r0, r0, #FIQ_STACK_SIZE + + /* IRQ mode */ + msr cpsr_c, #MODE_IRQ|I_BIT|F_BIT + mov sp, r0 + sub r0, r0, #IRQ_STACK_SIZE + + /* supervisor mode */ + msr cpsr_c, #MODE_SVC + mov sp, r0 + +#ifdef __FLASH_BUILD__ + /* Relocate .data section (Copy from ROM to RAM) */ + ldr r1, =_etext + ldr r2, =_data + ldr r3, =_edata +data_loop: + cmp r2, r3 + ldrlo r0, [r1], #4 + strlo r0, [r2], #4 + blo data_loop +#else + /* remap SRAM to 0x0000 */ + ldr r0, =0xFFFFFF00 + mov r1, #0x01 + str r1, [r0] +#endif + + /* mask all IRQs */ + ldr r1, =0xFFFFF124 + ldr r0, =0XFFFFFFFF + str r0, [r1] + + /* start RT-Thread Kernel */ + ldr pc, _rtthread_startup + +_rtthread_startup: .word rtthread_startup + +/* exception handlers */ +vector_undef: b vector_undef +vector_swi : b vector_swi +vector_pabt : b vector_pabt +vector_dabt : b vector_dabt +vector_resv : b vector_resv + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +vector_irq: + stmfd sp!, {r0-r12,lr} + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + + /* + * if rt_thread_switch_interrupt_flag set, jump to + * rt_hw_context_switch_interrupt_do and don't return + */ + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq rt_hw_context_switch_interrupt_do + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc,lr,#4 + +/* + * void rt_hw_context_switch_interrupt_do(rt_base_t flag) + */ +rt_hw_context_switch_interrupt_do: + mov r1, #0 /* clear flag */ + str r1, [r0] + + ldmfd sp!, {r0-r12,lr} /* reload saved registers */ + stmfd sp!, {r0-r3} /* save r0-r3 */ + mov r1, sp + add sp, sp, #16 /* restore sp */ + sub r2, lr, #4 /* save old task's pc to r2 */ + + mrs r3, spsr /* disable interrupt */ + orr r0, r3, #I_BIT|F_BIT + msr spsr_c, r0 + + ldr r0, =.+8 /* switch to interrupted task's stack */ + movs pc, r0 + + stmfd sp!, {r2} /* push old task's pc */ + stmfd sp!, {r4-r12,lr} /* push old task's lr,r12-r4 */ + mov r4, r1 /* Special optimised code below */ + mov r5, r3 + ldmfd r4!, {r0-r3} + stmfd sp!, {r0-r3} /* push old task's r3-r0 */ + stmfd sp!, {r5} /* push old task's psr */ + mrs r4, spsr + stmfd sp!, {r4} /* push old task's spsr */ + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] /* store sp in preempted tasks's TCB */ + + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] /* get new task's stack pointer */ + + ldmfd sp!, {r4} /* pop new task's spsr */ + msr SPSR_cxsf, r4 + ldmfd sp!, {r4} /* pop new task's psr */ + msr CPSR_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc} /* pop new task's r0-r12,lr & pc */ diff --git a/rt-thread/libcpu/arm/AT91SAM7S/start_rvds.S b/rt-thread/libcpu/arm/AT91SAM7S/start_rvds.S new file mode 100644 index 0000000..84274bb --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/start_rvds.S @@ -0,0 +1,499 @@ +;/*****************************************************************************/ +;/* SAM7.S: Startup file for Atmel AT91SAM7 device series */ +;/*****************************************************************************/ +;/* <<< Use Configuration Wizard in Context Menu >>> */ +;/*****************************************************************************/ +;/* This file is part of the uVision/ARM development tools. */ +;/* Copyright (c) 2005-2006 Keil Software. All rights reserved. */ +;/* This software may only be used under the terms of a valid, current, */ +;/* end user licence from KEIL for a compatible version of KEIL software */ +;/* development tools. Nothing else gives you the right to use this software. */ +;/*****************************************************************************/ + + +;/* +; * The SAM7.S code is executed after CPU Reset. This file may be +; * translated with the following SET symbols. In uVision these SET +; * symbols are entered under Options - ASM - Define. +; * +; * REMAP: when set the startup code remaps exception vectors from +; * on-chip RAM to address 0. +; * +; * RAM_INTVEC: when set the startup code copies exception vectors +; * from on-chip Flash to on-chip RAM. +; */ + + +; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs + +Mode_USR EQU 0x10 +Mode_FIQ EQU 0x11 +Mode_IRQ EQU 0x12 +Mode_SVC EQU 0x13 +Mode_ABT EQU 0x17 +Mode_UND EQU 0x1B +Mode_SYS EQU 0x1F + +I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled +F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled + + +; Internal Memory Base Addresses +FLASH_BASE EQU 0x00100000 +RAM_BASE EQU 0x00200000 + + +;// Stack Configuration (Stack Sizes in Bytes) +;// Undefined Mode <0x0-0xFFFFFFFF:8> +;// Supervisor Mode <0x0-0xFFFFFFFF:8> +;// Abort Mode <0x0-0xFFFFFFFF:8> +;// Fast Interrupt Mode <0x0-0xFFFFFFFF:8> +;// Interrupt Mode <0x0-0xFFFFFFFF:8> +;// User/System Mode <0x0-0xFFFFFFFF:8> +;// + +UND_Stack_Size EQU 0x00000000 +SVC_Stack_Size EQU 0x00000100 +ABT_Stack_Size EQU 0x00000000 +FIQ_Stack_Size EQU 0x00000000 +IRQ_Stack_Size EQU 0x00000100 +USR_Stack_Size EQU 0x00000100 + +ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + FIQ_Stack_Size + IRQ_Stack_Size) + + AREA STACK, NOINIT, READWRITE, ALIGN=3 + +Stack_Mem SPACE USR_Stack_Size +__initial_sp SPACE ISR_Stack_Size +Stack_Top + + +;// Heap Configuration +;// Heap Size (in Bytes) <0x0-0xFFFFFFFF> +;// + +Heap_Size EQU 0x00000000 + + AREA HEAP, NOINIT, READWRITE, ALIGN=3 +__heap_base +Heap_Mem SPACE Heap_Size +__heap_limit + + +; Reset Controller (RSTC) definitions +RSTC_BASE EQU 0xFFFFFD00 ; RSTC Base Address +RSTC_MR EQU 0x08 ; RSTC_MR Offset + +;/* +;// Reset Controller (RSTC) +;// URSTEN: User Reset Enable +;// Enables NRST Pin to generate Reset +;// ERSTL: External Reset Length <0-15> +;// External Reset Time in 2^(ERSTL+1) Slow Clock Cycles +;// +;*/ +RSTC_SETUP EQU 1 +RSTC_MR_Val EQU 0xA5000401 + + +; Embedded Flash Controller (EFC) definitions +EFC_BASE EQU 0xFFFFFF00 ; EFC Base Address +EFC0_FMR EQU 0x60 ; EFC0_FMR Offset +EFC1_FMR EQU 0x70 ; EFC1_FMR Offset + +;// Embedded Flash Controller 0 (EFC0) +;// FMCN: Flash Microsecond Cycle Number <0-255> +;// Number of Master Clock Cycles in 1us +;// FWS: Flash Wait State +;// <0=> Read: 1 cycle / Write: 2 cycles +;// <1=> Read: 2 cycle / Write: 3 cycles +;// <2=> Read: 3 cycle / Write: 4 cycles +;// <3=> Read: 4 cycle / Write: 4 cycles +;// +EFC0_SETUP EQU 1 +EFC0_FMR_Val EQU 0x00320100 + +;// Embedded Flash Controller 1 (EFC1) +;// FMCN: Flash Microsecond Cycle Number <0-255> +;// Number of Master Clock Cycles in 1us +;// FWS: Flash Wait State +;// <0=> Read: 1 cycle / Write: 2 cycles +;// <1=> Read: 2 cycle / Write: 3 cycles +;// <2=> Read: 3 cycle / Write: 4 cycles +;// <3=> Read: 4 cycle / Write: 4 cycles +;// +EFC1_SETUP EQU 0 +EFC1_FMR_Val EQU 0x00320100 + + +; Watchdog Timer (WDT) definitions +WDT_BASE EQU 0xFFFFFD40 ; WDT Base Address +WDT_MR EQU 0x04 ; WDT_MR Offset + +;// Watchdog Timer (WDT) +;// WDV: Watchdog Counter Value <0-4095> +;// WDD: Watchdog Delta Value <0-4095> +;// WDFIEN: Watchdog Fault Interrupt Enable +;// WDRSTEN: Watchdog Reset Enable +;// WDRPROC: Watchdog Reset Processor +;// WDDBGHLT: Watchdog Debug Halt +;// WDIDLEHLT: Watchdog Idle Halt +;// WDDIS: Watchdog Disable +;// +WDT_SETUP EQU 1 +WDT_MR_Val EQU 0x00008000 + + +; Power Mangement Controller (PMC) definitions +PMC_BASE EQU 0xFFFFFC00 ; PMC Base Address +PMC_MOR EQU 0x20 ; PMC_MOR Offset +PMC_MCFR EQU 0x24 ; PMC_MCFR Offset +PMC_PLLR EQU 0x2C ; PMC_PLLR Offset +PMC_MCKR EQU 0x30 ; PMC_MCKR Offset +PMC_SR EQU 0x68 ; PMC_SR Offset +PMC_MOSCEN EQU (1<<0) ; Main Oscillator Enable +PMC_OSCBYPASS EQU (1<<1) ; Main Oscillator Bypass +PMC_OSCOUNT EQU (0xFF<<8) ; Main OScillator Start-up Time +PMC_DIV EQU (0xFF<<0) ; PLL Divider +PMC_PLLCOUNT EQU (0x3F<<8) ; PLL Lock Counter +PMC_OUT EQU (0x03<<14) ; PLL Clock Frequency Range +PMC_MUL EQU (0x7FF<<16) ; PLL Multiplier +PMC_USBDIV EQU (0x03<<28) ; USB Clock Divider +PMC_CSS EQU (3<<0) ; Clock Source Selection +PMC_PRES EQU (7<<2) ; Prescaler Selection +PMC_MOSCS EQU (1<<0) ; Main Oscillator Stable +PMC_LOCK EQU (1<<2) ; PLL Lock Status +PMC_MCKRDY EQU (1<<3) ; Master Clock Status + +;// Power Mangement Controller (PMC) +;// Main Oscillator +;// MOSCEN: Main Oscillator Enable +;// OSCBYPASS: Oscillator Bypass +;// OSCCOUNT: Main Oscillator Startup Time <0-255> +;// +;// Phase Locked Loop (PLL) +;// DIV: PLL Divider <0-255> +;// MUL: PLL Multiplier <0-2047> +;// PLL Output is multiplied by MUL+1 +;// OUT: PLL Clock Frequency Range +;// <0=> 80..160MHz <1=> Reserved +;// <2=> 150..220MHz <3=> Reserved +;// PLLCOUNT: PLL Lock Counter <0-63> +;// USBDIV: USB Clock Divider +;// <0=> None <1=> 2 <2=> 4 <3=> Reserved +;// +;// CSS: Clock Source Selection +;// <0=> Slow Clock +;// <1=> Main Clock +;// <2=> Reserved +;// <3=> PLL Clock +;// PRES: Prescaler +;// <0=> None +;// <1=> Clock / 2 <2=> Clock / 4 +;// <3=> Clock / 8 <4=> Clock / 16 +;// <5=> Clock / 32 <6=> Clock / 64 +;// <7=> Reserved +;// +PMC_SETUP EQU 1 +PMC_MOR_Val EQU 0x00000601 +PMC_PLLR_Val EQU 0x00191C05 +PMC_MCKR_Val EQU 0x00000007 + + + PRESERVE8 + + +; Area Definition and Entry Point +; Startup Code must be linked first at Address at which it expects to run. + + AREA RESET, CODE, READONLY + ARM + + +; Exception Vectors +; Mapped to Address 0. +; Absolute addressing mode must be used. +; Dummy Handlers are implemented as infinite loops which can be modified. + +Vectors LDR PC,Reset_Addr + LDR PC,Undef_Addr + LDR PC,SWI_Addr + LDR PC,PAbt_Addr + LDR PC,DAbt_Addr + NOP ; Reserved Vector + LDR PC,IRQ_Addr + LDR PC,FIQ_Addr + +Reset_Addr DCD Reset_Handler +Undef_Addr DCD Undef_Handler +SWI_Addr DCD SWI_Handler +PAbt_Addr DCD PAbt_Handler +DAbt_Addr DCD DAbt_Handler + DCD 0 ; Reserved Address +IRQ_Addr DCD IRQ_Handler +FIQ_Addr DCD FIQ_Handler + +Undef_Handler B Undef_Handler +SWI_Handler B SWI_Handler +PAbt_Handler B PAbt_Handler +DAbt_Handler B DAbt_Handler +FIQ_Handler B FIQ_Handler + + +; Reset Handler + + EXPORT Reset_Handler +Reset_Handler + + +; Setup RSTC + IF RSTC_SETUP != 0 + LDR R0, =RSTC_BASE + LDR R1, =RSTC_MR_Val + STR R1, [R0, #RSTC_MR] + ENDIF + + +; Setup EFC0 + IF EFC0_SETUP != 0 + LDR R0, =EFC_BASE + LDR R1, =EFC0_FMR_Val + STR R1, [R0, #EFC0_FMR] + ENDIF + +; Setup EFC1 + IF EFC1_SETUP != 0 + LDR R0, =EFC_BASE + LDR R1, =EFC1_FMR_Val + STR R1, [R0, #EFC1_FMR] + ENDIF + +; Setup WDT + IF WDT_SETUP != 0 + LDR R0, =WDT_BASE + LDR R1, =WDT_MR_Val + STR R1, [R0, #WDT_MR] + ENDIF + + +; Setup PMC + IF PMC_SETUP != 0 + LDR R0, =PMC_BASE + +; Setup Main Oscillator + LDR R1, =PMC_MOR_Val + STR R1, [R0, #PMC_MOR] + +; Wait until Main Oscillator is stablilized + IF (PMC_MOR_Val:AND:PMC_MOSCEN) != 0 +MOSCS_Loop LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MOSCS + BEQ MOSCS_Loop + ENDIF + +; Setup the PLL + IF (PMC_PLLR_Val:AND:PMC_MUL) != 0 + LDR R1, =PMC_PLLR_Val + STR R1, [R0, #PMC_PLLR] + +; Wait until PLL is stabilized +PLL_Loop LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_LOCK + BEQ PLL_Loop + ENDIF + +; Select Clock + IF (PMC_MCKR_Val:AND:PMC_CSS) == 1 ; Main Clock Selected + LDR R1, =PMC_MCKR_Val + AND R1, #PMC_CSS + STR R1, [R0, #PMC_MCKR] +WAIT_Rdy1 LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MCKRDY + BEQ WAIT_Rdy1 + LDR R1, =PMC_MCKR_Val + STR R1, [R0, #PMC_MCKR] +WAIT_Rdy2 LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MCKRDY + BEQ WAIT_Rdy2 + ELIF (PMC_MCKR_Val:AND:PMC_CSS) == 3 ; PLL Clock Selected + LDR R1, =PMC_MCKR_Val + AND R1, #PMC_PRES + STR R1, [R0, #PMC_MCKR] +WAIT_Rdy1 LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MCKRDY + BEQ WAIT_Rdy1 + LDR R1, =PMC_MCKR_Val + STR R1, [R0, #PMC_MCKR] +WAIT_Rdy2 LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MCKRDY + BEQ WAIT_Rdy2 + ENDIF ; Select Clock + ENDIF ; PMC_SETUP + + +; Copy Exception Vectors to Internal RAM + + IF :DEF:RAM_INTVEC + ADR R8, Vectors ; Source + LDR R9, =RAM_BASE ; Destination + LDMIA R8!, {R0-R7} ; Load Vectors + STMIA R9!, {R0-R7} ; Store Vectors + LDMIA R8!, {R0-R7} ; Load Handler Addresses + STMIA R9!, {R0-R7} ; Store Handler Addresses + ENDIF + + +; Remap on-chip RAM to address 0 + +MC_BASE EQU 0xFFFFFF00 ; MC Base Address +MC_RCR EQU 0x00 ; MC_RCR Offset + + IF :DEF:REMAP + LDR R0, =MC_BASE + MOV R1, #1 + STR R1, [R0, #MC_RCR] ; Remap + ENDIF + + +; Setup Stack for each mode + + LDR R0, =Stack_Top + +; Enter Undefined Instruction Mode and set its Stack Pointer + MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #UND_Stack_Size + +; Enter Abort Mode and set its Stack Pointer + MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #ABT_Stack_Size + +; Enter FIQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #FIQ_Stack_Size + +; Enter IRQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #IRQ_Stack_Size + +; Enter Supervisor Mode and set its Stack Pointer + MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #SVC_Stack_Size + +; Enter User Mode and set its Stack Pointer + ; MSR CPSR_c, #Mode_USR + IF :DEF:__MICROLIB + + EXPORT __initial_sp + + ELSE + + ; No usr mode stack here. + ;MOV SP, R0 + ;SUB SL, SP, #USR_Stack_Size + + ENDIF + + +; Enter the C code + + IMPORT __main + LDR R0, =__main + BX R0 + + IMPORT rt_interrupt_enter + IMPORT rt_interrupt_leave + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + IMPORT rt_hw_trap_irq + +IRQ_Handler PROC + EXPORT IRQ_Handler + STMFD sp!, {r0-r12,lr} + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; if rt_thread_switch_interrupt_flag set, jump to + ; rt_hw_context_switch_interrupt_do and don't return + LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD sp!, {r0-r12,lr} + SUBS pc, lr, #4 + ENDP + +; /* +; * void rt_hw_context_switch_interrupt_do(rt_base_t flag) +; */ +rt_hw_context_switch_interrupt_do PROC + EXPORT rt_hw_context_switch_interrupt_do + MOV r1, #0 ; clear flag + STR r1, [r0] + + LDMFD sp!, {r0-r12,lr}; reload saved registers + STMFD sp!, {r0-r3} ; save r0-r3 + MOV r1, sp + ADD sp, sp, #16 ; restore sp + SUB r2, lr, #4 ; save old task's pc to r2 + + MRS r3, spsr ; get cpsr of interrupt thread + + ; switch to SVC mode and no interrupt + MSR cpsr_c, #I_Bit|F_Bit|Mode_SVC + + STMFD sp!, {r2} ; push old task's pc + STMFD sp!, {r4-r12,lr}; push old task's lr,r12-r4 + MOV r4, r1 ; Special optimised code below + MOV r5, r3 + LDMFD r4!, {r0-r3} + STMFD sp!, {r0-r3} ; push old task's r3-r0 + STMFD sp!, {r5} ; push old task's cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push old task's spsr + + LDR r4, =rt_interrupt_from_thread + LDR r5, [r4] + STR sp, [r5] ; store sp in preempted tasks's TCB + + LDR r6, =rt_interrupt_to_thread + LDR r6, [r6] + LDR sp, [r6] ; get new task's stack pointer + + LDMFD sp!, {r4} ; pop new task's spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task's psr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc + ENDP + + IF :DEF:__MICROLIB + + EXPORT __heap_base + EXPORT __heap_limit + + ELSE +; User Initial Stack & Heap + AREA |.text|, CODE, READONLY + + IMPORT __use_two_region_memory + EXPORT __user_initial_stackheap +__user_initial_stackheap + + LDR R0, = Heap_Mem + LDR R1, = (Stack_Mem + IRQ_Stack_Size) + LDR R2, = (Heap_Mem + Heap_Size) + LDR R3, = Stack_Mem + BX LR + ENDIF + + END diff --git a/rt-thread/libcpu/arm/AT91SAM7S/trap.c b/rt-thread/libcpu/arm/AT91SAM7S/trap.c new file mode 100644 index 0000000..18534cd --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7S/trap.c @@ -0,0 +1,40 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-08-25 Bernard first version + */ + +#include +#include + +#include "AT91SAM7S.h" + +/** + * @addtogroup AT91SAM7 + */ +/*@{*/ + +void rt_hw_trap_irq() +{ + rt_isr_handler_t hander = (rt_isr_handler_t)AT91C_AIC_IVR; + + hander(AT91C_AIC_ISR); + + /* end of interrupt */ + AT91C_AIC_EOICR = 0; +} + +void rt_hw_trap_fiq() +{ + rt_kprintf("fast interrupt request\n"); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/AT91SAM7X/context_gcc.S b/rt-thread/libcpu/arm/AT91SAM7X/context_gcc.S new file mode 100644 index 0000000..e8f0803 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7X/context_gcc.S @@ -0,0 +1,99 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + */ + +/*! + * \addtogroup xgs3c4510 + */ +/*@{*/ + +#define NOINT 0xc0 + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + orr r1, r0, #NOINT + msr cpsr_c, r1 + mov pc, lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + mov pc, lr + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + stmfd sp!, {r4} @ push cpsr + mrs r4, spsr + stmfd sp!, {r4} @ push spsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r4} @ pop new task cpsr + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r4} @ pop new task cpsr + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 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] + mov pc, lr diff --git a/rt-thread/libcpu/arm/AT91SAM7X/context_rvds.S b/rt-thread/libcpu/arm/AT91SAM7X/context_rvds.S new file mode 100644 index 0000000..641ec7a --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7X/context_rvds.S @@ -0,0 +1,107 @@ +;/* +; * File : context_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, 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-20 Bernard first version +; */ + +NOINT EQU 0xc0 ; disable interrupt in psr + + AREA |.text|, CODE, READONLY, ALIGN=2 + ARM + REQUIRE8 + PRESERVE8 + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ +rt_hw_interrupt_disable PROC + EXPORT rt_hw_interrupt_disable + MRS r0, cpsr + ORR r1, r0, #NOINT + MSR cpsr_c, r1 + BX lr + ENDP + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ +rt_hw_interrupt_enable PROC + EXPORT rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + ENDP + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ +rt_hw_context_switch PROC + EXPORT rt_hw_context_switch + STMFD sp!, {lr} ; push pc (lr should be pushed in place of PC) + STMFD sp!, {r0-r12, lr} ; push lr & register file + + MRS r4, cpsr + STMFD sp!, {r4} ; push cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push spsr + + STR sp, [r0] ; store sp in preempted tasks TCB + LDR sp, [r1] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ +rt_hw_context_switch_to PROC + EXPORT rt_hw_context_switch_to + LDR sp, [r0] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +rt_hw_context_switch_interrupt PROC + EXPORT rt_hw_context_switch_interrupt + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 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] + BX lr + ENDP + + END \ No newline at end of file diff --git a/rt-thread/libcpu/arm/AT91SAM7X/cpu.c b/rt-thread/libcpu/arm/AT91SAM7X/cpu.c new file mode 100644 index 0000000..1905da8 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7X/cpu.c @@ -0,0 +1,42 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop 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 first version + */ + +#include + + +/** + * @addtogroup AT91SAM7X + */ +/*@{*/ + +/** + * this function will reset CPU + * + */ +void rt_hw_cpu_reset() +{ +} + +/** + * this function will shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_kprintf("shutdown...\n"); + + while (1); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/AT91SAM7X/interrupt.c b/rt-thread/libcpu/arm/AT91SAM7X/interrupt.c new file mode 100644 index 0000000..71884f9 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7X/interrupt.c @@ -0,0 +1,114 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-08-23 Bernard first version + * 2013-03-29 aozima Modify the interrupt interface implementations. + */ + +#include +#include +#include "AT91SAM7X256.h" + +#define MAX_HANDLERS 32 + +/* exception and interrupt handler table */ +struct rt_irq_desc irq_desc[MAX_HANDLERS]; + +extern rt_uint32_t rt_interrupt_nest; + +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +/** + * @addtogroup AT91SAM7 + */ +/*@{*/ + +static void rt_hw_interrupt_handler(int vector, void *param) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + rt_base_t index; + + /* init exceptions table */ + for(index=0; index < MAX_HANDLERS; index++) + { + irq_desc[index].handler = (rt_isr_handler_t)rt_hw_interrupt_handler; + irq_desc[index].param = RT_NULL; + } + + for (index = 0; index < MAX_HANDLERS; index ++) + { + AT91C_BASE_AIC->AIC_SVR[index] = (rt_uint32_t)rt_hw_interrupt_handler; + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + /* disable interrupt */ + AT91C_BASE_AIC->AIC_IDCR = 1 << vector; + + /* clear interrupt */ + AT91C_BASE_AIC->AIC_ICCR = 1 << vector; +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + AT91C_BASE_AIC->AIC_IECR = 1 << vector; +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param handler the interrupt service routine to be installed + * @param param the parameter for interrupt service routine + * @name unused. + * + * @return the old handler + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + if(vector >= 0 && vector < MAX_HANDLERS) + { + old_handler = irq_desc[vector].handler; + if (handler != RT_NULL) + { + irq_desc[vector].handler = (rt_isr_handler_t)handler; + irq_desc[vector].param = param; + } + } + + return old_handler; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/AT91SAM7X/stack.c b/rt-thread/libcpu/arm/AT91SAM7X/stack.c new file mode 100644 index 0000000..d6711a5 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7X/stack.c @@ -0,0 +1,63 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-08-23 Bernard the first version + */ +#include + +#define SVCMODE 0x13 + +/** + * @addtogroup AT91SAM7 + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + *(--stk) = SVCMODE; /* cpsr */ + *(--stk) = SVCMODE; /* spsr */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/AT91SAM7X/start_gcc.S b/rt-thread/libcpu/arm/AT91SAM7X/start_gcc.S new file mode 100644 index 0000000..119f3cd --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7X/start_gcc.S @@ -0,0 +1,279 @@ +/* + * File : start.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-08-31 Bernard first version + */ + + /* Internal Memory Base Addresses */ + .equ FLASH_BASE, 0x00100000 + .equ RAM_BASE, 0x00200000 + + /* Stack Configuration */ + .equ TOP_STACK, 0x00204000 + .equ UND_STACK_SIZE, 0x00000100 + .equ SVC_STACK_SIZE, 0x00000400 + .equ ABT_STACK_SIZE, 0x00000100 + .equ FIQ_STACK_SIZE, 0x00000100 + .equ IRQ_STACK_SIZE, 0x00000100 + .equ USR_STACK_SIZE, 0x00000004 + + /* ARM architecture definitions */ + .equ MODE_USR, 0x10 + .equ MODE_FIQ, 0x11 + .equ MODE_IRQ, 0x12 + .equ MODE_SVC, 0x13 + .equ MODE_ABT, 0x17 + .equ MODE_UND, 0x1B + .equ MODE_SYS, 0x1F + + .equ I_BIT, 0x80 /* when this bit is set, IRQ is disabled */ + .equ F_BIT, 0x40 /* when this bit is set, FIQ is disabled */ + +.section .init, "ax" +.code 32 +.align 0 +.globl _start +_start: + b reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + nop /* reserved vector */ + ldr pc, _vector_irq + ldr pc, _vector_fiq + +_vector_undef: .word vector_undef +_vector_swi: .word vector_swi +_vector_pabt: .word vector_pabt +_vector_dabt: .word vector_dabt +_vector_resv: .word vector_resv +_vector_irq: .word vector_irq +_vector_fiq: .word vector_fiq + +/* + * rtthread bss start and end + * which are defined in linker script + */ +.globl _bss_start +_bss_start: .word __bss_start +.globl _bss_end +_bss_end: .word __bss_end + +/* the system entry */ +reset: + /* disable watchdog */ + ldr r0, =0xFFFFFD40 + ldr r1, =0x00008000 + str r1, [r0, #0x04] + + /* enable the main oscillator */ + ldr r0, =0xFFFFFC00 + ldr r1, =0x00000601 + str r1, [r0, #0x20] + + /* wait for main oscillator to stabilize */ +moscs_loop: + ldr r2, [r0, #0x68] + ands r2, r2, #1 + beq moscs_loop + + /* set up the PLL */ + ldr r1, =0x00191C05 + str r1, [r0, #0x2C] + + /* wait for PLL to lock */ +pll_loop: + ldr r2, [r0, #0x68] + ands r2, r2, #0x04 + beq pll_loop + + /* select clock */ + ldr r1, =0x00000007 + str r1, [r0, #0x30] + +#ifdef __FLASH_BUILD__ + /* copy exception vectors into internal sram */ + /* + mov r8, #RAM_BASE + ldr r9, =_start + ldmia r9!, {r0-r7} + stmia r8!, {r0-r7} + ldmia r9!, {r0-r6} + stmia r8!, {r0-r6} + */ +#endif + + /* setup stack for each mode */ + ldr r0, =TOP_STACK + + /* set stack */ + /* undefined instruction mode */ + msr cpsr_c, #MODE_UND|I_BIT|F_BIT + mov sp, r0 + sub r0, r0, #UND_STACK_SIZE + + /* abort mode */ + msr cpsr_c, #MODE_ABT|I_BIT|F_BIT + mov sp, r0 + sub r0, r0, #ABT_STACK_SIZE + + /* FIQ mode */ + msr cpsr_c, #MODE_FIQ|I_BIT|F_BIT + mov sp, r0 + sub r0, r0, #FIQ_STACK_SIZE + + /* IRQ mode */ + msr cpsr_c, #MODE_IRQ|I_BIT|F_BIT + mov sp, r0 + sub r0, r0, #IRQ_STACK_SIZE + + /* supervisor mode */ + msr cpsr_c, #MODE_SVC|I_BIT|F_BIT + mov sp, r0 + + /* remap SRAM to 0x0000 */ + /* + ldr r0, =0xFFFFFF00 + mov r1, #0x01 + str r1, [r0] + */ + + /* mask all IRQs */ + ldr r1, =0xFFFFF124 + ldr r0, =0XFFFFFFFF + str r0, [r1] + + /* copy .data to SRAM */ + ldr r1, =_sidata /* .data start in image */ + ldr r2, =_edata /* .data end in image */ + ldr r3, =_sdata /* sram data start */ +data_loop: + ldr r0, [r1, #0] + str r0, [r3] + + add r1, r1, #4 + add r3, r3, #4 + + cmp r3, r2 /* check if data to clear */ + blo data_loop /* loop until done */ + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop +ctor_end: + + + /* start RT-Thread Kernel */ + ldr pc, _rtthread_startup + +_rtthread_startup: .word rtthread_startup + +/* exception handlers */ +vector_undef: b vector_undef +vector_swi : b vector_swi +vector_pabt : b vector_pabt +vector_dabt : b vector_dabt +vector_resv : b vector_resv + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +vector_irq: + stmfd sp!, {r0-r12,lr} + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + + /* + * if rt_thread_switch_interrupt_flag set, jump to + * rt_hw_context_switch_interrupt_do and don't return + */ + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq rt_hw_context_switch_interrupt_do + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc,lr,#4 + +/* + * void rt_hw_context_switch_interrupt_do(rt_base_t flag) + */ +rt_hw_context_switch_interrupt_do: + mov r1, #0 @ clear flag + str r1, [r0] + + ldmfd sp!, {r0-r12,lr}@ reload saved registers + stmfd sp!, {r0-r3} @ save r0-r3 + mov r1, sp + add sp, sp, #16 @ restore sp + sub r2, lr, #4 @ save old task's pc to r2 + + mrs r3, spsr @ disable interrupt + orr r0, r3, #I_BIT|F_BIT + msr spsr_c, r0 + + ldr r0, =.+8 @ switch to interrupted task's stack + movs pc, r0 + + stmfd sp!, {r2} @ push old task's pc + stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4 + mov r4, r1 @ Special optimised code below + mov r5, r3 + ldmfd r4!, {r0-r3} + stmfd sp!, {r0-r3} @ push old task's r3-r0 + stmfd sp!, {r5} @ push old task's psr + mrs r4, spsr + stmfd sp!, {r4} @ push old task's spsr + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] @ store sp in preempted tasks's TCB + + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] @ get new task's stack pointer + + ldmfd sp!, {r4} @ pop new task's spsr + msr SPSR_cxsf, r4 + ldmfd sp!, {r4} @ pop new task's psr + msr CPSR_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc} @ pop new task's r0-r12,lr & pc diff --git a/rt-thread/libcpu/arm/AT91SAM7X/start_rvds.S b/rt-thread/libcpu/arm/AT91SAM7X/start_rvds.S new file mode 100644 index 0000000..9760965 --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7X/start_rvds.S @@ -0,0 +1,517 @@ +;/*****************************************************************************/ +;/* SAM7.S: Startup file for Atmel AT91SAM7 device series */ +;/*****************************************************************************/ +;/* <<< Use Configuration Wizard in Context Menu >>> */ +;/*****************************************************************************/ +;/* This file is part of the uVision/ARM development tools. */ +;/* Copyright (c) 2005-2006 Keil Software. All rights reserved. */ +;/* This software may only be used under the terms of a valid, current, */ +;/* end user licence from KEIL for a compatible version of KEIL software */ +;/* development tools. Nothing else gives you the right to use this software. */ +;/*****************************************************************************/ + + +;/* +; * The SAM7.S code is executed after CPU Reset. This file may be +; * translated with the following SET symbols. In uVision these SET +; * symbols are entered under Options - ASM - Define. +; * +; * REMAP: when set the startup code remaps exception vectors from +; * on-chip RAM to address 0. +; * +; * RAM_INTVEC: when set the startup code copies exception vectors +; * from on-chip Flash to on-chip RAM. +; */ + + +; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs + +; 2009-12-28 MingBai Bug fix (USR mode stack removed). +; 2009-12-29 MingBai Merge svc and irq stack, add abort handler. + +Mode_USR EQU 0x10 +Mode_FIQ EQU 0x11 +Mode_IRQ EQU 0x12 +Mode_SVC EQU 0x13 +Mode_ABT EQU 0x17 +Mode_UND EQU 0x1B +Mode_SYS EQU 0x1F + +I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled +F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled + + +; Internal Memory Base Addresses +FLASH_BASE EQU 0x00100000 +RAM_BASE EQU 0x00200000 + + +;// Stack Configuration (Stack Sizes in Bytes) +;// Undefined Mode <0x0-0xFFFFFFFF:8> +;// Supervisor Mode <0x0-0xFFFFFFFF:8> +;// Abort Mode <0x0-0xFFFFFFFF:8> +;// Fast Interrupt Mode <0x0-0xFFFFFFFF:8> +;// Interrupt Mode <0x0-0xFFFFFFFF:8> +;// User/System Mode <0x0-0xFFFFFFFF:8> +;// + +UND_Stack_Size EQU 0x00000000 +SVC_Stack_Size EQU 0x00000000 +ABT_Stack_Size EQU 0x00000000 +FIQ_Stack_Size EQU 0x00000000 +IRQ_Stack_Size EQU 0x00000100 +USR_Stack_Size EQU 0x00000000 + +ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + FIQ_Stack_Size + IRQ_Stack_Size) + + AREA STACK, NOINIT, READWRITE, ALIGN=3 + +Stack_Mem SPACE USR_Stack_Size +__initial_sp SPACE ISR_Stack_Size +Stack_Top + + +;// Heap Configuration +;// Heap Size (in Bytes) <0x0-0xFFFFFFFF> +;// + +Heap_Size EQU 0x00000000 + + AREA HEAP, NOINIT, READWRITE, ALIGN=3 +__heap_base +Heap_Mem SPACE Heap_Size +__heap_limit + + +; Reset Controller (RSTC) definitions +RSTC_BASE EQU 0xFFFFFD00 ; RSTC Base Address +RSTC_MR EQU 0x08 ; RSTC_MR Offset + +;/* +;// Reset Controller (RSTC) +;// URSTEN: User Reset Enable +;// Enables NRST Pin to generate Reset +;// ERSTL: External Reset Length <0-15> +;// External Reset Time in 2^(ERSTL+1) Slow Clock Cycles +;// +;*/ +RSTC_SETUP EQU 1 +RSTC_MR_Val EQU 0xA5000401 + + +; Embedded Flash Controller (EFC) definitions +EFC_BASE EQU 0xFFFFFF00 ; EFC Base Address +EFC0_FMR EQU 0x60 ; EFC0_FMR Offset +EFC1_FMR EQU 0x70 ; EFC1_FMR Offset + +;// Embedded Flash Controller 0 (EFC0) +;// FMCN: Flash Microsecond Cycle Number <0-255> +;// Number of Master Clock Cycles in 1us +;// FWS: Flash Wait State +;// <0=> Read: 1 cycle / Write: 2 cycles +;// <1=> Read: 2 cycle / Write: 3 cycles +;// <2=> Read: 3 cycle / Write: 4 cycles +;// <3=> Read: 4 cycle / Write: 4 cycles +;// +EFC0_SETUP EQU 1 +EFC0_FMR_Val EQU 0x00320100 + +;// Embedded Flash Controller 1 (EFC1) +;// FMCN: Flash Microsecond Cycle Number <0-255> +;// Number of Master Clock Cycles in 1us +;// FWS: Flash Wait State +;// <0=> Read: 1 cycle / Write: 2 cycles +;// <1=> Read: 2 cycle / Write: 3 cycles +;// <2=> Read: 3 cycle / Write: 4 cycles +;// <3=> Read: 4 cycle / Write: 4 cycles +;// +EFC1_SETUP EQU 0 +EFC1_FMR_Val EQU 0x00320100 + + +; Watchdog Timer (WDT) definitions +WDT_BASE EQU 0xFFFFFD40 ; WDT Base Address +WDT_MR EQU 0x04 ; WDT_MR Offset + +;// Watchdog Timer (WDT) +;// WDV: Watchdog Counter Value <0-4095> +;// WDD: Watchdog Delta Value <0-4095> +;// WDFIEN: Watchdog Fault Interrupt Enable +;// WDRSTEN: Watchdog Reset Enable +;// WDRPROC: Watchdog Reset Processor +;// WDDBGHLT: Watchdog Debug Halt +;// WDIDLEHLT: Watchdog Idle Halt +;// WDDIS: Watchdog Disable +;// +WDT_SETUP EQU 1 +WDT_MR_Val EQU 0x00008000 + + +; Power Mangement Controller (PMC) definitions +PMC_BASE EQU 0xFFFFFC00 ; PMC Base Address +PMC_MOR EQU 0x20 ; PMC_MOR Offset +PMC_MCFR EQU 0x24 ; PMC_MCFR Offset +PMC_PLLR EQU 0x2C ; PMC_PLLR Offset +PMC_MCKR EQU 0x30 ; PMC_MCKR Offset +PMC_SR EQU 0x68 ; PMC_SR Offset +PMC_MOSCEN EQU (1<<0) ; Main Oscillator Enable +PMC_OSCBYPASS EQU (1<<1) ; Main Oscillator Bypass +PMC_OSCOUNT EQU (0xFF<<8) ; Main OScillator Start-up Time +PMC_DIV EQU (0xFF<<0) ; PLL Divider +PMC_PLLCOUNT EQU (0x3F<<8) ; PLL Lock Counter +PMC_OUT EQU (0x03<<14) ; PLL Clock Frequency Range +PMC_MUL EQU (0x7FF<<16) ; PLL Multiplier +PMC_USBDIV EQU (0x03<<28) ; USB Clock Divider +PMC_CSS EQU (3<<0) ; Clock Source Selection +PMC_PRES EQU (7<<2) ; Prescaler Selection +PMC_MOSCS EQU (1<<0) ; Main Oscillator Stable +PMC_LOCK EQU (1<<2) ; PLL Lock Status +PMC_MCKRDY EQU (1<<3) ; Master Clock Status + +;// Power Mangement Controller (PMC) +;// Main Oscillator +;// MOSCEN: Main Oscillator Enable +;// OSCBYPASS: Oscillator Bypass +;// OSCCOUNT: Main Oscillator Startup Time <0-255> +;// +;// Phase Locked Loop (PLL) +;// DIV: PLL Divider <0-255> +;// MUL: PLL Multiplier <0-2047> +;// PLL Output is multiplied by MUL+1 +;// OUT: PLL Clock Frequency Range +;// <0=> 80..160MHz <1=> Reserved +;// <2=> 150..220MHz <3=> Reserved +;// PLLCOUNT: PLL Lock Counter <0-63> +;// USBDIV: USB Clock Divider +;// <0=> None <1=> 2 <2=> 4 <3=> Reserved +;// +;// CSS: Clock Source Selection +;// <0=> Slow Clock +;// <1=> Main Clock +;// <2=> Reserved +;// <3=> PLL Clock +;// PRES: Prescaler +;// <0=> None +;// <1=> Clock / 2 <2=> Clock / 4 +;// <3=> Clock / 8 <4=> Clock / 16 +;// <5=> Clock / 32 <6=> Clock / 64 +;// <7=> Reserved +;// +PMC_SETUP EQU 1 +PMC_MOR_Val EQU 0x00000601 +PMC_PLLR_Val EQU 0x00191C05 +PMC_MCKR_Val EQU 0x00000007 + + + PRESERVE8 + + +; Area Definition and Entry Point +; Startup Code must be linked first at Address at which it expects to run. + + AREA RESET, CODE, READONLY + ARM + + +; Exception Vectors +; Mapped to Address 0. +; Absolute addressing mode must be used. +; Dummy Handlers are implemented as infinite loops which can be modified. + +Vectors LDR PC,Reset_Addr + LDR PC,Undef_Addr + LDR PC,SWI_Addr + LDR PC,PAbt_Addr + LDR PC,DAbt_Addr + NOP ; Reserved Vector + LDR PC,IRQ_Addr + LDR PC,FIQ_Addr + +Reset_Addr DCD Reset_Handler +Undef_Addr DCD Undef_Handler +SWI_Addr DCD SWI_Handler +PAbt_Addr DCD PAbt_Handler +DAbt_Addr DCD DAbt_Handler + DCD 0 ; Reserved Address +IRQ_Addr DCD IRQ_Handler +FIQ_Addr DCD FIQ_Handler + +Undef_Handler B Undef_Handler +SWI_Handler B SWI_Handler +PAbt_Handler B Abort_Handler +DAbt_Handler B Abort_Handler +FIQ_Handler B FIQ_Handler + + +; Reset Handler + + EXPORT Reset_Handler +Reset_Handler + + +; Setup RSTC + IF RSTC_SETUP != 0 + LDR R0, =RSTC_BASE + LDR R1, =RSTC_MR_Val + STR R1, [R0, #RSTC_MR] + ENDIF + + +; Setup EFC0 + IF EFC0_SETUP != 0 + LDR R0, =EFC_BASE + LDR R1, =EFC0_FMR_Val + STR R1, [R0, #EFC0_FMR] + ENDIF + +; Setup EFC1 + IF EFC1_SETUP != 0 + LDR R0, =EFC_BASE + LDR R1, =EFC1_FMR_Val + STR R1, [R0, #EFC1_FMR] + ENDIF + +; Setup WDT + IF WDT_SETUP != 0 + LDR R0, =WDT_BASE + LDR R1, =WDT_MR_Val + STR R1, [R0, #WDT_MR] + ENDIF + + +; Setup PMC + IF PMC_SETUP != 0 + LDR R0, =PMC_BASE + +; Setup Main Oscillator + LDR R1, =PMC_MOR_Val + STR R1, [R0, #PMC_MOR] + +; Wait until Main Oscillator is stablilized + IF (PMC_MOR_Val:AND:PMC_MOSCEN) != 0 +MOSCS_Loop LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MOSCS + BEQ MOSCS_Loop + ENDIF + +; Setup the PLL + IF (PMC_PLLR_Val:AND:PMC_MUL) != 0 + LDR R1, =PMC_PLLR_Val + STR R1, [R0, #PMC_PLLR] + +; Wait until PLL is stabilized +PLL_Loop LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_LOCK + BEQ PLL_Loop + ENDIF + +; Select Clock + IF (PMC_MCKR_Val:AND:PMC_CSS) == 1 ; Main Clock Selected + LDR R1, =PMC_MCKR_Val + AND R1, #PMC_CSS + STR R1, [R0, #PMC_MCKR] +WAIT_Rdy1 LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MCKRDY + BEQ WAIT_Rdy1 + LDR R1, =PMC_MCKR_Val + STR R1, [R0, #PMC_MCKR] +WAIT_Rdy2 LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MCKRDY + BEQ WAIT_Rdy2 + ELIF (PMC_MCKR_Val:AND:PMC_CSS) == 3 ; PLL Clock Selected + LDR R1, =PMC_MCKR_Val + AND R1, #PMC_PRES + STR R1, [R0, #PMC_MCKR] +WAIT_Rdy1 LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MCKRDY + BEQ WAIT_Rdy1 + LDR R1, =PMC_MCKR_Val + STR R1, [R0, #PMC_MCKR] +WAIT_Rdy2 LDR R2, [R0, #PMC_SR] + ANDS R2, R2, #PMC_MCKRDY + BEQ WAIT_Rdy2 + ENDIF ; Select Clock + ENDIF ; PMC_SETUP + + +; Copy Exception Vectors to Internal RAM + + IF :DEF:RAM_INTVEC + ADR R8, Vectors ; Source + LDR R9, =RAM_BASE ; Destination + LDMIA R8!, {R0-R7} ; Load Vectors + STMIA R9!, {R0-R7} ; Store Vectors + LDMIA R8!, {R0-R7} ; Load Handler Addresses + STMIA R9!, {R0-R7} ; Store Handler Addresses + ENDIF + + +; Remap on-chip RAM to address 0 + +MC_BASE EQU 0xFFFFFF00 ; MC Base Address +MC_RCR EQU 0x00 ; MC_RCR Offset + + IF :DEF:REMAP + LDR R0, =MC_BASE + MOV R1, #1 + STR R1, [R0, #MC_RCR] ; Remap + ENDIF + + +; Setup Stack for each mode + + LDR R0, =Stack_Top + +; Enter Undefined Instruction Mode and set its Stack Pointer + MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit + MOV SP, R0 + ;SUB R0, R0, #UND_Stack_Size + +; Enter Abort Mode and set its Stack Pointer + MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit + MOV SP, R0 + ;SUB R0, R0, #ABT_Stack_Size + +; Enter FIQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + ;SUB R0, R0, #FIQ_Stack_Size + +; Enter IRQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + ;SUB R0, R0, #IRQ_Stack_Size + +; Enter Supervisor Mode and set its Stack Pointer + MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit + MOV SP, R0 + ; SUB R0, R0, #SVC_Stack_Size + +; Enter User Mode and set its Stack Pointer + ; MSR CPSR_c, #Mode_USR + IF :DEF:__MICROLIB + + EXPORT __initial_sp + + ELSE + + ; No usr mode stack here. + ;MOV SP, R0 + ;SUB SL, SP, #USR_Stack_Size + + ENDIF + + +; Enter the C code + + IMPORT __main + LDR R0, =__main + BX R0 + + IMPORT rt_interrupt_enter + IMPORT rt_interrupt_leave + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + IMPORT rt_hw_trap_irq + IMPORT rt_hw_trap_abort + IMPORT rt_interrupt_nest + +Abort_Handler PROC + EXPORT Abort_Handler + stmfd sp!, {r0-r12,lr} + LDR r0, =rt_interrupt_nest + LDR r1, [r0] + CMP r1, #0 +DeadLoop BHI DeadLoop ; Abort happened in irq mode, halt system. + bl rt_interrupt_enter + bl rt_hw_trap_abort + bl rt_interrupt_leave + b SWITCH + ENDP + +IRQ_Handler PROC + EXPORT IRQ_Handler + STMFD sp!, {r0-r12,lr} + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; if rt_thread_switch_interrupt_flag set, jump to + ; rt_hw_context_switch_interrupt_do and don't return +SWITCH LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD sp!, {r0-r12,lr} + SUBS pc, lr, #4 + ENDP + +; /* +; * void rt_hw_context_switch_interrupt_do(rt_base_t flag) +; */ +rt_hw_context_switch_interrupt_do PROC + EXPORT rt_hw_context_switch_interrupt_do + MOV r1, #0 ; clear flag + STR r1, [r0] + + LDMFD sp!, {r0-r12,lr}; reload saved registers + STMFD sp!, {r0-r3} ; save r0-r3 + MOV r1, sp + ADD sp, sp, #16 ; restore sp + SUB r2, lr, #4 ; save old task's pc to r2 + + MRS r3, spsr ; get cpsr of interrupt thread + + ; switch to SVC mode and no interrupt + MSR cpsr_c, #I_Bit|F_Bit|Mode_SVC + + STMFD sp!, {r2} ; push old task's pc + STMFD sp!, {r4-r12,lr}; push old task's lr,r12-r4 + MOV r4, r1 ; Special optimised code below + MOV r5, r3 + LDMFD r4!, {r0-r3} + STMFD sp!, {r0-r3} ; push old task's r3-r0 + STMFD sp!, {r5} ; push old task's cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push old task's spsr + + LDR r4, =rt_interrupt_from_thread + LDR r5, [r4] + STR sp, [r5] ; store sp in preempted tasks's TCB + + LDR r6, =rt_interrupt_to_thread + LDR r6, [r6] + LDR sp, [r6] ; get new task's stack pointer + + LDMFD sp!, {r4} ; pop new task's spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task's psr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc + ENDP + + IF :DEF:__MICROLIB + + EXPORT __heap_base + EXPORT __heap_limit + + ELSE +; User Initial Stack & Heap + AREA |.text|, CODE, READONLY + + IMPORT __use_two_region_memory + EXPORT __user_initial_stackheap +__user_initial_stackheap + + LDR R0, = Heap_Mem + LDR R1, = (Stack_Mem + IRQ_Stack_Size) + LDR R2, = (Heap_Mem + Heap_Size) + LDR R3, = Stack_Mem + BX LR + ENDIF + + END diff --git a/rt-thread/libcpu/arm/AT91SAM7X/trap.c b/rt-thread/libcpu/arm/AT91SAM7X/trap.c new file mode 100644 index 0000000..74d1cba --- /dev/null +++ b/rt-thread/libcpu/arm/AT91SAM7X/trap.c @@ -0,0 +1,53 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-08-25 Bernard first version + */ + +#include +#include + +#include "AT91SAM7X256.h" + +/** + * @addtogroup AT91SAM7 + */ +/*@{*/ + +void rt_hw_trap_irq(void) +{ + int irqno; + extern struct rt_irq_desc irq_desc[]; + + /* get interrupt number */ + irqno = AT91C_BASE_AIC->AIC_ISR; + + /* invoke isr with parameters */ + irq_desc[irqno].handler(irqno, irq_desc[irqno].param); + + /* end of interrupt */ + AT91C_BASE_AIC->AIC_EOICR = 0; +} + +void rt_hw_trap_fiq(void) +{ + rt_kprintf("fast interrupt request\n"); +} + +extern struct rt_thread* rt_current_thread; +void rt_hw_trap_abort(void) +{ + rt_kprintf("Abort occured!!! Thread [%s] suspended.\n",rt_current_thread->name); + rt_thread_suspend(rt_current_thread); + rt_schedule(); + +} +/*@}*/ diff --git a/rt-thread/libcpu/arm/am335x/am33xx.h b/rt-thread/libcpu/arm/am335x/am33xx.h new file mode 100644 index 0000000..68ea447 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/am33xx.h @@ -0,0 +1,341 @@ +#ifndef __AM33XX_H__ +#define __AM33XX_H__ + +#define REG32(x) (*((volatile unsigned int *)(x))) +#define REG16(x) (*((volatile unsigned short *)(x))) + +/** Cache Line size in ARM Cortex-A8. */ +#define AM33XX_CACHELINE_SIZE (64) + +/** @brief Base address of AINTC memory mapped registers */ +#define AM33XX_AINTC_REGS (0x48200000) + + +/** @brief Base addresses of control module registers */ +#define AM33XX_CTLM_REGS (0x44e10000) + +/** @brief Base addresses of USB memory mapped registers */ +#define AM33XX_USB_0_BASE (0x47401400) +#define AM33XX_USB_1_BASE (0x47401C00) +/** @brief Base addresses of SPI memory mapped registers */ +#define AM33XX_SPI_0_REGS (0x48030000) +#define AM33XX_SPI_1_REGS (0x481A0000) + +/** @brief Base addresses of GPIO memory mapped registers */ +#define AM33XX_GPIO_0_REGS (0x44E07000) +#define AM33XX_GPIO_1_REGS (0x4804C000) +#define AM33XX_GPIO_2_REGS (0x481AC000) +#define AM33XX_GPIO_3_REGS (0x481AE000) + +/** @brief Base addresses of DMTIMER memory mapped registers */ +#define AM33XX_DMTIMER_0_REGS (0x44E05000) +#define AM33XX_DMTIMER_1_REGS (0x44E31000) +#define AM33XX_DMTIMER_2_REGS (0x48040000) +#define AM33XX_DMTIMER_3_REGS (0x48042000) +#define AM33XX_DMTIMER_4_REGS (0x48044000) +#define AM33XX_DMTIMER_5_REGS (0x48046000) +#define AM33XX_DMTIMER_6_REGS (0x48048000) +#define AM33XX_DMTIMER_7_REGS (0x4804A000) + +/** @brief Base address of MMC memory mapped registers */ +#define AM33XX_MMCHS_0_REGS (0x48060000) +#define AM33XX_MMCHS_1_REGS (0x481D8000) +#define AM33XX_MMCHS_2_REGS (0x47810000) + +/** @brief Base address of GPMC memory mapped registers */ +#define AM33XX_GPMC_0_REGS (0x50000000) + +/** @brief Base address of GPMC memory mapped registers */ +#define AM33XX_ELM_0_REGS (0x48080000) + +/** @brief Base address of I2C memory mapped registers */ +#define AM33XX_I2C_0_REGS (0x44E0B000) +#define AM33XX_I2C_1_REGS (0x4802A000) +#define AM33XX_I2C_2_REGS (0x4819C000) + +/** @brief Base address of WDT memory mapped registers */ +#define AM33XX_WDT_0_REGS (0x44E33000) +#define AM33XX_WDT_1_REGS (0x44E35000) + +/** @brief Base address of WDT memory mapped registers */ +#define AM33XX_CPSW_SS_REGS (0x4A100000) +#define AM33XX_CPSW_MDIO_REGS (0x4A101000) +#define AM33XX_CPSW_WR_REGS (0x4A101200) +#define AM33XX_CPSW_CPDMA_REGS (0x4A100800) +#define AM33XX_CPSW_ALE_REGS (0x4A100D00) +#define AM33XX_CPSW_STAT_REGS (0x4A100900) +#define AM33XX_CPSW_PORT_0_REGS (0x4A100100) +#define AM33XX_CPSW_PORT_1_REGS (0x4A100200) +#define AM33XX_CPSW_SLIVER_1_REGS (0x4A100D80) +#define AM33XX_CPSW_PORT_2_REGS (0x4A100300) +#define AM33XX_CPSW_SLIVER_2_REGS (0x4A100DC0) +#define AM33XX_CPSW_CPPI_RAM_REGS (0x4A102000) + +/** @brief Base address of McASP memory mapped registers */ +#define AM33XX_MCASP_1_CTRL_REGS (0x4803C000) +#define AM33XX_MCASP_1_FIFO_REGS (AM33XX_MCASP_1_CTRL_REGS + 0x1000) +#define AM33XX_MCASP_1_DATA_REGS (0x46400000) + +/** @brief Base address of EMIF memory mapped registers */ +#define AM33XX_EMIF_0_REGS (0x4C000000) + +/** @brief Base addresses of RTC memory mapped registers */ +#define AM33XX_RTC_0_REGS (0x44E3E000) + +#define CM_PER(base) ((base) + 0) +#define CM_PER_L4LS_CLKSTCTRL(base) (CM_PER(base) + 0) +#define CM_PER_UART1_CLKCTRL(base) (CM_PER(base) + 0x6C) +#define CM_PER_UART2_CLKCTRL(base) (CM_PER(base) + 0x70) +#define CM_PER_UART3_CLKCTRL(base) (CM_PER(base) + 0x74) +#define CM_PER_UART4_CLKCTRL(base) (CM_PER(base) + 0x78) +#define CM_PER_UART5_CLKCTRL(base) (CM_PER(base) + 0x38) +#define CM_WKUP(base) ((base) + 0x400) +#define CM_DPLL(base) ((base) + 0x500) +#define CM_MPU(base) ((base) + 0x600) +#define CM_DEVICE(base) ((base) + 0x700) +#define CM_RTC(base) ((base) + 0x800) +#define CM_GFX(base) ((base) + 0x900) +#define CM_CEFUSE(base) ((base) + 0xA00) +#define OCP_AM33XXKET_RAM(base) ((base) + 0xB00) +#define PRM_PER(base) ((base) + 0xC00) +#define PRM_PER_PWRSTST(base) (PRM_PER(base) + 0x008) +#define PRM_PER_PWRSTCTRL(base) (PRM_PER(base) + 0x00C) +#define PRM_WKUP(base) ((base) + 0xD00) +#define PRM_MPU(base) ((base) + 0xE00) +#define PRM_DEVICE(base) ((base) + 0xF00) +#define PRM_RTC(base) ((base) + 0x1000) +#define PRM_GFX(base) ((base) + 0x1100) +#define PRM_CEFUSE(base) ((base) + 0x1200) + +/** @brief Base addresses of PRCM memory mapped registers */ +#define AM33XX_PRCM_REGS (0x44E00000) +#define AM33XX_CM_PER_REGS CM_PER(AM33XX_PRCM_REGS) +#define AM33XX_CM_WKUP_REGS CM_WKUP(AM33XX_PRCM_REGS) +#define AM33XX_CM_DPLL_REGS CM_DPLL(AM33XX_PRCM_REGS) +#define AM33XX_CM_MPU_REGS CM_MPU(AM33XX_PRCM_REGS) +#define AM33XX_CM_DEVICE_REGS CM_DEVICE(AM33XX_PRCM_REGS) +#define AM33XX_CM_RTC_REGS CM_RTC(AM33XX_PRCM_REGS) +#define AM33XX_CM_GFX_REGS CM_GFX(AM33XX_PRCM_REGS) +#define AM33XX_CM_CEFUSE_REGS CM_CEFUSE(AM33XX_PRCM_REGS) +#define AM33XX_OCP_AM33XXKET_RAM_REGS OCP_AM33XXKET_RAM(AM33XX_PRCM_REGS) +#define AM33XX_PRM_PER_REGS PRM_PER(AM33XX_PRCM_REGS) +#define AM33XX_PRM_WKUP_REGS PRM_WKUP(AM33XX_PRCM_REGS) +#define AM33XX_PRM_MPU_REGS PRM_MPU(AM33XX_PRCM_REGS) +#define AM33XX_PRM_DEVICE_REGS PRM_DEVICE(AM33XX_PRCM_REGS) +#define AM33XX_PRM_RTC_REGS PRM_RTC(AM33XX_PRCM_REGS) +#define AM33XX_PRM_GFX_REGS PRM_GFX(AM33XX_PRCM_REGS) +#define AM33XX_PRM_CEFUSE_REGS PRM_CEFUSE(AM33XX_PRCM_REGS) + +/** @brief Base address of control module memory mapped registers */ +#define AM33XX_CONTROL_REGS (0x44E10000) + + +/** @brief Base address of Channel controller memory mapped registers */ +#define AM33XX_EDMA30CC_0_REGS (0x49000000) + +/** @brief Base address of DCAN module memory mapped registers */ +#define AM33XX_DCAN_0_REGS (0x481CC000) +#define AM33XX_DCAN_1_REGS (0x481D0000) + +/******************************************************************************\ +* Parameterizable Configuration:- These are fed directly from the RTL +* parameters for the given AM33XX +\******************************************************************************/ +#define TPCC_MUX(n) 0xF90 + ((n) * 4) + + +#define AM33XX_LCDC_0_REGS 0x4830E000 + +#define AM33XX_ADC_TSC_0_REGS 0x44E0D000 + +/** @brief Base addresses of PWMSS memory mapped registers. */ + +#define AM33XX_PWMSS0_REGS (0x48300000) +#define AM33XX_PWMSS1_REGS (0x48302000) +#define AM33XX_PWMSS2_REGS (0x48304000) + +#define AM33XX_ECAP_REGS (0x00000100) +#define AM33XX_EQEP_REGS (0x00000180) +#define AM33XX_EPWM_REGS (0x00000200) + +#define AM33XX_ECAP_0_REGS (AM33XX_PWMSS0_REGS + AM33XX_ECAP_REGS) +#define AM33XX_ECAP_1_REGS (AM33XX_PWMSS1_REGS + AM33XX_ECAP_REGS) +#define AM33XX_ECAP_2_REGS (AM33XX_PWMSS2_REGS + AM33XX_ECAP_REGS) + +#define AM33XX_EQEP_0_REGS (AM33XX_PWMSS0_REGS + AM33XX_EQEP_REGS) +#define AM33XX_EQEP_1_REGS (AM33XX_PWMSS1_REGS + AM33XX_EQEP_REGS) +#define AM33XX_EQEP_2_REGS (AM33XX_PWMSS2_REGS + AM33XX_EQEP_REGS) + +#define AM33XX_EPWM_0_REGS (AM33XX_PWMSS0_REGS + AM33XX_EPWM_REGS) +#define AM33XX_EPWM_1_REGS (AM33XX_PWMSS1_REGS + AM33XX_EPWM_REGS) +#define AM33XX_EPWM_2_REGS (AM33XX_PWMSS2_REGS + AM33XX_EPWM_REGS) + +#define AM33XX_EPWM_MODULE_FREQ 100 + +/* PRCM registers */ +#define CM_PER_L4LS_CLKSTCTRL_REG(base) REG32((base) + 0x0) +#define CM_PER_UART1_CLKCTRL_REG(base) REG32(CM_PER_UART1_CLKCTRL(base)) +#define CM_PER_UART2_CLKCTRL_REG(base) REG32(CM_PER_UART2_CLKCTRL(base)) +#define CM_PER_UART3_CLKCTRL_REG(base) REG32(CM_PER_UART3_CLKCTRL(base)) +#define CM_PER_UART4_CLKCTRL_REG(base) REG32(CM_PER_UART4_CLKCTRL(base)) +#define CM_PER_UART5_CLKCTRL_REG(base) REG32(CM_PER_UART5_CLKCTRL(base)) + +#define CM_PER_TIMER7_CLKCTRL(base) REG32((base) + 0x7C) +#define CM_PER_TIMER2_CLKCTRL(base) REG32((base) + 0x80) + +#define PRM_PER_PWRSTST_REG(base) REG32(PRM_PER_PWRSTST(base)) +#define PRM_PER_PWRSTCTRL_REG(base) REG32(PRM_PER_PWRSTCTRL(base)) + +#define CM_DPLL_CLKSEL_TIMER7_CLK(base) REG32(CM_DPLL(base) + 0x4) +#define CM_DPLL_CLKSEL_TIMER2_CLK(base) REG32(CM_DPLL(base) + 0x8) + +/* timer registers */ +#define DMTIMER_TIDR(base) REG32(base + 0x0) +#define DMTIMER_TIOCP_CFG(base) REG32(base + 0x10) +#define DMTIMER_IRQ_EOI(base) REG32(base + 0x20) +#define DMTIMER_IRQSTATUS_RAW(base) REG32(base + 0x24) +#define DMTIMER_IRQSTATUS(base) REG32(base + 0x28) +#define DMTIMER_IRQENABLE_SET(base) REG32(base + 0x2C) +#define DMTIMER_IRQENABLE_CLR(base) REG32(base + 0x30) +#define DMTIMER_IRQWAKEEN(base) REG32(base + 0x34) +#define DMTIMER_TCLR(base) REG32(base + 0x38) +#define DMTIMER_TCRR(base) REG32(base + 0x3C) +#define DMTIMER_TLDR(base) REG32(base + 0x40) +#define DMTIMER_TTGR(base) REG32(base + 0x44) +#define DMTIMER_TWPS(base) REG32(base + 0x48) +#define DMTIMER_TMAR(base) REG32(base + 0x4C) +#define DMTIMER_TCAR(base, n) REG32(base + 0x50 + (((n) - 1) * 8)) +#define DMTIMER_TSICR(base) REG32(base + 0x54) + +#define EMU_INT 0 +#define COMMTX_INT 1 +#define COMMRX_INT 2 +#define BENCH_INT 3 +#define ELM_IRQ_INT 4 +#define NMI_INT 7 +#define L3DEBUG_INT 9 +#define L3APP_INT 10 +#define PRCM_INT 11 +#define EDMACOMP_INT 12 +#define EDMAMPERR_INT 13 +#define EDMAERR_INT 14 +#define ADC_TSC_GEN_INT 16 +#define USBSS_INT 17 +#define USB_INT0 18 +#define USB_INT1 19 +#define PRU_ICSS_EVTOUT0_INT 20 +#define PRU_ICSS_EVTOUT1_INT 21 +#define PRU_ICSS_EVTOUT2_INT 22 +#define PRU_ICSS_EVTOUT3_INT 23 +#define PRU_ICSS_EVTOUT4_INT 24 +#define PRU_ICSS_EVTOUT5_INT 25 +#define PRU_ICSS_EVTOUT6_INT 26 +#define PRU_ICSS_EVTOUT7_INT 27 +#define MMCSD1_INT 28 +#define MMCSD2_INT 29 +#define I2C2_INT 30 +#define ECAP0_INT 31 +#define GPIO_INT2A 32 +#define GPIO_INT2B 33 +#define USBWAKEUP_INT 34 +#define LCDC_INT 36 +#define GFX_INT 37 +#define EPWM2_INT 39 +#define CPSW_RXTHR0_INT 40 +#define CPSW_RX_INT0 41 +#define CPSW_TX_INT0 42 +#define CPSW_MISC0_INT 43 +#define UART3_INT 44 +#define UART4_INT 45 +#define UART5_INT 46 +#define ECAP1_INT 47 +#define DCAN0_INT0 52 +#define DCAN0_INT1 53 +#define DCAN0_PARITY 54 +#define DCAN1_INT0 55 +#define DCAN1_INT1 56 +#define DCAN1_PARITY 57 +#define EPWM0_TZINT 58 +#define EPWM1_TZINT 59 +#define EPWM2_TZINT 60 +#define ECAP2_INT 61 +#define GPIO_INT3A 62 +#define GPIO_INT3B 63 +#define MMCSD0_INT 64 +#define MCSPI0_INT 65 +#define TINT0 66 +#define TINT1_1MS 67 +#define TINT2 68 +#define TINT3 69 +#define I2C0_INT 70 +#define I2C1_INT 71 +#define UART0_INT 72 +#define UART1_INT 73 +#define UART2_INT 74 +#define RTC_INT 75 +#define RTC_ALARM_INT 76 +#define MB_INT0 77 +#define M3_TXEV 78 +#define EQEP0_INT 79 +#define MACTX_INT0 80 +#define MCARX_INT0 81 +#define MCATX_INT1 82 +#define MCARX_INT1 83 +#define EPWM0_INT 86 +#define EPWM1_INT 87 +#define EQEP1_INT 88 +#define EQEP2_INT 89 +#define DMA_INTR_PIN2 90 +#define WDT1_INT 91 +#define TINT4 92 +#define TINT5 93 +#define TINT6 94 +#define TINT7 95 +#define GPIO_INT0A 96 +#define GPIO_INT0B 97 +#define GPIO_INT1A 98 +#define GPIO_INT1B 99 +#define GPMC_INT 100 +#define DDRERR0 101 +#define TCERR_INT0 112 +#define TCERR_INT1 113 +#define TCERR_INT2 114 +#define ADC_TSC_PEN_INT 115 +#define SMRFLX_MPU 120 +#define SMRFLX_CORE 121 +#define DMA_INTR_PIN0 123 +#define DMA_INTR_PIN1 124 +#define MCSPI1_INT 125 + +struct rt_hw_register +{ + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long sp; + unsigned long lr; + unsigned long pc; + unsigned long cpsr; + unsigned long ORIG_r0; +}; + +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define ABORTMODE 0x17 +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +#endif diff --git a/rt-thread/libcpu/arm/am335x/context_gcc.S b/rt-thread/libcpu/arm/am335x/context_gcc.S new file mode 100644 index 0000000..a49ce08 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/context_gcc.S @@ -0,0 +1,102 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + cpsid if + bx lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr_c, r0 + bx lr + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + tst lr, #0x01 + orrne r4, r4, #0x20 @ it's thumb code + + stmfd sp!, {r4} @ push cpsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task cpsr to spsr + msr spsr_cxsf, r4 + +_do_switch: + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + + bic r4, r4, #0x20 @ must be ARM mode + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 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] + bx lr diff --git a/rt-thread/libcpu/arm/am335x/context_iar.S b/rt-thread/libcpu/arm/am335x/context_iar.S new file mode 100644 index 0000000..c53e15a --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/context_iar.S @@ -0,0 +1,96 @@ +;/* +; * File : context_iar.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; * 2011-08-14 weety copy from mini2440 +; * 2015-04-15 ArdaFu convert from context_gcc.s +; */ + +#define NOINT 0xc0 + + SECTION .text:CODE(6) +/* + * rt_base_t rt_hw_interrupt_disable(); + */ + PUBLIC rt_hw_interrupt_disable +rt_hw_interrupt_disable: + MRS R0, CPSR + ORR R1, R0, #NOINT + MSR CPSR_C, R1 + MOV PC, LR + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ + PUBLIC rt_hw_interrupt_enable +rt_hw_interrupt_enable: + MSR CPSR_CXSF, R0 + MOV PC, LR + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ + PUBLIC rt_hw_context_switch +rt_hw_context_switch: + STMFD SP!, {LR} ; push pc (lr should be pushed in place of PC) + STMFD SP!, {R0-R12, LR} ; push lr & register file + MRS R4, CPSR + STMFD SP!, {R4} ; push cpsr + STR SP, [R0] ; store sp in preempted tasks TCB + LDR SP, [R1] ; get new task stack pointer + LDMFD SP!, {R4} ; pop new task spsr + MSR SPSR_cxsf, R4 + LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ + PUBLIC rt_hw_context_switch_to +rt_hw_context_switch_to: + LDR SP, [R0] ; get new task stack pointer + LDMFD SP!, {R4} ; pop new task spsr + MSR SPSR_cxsf, R4 + LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + PUBLIC rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + LDR R2, =rt_thread_switch_interrupt_flag + LDR R3, [R2] + CMP R3, #1 + BEQ _reswitch + MOV R3, #1 ; set flag to 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] + MOV PC, LR + END + diff --git a/rt-thread/libcpu/arm/am335x/cp15_gcc.S b/rt-thread/libcpu/arm/am335x/cp15_gcc.S new file mode 100644 index 0000000..1f8e685 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/cp15_gcc.S @@ -0,0 +1,145 @@ +/* + * File : cp15_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * http://www.rt-thread.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.globl rt_cpu_vector_set_base +rt_cpu_vector_set_base: + mcr p15, #0, r0, c12, c0, #0 + dsb + bx lr + +.globl rt_cpu_vector_get_base +rt_cpu_vector_get_base: + mrc p15, #0, r0, c12, c0, #0 + bx lr + +.globl rt_cpu_get_sctlr +rt_cpu_get_sctlr: + mrc p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_cpu_dcache_enable +rt_cpu_dcache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_cpu_icache_enable +rt_cpu_icache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +_FLD_MAX_WAY: + .word 0x3ff +_FLD_MAX_IDX: + .word 0x7ff + +.globl rt_cpu_dcache_clean_flush +rt_cpu_dcache_clean_flush: + push {r4-r11} + dmb + mrc p15, #1, r0, c0, c0, #1 @ read clid register + ands r3, r0, #0x7000000 @ get level of coherency + mov r3, r3, lsr #23 + beq finished + mov r10, #0 +loop1: + add r2, r10, r10, lsr #1 + mov r1, r0, lsr r2 + and r1, r1, #7 + cmp r1, #2 + blt skip + mcr p15, #2, r10, c0, c0, #0 + isb + mrc p15, #1, r1, c0, c0, #0 + and r2, r1, #7 + add r2, r2, #4 + ldr r4, _FLD_MAX_WAY + ands r4, r4, r1, lsr #3 + clz r5, r4 + ldr r7, _FLD_MAX_IDX + ands r7, r7, r1, lsr #13 +loop2: + mov r9, r4 +loop3: + orr r11, r10, r9, lsl r5 + orr r11, r11, r7, lsl r2 + mcr p15, #0, r11, c7, c14, #2 + subs r9, r9, #1 + bge loop3 + subs r7, r7, #1 + bge loop2 +skip: + add r10, r10, #2 + cmp r3, r10 + bgt loop1 + +finished: + dsb + isb + pop {r4-r11} + bx lr + +.globl rt_cpu_dcache_disable +rt_cpu_dcache_disable: + push {r4-r11, lr} + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + bl rt_cpu_dcache_clean_flush + pop {r4-r11, lr} + bx lr + +.globl rt_cpu_icache_disable +rt_cpu_icache_disable: + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_cpu_mmu_disable +rt_cpu_mmu_disable: + mcr p15, #0, r0, c8, c7, #0 @ invalidate tlb + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #1 + mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit + dsb + bx lr + +.globl rt_cpu_mmu_enable +rt_cpu_mmu_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x001 + mcr p15, #0, r0, c1, c0, #0 @ set mmu enable bit + dsb + bx lr + +.globl rt_cpu_tlb_set +rt_cpu_tlb_set: + mcr p15, #0, r0, c2, c0, #0 + dmb + bx lr diff --git a/rt-thread/libcpu/arm/am335x/cp15_iar.s b/rt-thread/libcpu/arm/am335x/cp15_iar.s new file mode 100644 index 0000000..ae59ed0 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/cp15_iar.s @@ -0,0 +1,154 @@ +/* + * File : cp15_iar.s + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * http://www.rt-thread.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-04-06 zchong change to iar compiler from convert from cp15_gcc.S + */ + + SECTION .text:CODE:NOROOT(2) + + ARM + + EXPORT rt_cpu_vector_set_base +rt_cpu_vector_set_base: + MCR p15, #0, r0, c12, c0, #0 + DSB + BX lr + + EXPORT rt_cpu_vector_get_base +rt_cpu_vector_get_base: + MRC p15, #0, r0, c12, c0, #0 + BX lr + + EXPORT rt_cpu_get_sctlr +rt_cpu_get_sctlr: + MRC p15, #0, r0, c1, c0, #0 + BX lr + + EXPORT rt_cpu_dcache_enable +rt_cpu_dcache_enable: + MRC p15, #0, r0, c1, c0, #0 + ORR r0, r0, #0x00000004 + MCR p15, #0, r0, c1, c0, #0 + BX lr + + EXPORT rt_cpu_icache_enable +rt_cpu_icache_enable: + MRC p15, #0, r0, c1, c0, #0 + ORR r0, r0, #0x00001000 + MCR p15, #0, r0, c1, c0, #0 + BX lr + +;_FLD_MAX_WAY DEFINE 0x3ff +;_FLD_MAX_IDX DEFINE 0x7ff + + + EXPORT rt_cpu_dcache_clean_flush +rt_cpu_dcache_clean_flush: + PUSH {r4-r11} + DMB + MRC p15, #1, r0, c0, c0, #1 ; read clid register + ANDS r3, r0, #0x7000000 ; get level of coherency + MOV r3, r3, lsr #23 + BEQ finished + MOV r10, #0 +loop1: + ADD r2, r10, r10, lsr #1 + MOV r1, r0, lsr r2 + AND r1, r1, #7 + CMP r1, #2 + BLT skip + MCR p15, #2, r10, c0, c0, #0 + ISB + MRC p15, #1, r1, c0, c0, #0 + AND r2, r1, #7 + ADD r2, r2, #4 + ;LDR r4, _FLD_MAX_WAY + LDR r4, =0x3FF + ANDS r4, r4, r1, lsr #3 + CLZ r5, r4 + ;LDR r7, _FLD_MAX_IDX + LDR r7, =0x7FF + ANDS r7, r7, r1, lsr #13 +loop2: + MOV r9, r4 +loop3: + ORR r11, r10, r9, lsl r5 + ORR r11, r11, r7, lsl r2 + MCR p15, #0, r11, c7, c14, #2 + SUBS r9, r9, #1 + BGE loop3 + SUBS r7, r7, #1 + BGE loop2 +skip: + ADD r10, r10, #2 + CMP r3, r10 + BGT loop1 + +finished: + DSB + ISB + POP {r4-r11} + BX lr + + + EXPORT rt_cpu_dcache_disable +rt_cpu_dcache_disable: + PUSH {r4-r11, lr} + MRC p15, #0, r0, c1, c0, #0 + BIC r0, r0, #0x00000004 + MCR p15, #0, r0, c1, c0, #0 + BL rt_cpu_dcache_clean_flush + POP {r4-r11, lr} + BX lr + + + EXPORT rt_cpu_icache_disable +rt_cpu_icache_disable: + MRC p15, #0, r0, c1, c0, #0 + BIC r0, r0, #0x00001000 + MCR p15, #0, r0, c1, c0, #0 + BX lr + + EXPORT rt_cpu_mmu_disable +rt_cpu_mmu_disable: + MCR p15, #0, r0, c8, c7, #0 ; invalidate tlb + MRC p15, #0, r0, c1, c0, #0 + BIC r0, r0, #1 + MCR p15, #0, r0, c1, c0, #0 ; clear mmu bit + DSB + BX lr + + EXPORT rt_cpu_mmu_enable +rt_cpu_mmu_enable: + MRC p15, #0, r0, c1, c0, #0 + ORR r0, r0, #0x001 + MCR p15, #0, r0, c1, c0, #0 ; set mmu enable bit + DSB + BX lr + + EXPORT rt_cpu_tlb_set +rt_cpu_tlb_set: + MCR p15, #0, r0, c2, c0, #0 + DMB + BX lr + + END diff --git a/rt-thread/libcpu/arm/am335x/cpu.c b/rt-thread/libcpu/arm/am335x/cpu.c new file mode 100644 index 0000000..d756007 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/cpu.c @@ -0,0 +1,168 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop 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 + * 2011-09-15 Bernard first version + */ + +#include +#include +#include "am33xx.h" + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +#define ICACHE_MASK (rt_uint32_t)(1 << 12) +#define DCACHE_MASK (rt_uint32_t)(1 << 2) + +#if defined(__CC_ARM) +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + __asm + { + mrc p15, 0, i, c1, c0, 0 + } + + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} +#elif defined(__GNUC__) +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + __asm__ __volatile__( \ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "orr r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + __asm__ __volatile__( \ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "bic r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} +#endif + + +#if defined(__CC_ARM)|(__GNUC__) +/** + * enable I-Cache + * + */ +void rt_hw_cpu_icache_enable() +{ + cache_enable(ICACHE_MASK); +} + +/** + * disable I-Cache + * + */ +void rt_hw_cpu_icache_disable() +{ + cache_disable(ICACHE_MASK); +} + +/** + * return the status of I-Cache + * + */ +rt_base_t rt_hw_cpu_icache_status() +{ + return (cp15_rd() & ICACHE_MASK); +} + +/** + * enable D-Cache + * + */ +void rt_hw_cpu_dcache_enable() +{ + cache_enable(DCACHE_MASK); +} + +/** + * disable D-Cache + * + */ +void rt_hw_cpu_dcache_disable() +{ + cache_disable(DCACHE_MASK); +} + +/** + * return the status of D-Cache + * + */ +rt_base_t rt_hw_cpu_dcache_status() +{ + return (cp15_rd() & DCACHE_MASK); +} +#endif + +/** + * shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + while (level) + { + RT_ASSERT(0); + } +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/am335x/interrupt.c b/rt-thread/libcpu/arm/am335x/interrupt.c new file mode 100644 index 0000000..a13d089 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/interrupt.c @@ -0,0 +1,217 @@ +/* + * File : interrupt.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 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 + * 2013-07-06 Bernard first version + * 2015-11-06 zchong support iar compiler + */ + +#include +#include + +#include "am33xx.h" +#include "interrupt.h" + +#define AINTC_BASE AM33XX_AINTC_REGS + +#define MAX_HANDLERS 128 + +extern volatile rt_uint8_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +struct rt_irq_desc isr_table[MAX_HANDLERS]; +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +void rt_dump_aintc(void) +{ + int k; + rt_kprintf("active irq %d", INTC_SIR_IRQ(AINTC_BASE)); + rt_kprintf("\n--- hw mask ---\n"); + for (k = 0; k < 4; k++) + { + rt_kprintf("0x%08x, ", INTC_MIR(AINTC_BASE, k)); + } + rt_kprintf("\n--- hw itr ---\n"); + for (k = 0; k < 4; k++) + { + rt_kprintf("0x%08x, ", INTC_ITR(AINTC_BASE, k)); + } + rt_kprintf("\n"); +} + +const unsigned int AM335X_VECTOR_BASE = 0x4030FC00; +extern void rt_cpu_vector_set_base(unsigned int addr); +#ifdef __ICCARM__ +extern int __vector; +#else +extern int system_vectors; +#endif + +static void rt_hw_vector_init(void) +{ + unsigned int *dest = (unsigned int *)AM335X_VECTOR_BASE; + +#ifdef __ICCARM__ + unsigned int *src = (unsigned int *)&__vector; +#else + unsigned int *src = (unsigned int *)&system_vectors; +#endif + + rt_memcpy(dest, src, 16 * 4); + rt_cpu_vector_set_base(AM335X_VECTOR_BASE); +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + /* initialize vector table */ + rt_hw_vector_init(); + + /* init exceptions table */ + rt_memset(isr_table, 0x00, sizeof(isr_table)); + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + INTC_MIR_SET(AINTC_BASE, vector >> 0x05) = 0x1 << (vector & 0x1f); +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + INTC_MIR_CLEAR(AINTC_BASE, vector >> 0x05) = 0x1 << (vector & 0x1f); +} + +/** + * This function will control the interrupt attribute. + * @param vector the interrupt number + */ +void rt_hw_interrupt_control(int vector, int priority, int route) +{ + int fiq; + + if (route == 0) + fiq = 0; + else + fiq = 1; + + INTC_ILR(AINTC_BASE, vector) = ((priority << 0x02) & 0x1FC) | fiq ; +} + +int rt_hw_interrupt_get_active(int fiq_irq) +{ + int ir; + if (fiq_irq == INT_FIQ) + { + ir = INTC_SIR_FIQ(AINTC_BASE) & 0x7f; + } + else + { + ir = INTC_SIR_IRQ(AINTC_BASE) & 0x7f; + } + + return ir; +} + +void rt_hw_interrupt_ack(int fiq_irq) +{ + if (fiq_irq == INT_FIQ) + { + /* new FIQ generation */ + INTC_CONTROL(AINTC_BASE) |= 0x02; + } + else + { + /* new IRQ generation */ + INTC_CONTROL(AINTC_BASE) |= 0x01; + } +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if(vector < MAX_HANDLERS) + { + old_handler = isr_table[vector].handler; + + if (handler != RT_NULL) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + } + + return old_handler; +} + +/** + * This function will trigger an interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_trigger(int vector) +{ + INTC_ISR_SET(AINTC_BASE, vector>>5) = 1 << (vector & 0x1f); +} + +void rt_hw_interrupt_clear(int vector) +{ + INTC_ISR_CLEAR(AINTC_BASE, vector>>5) = 1 << (vector & 0x1f); +} + +void rt_dump_isr_table(void) +{ + int idx; + for(idx = 0; idx < MAX_HANDLERS; idx++) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_kprintf("nr:%4d, name: %*.s, handler: 0x%p, param: 0x%08x\r\n", + idx, RT_NAME_MAX, isr_table[idx].name, + isr_table[idx].handler, isr_table[idx].param); +#else + rt_kprintf("nr:%4d, handler: 0x%p, param: 0x%08x\r\n", + idx, isr_table[idx].handler, isr_table[idx].param); +#endif + } +} +/*@}*/ + + diff --git a/rt-thread/libcpu/arm/am335x/interrupt.h b/rt-thread/libcpu/arm/am335x/interrupt.h new file mode 100644 index 0000000..d81f1c8 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/interrupt.h @@ -0,0 +1,50 @@ +/* + * File : interrupt.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 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 + * 2013-07-06 Bernard first version + */ + +#ifndef __INTERRUPT_H__ +#define __INTERRUPT_H__ + +#define INT_IRQ 0x00 +#define INT_FIQ 0x01 + +#define INTC_REVISION(hw_base) REG32((hw_base) + 0x0) +#define INTC_SYSCONFIG(hw_base) REG32((hw_base) + 0x10) +#define INTC_SYSSTATUS(hw_base) REG32((hw_base) + 0x14) +#define INTC_SIR_IRQ(hw_base) REG32((hw_base) + 0x40) +#define INTC_SIR_FIQ(hw_base) REG32((hw_base) + 0x44) +#define INTC_CONTROL(hw_base) REG32((hw_base) + 0x48) +#define INTC_PROTECTION(hw_base) REG32((hw_base) + 0x4c) +#define INTC_IDLE(hw_base) REG32((hw_base) + 0x50) +#define INTC_IRQ_PRIORITY(hw_base) REG32((hw_base) + 0x60) +#define INTC_FIQ_PRIORITY(hw_base) REG32((hw_base) + 0x64) +#define INTC_THRESHOLD(hw_base) REG32((hw_base) + 0x68) +#define INTC_SICR(hw_base) REG32((hw_base) + 0x6c) +#define INTC_SCR(hw_base, n) REG32((hw_base) + 0x70 + ((n) * 0x04)) +#define INTC_ITR(hw_base, n) REG32((hw_base) + 0x80 + ((n) * 0x20)) +#define INTC_MIR(hw_base, n) REG32((hw_base) + 0x84 + ((n) * 0x20)) +#define INTC_MIR_CLEAR(hw_base, n) REG32((hw_base) + 0x88 + ((n) * 0x20)) +#define INTC_MIR_SET(hw_base, n) REG32((hw_base) + 0x8c + ((n) * 0x20)) +#define INTC_ISR_SET(hw_base, n) REG32((hw_base) + 0x90 + ((n) * 0x20)) +#define INTC_ISR_CLEAR(hw_base, n) REG32((hw_base) + 0x94 + ((n) * 0x20)) +#define INTC_PENDING_IRQ(hw_base, n) REG32((hw_base) + 0x98 + ((n) * 0x20)) +#define INTC_PENDING_FIQ(hw_base, n) REG32((hw_base) + 0x9c + ((n) * 0x20)) +#define INTC_ILR(hw_base, n) REG32((hw_base) + 0x100 + ((n) * 0x04)) + +void rt_hw_interrupt_control(int vector, int priority, int route); +int rt_hw_interrupt_get_active(int fiq_irq); +void rt_hw_interrupt_ack(int fiq_irq); +void rt_hw_interrupt_trigger(int vector); +void rt_hw_interrupt_clear(int vector); + +#endif diff --git a/rt-thread/libcpu/arm/am335x/mmu.c b/rt-thread/libcpu/arm/am335x/mmu.c new file mode 100644 index 0000000..03fe2e6 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/mmu.c @@ -0,0 +1,193 @@ +/* + * File : mmu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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 + * 2012-01-10 bernard porting to AM1808 + */ + +#include +#include "am33xx.h" +#include + +extern void rt_cpu_dcache_disable(void); +extern void rt_hw_cpu_dcache_enable(void); +extern void rt_cpu_icache_disable(void); +extern void rt_hw_cpu_icache_enable(void); +extern void rt_cpu_mmu_disable(void); +extern void rt_cpu_mmu_enable(void); +extern void rt_cpu_tlb_set(register rt_uint32_t i); + +void mmu_disable_dcache() +{ + rt_cpu_dcache_disable(); +} + +void mmu_enable_dcache() +{ + rt_hw_cpu_dcache_enable(); +} + +void mmu_disable_icache() +{ + rt_cpu_icache_disable(); +} + +void mmu_enable_icache() +{ + rt_hw_cpu_icache_enable(); +} + +void mmu_disable() +{ + rt_cpu_mmu_disable(); +} + +void mmu_enable() +{ + rt_cpu_mmu_enable(); +} + +void mmu_setttbase(register rt_uint32_t i) +{ + register rt_uint32_t value; + + /* Invalidates all TLBs.Domain access is selected as + * client by configuring domain access register, + * in that case access controlled by permission value + * set by page table entry + */ + value = 0; + asm volatile ("mcr p15, 0, %0, c8, c7, 0"::"r"(value)); + + value = 0x55555555; + asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(value)); + + rt_cpu_tlb_set(i); +} + +void mmu_set_domain(register rt_uint32_t i) +{ + asm volatile ("mcr p15,0, %0, c3, c0, 0": :"r" (i)); +} + +void mmu_enable_alignfault() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= (1 << 1); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable_alignfault() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~(1 << 1); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_clean_invalidated_cache_index(int index) +{ + asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index)); +} + +void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~0x1f; + + while (ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr)); + ptr += 32; + } +} + +void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~0x1f; + + while (ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr)); + ptr += 32; + } +} + +void mmu_invalidate_tlb() +{ + asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0)); +} + +void mmu_invalidate_icache() +{ + asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0)); +} + +/* level1 page table */ +static volatile unsigned int _page_table[4*1024] __attribute__((aligned(16*1024))); +void mmu_setmtt(rt_uint32_t vaddrStart, rt_uint32_t vaddrEnd, rt_uint32_t paddrStart, rt_uint32_t attr) +{ + volatile rt_uint32_t *pTT; + volatile int i,nSec; + pTT=(rt_uint32_t *)_page_table+(vaddrStart>>20); + nSec=(vaddrEnd>>20)-(vaddrStart>>20); + for(i=0;i<=nSec;i++) + { + *pTT = attr |(((paddrStart>>20)+i)<<20); + pTT++; + } +} + +/* set page table */ +RT_WEAK void mmu_setmtts(void) +{ + mmu_setmtt(0x00000000, 0xFFFFFFFF, 0x00000000, RW_NCNB); /* None cached for 4G memory */ + mmu_setmtt(0x80200000, 0x80800000 - 1, 0x80200000, RW_CB); /* 126M cached DDR memory */ + mmu_setmtt(0x80000000, 0x80200000 - 1, 0x80000000, RW_NCNB); /* 2M none-cached DDR memory */ + mmu_setmtt(0x402F0000, 0x40300000 - 1, 0x402F0000, RW_CB); /* 63K OnChip memory */ +} + +void rt_hw_mmu_init(void) +{ + /* disable I/D cache */ + mmu_disable_dcache(); + mmu_disable_icache(); + mmu_disable(); + mmu_invalidate_tlb(); + + mmu_setmtts(); + + /* set MMU table address */ + mmu_setttbase((rt_uint32_t)_page_table); + + /* enables MMU */ + mmu_enable(); + + /* enable Instruction Cache */ + mmu_enable_icache(); + + /* enable Data Cache */ + mmu_enable_dcache(); +} + diff --git a/rt-thread/libcpu/arm/am335x/mmu.h b/rt-thread/libcpu/arm/am335x/mmu.h new file mode 100644 index 0000000..11ea525 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/mmu.h @@ -0,0 +1,51 @@ +/* + * File : mmu.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef __MMU_H__ +#define __MMU_H__ + +#include + +#define DESC_SEC (0x2) +#define CB (3<<2) //cache_on, write_back +#define CNB (2<<2) //cache_on, write_through +#define NCB (1<<2) //cache_off,WR_BUF on +#define NCNB (0<<2) //cache_off,WR_BUF off +#define AP_RW (3<<10) //supervisor=RW, user=RW +#define AP_RO (2<<10) //supervisor=RW, user=RO + +#define DOMAIN_FAULT (0x0) +#define DOMAIN_CHK (0x1) +#define DOMAIN_NOTCHK (0x3) +#define DOMAIN0 (0x0<<5) +#define DOMAIN1 (0x1<<5) + +#define DOMAIN0_ATTR (DOMAIN_CHK<<0) +#define DOMAIN1_ATTR (DOMAIN_FAULT<<2) + +#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */ +#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */ +#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */ +#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */ + +void rt_hw_mmu_init(void); + +#endif diff --git a/rt-thread/libcpu/arm/am335x/stack.c b/rt-thread/libcpu/arm/am335x/stack.c new file mode 100644 index 0000000..7415e23 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/stack.c @@ -0,0 +1,68 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 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 + * 2011-09-23 Bernard the first version + * 2011-10-05 Bernard add thumb mode + */ +#include +#include "am33xx.h" + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/am335x/start_gcc.S b/rt-thread/libcpu/arm/am335x/start_gcc.S new file mode 100644 index 0000000..f80aca6 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/start_gcc.S @@ -0,0 +1,265 @@ +/* + * File : start_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.equ Mode_USR, 0x10 +.equ Mode_FIQ, 0x11 +.equ Mode_IRQ, 0x12 +.equ Mode_SVC, 0x13 +.equ Mode_ABT, 0x17 +.equ Mode_UND, 0x1B +.equ Mode_SYS, 0x1F + +.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled +.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled + +.equ UND_Stack_Size, 0x00000200 +.equ SVC_Stack_Size, 0x00000100 +.equ ABT_Stack_Size, 0x00000000 +.equ FIQ_Stack_Size, 0x00000000 +.equ IRQ_Stack_Size, 0x00000100 +.equ USR_Stack_Size, 0x00000100 + +#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + FIQ_Stack_Size + IRQ_Stack_Size) + +/* stack */ +.globl stack_start +.globl stack_top + +stack_start: +.rept ISR_Stack_Size +.long 0 +.endr +stack_top: + +/* reset entry */ +.globl _reset +_reset: + /* set the cpu to SVC32 mode and disable interrupt */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0x13 + msr cpsr_c, r0 + + /* setup stack */ + bl stack_setup + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop +ctor_end: + + /* start RT-Thread Kernel */ + ldr pc, _rtthread_startup +_rtthread_startup: + .word rtthread_startup + +stack_setup: + ldr r0, =stack_top + + @ Enter Undefined Instruction Mode and set its Stack Pointer + msr cpsr_c, #Mode_UND|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #UND_Stack_Size + + @ Enter Abort Mode and set its Stack Pointer + msr cpsr_c, #Mode_ABT|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #ABT_Stack_Size + + @ Enter FIQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #FIQ_Stack_Size + + @ Enter IRQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #IRQ_Stack_Size + + @ Enter Supervisor Mode and set its Stack Pointer + msr cpsr_c, #Mode_SVC|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #SVC_Stack_Size + + @ Enter User Mode and set its Stack Pointer + mov sp, r0 + sub sl, sp, #USR_Stack_Size + bx lr + +/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */ + .align 5 +.globl vector_undef +vector_undef: + sub sp, sp, #72 + stmia sp, {r0 - r12} @/* Calling r0-r12 */ + add r8, sp, #60 + + mrs r1, cpsr + mrs r2, spsr + orr r2,r2, #I_Bit|F_Bit + msr cpsr_c, r2 + mov r0, r0 + stmdb r8, {sp, lr} @/* Calling SP, LR */ + msr cpsr_c, r1 @/* return to Undefined Instruction mode */ + + str lr, [r8, #0] @/* Save calling PC */ + mrs r6, spsr + str r6, [r8, #4] @/* Save CPSR */ + str r0, [r8, #8] @/* Save OLD_R0 */ + mov r0, sp + + bl rt_hw_trap_udef + + ldmia sp, {r0 - r12} @/* Calling r0 - r2 */ + mov r0, r0 + ldr lr, [sp, #60] @/* Get PC */ + add sp, sp, #72 + movs pc, lr @/* return & move spsr_svc into cpsr */ + + .align 5 +.globl vector_swi +vector_swi: + bl rt_hw_trap_swi + + .align 5 +.globl vector_pabt +vector_pabt: + bl rt_hw_trap_pabt + + .align 5 +.globl vector_dabt +vector_dabt: + sub sp, sp, #72 + stmia sp, {r0 - r12} @/* Calling r0-r12 */ + add r8, sp, #60 + stmdb r8, {sp, lr} @/* Calling SP, LR */ + str lr, [r8, #0] @/* Save calling PC */ + mrs r6, spsr + str r6, [r8, #4] @/* Save CPSR */ + str r0, [r8, #8] @/* Save OLD_R0 */ + mov r0, sp + + bl rt_hw_trap_dabt + + ldmia sp, {r0 - r12} @/* Calling r0 - r2 */ + mov r0, r0 + ldr lr, [sp, #60] @/* Get PC */ + add sp, sp, #72 + movs pc, lr @/* return & move spsr_svc into cpsr */ + + .align 5 +.globl vector_resv +vector_resv: + b . + + .align 5 +.globl vector_fiq +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc,lr,#4 + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread + +.globl rt_current_thread +.globl vmm_thread +.globl vmm_virq_check + +.globl vector_irq +vector_irq: + stmfd sp!, {r0-r12,lr} + + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + + @ if rt_thread_switch_interrupt_flag set, jump to + @ rt_hw_context_switch_interrupt_do and don't return + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq rt_hw_context_switch_interrupt_do + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +rt_hw_context_switch_interrupt_do: + mov r1, #0 @ clear flag + str r1, [r0] + + ldmfd sp!, {r0-r12,lr}@ reload saved registers + stmfd sp, {r0-r2} @ save r0-r2 + + mrs r0, spsr @ get cpsr of interrupt thread + + sub r1, sp, #4*3 + sub r2, lr, #4 @ save old task's pc to r2 + + @ switch to SVC mode with no interrupt + msr cpsr_c, #I_Bit|F_Bit|Mode_SVC + + stmfd sp!, {r2} @ push old task's pc + stmfd sp!, {r3-r12,lr}@ push old task's lr,r12-r4 + ldmfd r1, {r1-r3} @ restore r0-r2 of the interrupt thread + stmfd sp!, {r1-r3} @ push old task's r0-r2 + stmfd sp!, {r0} @ push old task's cpsr + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] @ store sp in preempted tasks's TCB + + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] @ get new task's stack pointer + + ldmfd sp!, {r4} @ pop new task's cpsr to spsr + msr spsr_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr diff --git a/rt-thread/libcpu/arm/am335x/start_iar.s b/rt-thread/libcpu/arm/am335x/start_iar.s new file mode 100644 index 0000000..61f977f --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/start_iar.s @@ -0,0 +1,292 @@ +/* + * File : start_iar.s + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-04-06 zchong the first version + */ + + MODULE ?cstartup + + ; -------------------- +; Mode, correspords to bits 0-5 in CPSR + +MODE_MSK DEFINE 0x1F ; Bit mask for mode bits in CPSR +I_Bit DEFINE 0x80 ; when I bit is set, IRQ is disabled +F_Bit DEFINE 0x40 ; when F bit is set, FIQ is disabled + +USR_MODE DEFINE 0x10 ; User mode +FIQ_MODE DEFINE 0x11 ; Fast Interrupt Request mode +IRQ_MODE DEFINE 0x12 ; Interrupt Request mode +SVC_MODE DEFINE 0x13 ; Supervisor mode +ABT_MODE DEFINE 0x17 ; Abort mode +UND_MODE DEFINE 0x1B ; Undefined Instruction mode +SYS_MODE DEFINE 0x1F ; System mode + + + ;; Forward declaration of sections. + SECTION IRQ_STACK:DATA:NOROOT(3) + SECTION FIQ_STACK:DATA:NOROOT(3) + SECTION SVC_STACK:DATA:NOROOT(3) + SECTION ABT_STACK:DATA:NOROOT(3) + SECTION UND_STACK:DATA:NOROOT(3) + SECTION CSTACK:DATA:NOROOT(3) + SECTION .text:CODE + + + SECTION .intvec:CODE:NOROOT(5) + + PUBLIC __vector + PUBLIC __iar_program_start + + +__iar_init$$done: ; The vector table is not needed + ; until after copy initialization is done + +__vector: ; Make this a DATA label, so that stack usage + ; analysis doesn't consider it an uncalled fun + ARM + + ; All default exception handlers (except reset) are + ; defined as weak symbol definitions. + ; If a handler is defined by the application it will take precedence. + LDR PC,Reset_Addr ; Reset + LDR PC,Undefined_Addr ; Undefined instructions + LDR PC,SWI_Addr ; Software interrupt (SWI/SVC) + LDR PC,Prefetch_Addr ; Prefetch abort + LDR PC,Abort_Addr ; Data abort + DCD 0 ; RESERVED + LDR PC,IRQ_Addr ; IRQ + LDR PC,FIQ_Addr ; FIQ + + DATA + +Reset_Addr: DCD __iar_program_start +Undefined_Addr: DCD Undefined_Handler +SWI_Addr: DCD SWI_Handler +Prefetch_Addr: DCD Prefetch_Handler +Abort_Addr: DCD Abort_Handler +IRQ_Addr: DCD IRQ_Handler +FIQ_Addr: DCD FIQ_Handler + + +; -------------------------------------------------- +; ?cstartup -- low-level system initialization code. +; +; After a reset execution starts here, the mode is ARM, supervisor +; with interrupts disabled. +; + + SECTION .text:CODE:NOROOT(2) + + EXTERN rt_hw_trap_udef + EXTERN rt_hw_trap_swi + EXTERN rt_hw_trap_pabt + EXTERN rt_hw_trap_dabt + EXTERN rt_hw_trap_fiq + EXTERN rt_hw_trap_irq + EXTERN rt_interrupt_enter + EXTERN rt_interrupt_leave + EXTERN rt_thread_switch_interrupt_flag + EXTERN rt_interrupt_from_thread + EXTERN rt_interrupt_to_thread + EXTERN rt_current_thread + EXTERN vmm_thread + EXTERN vmm_virq_check + + EXTERN __cmain + REQUIRE __vector + EXTWEAK __iar_init_core + EXTWEAK __iar_init_vfp + + + ARM + +__iar_program_start: +?cstartup: + +; +; Add initialization needed before setup of stackpointers here. +; + +; +; Initialize the stack pointers. +; The pattern below can be used for any of the exception stacks: +; FIQ, IRQ, SVC, ABT, UND, SYS. +; The USR mode uses the same stack as SYS. +; The stack segments must be defined in the linker command file, +; and be declared above. +; + + MRS r0, cpsr ; Original PSR value + + ;; Set up the interrupt stack pointer. + BIC r0, r0, #MODE_MSK ; Clear the mode bits + ORR r0, r0, #IRQ_MODE ; Set IRQ mode bits + MSR cpsr_c, r0 ; Change the mode + LDR sp, =SFE(IRQ_STACK) ; End of IRQ_STACK + BIC sp,sp,#0x7 ; Make sure SP is 8 aligned + + ;; Set up the fast interrupt stack pointer. + BIC r0, r0, #MODE_MSK ; Clear the mode bits + ORR r0, r0, #FIQ_MODE ; Set FIR mode bits + MSR cpsr_c, r0 ; Change the mode + LDR sp, =SFE(FIQ_STACK) ; End of FIQ_STACK + BIC sp,sp,#0x7 ; Make sure SP is 8 aligned + + BIC r0,r0,#MODE_MSK ; Clear the mode bits + ORR r0,r0,#ABT_MODE ; Set Abort mode bits + MSR cpsr_c,r0 ; Change the mode + LDR sp,=SFE(ABT_STACK) ; End of ABT_STACK + BIC sp,sp,#0x7 ; Make sure SP is 8 aligned + + BIC r0,r0,#MODE_MSK ; Clear the mode bits + ORR r0,r0,#UND_MODE ; Set Undefined mode bits + MSR cpsr_c,r0 ; Change the mode + LDR sp,=SFE(UND_STACK) ; End of UND_STACK + BIC sp,sp,#0x7 ; Make sure SP is 8 aligned + + ;; Set up the normal stack pointer. + BIC r0 ,r0, #MODE_MSK ; Clear the mode bits + ORR r0 ,r0, #SVC_MODE ; Set System mode bits + MSR cpsr_c, r0 ; Change the mode + LDR sp, =SFE(SVC_STACK) ; End of SVC_STACK + BIC sp,sp,#0x7 ; Make sure SP is 8 aligned + + ;; Turn on core features assumed to be enabled. + BL __iar_init_core + + ;; Initialize VFP (if needed). + BL __iar_init_vfp + + + ;; Continue to __cmain for C-level initialization. + B __cmain + + +Undefined_Handler: + SUB sp, sp, #72 + STMIA sp, {r0 - r12} ;/* Calling r0-r12 */ + ADD r8, sp, #60 + + MRS r1, cpsr + MRS r2, spsr + ORR r2,r2, #I_Bit | F_Bit + MSR cpsr_c, r2 + MOV r0, r0 + STMDB r8, {sp, lr} ;/* Calling SP, LR */ + MSR cpsr_c, r1 ;/* return to Undefined Instruction mode */ + + STR lr, [r8, #0] ;/* Save calling PC */ + MRS r6, spsr + STR r6, [r8, #4] ;/* Save CPSR */ + STR r0, [r8, #8] ;/* Save OLD_R0 */ + MOV r0, sp + + BL rt_hw_trap_udef + + LDMIA sp, {r0 - r12} ;/* Calling r0 - r2 */ + MOV r0, r0 + LDR lr, [sp, #60] ;/* Get PC */ + ADD sp, sp, #72 + MOVS pc, lr ;/* return & move spsr_svc into cpsr */ + +SWI_Handler: + BL rt_hw_trap_swi + +Prefetch_Handler: + BL rt_hw_trap_pabt + +Abort_Handler: + SUB sp, sp, #72 + STMIA sp, {r0 - r12} ;/* Calling r0-r12 */ + ADD r8, sp, #60 + STMDB r8, {sp, lr} ;/* Calling SP, LR */ + STR lr, [r8, #0] ;/* Save calling PC */ + MRS r6, spsr + STR r6, [r8, #4] ;/* Save CPSR */ + STR r0, [r8, #8] ;/* Save OLD_R0 */ + MOV r0, sp + + BL rt_hw_trap_dabt + + LDMIA sp, {r0 - r12} ;/* Calling r0 - r2 */ + MOV r0, r0 + LDR lr, [sp, #60] ;/* Get PC */ + ADD sp, sp, #72 + MOVS pc, lr ;/* return & move spsr_svc into cpsr */ + +FIQ_Handler: + STMFD sp!,{r0-r7,lr} + BL rt_hw_trap_fiq + LDMFD sp!,{r0-r7,lr} + SUBS pc,lr,#4 + +IRQ_Handler: + STMFD sp!, {r0-r12,lr} + + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; if rt_thread_switch_interrupt_flag set, jump to + ; rt_hw_context_switch_interrupt_do and don't return + LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD sp!, {r0-r12,lr} + SUBS pc, lr, #4 + +rt_hw_context_switch_interrupt_do: + MOV r1, #0 ; clear flag + STR r1, [r0] + + LDMFD sp!, {r0-r12,lr}; reload saved registers + STMFD sp, {r0-r2} ; save r0-r2 + + MRS r0, spsr ; get cpsr of interrupt thread + + SUB r1, sp, #4*3 + SUB r2, lr, #4 ; save old task's pc to r2 + + ; switch to SVC mode with no interrupt + MSR cpsr_c, #I_Bit | F_Bit | SVC_MODE + + STMFD sp!, {r2} ; push old task's pc + STMFD sp!, {r3-r12,lr}; push old task's lr,r12-r4 + LDMFD r1, {r1-r3} ; restore r0-r2 of the interrupt thread + STMFD sp!, {r1-r3} ; push old task's r0-r2 + STMFD sp!, {r0} ; push old task's cpsr + + LDR r4, =rt_interrupt_from_thread + LDR r5, [r4] + STR sp, [r5] ; store sp in preempted tasks's TCB + + LDR r6, =rt_interrupt_to_thread + LDR r6, [r6] + LDR sp, [r6] ; get new task's stack pointer + + LDMFD sp!, {r4} ; pop new task's cpsr to spsr + MSR spsr_cxsf, r4 + + LDMFD sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr + + END diff --git a/rt-thread/libcpu/arm/am335x/trap.c b/rt-thread/libcpu/arm/am335x/trap.c new file mode 100644 index 0000000..89dc142 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/trap.c @@ -0,0 +1,200 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop 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 + * 2011-09-23 Bernard first version + */ + +#include +#include + +#include "am33xx.h" +#include "interrupt.h" + +#ifdef RT_USING_GDB +#include "gdb_stub.h" +#endif + +/** + * @addtogroup AM33XX + */ +/*@{*/ + +extern struct rt_thread *rt_current_thread; +#ifdef RT_USING_FINSH +extern long list_thread(void); +#endif + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ + +void rt_hw_show_register (struct rt_hw_register *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When ARM7TDMI comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_udef(struct rt_hw_register *regs) +{ + +#ifdef RT_USING_GDB + regs->pc -= 4; //lr in undef is pc + 4 + if (gdb_undef_hook(regs)) + return; +#endif + + rt_hw_show_register(regs); + + rt_kprintf("undefined instruction\n"); + rt_kprintf("thread %.*s stack:\n", RT_NAME_MAX, rt_current_thread->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("software interrupt\n"); + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("prefetch abort\n"); + rt_kprintf("thread %.*s stack:\n", RT_NAME_MAX, rt_current_thread->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_register *regs) +{ + +#ifdef RT_USING_GDB + if (gdb_mem_fault_handler) { + regs->pc = (unsigned long)gdb_mem_fault_handler; + return; + } +#endif + rt_hw_show_register(regs); + + rt_kprintf("data abort\n"); + rt_kprintf("thread %.*s stack:\n", RT_NAME_MAX, rt_current_thread->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +void rt_hw_trap_irq() +{ + void *param; + unsigned long ir; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + ir = rt_hw_interrupt_get_active(INT_IRQ); + if (ir == 127) + { + /* new IRQ generation */ + rt_hw_interrupt_ack(INT_IRQ); + ir = rt_hw_interrupt_get_active(INT_IRQ); + if (ir == 127) + { + /* still spurious interrupt, get out */ + /*rt_kprintf("still spurious interrupt\n");*/ + return; + } + /*rt_kprintf("new IRQ: %d\n", ir);*/ + } + + /* get interrupt service routine */ + isr_func = isr_table[ir].handler; + param = isr_table[ir].param; + + /* turn to interrupt service routine */ + if (isr_func != RT_NULL) + isr_func(ir, param); + + /* new IRQ generation */ + rt_hw_interrupt_ack(INT_IRQ); +} + +void rt_hw_trap_fiq() +{ + void *param; + unsigned long ir; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + ir = rt_hw_interrupt_get_active(INT_FIQ); + + /* get interrupt service routine */ + isr_func = isr_table[ir].handler; + param = isr_table[ir].param; + + /* turn to interrupt service routine */ + isr_func(ir, param); + + /* new FIQ generation */ + rt_hw_interrupt_ack(INT_FIQ); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/am335x/vector_gcc.S b/rt-thread/libcpu/arm/am335x/vector_gcc.S new file mode 100644 index 0000000..4a44a73 --- /dev/null +++ b/rt-thread/libcpu/arm/am335x/vector_gcc.S @@ -0,0 +1,65 @@ +/* + * File : vector_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.section .vectors, "ax" +.code 32 + +.globl system_vectors +system_vectors: + ldr pc, _vector_reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + ldr pc, _vector_resv + ldr pc, _vector_irq + ldr pc, _vector_fiq + +.globl _reset +.globl vector_undef +.globl vector_swi +.globl vector_pabt +.globl vector_dabt +.globl vector_resv +.globl vector_irq +.globl vector_fiq + +_vector_reset: + .word _reset +_vector_undef: + .word vector_undef +_vector_swi: + .word vector_swi +_vector_pabt: + .word vector_pabt +_vector_dabt: + .word vector_dabt +_vector_resv: + .word vector_resv +_vector_irq: + .word vector_irq +_vector_fiq: + .word vector_fiq + +.balignl 16,0xdeadbeef diff --git a/rt-thread/libcpu/arm/arm926/context_gcc.S b/rt-thread/libcpu/arm/arm926/context_gcc.S new file mode 100644 index 0000000..5152618 --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/context_gcc.S @@ -0,0 +1,92 @@ +;/* +; * File : context_iar.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; * 2011-08-14 weety copy from mini2440 +; */ + +#define NOINT 0xC0 + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ + .globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + MRS R0, CPSR + ORR R1, R0, #NOINT + MSR CPSR_c, R1 + BX LR + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ + .globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + MSR CPSR, R0 + BX LR + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ + .globl rt_hw_context_switch +rt_hw_context_switch: + STMFD SP!, {LR} @; push pc (lr should be pushed in place of pc) + STMFD SP!, {R0-R12, LR} @; push lr & register file + MRS R4, CPSR + STMFD SP!, {R4} @; push cpsr + STR SP, [R0] @; store sp in preempted tasks tcb + LDR SP, [R1] @; get new task stack pointer + LDMFD SP!, {R4} @; pop new task spsr + MSR SPSR_cxsf, R4 + LDMFD SP!, {R0-R12, LR, PC}^ @; pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ + .globl rt_hw_context_switch_to +rt_hw_context_switch_to: + LDR SP, [R0] @; get new task stack pointer + LDMFD SP!, {R4} @; pop new task cpsr + MSR SPSR_cxsf, R4 + LDMFD SP!, {R0-R12, LR, PC}^ @; pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ + .globl rt_thread_switch_interrupt_flag + .globl rt_interrupt_from_thread + .globl rt_interrupt_to_thread + .globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + LDR R2, =rt_thread_switch_interrupt_flag + LDR R3, [R2] + CMP R3, #1 + BEQ _reswitch + MOV R3, #1 @; set flag to 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] + BX LR diff --git a/rt-thread/libcpu/arm/arm926/context_iar.S b/rt-thread/libcpu/arm/arm926/context_iar.S new file mode 100644 index 0000000..14110e5 --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/context_iar.S @@ -0,0 +1,96 @@ +;/* +; * File : context_iar.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; * 2011-08-14 weety copy from mini2440 +; * 2015-04-15 ArdaFu convert from context_gcc.s +; */ + +#define NOINT 0xc0 + + SECTION .text:CODE(6) +/* + * rt_base_t rt_hw_interrupt_disable(); + */ + PUBLIC rt_hw_interrupt_disable +rt_hw_interrupt_disable: + MRS R0, CPSR + ORR R1, R0, #NOINT + MSR CPSR_C, R1 + MOV PC, LR + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ + PUBLIC rt_hw_interrupt_enable +rt_hw_interrupt_enable: + MSR CPSR_CXSF, R0 + MOV PC, LR + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ + PUBLIC rt_hw_context_switch +rt_hw_context_switch: + STMFD SP!, {LR} ; push pc (lr should be pushed in place of PC) + STMFD SP!, {R0-R12, LR} ; push lr & register file + MRS R4, CPSR + STMFD SP!, {R4} ; push cpsr + STR SP, [R0] ; store sp in preempted tasks TCB + LDR SP, [R1] ; get new task stack pointer + LDMFD SP!, {R4} ; pop new task spsr + MSR SPSR_cxsf, R4 + LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ + PUBLIC rt_hw_context_switch_to +rt_hw_context_switch_to: + LDR SP, [R0] ; get new task stack pointer + LDMFD SP!, {R4} ; pop new task spsr + MSR SPSR_cxsf, R4 + LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + PUBLIC rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + LDR R2, =rt_thread_switch_interrupt_flag + LDR R3, [R2] + CMP R3, #1 + BEQ _reswitch + MOV R3, #1 ; set flag to 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] + MOV PC, LR + END + diff --git a/rt-thread/libcpu/arm/arm926/context_rvds.S b/rt-thread/libcpu/arm/arm926/context_rvds.S new file mode 100644 index 0000000..32bd235 --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/context_rvds.S @@ -0,0 +1,105 @@ +;/* +; * file : context_rvds.s +; * this file is part of rt-thread rtos +; * copyright (c) 2006, rt-thread development team +; * +; * this program is free software; you can redistribute it and/or modify +; * it under the terms of the gnu general public license as published by +; * the free software foundation; either version 2 of the license, or +; * (at your option) any later version. +; * +; * this program is distributed in the hope that it will be useful, +; * but without any warranty; without even the implied warranty of +; * merchantability or fitness for a particular purpose. see the +; * gnu general public license for more details. +; * +; * you should have received a copy of the gnu general public license along +; * with this program; if not, write to the free software foundation, inc., +; * 51 franklin street, fifth floor, boston, ma 02110-1301 usa. +; * +; * change logs: +; * date author notes +; * 2011-08-14 weety copy from mini2440 +; */ + +NOINT EQU 0XC0 ; disable interrupt in psr + + AREA |.TEXT|, CODE, READONLY, ALIGN=2 + ARM + REQUIRE8 + PRESERVE8 + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ +rt_hw_interrupt_disable PROC + EXPORT rt_hw_interrupt_disable + MRS R0, CPSR + ORR R1, R0, #NOINT + MSR CPSR_C, R1 + BX LR + ENDP + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ +rt_hw_interrupt_enable proc + export rt_hw_interrupt_enable + msr cpsr_c, r0 + bx lr + endp + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ +rt_hw_context_switch proc + export rt_hw_context_switch + stmfd sp!, {lr} ; push pc (lr should be pushed in place of pc) + stmfd sp!, {r0-r12, lr} ; push lr & register file + mrs r4, cpsr + stmfd sp!, {r4} ; push cpsr + str sp, [r0] ; store sp in preempted tasks tcb + ldr sp, [r1] ; get new task stack pointer + ldmfd sp!, {r4} ; pop new task spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc + endp + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ +rt_hw_context_switch_to proc + export rt_hw_context_switch_to + ldr sp, [r0] ; get new task stack pointer + ldmfd sp!, {r4} ; pop new task spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc + endp + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + import rt_thread_switch_interrupt_flag + import rt_interrupt_from_thread + import rt_interrupt_to_thread + +rt_hw_context_switch_interrupt proc + export rt_hw_context_switch_interrupt + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + mov r3, #1 ; set flag to 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] + bx lr + endp + + end diff --git a/rt-thread/libcpu/arm/arm926/cpuport.c b/rt-thread/libcpu/arm/arm926/cpuport.c new file mode 100644 index 0000000..fb90df9 --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/cpuport.c @@ -0,0 +1,244 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-01-13 weety modified from mini2440 + * 2015-04-15 ArdaFu Add code for IAR + */ + +#include +#include + +#define ICACHE_MASK (rt_uint32_t)(1 << 12) +#define DCACHE_MASK (rt_uint32_t)(1 << 2) + +extern void machine_reset(void); +extern void machine_shutdown(void); + +#if defined(__GNUC__) || defined(__ICCARM__) +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + __asm volatile("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + __asm volatile(\ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "orr r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + __asm volatile(\ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "bic r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} +#endif + +#if defined(__CC_ARM) +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + __asm volatile + { + mrc p15, 0, i, c1, c0, 0 + } + + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} +#endif + +/** + * enable I-Cache + * + */ +void rt_hw_cpu_icache_enable() +{ + cache_enable(ICACHE_MASK); +} + +/** + * disable I-Cache + * + */ +void rt_hw_cpu_icache_disable() +{ + cache_disable(ICACHE_MASK); +} + +/** + * return the status of I-Cache + * + */ +rt_base_t rt_hw_cpu_icache_status() +{ + return (cp15_rd() & ICACHE_MASK); +} + +/** + * enable D-Cache + * + */ +void rt_hw_cpu_dcache_enable() +{ + cache_enable(DCACHE_MASK); +} + +/** + * disable D-Cache + * + */ +void rt_hw_cpu_dcache_disable() +{ + cache_disable(DCACHE_MASK); +} + +/** + * return the status of D-Cache + * + */ +rt_base_t rt_hw_cpu_dcache_status() +{ + return (cp15_rd() & DCACHE_MASK); +} + +/** + * reset cpu by dog's time-out + * + */ +void rt_hw_cpu_reset() +{ + + rt_kprintf("Restarting system...\n"); + machine_reset(); + + while(1); /* loop forever and wait for reset to happen */ + + /* NEVER REACHED */ +} + +/** + * shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + machine_shutdown(); + while (level) + { + RT_ASSERT(0); + } +} + +#ifdef RT_USING_CPU_FFS +/** + * This function finds the first bit set (beginning with the least significant bit) + * in value and return the index of that bit. + * + * Bits are numbered starting at 1 (the least significant bit). A return value of + * zero from any of these functions means that the argument was zero. + * + * @return return the index of the first bit set. If value is 0, then this function + * shall return 0. + */ +#if defined(__CC_ARM) +int __rt_ffs(int value) +{ + register rt_uint32_t x; + + if (value == 0) + return value; + + __asm + { + rsb x, value, #0 + and x, x, value + clz x, x + rsb x, x, #32 + } + + return x; +} +#elif defined(__GNUC__) || defined(__ICCARM__) +int __rt_ffs(int value) +{ + register rt_uint32_t x; + + if (value == 0) + return value; + + __asm + ( + "rsb %[temp], %[val], #0\n" + "and %[temp], %[temp], %[val]\n" + "clz %[temp], %[temp]\n" + "rsb %[temp], %[temp], #32\n" + :[temp] "=r"(x) + :[val] "r"(value) + ); + return x; +} +#endif + +#endif + + +/*@}*/ diff --git a/rt-thread/libcpu/arm/arm926/mmu.c b/rt-thread/libcpu/arm/arm926/mmu.c new file mode 100644 index 0000000..b8cfd31 --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/mmu.c @@ -0,0 +1,457 @@ +/* + * File : mmu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2015-04-15 ArdaFu Add code for IAR + */ + +#include "mmu.h" + +/*----- Keil -----------------------------------------------------------------*/ +#ifdef __CC_ARM +void mmu_setttbase(rt_uint32_t i) +{ + register rt_uint32_t value; + + /* Invalidates all TLBs.Domain access is selected as + * client by configuring domain access register, + * in that case access controlled by permission value + * set by page table entry + */ + value = 0; + __asm volatile{ mcr p15, 0, value, c8, c7, 0 } + value = 0x55555555; + __asm volatile { mcr p15, 0, value, c3, c0, 0 } + __asm volatile { mcr p15, 0, i, c2, c0, 0 } +} + +void mmu_set_domain(rt_uint32_t i) +{ + __asm volatile { mcr p15, 0, i, c3, c0, 0 } +} + +void mmu_enable() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x01 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x01 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_icache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x1000 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_dcache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x04 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_icache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x1000 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_dcache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x04 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_alignfault() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x02 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_alignfault() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x02 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_clean_invalidated_cache_index(int index) +{ + __asm volatile { mcr p15, 0, index, c7, c14, 2 } +} + +void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while(ptr < buffer + size) + { + __asm volatile { MCR p15, 0, ptr, c7, c14, 1 } + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + __asm volatile { MCR p15, 0, ptr, c7, c10, 1 } + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + __asm volatile { MCR p15, 0, ptr, c7, c6, 1 } + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_tlb() +{ + register rt_uint32_t value; + + value = 0; + __asm volatile { mcr p15, 0, value, c8, c7, 0 } +} + +void mmu_invalidate_icache() +{ + register rt_uint32_t value; + + value = 0; + + __asm volatile { mcr p15, 0, value, c7, c5, 0 } +} + + +void mmu_invalidate_dcache_all() +{ + register rt_uint32_t value; + + value = 0; + + __asm volatile { mcr p15, 0, value, c7, c6, 0 } +} +/*----- GNU ------------------------------------------------------------------*/ +#elif defined(__GNUC__) || defined(__ICCARM__) +void mmu_setttbase(register rt_uint32_t i) +{ + register rt_uint32_t value; + + /* Invalidates all TLBs.Domain access is selected as + * client by configuring domain access register, + * in that case access controlled by permission value + * set by page table entry + */ + value = 0; + asm volatile ("mcr p15, 0, %0, c8, c7, 0"::"r"(value)); + + value = 0x55555555; + asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(value)); + + asm volatile ("mcr p15, 0, %0, c2, c0, 0"::"r"(i)); + +} + +void mmu_set_domain(register rt_uint32_t i) +{ + asm volatile ("mcr p15,0, %0, c3, c0, 0": :"r" (i)); +} + +void mmu_enable() +{ + asm volatile + ( + "mrc p15, 0, r0, c1, c0, 0 \n" + "orr r0, r0, #0x1 \n" + "mcr p15, 0, r0, c1, c0, 0 \n" + :::"r0" + ); +} + +void mmu_disable() +{ + asm volatile + ( + "mrc p15, 0, r0, c1, c0, 0 \n" + "bic r0, r0, #0x1 \n" + "mcr p15, 0, r0, c1, c0, 0 \n" + :::"r0" + ); + +} + +void mmu_enable_icache() +{ + asm volatile + ( + "mrc p15, 0, r0, c1, c0, 0 \n" + "orr r0, r0, #(1<<12) \n" + "mcr p15, 0, r0, c1, c0, 0 \n" + :::"r0" + ); +} + +void mmu_enable_dcache() +{ + asm volatile + ( + "mrc p15, 0, r0, c1, c0, 0 \n" + "orr r0, r0, #(1<<2) \n" + "mcr p15, 0, r0, c1, c0, 0 \n" + :::"r0" + ); + +} + +void mmu_disable_icache() +{ + asm volatile + ( + "mrc p15, 0, r0, c1, c0, 0 \n" + "bic r0, r0, #(1<<12) \n" + "mcr p15, 0, r0, c1, c0, 0 \n" + :::"r0" + ); + +} + +void mmu_disable_dcache() +{ + asm volatile + ( + "mrc p15, 0, r0, c1, c0, 0 \n" + "bic r0, r0, #(1<<2) \n" + "mcr p15, 0, r0, c1, c0, 0 \n" + :::"r0" + ); + +} + +void mmu_enable_alignfault() +{ + asm volatile + ( + "mrc p15, 0, r0, c1, c0, 0 \n" + "orr r0, r0, #1 \n" + "mcr p15, 0, r0, c1, c0, 0 \n" + :::"r0" + ); + +} + +void mmu_disable_alignfault() +{ + asm volatile + ( + "mrc p15, 0, r0, c1, c0, 0 \n" + "bic r0, r0, #1 \n" + "mcr p15, 0, r0, c1, c0, 0 \n" + :::"r0" + ); + +} + +void mmu_clean_invalidated_cache_index(int index) +{ + asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index)); +} + +void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while(ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c14, 1": :"r" (ptr)); + + ptr += CACHE_LINE_SIZE; + } +} + + +void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr)); + + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr)); + + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_tlb() +{ + asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0)); + +} + +void mmu_invalidate_icache() +{ + asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0)); + +} + +void mmu_invalidate_dcache_all() +{ + asm volatile ("mcr p15, 0, %0, c7, c6, 0": :"r" (0)); + +} +#endif + +/* level1 page table */ +#if defined(__ICCARM__) +#pragma data_alignment=(16*1024) +static volatile rt_uint32_t _page_table[4*1024]; +#else +static volatile rt_uint32_t _page_table[4*1024] \ + __attribute__((aligned(16*1024))); +#endif + +void mmu_setmtt(rt_uint32_t vaddrStart, rt_uint32_t vaddrEnd, + rt_uint32_t paddrStart, rt_uint32_t attr) +{ + volatile rt_uint32_t *pTT; + volatile int nSec; + int i = 0; + pTT=(rt_uint32_t *)_page_table+(vaddrStart>>20); + nSec=(vaddrEnd>>20)-(vaddrStart>>20); + for(i=0; i<=nSec; i++) + { + *pTT = attr |(((paddrStart>>20)+i)<<20); + pTT++; + } +} + +void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size) +{ + /* disable I/D cache */ + mmu_disable_dcache(); + mmu_disable_icache(); + mmu_disable(); + mmu_invalidate_tlb(); + + /* set page table */ + for (; size > 0; size--) + { + mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end, + mdesc->paddr_start, mdesc->attr); + mdesc++; + } + + /* set MMU table address */ + mmu_setttbase((rt_uint32_t)_page_table); + + /* enables MMU */ + mmu_enable(); + + /* enable Instruction Cache */ + mmu_enable_icache(); + + /* enable Data Cache */ + mmu_enable_dcache(); + + mmu_invalidate_icache(); + mmu_invalidate_dcache_all(); +} diff --git a/rt-thread/libcpu/arm/arm926/mmu.h b/rt-thread/libcpu/arm/arm926/mmu.h new file mode 100644 index 0000000..34fc8f0 --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/mmu.h @@ -0,0 +1,63 @@ +/* + * File : mmu.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __MMU_H__ +#define __MMU_H__ + +#include + +#define CACHE_LINE_SIZE 32 + +#define DESC_SEC (0x2|(1<<4)) +#define CB (3<<2) //cache_on, write_back +#define CNB (2<<2) //cache_on, write_through +#define NCB (1<<2) //cache_off,WR_BUF on +#define NCNB (0<<2) //cache_off,WR_BUF off +#define AP_RW (3<<10) //supervisor=RW, user=RW +#define AP_RO (2<<10) //supervisor=RW, user=RO + +#define DOMAIN_FAULT (0x0) +#define DOMAIN_CHK (0x1) +#define DOMAIN_NOTCHK (0x3) +#define DOMAIN0 (0x0<<5) +#define DOMAIN1 (0x1<<5) + +#define DOMAIN0_ATTR (DOMAIN_CHK<<0) +#define DOMAIN1_ATTR (DOMAIN_FAULT<<2) + +#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */ +#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */ +#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */ +#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */ + +struct mem_desc +{ + rt_uint32_t vaddr_start; + rt_uint32_t vaddr_end; + rt_uint32_t paddr_start; + rt_uint32_t attr; +}; + +void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size); + +#endif diff --git a/rt-thread/libcpu/arm/arm926/stack.c b/rt-thread/libcpu/arm/arm926/stack.c new file mode 100644 index 0000000..966088f --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/stack.c @@ -0,0 +1,80 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-01-13 weety copy from mini2440 + */ +#include + +/*****************************/ +/* CPU Mode */ +/*****************************/ +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define ABORTMODE 0x17 +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} diff --git a/rt-thread/libcpu/arm/arm926/start_gcc.S b/rt-thread/libcpu/arm/arm926/start_gcc.S new file mode 100644 index 0000000..130bc04 --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/start_gcc.S @@ -0,0 +1,319 @@ +/* + * File : start_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-01-13 weety first version + * 2015-04-15 ArdaFu Split from AT91SAM9260 BSP + * 2015-04-21 ArdaFu Remove remap code. Using mmu to map vector table + * 2015-06-04 aozima Align stack address to 8 byte. + */ + +#include "rt_low_level_init.h" + +#define S_FRAME_SIZE (18*4) //72 + +@#define S_SPSR (17*4) //SPSR +@#define S_CPSR (16*4) //CPSR +#define S_PC (15*4) //R15 +@#define S_LR (14*4) //R14 +@#define S_SP (13*4) //R13 + +@#define S_IP (12*4) //R12 +@#define S_FP (11*4) //R11 +@#define S_R10 (10*4) +@#define S_R9 (9*4) +@#define S_R8 (8*4) +@#define S_R7 (7*4) +@#define S_R6 (6*4) +@#define S_R5 (5*4) +@#define S_R4 (4*4) +@#define S_R3 (3*4) +@#define S_R2 (2*4) +@#define S_R1 (1*4) +@#define S_R0 (0*4) + +#define MODE_SYS 0x1F +#define MODE_FIQ 0x11 +#define MODE_IRQ 0x12 +#define MODE_SVC 0x13 +#define MODE_ABT 0x17 +#define MODE_UND 0x1B +#define MODEMASK 0x1F + +#define NOINT 0xC0 + +@;----------------------- Stack and Heap Definitions --------------------------- + .section .nobss, "w" + + .space UND_STK_SIZE + .align 3 + .global UND_STACK_START +UND_STACK_START: + + .space ABT_STK_SIZE + .align 3 + .global ABT_STACK_START +ABT_STACK_START: + + .space FIQ_STK_SIZE + .align 3 + .global FIQ_STACK_START +FIQ_STACK_START: + + .space IRQ_STK_SIZE + .align 3 + .global IRQ_STACK_START +IRQ_STACK_START: + + .skip SYS_STK_SIZE + .align 3 + .global SYS_STACK_START +SYS_STACK_START: + + .space SVC_STK_SIZE + .align 3 + .global SVC_STACK_START +SVC_STACK_START: + +@;--------------Jump vector table----------------------------------------------- + .section .init, "ax" + .arm + + .global start +start: + LDR PC, vector_reset + LDR PC, vector_undef + LDR PC, vector_swi + LDR PC, vector_pabt + LDR PC, vector_dabt + LDR PC, vector_resv + LDR PC, vector_irq + LDR PC, vector_fiq + +vector_reset: + .word Reset_Handler +vector_undef: + .word Undef_Handler +vector_swi: + .word SWI_Handler +vector_pabt: + .word PAbt_Handler +vector_dabt: + .word DAbt_Handler +vector_resv: + .word Resv_Handler +vector_irq: + .word IRQ_Handler +vector_fiq: + .word FIQ_Handler + + .balignl 16,0xdeadbeef + +@;----------------- Reset Handler --------------------------------------------- + .global rt_low_level_init + .global main + .global Reset_Handler +Reset_Handler: + @; Set the cpu to SVC32 mode + MRS R0, CPSR + BIC R0, R0, #MODEMASK + ORR R0, R0, #MODE_SVC|NOINT + MSR CPSR_cxsf, R0 + + @; Set CO-Processor + @; little-end,disbale I/D Cache MMU, vector table is 0x00000000 + MRC P15, 0, R0, C1, C0, 0 @; Read CP15 + LDR R1, =0x00003085 @; set clear bits + BIC R0, R0, R1 + MCR P15, 0, R0, C1, C0, 0 @; Write CP15 + + @; Call low level init function, + @; disable and clear all IRQs, Init MMU, Init interrupt controller, etc. + LDR SP, =SVC_STACK_START + LDR R0, =rt_low_level_init + BLX R0 + +Setup_Stack: + @; Setup Stack for each mode + MRS R0, CPSR + BIC R0, R0, #MODEMASK + + ORR R1, R0, #MODE_UND|NOINT + MSR CPSR_cxsf, R1 @; Undef mode + LDR SP, =UND_STACK_START + + ORR R1, R0, #MODE_ABT|NOINT + MSR CPSR_cxsf, R1 @; Abort mode + LDR SP, =ABT_STACK_START + + ORR R1, R0, #MODE_IRQ|NOINT + MSR CPSR_cxsf, R1 @; IRQ mode + LDR SP, =IRQ_STACK_START + + ORR R1, R0, #MODE_FIQ|NOINT + MSR CPSR_cxsf, R1 @; FIQ mode + LDR SP, =FIQ_STACK_START + + ORR R1, R0, #MODE_SYS|NOINT + MSR CPSR_cxsf,R1 @; SYS/User mode + LDR SP, =SYS_STACK_START + + ORR R1, R0, #MODE_SVC|NOINT + MSR CPSR_cxsf, R1 @; SVC mode + LDR SP, =SVC_STACK_START + + @; clear .bss + MOV R0, #0 @; get a zero + LDR R1, =__bss_start__ @; bss start + LDR R2, =__bss_end__ @; bss end + +bss_clear_loop: + CMP R1, R2 @; check if data to clear + STRLO R0, [R1], #4 @; clear 4 bytes + BLO bss_clear_loop @; loop until done + + @; call C++ constructors of global objects + LDR R0, =__ctors_start__ + LDR R1, =__ctors_end__ + +ctor_loop: + CMP R0, R1 + BEQ ctor_end + LDR R2, [R0], #4 + STMFD SP!, {R0-R1} + MOV LR, PC + BX R2 + LDMFD SP!, {R0-R1} + B ctor_loop +ctor_end: + + @; Enter the C code + LDR R0, =rtthread_startup + BLX R0 + +@;----------------- Exception Handler ----------------------------------------- + .global rt_hw_trap_udef + .global rt_hw_trap_swi + .global rt_hw_trap_pabt + .global rt_hw_trap_dabt + .global rt_hw_trap_resv + .global rt_hw_trap_irq + .global rt_hw_trap_fiq + + .global rt_interrupt_enter + .global rt_interrupt_leave + .global rt_thread_switch_interrupt_flag + .global rt_interrupt_from_thread + .global rt_interrupt_to_thread + + .align 5 +Undef_Handler: + SUB SP, SP, #S_FRAME_SIZE + STMIA SP, {R0 - R12} @; Calling R0-R12 + ADD R8, SP, #S_PC + STMDB R8, {SP, LR} @; Calling SP, LR + STR LR, [R8, #0] @; Save calling PC + MRS R6, SPSR + STR R6, [R8, #4] @; Save CPSR + STR R0, [R8, #8] @; Save SPSR + MOV R0, SP + BL rt_hw_trap_udef + + .align 5 +SWI_Handler: + BL rt_hw_trap_swi + + .align 5 +PAbt_Handler: + BL rt_hw_trap_pabt + + .align 5 +DAbt_Handler: + SUB SP, SP, #S_FRAME_SIZE + STMIA SP, {R0 - R12} @; Calling R0-R12 + ADD R8, SP, #S_PC + STMDB R8, {SP, LR} @; Calling SP, LR + STR LR, [R8, #0] @; Save calling PC + MRS R6, SPSR + STR R6, [R8, #4] @; Save CPSR + STR R0, [R8, #8] @; Save SPSR + MOV R0, SP + BL rt_hw_trap_dabt + + .align 5 +Resv_Handler: + BL rt_hw_trap_resv + + .align 5 +FIQ_Handler: + STMFD SP!, {R0-R7,LR} + BL rt_hw_trap_fiq + LDMFD SP!, {R0-R7,LR} + SUBS PC, LR, #4 + + .align 5 +IRQ_Handler: + STMFD SP!, {R0-R12,LR} + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + @; If rt_thread_switch_interrupt_flag set, + @; jump to rt_hw_context_switch_interrupt_do and don't return + LDR R0, =rt_thread_switch_interrupt_flag + LDR R1, [R0] + CMP R1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD SP!, {R0-R12,LR} + SUBS PC, LR, #4 + +@;------ void rt_hw_context_switch_interrupt_do(rt_base_t flag) ----------------- +rt_hw_context_switch_interrupt_do: + MOV R1, #0 @; Clear flag + STR R1, [R0] @; Save to flag variable + + LDMFD SP!, {R0-R12,LR} @; Reload saved registers + STMFD SP, {R0-R2} @; Save R0-R2 + SUB R1, SP, #4*3 @; Save old task's SP to R1 + SUB R2, LR, #4 @; Save old task's PC to R2 + + MRS R0, SPSR @; Get CPSR of interrupt thread + + MSR CPSR_c, #MODE_SVC|NOINT @; Switch to SVC mode and no interrupt + + STMFD SP!, {R2} @; Push old task's PC + STMFD SP!, {R3-R12,LR} @; Push old task's LR,R12-R3 + LDMFD R1, {R1-R3} + STMFD SP!, {R1-R3} @; Push old task's R2-R0 + STMFD SP!, {R0} @; Push old task's CPSR + + LDR R4, =rt_interrupt_from_thread + LDR R5, [R4] @; R5 = stack ptr in old tasks's TCB + STR SP, [R5] @; Store SP in preempted tasks's TCB + + LDR R6, =rt_interrupt_to_thread + LDR R6, [R6] @; R6 = stack ptr in new tasks's TCB + LDR SP, [R6] @; Get new task's stack pointer + + LDMFD SP!, {R4} @; Pop new task's SPSR + MSR SPSR_cxsf, R4 + + LDMFD SP!, {R0-R12,LR,PC}^ @; pop new task's R0-R12,LR & PC SPSR 2 CPSR diff --git a/rt-thread/libcpu/arm/arm926/start_iar.S b/rt-thread/libcpu/arm/arm926/start_iar.S new file mode 100644 index 0000000..880f2d9 --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/start_iar.S @@ -0,0 +1,292 @@ +;/* +; * File : start.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; * 2011-01-13 weety first version +; * 2015-04-15 ArdaFu Split from AT91SAM9260 BSP +; * 2015-04-21 ArdaFu Remove remap code. Using mmu to map vector table +; * 2015-06-04 aozima Align stack address to 8 byte. +; */ + +#include "rt_low_level_init.h" + +#define S_FRAME_SIZE (18*4) ;72 + +;#define S_SPSR (17*4) ;SPSR +;#define S_CPSR (16*4) ;CPSR +#define S_PC (15*4) ;R15 +;#define S_LR (14*4) ;R14 +;#define S_SP (13*4) ;R13 + +;#define S_IP (12*4) ;R12 +;#define S_FP (11*4) ;R11 +;#define S_R10 (10*4) +;#define S_R9 (9*4) +;#define S_R8 (8*4) +;#define S_R7 (7*4) +;#define S_R6 (6*4) +;#define S_R5 (5*4) +;#define S_R4 (4*4) +;#define S_R3 (3*4) +;#define S_R2 (2*4) +;#define S_R1 (1*4) +;#define S_R0 (0*4) + +#define MODE_SYS 0x1F +#define MODE_FIQ 0x11 +#define MODE_IRQ 0x12 +#define MODE_SVC 0x13 +#define MODE_ABT 0x17 +#define MODE_UND 0x1B +#define MODEMASK 0x1F + +#define NOINT 0xC0 + +;----------------------- Stack and Heap Definitions ---------------------------- + MODULE ?cstartup + SECTION .noinit:DATA:NOROOT(3) + DATA + + ALIGNRAM 3 + DS8 UND_STK_SIZE + PUBLIC UND_STACK_START +UND_STACK_START: + + ALIGNRAM 3 + DS8 ABT_STK_SIZE + PUBLIC ABT_STACK_START +ABT_STACK_START: + + ALIGNRAM 3 + DS8 FIQ_STK_SIZE + PUBLIC FIQ_STACK_START +FIQ_STACK_START: + + ALIGNRAM 3 + DS8 IRQ_STK_SIZE + PUBLIC IRQ_STACK_START +IRQ_STACK_START: + + ALIGNRAM 3 + DS8 SYS_STK_SIZE + PUBLIC SYS_STACK_START +SYS_STACK_START: + + ALIGNRAM 3 + DS8 SVC_STK_SIZE + PUBLIC SVC_STACK_START +SVC_STACK_START: + +;--------------Jump vector table------------------------------------------------ + SECTION .intvec:CODE:ROOT(2) + ARM + PUBLIC Entry_Point +Entry_Point: +__iar_init$$done: ; The interrupt vector is not needed + ; until after copy initialization is done + LDR PC, vector_reset + LDR PC, vector_undef + LDR PC, vector_swi + LDR PC, vector_pabt + LDR PC, vector_dabt + LDR PC, vector_resv + LDR PC, vector_irq + LDR PC, vector_fiq + +vector_reset: + DC32 Reset_Handler +vector_undef: + DC32 Undef_Handler +vector_swi: + DC32 SWI_Handler +vector_pabt: + DC32 PAbt_Handler +vector_dabt: + DC32 DAbt_Handler +vector_resv: + DC32 Resv_Handler +vector_irq: + DC32 IRQ_Handler +vector_fiq: + DC32 FIQ_Handler + +;----------------- Reset Handler ----------------------------------------------- + EXTERN rt_low_level_init + EXTERN ?main + PUBLIC __iar_program_start +__iar_program_start: +Reset_Handler: + ; Set the cpu to SVC32 mode + MRS R0, CPSR + BIC R0, R0, #MODEMASK + ORR R0, R0, #MODE_SVC|NOINT + MSR CPSR_cxsf, R0 + + ; Set CO-Processor + ; little-end,disbale I/D Cache MMU, vector table is 0x00000000 + MRC P15, 0, R0, C1, C0, 0 ; Read CP15 + LDR R1, =0x00003085 ; set clear bits + BIC R0, R0, R1 + MCR P15, 0, R0, C1, C0, 0 ; Write CP15 + + ; Call low level init function, + ; disable and clear all IRQs, Init MMU, Init interrupt controller, etc. + LDR SP, =SVC_STACK_START + LDR R0, =rt_low_level_init + BLX R0 + +Setup_Stack: + ; Setup Stack for each mode + MRS R0, CPSR + BIC R0, R0, #MODEMASK + + ORR R1, R0, #MODE_UND|NOINT + MSR CPSR_cxsf, R1 ; Undef mode + LDR SP, =UND_STACK_START + + ORR R1,R0,#MODE_ABT|NOINT + MSR CPSR_cxsf,R1 ; Abort mode + LDR SP, =ABT_STACK_START + + ORR R1,R0,#MODE_IRQ|NOINT + MSR CPSR_cxsf,R1 ; IRQ mode + LDR SP, =IRQ_STACK_START + + ORR R1,R0,#MODE_FIQ|NOINT + MSR CPSR_cxsf,R1 ; FIQ mode + LDR SP, =FIQ_STACK_START + + ORR R1,R0,#MODE_SYS|NOINT + MSR CPSR_cxsf,R1 ; SYS/User mode + LDR SP, =SYS_STACK_START + + ORR R1,R0,#MODE_SVC|NOINT + MSR CPSR_cxsf,R1 ; SVC mode + LDR SP, =SVC_STACK_START + + ; Enter the C code + LDR R0, =?main + BLX R0 + +;----------------- Exception Handler ------------------------------------------- + IMPORT rt_hw_trap_udef + IMPORT rt_hw_trap_swi + IMPORT rt_hw_trap_pabt + IMPORT rt_hw_trap_dabt + IMPORT rt_hw_trap_resv + IMPORT rt_hw_trap_irq + IMPORT rt_hw_trap_fiq + + IMPORT rt_interrupt_enter + IMPORT rt_interrupt_leave + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + + SECTION .text:CODE:ROOT(2) + ARM +Undef_Handler: + SUB SP, SP, #S_FRAME_SIZE + STMIA SP, {R0 - R12} ; Calling R0-R12 + ADD R8, SP, #S_PC + STMDB R8, {SP, LR} ; Calling SP, LR + STR LR, [R8, #0] ; Save calling PC + MRS R6, SPSR + STR R6, [R8, #4] ; Save CPSR + STR R0, [R8, #8] ; Save SPSR + MOV R0, SP + BL rt_hw_trap_udef + +SWI_Handler: + BL rt_hw_trap_swi + +PAbt_Handler: + BL rt_hw_trap_pabt + +DAbt_Handler: + SUB SP, SP, #S_FRAME_SIZE + STMIA SP, {R0 - R12} ; Calling R0-R12 + ADD R8, SP, #S_PC + STMDB R8, {SP, LR} ; Calling SP, LR + STR LR, [R8, #0] ; Save calling PC + MRS R6, SPSR + STR R6, [R8, #4] ; Save CPSR + STR R0, [R8, #8] ; Save SPSR + MOV R0, SP + BL rt_hw_trap_dabt + +Resv_Handler: + BL rt_hw_trap_resv + +IRQ_Handler: + STMFD SP!, {R0-R12,LR} + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; If rt_thread_switch_interrupt_flag set, + ; jump to rt_hw_context_switch_interrupt_do and don't return + LDR R0, =rt_thread_switch_interrupt_flag + LDR R1, [R0] + CMP R1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD SP!, {R0-R12,LR} + SUBS PC, LR, #4 + +FIQ_Handler: + STMFD SP!, {R0-R7,LR} + BL rt_hw_trap_fiq + LDMFD SP!, {R0-R7,LR} + SUBS PC, LR, #4 + +;------ void rt_hw_context_switch_interrupt_do(rt_base_t flag) ----------------- +rt_hw_context_switch_interrupt_do: + MOV R1, #0 ; Clear flag + STR R1, [R0] ; Save to flag variable + + LDMFD SP!, {R0-R12,LR} ; Reload saved registers + STMFD SP, {R0-R2} ; Save R0-R2 + SUB R1, SP, #4*3 ; Save old task's SP to R1 + SUB R2, LR, #4 ; Save old task's PC to R2 + + MRS R0, SPSR ; Get CPSR of interrupt thread + + MSR CPSR_c, #MODE_SVC|NOINT ; Switch to SVC mode and no interrupt + + STMFD SP!, {R2} ; Push old task's PC + STMFD SP!, {R3-R12,LR} ; Push old task's LR,R12-R3 + LDMFD R1, {R1-R3} + STMFD SP!, {R1-R3} ; Push old task's R2-R0 + STMFD SP!, {R0} ; Push old task's CPSR + + LDR R4, =rt_interrupt_from_thread + LDR R5, [R4] ; R5 = stack ptr in old tasks's TCB + STR SP, [R5] ; Store SP in preempted tasks's TCB + + LDR R6, =rt_interrupt_to_thread + LDR R6, [R6] ; R6 = stack ptr in new tasks's TCB + LDR SP, [R6] ; Get new task's stack pointer + + LDMFD SP!, {R4} ; Pop new task's SPSR + MSR SPSR_cxsf, R4 + + LDMFD SP!, {R0-R12,LR,PC}^ ; pop new task's R0-R12,LR & PC SPSR to CPSR + END diff --git a/rt-thread/libcpu/arm/arm926/start_rvds.S b/rt-thread/libcpu/arm/arm926/start_rvds.S new file mode 100644 index 0000000..9f789b9 --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/start_rvds.S @@ -0,0 +1,327 @@ +;/* +; * File : start_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; * 2011-08-14 weety first version +; * 2015-04-15 ArdaFu Split from AT91SAM9260 BSP +; * 2015-04-21 ArdaFu Remove remap code. Using mmu to map vector table +; * 2015-06-04 aozima Align stack address to 8 byte. +; */ + +#include "rt_low_level_init.h" + +S_FRAME_SIZE EQU (18*4) ;72 +;S_SPSR EQU (17*4) ;SPSR +;S_CPSR EQU (16*4) ;CPSR +S_PC EQU (15*4) ;R15 +;S_LR EQU (14*4) ;R14 +;S_SP EQU (13*4) ;R13 + +;S_IP EQU (12*4) ;R12 +;S_FP EQU (11*4) ;R11 +;S_R10 EQU (10*4) +;S_R9 EQU (9*4) +;S_R8 EQU (8*4) +;S_R7 EQU (7*4) +;S_R6 EQU (6*4) +;S_R5 EQU (5*4) +;S_R4 EQU (4*4) +;S_R3 EQU (3*4) +;S_R2 EQU (2*4) +;S_R1 EQU (1*4) +;S_R0 EQU (0*4) + +MODE_USR EQU 0X10 +MODE_FIQ EQU 0X11 +MODE_IRQ EQU 0X12 +MODE_SVC EQU 0X13 +MODE_ABT EQU 0X17 +MODE_UND EQU 0X1B +MODE_SYS EQU 0X1F +MODEMASK EQU 0X1F + +NOINT EQU 0xC0 + +;----------------------- Stack and Heap Definitions ---------------------------- + AREA STACK, NOINIT, READWRITE, ALIGN=3 +Stack_Mem + + SPACE UND_STK_SIZE + EXPORT UND_STACK_START +UND_STACK_START + + ALIGN 8 + SPACE ABT_STK_SIZE + EXPORT ABT_STACK_START +ABT_STACK_START + + ALIGN 8 + SPACE FIQ_STK_SIZE + EXPORT FIQ_STACK_START +FIQ_STACK_START + + ALIGN 8 + SPACE IRQ_STK_SIZE + EXPORT IRQ_STACK_START +IRQ_STACK_START + + ALIGN 8 + SPACE SYS_STK_SIZE + EXPORT SYS_STACK_START +SYS_STACK_START + + ALIGN 8 + SPACE SVC_STK_SIZE + EXPORT SVC_STACK_START +SVC_STACK_START +Stack_Top +__initial_sp + +__heap_base +Heap_Mem SPACE Heap_Size +__heap_limit + + PRESERVE8 +;--------------Jump vector table------------------------------------------------ + EXPORT Entry_Point + AREA RESET, CODE, READONLY + ARM +Entry_Point + LDR PC, vector_reset + LDR PC, vector_undef + LDR PC, vector_swi + LDR PC, vector_pabt + LDR PC, vector_dabt + LDR PC, vector_resv + LDR PC, vector_irq + LDR PC, vector_fiq + +vector_reset + DCD Reset_Handler +vector_undef + DCD Undef_Handler +vector_swi + DCD SWI_Handler +vector_pabt + DCD PAbt_Handler +vector_dabt + DCD DAbt_Handler +vector_resv + DCD Resv_Handler +vector_irq + DCD IRQ_Handler +vector_fiq + DCD FIQ_Handler + +;----------------- Reset Handler ----------------------------------------------- + IMPORT rt_low_level_init + IMPORT __main + EXPORT Reset_Handler +Reset_Handler + ; set the cpu to SVC32 mode + MRS R0,CPSR + BIC R0,R0,#MODEMASK + ORR R0,R0,#MODE_SVC:OR:NOINT + MSR CPSR_cxsf,R0 + + ; Set CO-Processor + ; little-end,disbale I/D Cache MMU, vector table is 0x00000000 + MRC p15, 0, R0, c1, c0, 0 ; Read CP15 + LDR R1, =0x00003085 ; set clear bits + BIC R0, R0, R1 + MCR p15, 0, R0, c1, c0, 0 ; Write CP15 + + ; Call low level init function, + ; disable and clear all IRQs, Init MMU, Init interrupt controller, etc. + LDR SP, =SVC_STACK_START + LDR R0, =rt_low_level_init + BLX R0 + +Setup_Stack + ; Setup Stack for each mode + MRS R0, CPSR + BIC R0, R0, #MODEMASK + + ORR R1, R0, #MODE_UND:OR:NOINT + MSR CPSR_cxsf, R1 ; Undef mode + LDR SP, =UND_STACK_START + + ORR R1,R0,#MODE_ABT:OR:NOINT + MSR CPSR_cxsf,R1 ; Abort mode + LDR SP, =ABT_STACK_START + + ORR R1,R0,#MODE_IRQ:OR:NOINT + MSR CPSR_cxsf,R1 ; IRQ mode + LDR SP, =IRQ_STACK_START + + ORR R1,R0,#MODE_FIQ:OR:NOINT + MSR CPSR_cxsf,R1 ; FIQ mode + LDR SP, =FIQ_STACK_START + + ORR R1,R0,#MODE_SYS:OR:NOINT + MSR CPSR_cxsf,R1 ; SYS/User mode + LDR SP, =SYS_STACK_START + + ORR R1,R0,#MODE_SVC:OR:NOINT + MSR CPSR_cxsf,R1 ; SVC mode + LDR SP, =SVC_STACK_START + + ; Enter the C code + LDR R0, =__main + BLX R0 + +;----------------- Exception Handler ------------------------------------------- + IMPORT rt_hw_trap_udef + IMPORT rt_hw_trap_swi + IMPORT rt_hw_trap_pabt + IMPORT rt_hw_trap_dabt + IMPORT rt_hw_trap_resv + IMPORT rt_hw_trap_irq + IMPORT rt_hw_trap_fiq + + IMPORT rt_interrupt_enter + IMPORT rt_interrupt_leave + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +Undef_Handler PROC + SUB SP, SP, #S_FRAME_SIZE + STMIA SP, {R0 - R12} ; Calling R0-R12 + ADD R8, SP, #S_PC + STMDB R8, {SP, LR} ; Calling SP, LR + STR LR, [R8, #0] ; Save calling PC + MRS R6, SPSR + STR R6, [R8, #4] ; Save CPSR + STR R0, [R8, #8] ; Save SPSR + MOV R0, SP + BL rt_hw_trap_udef + ENDP + +SWI_Handler PROC + BL rt_hw_trap_swi + ENDP + +PAbt_Handler PROC + BL rt_hw_trap_pabt + ENDP + +DAbt_Handler PROC + SUB SP, SP, #S_FRAME_SIZE + STMIA SP, {R0 - R12} ; Calling R0-R12 + ADD R8, SP, #S_PC + STMDB R8, {SP, LR} ; Calling SP, LR + STR LR, [R8, #0] ; Save calling PC + MRS R6, SPSR + STR R6, [R8, #4] ; Save CPSR + STR R0, [R8, #8] ; Save SPSR + MOV R0, SP + BL rt_hw_trap_dabt + ENDP + +Resv_Handler PROC + BL rt_hw_trap_resv + ENDP + +FIQ_Handler PROC + STMFD SP!, {R0-R7,LR} + BL rt_hw_trap_fiq + LDMFD SP!, {R0-R7,LR} + SUBS PC, LR, #4 + ENDP + +IRQ_Handler PROC + STMFD SP!, {R0-R12,LR} + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; If rt_thread_switch_interrupt_flag set, + ; jump to rt_hw_context_switch_interrupt_do and don't return + LDR R0, =rt_thread_switch_interrupt_flag + LDR R1, [R0] + CMP R1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD SP!, {R0-R12,LR} + SUBS PC, LR, #4 + ENDP + +;------ void rt_hw_context_switch_interrupt_do(rt_base_t flag) ----------------- +rt_hw_context_switch_interrupt_do PROC + MOV R1, #0 ; Clear flag + STR R1, [R0] ; Save to flag variable + + LDMFD SP!, {R0-R12,LR} ; Reload saved registers + STMFD SP, {R0-R2} ; Save R0-R2 + SUB R1, SP, #4*3 ; Save old task's SP to R1 + SUB R2, LR, #4 ; Save old task's PC to R2 + + MRS R0, SPSR ; Get CPSR of interrupt thread + + MSR CPSR_c, #MODE_SVC:OR:NOINT ; Switch to SVC mode and no interrupt + + STMFD SP!, {R2} ; Push old task's PC + STMFD SP!, {R3-R12,LR} ; Push old task's LR,R12-R3 + LDMFD R1, {R1-R3} + STMFD SP!, {R1-R3} ; Push old task's R2-R0 + STMFD SP!, {R0} ; Push old task's CPSR + + LDR R4, =rt_interrupt_from_thread + LDR R5, [R4] ; R5 = stack ptr in old tasks's TCB + STR SP, [R5] ; Store SP in preempted tasks's TCB + + LDR R6, =rt_interrupt_to_thread + LDR R6, [R6] ; R6 = stack ptr in new tasks's TCB + LDR SP, [R6] ; Get new task's stack pointer + + LDMFD SP!, {R4} ; Pop new task's SPSR + MSR SPSR_cxsf, R4 + + LDMFD SP!, {R0-R12,LR,PC}^ ; pop new task's R0-R12,LR & PC SPSR to CPSR + ENDP + +;******************************************************************************* +; User Stack and Heap initialization +;******************************************************************************* + IF :DEF:__MICROLIB + + EXPORT __initial_sp + EXPORT __heap_base + EXPORT __heap_limit + + ELSE + + IMPORT __use_two_region_memory + EXPORT __user_initial_stackheap + +__user_initial_stackheap + + LDR R0, = Heap_Mem ; heap base + LDR R1, = SVC_STACK_START ; stack base (top-address) + LDR R2, = (Heap_Mem + Heap_Size) ; heap limit + LDR R3, = (SVC_STACK_START - SVC_STK_SIZE) ; stack limit (low-address) + BX LR + + ALIGN + + ENDIF + + END diff --git a/rt-thread/libcpu/arm/arm926/trap.c b/rt-thread/libcpu/arm/arm926/trap.c new file mode 100644 index 0000000..726f22a --- /dev/null +++ b/rt-thread/libcpu/arm/arm926/trap.c @@ -0,0 +1,221 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-01-13 weety modified from mini2440 + * 2015-04-15 ArdaFu Split from AT91SAM9260 BSP + */ + +#include +#include + +#define INT_IRQ 0x00 +#define INT_FIQ 0x01 + +extern struct rt_thread *rt_current_thread; +#ifdef RT_USING_FINSH +extern long list_thread(void); +#endif + +struct rt_hw_register +{ + rt_uint32_t r0; + rt_uint32_t r1; + rt_uint32_t r2; + rt_uint32_t r3; + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t fp; + rt_uint32_t ip; + rt_uint32_t sp; + rt_uint32_t lr; + rt_uint32_t pc; + rt_uint32_t cpsr; + rt_uint32_t ORIG_r0; +}; + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ + +void rt_hw_show_register (struct rt_hw_register *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", + regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", + regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", + regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", + regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", + regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When ARM7TDMI comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_udef(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("undefined instruction\n"); + rt_kprintf("thread - %s stack:\n", rt_current_thread->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("software interrupt\n"); + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("prefetch abort\n"); + rt_kprintf("thread - %s stack:\n", RT_NAME_MAX, rt_current_thread->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("data abort\n"); + rt_kprintf("thread - %s stack:\n", RT_NAME_MAX, rt_current_thread->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_register *regs) +{ + rt_kprintf("not used\n"); + rt_hw_show_register(regs); + rt_hw_cpu_shutdown(); +} + +extern struct rt_irq_desc irq_desc[]; +extern rt_uint32_t rt_hw_interrupt_get_active(rt_uint32_t fiq_irq); +extern void rt_hw_interrupt_ack(rt_uint32_t fiq_irq, rt_uint32_t id); + +void rt_hw_trap_irq() +{ + rt_isr_handler_t isr_func; + rt_uint32_t irq; + void *param; + + /* get irq number */ + irq = rt_hw_interrupt_get_active(INT_IRQ); + + /* get interrupt service routine */ + isr_func = irq_desc[irq].handler; + param = irq_desc[irq].param; + + /* turn to interrupt service routine */ + isr_func(irq, param); + + rt_hw_interrupt_ack(INT_IRQ, irq); +#ifdef RT_USING_INTERRUPT_INFO + irq_desc[irq].counter ++; +#endif +} + +void rt_hw_trap_fiq() +{ + rt_isr_handler_t isr_func; + rt_uint32_t irq; + void *param; + + /* get irq number */ + irq = rt_hw_interrupt_get_active(INT_FIQ); + + /* get interrupt service routine */ + isr_func = irq_desc[irq].handler; + param = irq_desc[irq].param; + + /* turn to interrupt service routine */ + isr_func(irq, param); + + rt_hw_interrupt_ack(INT_FIQ, irq); +#ifdef RT_USING_INTERRUPT_INFO + irq_desc[irq].counter ++; +#endif +} diff --git a/rt-thread/libcpu/arm/armv6/arm_entry_gcc.S b/rt-thread/libcpu/arm/armv6/arm_entry_gcc.S new file mode 100644 index 0000000..3aa9930 --- /dev/null +++ b/rt-thread/libcpu/arm/armv6/arm_entry_gcc.S @@ -0,0 +1,140 @@ +/* + * File : arm_entry_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2014-11-07 weety first version + */ + +#include + +#include "armv6.h" + +//#define DEBUG + +.macro PRINT, str +#ifdef DEBUG + stmfd sp!, {r0-r3, ip, lr} + add r0, pc, #4 + bl rt_kprintf + b 1f + .asciz "UNDEF: \str\n" + .balign 4 +1: ldmfd sp!, {r0-r3, ip, lr} +#endif + .endm + +.macro PRINT1, str, arg +#ifdef DEBUG + stmfd sp!, {r0-r3, ip, lr} + mov r1, \arg + add r0, pc, #4 + bl rt_kprintf + b 1f + .asciz "UNDEF: \str\n" + .balign 4 +1: ldmfd sp!, {r0-r3, ip, lr} +#endif + .endm + +.macro PRINT3, str, arg1, arg2, arg3 +#ifdef DEBUG + stmfd sp!, {r0-r3, ip, lr} + mov r3, \arg3 + mov r2, \arg2 + mov r1, \arg1 + add r0, pc, #4 + bl rt_kprintf + b 1f + .asciz "UNDEF: \str\n" + .balign 4 +1: ldmfd sp!, {r0-r3, ip, lr} +#endif + .endm + +.macro get_current_thread, rd + ldr \rd, .current_thread + ldr \rd, [\rd] + .endm + +.current_thread: + .word rt_current_thread + +#ifdef RT_USING_NEON + .align 6 + +/* is the neon instuction on arm mode? */ +.neon_opcode: + .word 0xfe000000 @ mask + .word 0xf2000000 @ opcode + + .word 0xff100000 @ mask + .word 0xf4000000 @ opcode + + .word 0x00000000 @ end mask + .word 0x00000000 @ end opcode +#endif + +/* undefined instruction exception processing */ +.globl undef_entry +undef_entry: + PRINT1 "r0=0x%08x", r0 + PRINT1 "r2=0x%08x", r2 + PRINT1 "r9=0x%08x", r9 + PRINT1 "sp=0x%08x", sp + +#ifdef RT_USING_NEON + ldr r6, .neon_opcode +__check_neon_instruction: + ldr r7, [r6], #4 @ load mask value + cmp r7, #0 @ end mask? + beq __check_vfp_instruction + and r8, r0, r7 + ldr r7, [r6], #4 @ load opcode value + cmp r8, r7 @ is NEON instruction? + bne __check_neon_instruction + b vfp_entry +__check_vfp_instruction: +#endif + tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC instruction has bit 27 + tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2 instruction + moveq pc, lr @ no vfp coprocessor instruction, return + get_current_thread r10 + and r8, r0, #0x00000f00 @ get coprocessor number + PRINT1 "CP=0x%08x", r8 + add pc, pc, r8, lsr #6 + nop + mov pc, lr @ CP0 + mov pc, lr @ CP1 + mov pc, lr @ CP2 + mov pc, lr @ CP3 + mov pc, lr @ CP4 + mov pc, lr @ CP5 + mov pc, lr @ CP6 + mov pc, lr @ CP7 + mov pc, lr @ CP8 + mov pc, lr @ CP9 + mov pc, lr @ CP10 VFP + mov pc, lr @ CP11 VFP + mov pc, lr @ CP12 + mov pc, lr @ CP13 + mov pc, lr @ CP14 DEBUG + mov pc, lr @ CP15 SYS CONTROL + + diff --git a/rt-thread/libcpu/arm/armv6/armv6.h b/rt-thread/libcpu/arm/armv6/armv6.h new file mode 100644 index 0000000..860f096 --- /dev/null +++ b/rt-thread/libcpu/arm/armv6/armv6.h @@ -0,0 +1,107 @@ +/* + * File : armv6.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __ARMV6_H__ +#define __ARMV6_H__ + + +/*****************************/ +/* CPU Mode */ +/*****************************/ +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define ABORTMODE 0x17 +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +#ifndef __ASSEMBLY__ +struct rt_hw_register +{ + rt_uint32_t cpsr; + rt_uint32_t r0; + rt_uint32_t r1; + rt_uint32_t r2; + rt_uint32_t r3; + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t fp; + rt_uint32_t ip; + rt_uint32_t sp; + rt_uint32_t lr; + rt_uint32_t pc; +}; +#if(0) +struct rt_hw_register{ + rt_uint32_t r0; + rt_uint32_t r1; + rt_uint32_t r2; + rt_uint32_t r3; + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t fp; + rt_uint32_t ip; + rt_uint32_t sp; + rt_uint32_t lr; + rt_uint32_t pc; + rt_uint32_t cpsr; + rt_uint32_t ORIG_r0; +}; +#endif +#endif + +/* rt_hw_register offset */ +#define S_FRAME_SIZE 68 + +#define S_PC 64 +#define S_LR 60 +#define S_SP 56 +#define S_IP 52 +#define S_FP 48 +#define S_R10 44 +#define S_R9 40 +#define S_R8 36 +#define S_R7 32 +#define S_R6 28 +#define S_R5 24 +#define S_R4 20 +#define S_R3 16 +#define S_R2 12 +#define S_R1 8 +#define S_R0 4 +#define S_CPSR 0 + + +#endif diff --git a/rt-thread/libcpu/arm/armv6/context_gcc.S b/rt-thread/libcpu/arm/armv6/context_gcc.S new file mode 100644 index 0000000..6f0b433 --- /dev/null +++ b/rt-thread/libcpu/arm/armv6/context_gcc.S @@ -0,0 +1,110 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-01-13 weety copy from mini2440 + */ + +/*! + * \addtogroup ARMv6 + */ +/*@{*/ + +#include + +#define NOINT 0xc0 +#define FPEXC_EN (1 << 30) /* VFP enable bit */ + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + cpsid if + bx lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr_c, r0 + bx lr + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + tst lr, #0x01 + orrne r4, r4, #0x20 @ it's thumb code + + stmfd sp!, {r4} @ push cpsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task cpsr to spsr + msr spsr_cxsf, r4 +_do_switch: + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + + bic r4, r4, #0x20 @ must be ARM mode + msr cpsr_cxsf, r4 + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 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] + bx lr diff --git a/rt-thread/libcpu/arm/armv6/cpuport.c b/rt-thread/libcpu/arm/armv6/cpuport.c new file mode 100644 index 0000000..a0578a6 --- /dev/null +++ b/rt-thread/libcpu/arm/armv6/cpuport.c @@ -0,0 +1,248 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-01-13 weety modified from mini2440 + */ + +#include +#include + +#define ICACHE_MASK (rt_uint32_t)(1 << 12) +#define DCACHE_MASK (rt_uint32_t)(1 << 2) + +extern void machine_reset(void); +extern void machine_shutdown(void); + +#ifdef __GNUC__ +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + __asm__ __volatile__( \ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "orr r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + __asm__ __volatile__( \ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "bic r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} + + +#endif + +#ifdef __CC_ARM +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + __asm + { + mrc p15, 0, i, c1, c0, 0 + } + + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} +#endif + +/** + * enable I-Cache + * + */ +void rt_hw_cpu_icache_enable() +{ + cache_enable(ICACHE_MASK); +} + +/** + * disable I-Cache + * + */ +void rt_hw_cpu_icache_disable() +{ + cache_disable(ICACHE_MASK); +} + +/** + * return the status of I-Cache + * + */ +rt_base_t rt_hw_cpu_icache_status() +{ + return (cp15_rd() & ICACHE_MASK); +} + +/** + * enable D-Cache + * + */ +void rt_hw_cpu_dcache_enable() +{ + cache_enable(DCACHE_MASK); +} + +/** + * disable D-Cache + * + */ +void rt_hw_cpu_dcache_disable() +{ + cache_disable(DCACHE_MASK); +} + +/** + * return the status of D-Cache + * + */ +rt_base_t rt_hw_cpu_dcache_status() +{ + return (cp15_rd() & DCACHE_MASK); +} + +/** + * reset cpu by dog's time-out + * + */ +void rt_hw_cpu_reset() +{ + + rt_kprintf("Restarting system...\n"); + machine_reset(); + + while(1); /* loop forever and wait for reset to happen */ + + /* NEVER REACHED */ +} + +/** + * shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + machine_shutdown(); + while (level) + { + RT_ASSERT(0); + } +} + +#ifdef RT_USING_CPU_FFS +/** + * This function finds the first bit set (beginning with the least significant bit) + * in value and return the index of that bit. + * + * Bits are numbered starting at 1 (the least significant bit). A return value of + * zero from any of these functions means that the argument was zero. + * + * @return return the index of the first bit set. If value is 0, then this function + * shall return 0. + */ +#if defined(__CC_ARM) +int __rt_ffs(int value) +{ + register rt_uint32_t x; + + if (value == 0) + return value; + + __asm + { + rsb x, value, #0 + and x, x, value + clz x, x + rsb x, x, #32 + } + + return x; +} +#elif defined(__IAR_SYSTEMS_ICC__) +int __rt_ffs(int value) +{ + if (value == 0) + return value; + + __ASM("RSB r4, r0, #0"); + __ASM("AND r4, r4, r0"); + __ASM("CLZ r4, r4"); + __ASM("RSB r0, r4, #32"); +} +#elif defined(__GNUC__) +int __rt_ffs(int value) +{ + if (value == 0) + return value; + + value &= (-value); + asm ("clz %0, %1": "=r"(value) :"r"(value)); + + return (32 - value); +} +#endif + +#endif + + +/*@}*/ diff --git a/rt-thread/libcpu/arm/armv6/mmu.c b/rt-thread/libcpu/arm/armv6/mmu.c new file mode 100644 index 0000000..2d47e99 --- /dev/null +++ b/rt-thread/libcpu/arm/armv6/mmu.c @@ -0,0 +1,562 @@ +/* + * File : mmu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +#include "mmu.h" + +#ifdef __CC_ARM +void mmu_setttbase(rt_uint32_t i) +{ + register rt_uint32_t value; + + /* Invalidates all TLBs.Domain access is selected as + * client by configuring domain access register, + * in that case access controlled by permission value + * set by page table entry + */ + value = 0; + __asm volatile + { + mcr p15, 0, value, c8, c7, 0 + } + + value = 0x55555555; + __asm volatile + { + mcr p15, 0, value, c3, c0, 0 + mcr p15, 0, i, c2, c0, 0 + } +} + +void mmu_set_domain(rt_uint32_t i) +{ + __asm volatile + { + mcr p15,0, i, c3, c0, 0 + } +} + +void mmu_enable() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x01 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x01 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_icache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x1000 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_dcache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x04 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_icache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x1000 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_dcache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x04 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_alignfault() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x02 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_alignfault() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x02 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_clean_invalidated_cache_index(int index) +{ + __asm volatile + { + mcr p15, 0, index, c7, c14, 2 + } +} + +void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while(ptr < buffer + size) + { + __asm volatile + { + MCR p15, 0, ptr, c7, c14, 1 + } + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + __asm volatile + { + MCR p15, 0, ptr, c7, c10, 1 + } + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + __asm volatile + { + MCR p15, 0, ptr, c7, c6, 1 + } + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_tlb() +{ + register rt_uint32_t value; + + value = 0; + __asm volatile + { + mcr p15, 0, value, c8, c7, 0 + } +} + +void mmu_invalidate_icache() +{ + register rt_uint32_t value; + + value = 0; + + __asm volatile + { + mcr p15, 0, value, c7, c5, 0 + } +} + + +void mmu_invalidate_dcache_all() +{ + register rt_uint32_t value; + + value = 0; + + __asm volatile + { + mcr p15, 0, value, c7, c6, 0 + } +} +#elif defined(__GNUC__) +void mmu_setttbase(register rt_uint32_t i) +{ + register rt_uint32_t value; + + /* Invalidates all TLBs.Domain access is selected as + * client by configuring domain access register, + * in that case access controlled by permission value + * set by page table entry + */ + value = 0; + asm volatile ("mcr p15, 0, %0, c8, c7, 0"::"r"(value)); + + value = 0x55555555; + asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(value)); + asm volatile ("mcr p15, 0, %0, c2, c0, 0"::"r"(i)); +} + +void mmu_set_domain(register rt_uint32_t i) +{ + asm volatile ("mcr p15,0, %0, c3, c0, 0": :"r" (i)); +} + +void mmu_enable() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= 0x1; + /* Enables the extended page tables to be configured for + the hardware page translation mechanism, Subpage AP bits disabled */ + i |= (1 << 23); /* support for ARMv6 MMU features */ + i |= (1 << 13); /* High exception vectors selected, address range = 0xFFFF0000-0xFFFF001C */ + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~0x1; + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_enable_icache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= (1 << 12); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_enable_dcache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= (1 << 2); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable_icache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~(1 << 12); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable_dcache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~(1 << 2); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_enable_alignfault() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= (1 << 1); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable_alignfault() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~(1 << 1); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_clean_invalidated_cache_index(int index) +{ + asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index)); +} + +void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while(ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c14, 1": :"r" (ptr)); + ptr += CACHE_LINE_SIZE; + } +} + + +void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr)); + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr)); + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_tlb() +{ + asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0)); +} + +void mmu_invalidate_icache() +{ + asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0)); +} + +void mmu_invalidate_dcache_all() +{ + asm volatile ("mcr p15, 0, %0, c7, c6, 0": :"r" (0)); +} +#endif + +/* level1 page table */ +static volatile unsigned int _pgd_table[4*1024] ALIGN(16*1024); +/* + * level2 page table + * RT_MMU_PTE_SIZE must be 1024*n + */ +#define RT_MMU_PTE_SIZE 4096 +static volatile unsigned int _pte_table[RT_MMU_PTE_SIZE] ALIGN(1*1024); + +void mmu_create_pgd(struct mem_desc *mdesc) +{ + volatile rt_uint32_t *pTT; + volatile int i, nSec; + pTT = (rt_uint32_t *)_pgd_table + (mdesc->vaddr_start >> 20); + nSec = (mdesc->vaddr_end >> 20) - (mdesc->vaddr_start >> 20); + for(i = 0; i <= nSec; i++) + { + *pTT = mdesc->sect_attr | (((mdesc->paddr_start >> 20) + i) << 20); + pTT++; + } +} + +void mmu_create_pte(struct mem_desc *mdesc) +{ + volatile rt_uint32_t *pTT; + volatile rt_uint32_t *p_pteentry; + int i; + rt_uint32_t vaddr; + rt_uint32_t total_page = 0; + rt_uint32_t pte_offset = 0; + rt_uint32_t sect_attr = 0; + + total_page = (mdesc->vaddr_end >> 12) - (mdesc->vaddr_start >> 12) + 1; + pte_offset = mdesc->sect_attr & 0xfffffc00; + sect_attr = mdesc->sect_attr & 0x3ff; + vaddr = mdesc->vaddr_start; + + for(i = 0; i < total_page; i++) + { + pTT = (rt_uint32_t *)_pgd_table + (vaddr >> 20); + if (*pTT == 0) /* Level 1 page table item not used, now update pgd item */ + { + *pTT = pte_offset | sect_attr; + p_pteentry = (rt_uint32_t *)pte_offset + + ((vaddr & 0x000ff000) >> 12); + pte_offset += 1024; + } + else /* using old Level 1 page table item */ + { + p_pteentry = (rt_uint32_t *)(*pTT & 0xfffffc00) + + ((vaddr & 0x000ff000) >> 12); + } + + + *p_pteentry = mdesc->page_attr | (((mdesc->paddr_start >> 12) + i) << 12); + vaddr += 0x1000; + } +} + +static void build_pte_mem_desc(struct mem_desc *mdesc, rt_uint32_t size) +{ + rt_uint32_t pte_offset = 0; + rt_uint32_t nsec = 0; + /* set page table */ + for (; size > 0; size--) + { + if (mdesc->mapped_mode == PAGE_MAPPED) + { + nsec = (RT_ALIGN(mdesc->vaddr_end, 0x100000) - RT_ALIGN_DOWN(mdesc->vaddr_start, 0x100000)) >> 20; + mdesc->sect_attr |= (((rt_uint32_t)_pte_table)& 0xfffffc00) + pte_offset; + pte_offset += nsec << 10; + } + if (pte_offset >= RT_MMU_PTE_SIZE) + { + rt_kprintf("PTE table size too little\n"); + RT_ASSERT(0); + } + + mdesc++; + } +} + + +void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size) +{ + /* disable I/D cache */ + mmu_disable_dcache(); + mmu_disable_icache(); + mmu_disable(); + mmu_invalidate_tlb(); + + /* clear pgd and pte table */ + rt_memset((void *)_pgd_table, 0, 16*1024); + rt_memset((void *)_pte_table, 0, RT_MMU_PTE_SIZE); + build_pte_mem_desc(mdesc, size); + /* set page table */ + for (; size > 0; size--) + { + if (mdesc->mapped_mode == SECT_MAPPED) + { + mmu_create_pgd(mdesc); + } + else + { + mmu_create_pte(mdesc); + } + + mdesc++; + } + + /* set MMU table address */ + mmu_setttbase((rt_uint32_t)_pgd_table); + + /* enables MMU */ + mmu_enable(); + + /* enable Instruction Cache */ + mmu_enable_icache(); + + /* enable Data Cache */ + mmu_enable_dcache(); + + mmu_invalidate_icache(); + mmu_invalidate_dcache_all(); +} + diff --git a/rt-thread/libcpu/arm/armv6/mmu.h b/rt-thread/libcpu/arm/armv6/mmu.h new file mode 100644 index 0000000..f6e788d --- /dev/null +++ b/rt-thread/libcpu/arm/armv6/mmu.h @@ -0,0 +1,208 @@ +/* + * File : mmu.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __MMU_H__ +#define __MMU_H__ + +#include + +#define CACHE_LINE_SIZE 32 + +/* + * Hardware page table definitions. + * + * + Level 1 descriptor (PGD) + * - common + */ +#define PGD_TYPE_MASK (3 << 0) +#define PGD_TYPE_FAULT (0 << 0) +#define PGD_TYPE_TABLE (1 << 0) +#define PGD_TYPE_SECT (2 << 0) +#define PGD_BIT4 (1 << 4) +#define PGD_DOMAIN(x) ((x) << 5) +#define PGD_PROTECTION (1 << 9) /* ARMv5 */ +/* + * - section + */ +#define PGD_SECT_BUFFERABLE (1 << 2) +#define PGD_SECT_CACHEABLE (1 << 3) +#define PGD_SECT_XN (1 << 4) /* ARMv6 */ +#define PGD_SECT_AP0 (1 << 10) +#define PGD_SECT_AP1 (1 << 11) +#define PGD_SECT_TEX(x) ((x) << 12) /* ARMv5 */ +#define PGD_SECT_APX (1 << 15) /* ARMv6 */ +#define PGD_SECT_S (1 << 16) /* ARMv6 */ +#define PGD_SECT_nG (1 << 17) /* ARMv6 */ +#define PGD_SECT_SUPER (1 << 18) /* ARMv6 */ + +#define PGD_SECT_UNCACHED (0) +#define PGD_SECT_BUFFERED (PGD_SECT_BUFFERABLE) +#define PGD_SECT_WT (PGD_SECT_CACHEABLE) +#define PGD_SECT_WB (PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE) +#define PGD_SECT_MINICACHE (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE) +#define PGD_SECT_WBWA (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE) +#define PGD_SECT_NONSHARED_DEV (PGD_SECT_TEX(2)) + + +/* + * + Level 2 descriptor (PTE) + * - common + */ +#define PTE_TYPE_MASK (3 << 0) +#define PTE_TYPE_FAULT (0 << 0) +#define PTE_TYPE_LARGE (1 << 0) +#define PTE_TYPE_SMALL (2 << 0) +#define PTE_TYPE_EXT (3 << 0) /* ARMv5 */ +#define PTE_BUFFERABLE (1 << 2) +#define PTE_CACHEABLE (1 << 3) + +/* + * - extended small page/tiny page + */ +#define PTE_EXT_XN (1 << 0) /* ARMv6 */ +#define PTE_EXT_AP_MASK (3 << 4) +#define PTE_EXT_AP0 (1 << 4) +#define PTE_EXT_AP1 (2 << 4) +#define PTE_EXT_AP_UNO_SRO (0 << 4) +#define PTE_EXT_AP_UNO_SRW (PTE_EXT_AP0) +#define PTE_EXT_AP_URO_SRW (PTE_EXT_AP1) +#define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0) +#define PTE_EXT_TEX(x) ((x) << 6) /* ARMv5 */ +#define PTE_EXT_APX (1 << 9) /* ARMv6 */ +#define PTE_EXT_SHARED (1 << 10) /* ARMv6 */ +#define PTE_EXT_NG (1 << 11) /* ARMv6 */ + +/* + * - small page + */ +#define PTE_SMALL_AP_MASK (0xff << 4) +#define PTE_SMALL_AP_UNO_SRO (0x00 << 4) +#define PTE_SMALL_AP_UNO_SRW (0x55 << 4) +#define PTE_SMALL_AP_URO_SRW (0xaa << 4) +#define PTE_SMALL_AP_URW_SRW (0xff << 4) + + +/* + * sector table properities + */ +#define SECT_CB (PGD_SECT_CACHEABLE|PGD_SECT_BUFFERABLE) //cache_on, write_back +#define SECT_CNB (PGD_SECT_CACHEABLE) //cache_on, write_through +#define SECT_NCB (PGD_SECT_BUFFERABLE) //cache_off,WR_BUF on +#define SECT_NCNB (0 << 2) //cache_off,WR_BUF off + +#define SECT_AP_RW (PGD_SECT_AP0|PGD_SECT_AP1) //supervisor=RW, user=RW +#define SECT_AP_RO (PGD_SECT_AP0|PGD_SECT_AP1|PGD_SECT_APX) //supervisor=RO, user=RO + +#define SECT_RWX_CB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT) /* Read/Write/executable, cache, write back */ +#define SECT_RWX_CNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT) /* Read/Write/executable, cache, write through */ +#define SECT_RWX_NCNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT) /* Read/Write/executable without cache and write buffer */ +#define SECT_RWX_FAULT (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT) /* Read/Write without cache and write buffer */ + +#define SECT_RWNX_CB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write, cache, write back */ +#define SECT_RWNX_CNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write, cache, write through */ +#define SECT_RWNX_NCNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write without cache and write buffer */ +#define SECT_RWNX_FAULT (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write without cache and write buffer */ + + +#define SECT_ROX_CB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT) /* Read Only/executable, cache, write back */ +#define SECT_ROX_CNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT) /* Read Only/executable, cache, write through */ +#define SECT_ROX_NCNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT) /* Read Only/executable without cache and write buffer */ +#define SECT_ROX_FAULT (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT) /* Read Only without cache and write buffer */ + +#define SECT_RONX_CB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only, cache, write back */ +#define SECT_RONX_CNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only, cache, write through */ +#define SECT_RONX_NCNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only without cache and write buffer */ +#define SECT_RONX_FAULT (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only without cache and write buffer */ + +#define SECT_TO_PAGE (PGD_DOMAIN(0)|PGD_TYPE_TABLE) /* Level 2 descriptor (PTE) entry properity */ + +/* + * page table properities + */ +#define PAGE_CB (PTE_BUFFERABLE|PTE_CACHEABLE) //cache_on, write_back +#define PAGE_CNB (PTE_CACHEABLE) //cache_on, write_through +#define PAGE_NCB (PTE_BUFFERABLE) //cache_off,WR_BUF on +#define PAGE_NCNB (0 << 2) //cache_off,WR_BUF off + +#define PAGE_AP_RW (PTE_EXT_AP0|PTE_EXT_AP1) //supervisor=RW, user=RW +#define PAGE_AP_RO (PTE_EXT_AP0|PTE_EXT_AP1|PTE_EXT_APX) //supervisor=RO, user=RO + +#define PAGE_RWX_CB (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL) /* Read/Write/executable, cache, write back */ +#define PAGE_RWX_CNB (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL) /* Read/Write/executable, cache, write through */ +#define PAGE_RWX_NCNB (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write/executable without cache and write buffer */ +#define PAGE_RWX_FAULT (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write without cache and write buffer */ + +#define PAGE_RWNX_CB (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write, cache, write back */ +#define PAGE_RWNX_CNB (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write, cache, write through */ +#define PAGE_RWNX_NCNB (PAGE_AP_RW|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write without cache and write buffer */ +#define PAGE_RWNX_FAULT (PAGE_AP_RW|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write without cache and write buffer */ + + +#define PAGE_ROX_CB (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL) /* Read Only/executable, cache, write back */ +#define PAGE_ROX_CNB (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL) /* Read Only/executable, cache, write through */ +#define PAGE_ROX_NCNB (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only/executable without cache and write buffer */ +#define PAGE_ROX_FAULT (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only without cache and write buffer */ + +#define PAGE_RONX_CB (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only, cache, write back */ +#define PAGE_RONX_CNB (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only, cache, write through */ +#define PAGE_RONX_NCNB (PAGE_AP_RO|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only without cache and write buffer */ +#define PAGE_RONX_FAULT (PAGE_AP_RO|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only without cache and write buffer */ + + +#define DESC_SEC (0x2|(1<<4)) +#define CB (3<<2) //cache_on, write_back +#define CNB (2<<2) //cache_on, write_through +#define NCB (1<<2) //cache_off,WR_BUF on +#define NCNB (0<<2) //cache_off,WR_BUF off +#define AP_RW (3<<10) //supervisor=RW, user=RW +#define AP_RO (2<<10) //supervisor=RW, user=RO + +#define DOMAIN_FAULT (0x0) +#define DOMAIN_CHK (0x1) +#define DOMAIN_NOTCHK (0x3) +#define DOMAIN0 (0x0<<5) +#define DOMAIN1 (0x1<<5) + +#define DOMAIN0_ATTR (DOMAIN_CHK<<0) +#define DOMAIN1_ATTR (DOMAIN_FAULT<<2) + +#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */ +#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */ +#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */ +#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */ + +struct mem_desc { + rt_uint32_t vaddr_start; + rt_uint32_t vaddr_end; + rt_uint32_t paddr_start; + rt_uint32_t sect_attr; /* when page mapped */ + rt_uint32_t page_attr; /* only sector mapped valid */ + rt_uint32_t mapped_mode; +#define SECT_MAPPED 0 +#define PAGE_MAPPED 1 +}; + +void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size); + +#endif + diff --git a/rt-thread/libcpu/arm/armv6/stack.c b/rt-thread/libcpu/arm/armv6/stack.c new file mode 100644 index 0000000..648ea7d --- /dev/null +++ b/rt-thread/libcpu/arm/armv6/stack.c @@ -0,0 +1,82 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-01-13 weety copy from mini2440 + */ +#include + +/*****************************/ +/* CPU Mode */ +/*****************************/ +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define ABORTMODE 0x17 +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + diff --git a/rt-thread/libcpu/arm/armv6/vfp.c b/rt-thread/libcpu/arm/armv6/vfp.c new file mode 100644 index 0000000..e432127 --- /dev/null +++ b/rt-thread/libcpu/arm/armv6/vfp.c @@ -0,0 +1,52 @@ +/* + * File : vfp.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2014-11-07 weety first version + */ + +#include +#include +#include "vfp.h" + +#ifdef RT_USING_VFP + +void vfp_init(void) +{ + int ret = 0; + unsigned int value; + asm volatile ("mrc p15, 0, %0, c1, c0, 2" + :"=r"(value) + :); + value |= 0xf00000;/*enable CP10, CP11 user access*/ + asm volatile("mcr p15, 0, %0, c1, c0, 2" + : + :"r"(value)); + + asm volatile("fmrx %0, fpexc" + :"=r"(value)); + value |=(1<<30); + asm volatile("fmxr fpexc, %0" + : + :"r"(value)); + +} + +#endif diff --git a/rt-thread/libcpu/arm/armv6/vfp.h b/rt-thread/libcpu/arm/armv6/vfp.h new file mode 100644 index 0000000..0ec7b26 --- /dev/null +++ b/rt-thread/libcpu/arm/armv6/vfp.h @@ -0,0 +1,110 @@ +/* + * File : vfp.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2014-11-07 weety first version + */ + +#ifndef __VFP_H__ +#define __VFP_H__ + +/* FPSID register bits */ +#define FPSID_IMPLEMENTER_BIT (24) +#define FPSID_IMPLEMENTER_MASK (0xff << FPSID_IMPLEMENTER_BIT) +#define FPSID_SW (1 << 23) +#define FPSID_FORMAT_BIT (21) +#define FPSID_FORMAT_MASK (0x3 << FPSID_FORMAT_BIT) +#define FPSID_NODOUBLE (1 << 20) +#define FPSID_ARCH_BIT (16) +#define FPSID_ARCH_MASK (0xF << FPSID_ARCH_BIT) +#define FPSID_PART_BIT (8) +#define FPSID_PART_MASK (0xFF << FPSID_PART_BIT) +#define FPSID_VARIANT_BIT (4) +#define FPSID_VARIANT_MASK (0xF << FPSID_VARIANT_BIT) +#define FPSID_REVISION_BIT (0) +#define FPSID_REVISION_MASK (0xF << FPSID_REVISION_BIT) + +/* FPSCR register bits */ +#define FPSCR_DN (1<<25) /* Default NaN mode enable bit */ +#define FPSCR_FZ (1<<24) /* Flush-to-zero mode enable bit */ +#define FPSCR_RN (0<<22) /* Round to nearest (RN) mode */ +#define FPSCR_RP (1<<22) /* Round towards plus infinity (RP) mode */ +#define FPSCR_RM (2<<22) /* Round towards minus infinity (RM) mode */ +#define FPSCR_RZ (3<<22) /* Round towards zero (RZ) mode */ +#define FPSCR_RMODE_BIT (22) +#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT) +#define FPSCR_STRIDE_BIT (20) +#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT) +#define FPSCR_LENGTH_BIT (16) +#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT) +#define FPSCR_IDE (1<<15) /* Input Subnormal exception trap enable bit */ +#define FPSCR_IXE (1<<12) /* Inexact exception trap enable bit */ +#define FPSCR_UFE (1<<11) /* Underflow exception trap enable bit */ +#define FPSCR_OFE (1<<10) /* Overflow exception trap enable bit */ +#define FPSCR_DZE (1<<9) /* Division by Zero exception trap enable bit */ +#define FPSCR_IOE (1<<8) /* Invalid Operation exception trap enable bit */ +#define FPSCR_IDC (1<<7) /* Input Subnormal cumulative exception flag */ +#define FPSCR_IXC (1<<4) /* Inexact cumulative exception flag */ +#define FPSCR_UFC (1<<3) /* Underflow cumulative exception flag */ +#define FPSCR_OFC (1<<2) /* Overflow cumulative exception flag */ +#define FPSCR_DZC (1<<1) /* Division by Zero cumulative exception flag */ +#define FPSCR_IOC (1<<0) /* Invalid Operation cumulative exception flag */ + +/* FPEXC register bits */ +#define FPEXC_EX (1 << 31) /* When EX is set, the VFP coprocessor is in the exceptional state */ +#define FPEXC_EN (1 << 30) /* VFP enable bit */ +#define FPEXC_DEX (1 << 29) /* Defined synchronous instruction exceptional flag */ +#define FPEXC_FP2V (1 << 28) /* FPINST2 instruction valid flag */ +#define FPEXC_LENGTH_BIT (8) +#define FPEXC_LENGTH_MASK (7 << FPEXC_LENGTH_BIT) +#define FPEXC_INV (1 << 7) /* Input exception flag */ +#define FPEXC_UFC (1 << 3) /* Potential underflow flag */ +#define FPEXC_OFC (1 << 2) /* Potential overflow flag */ +#define FPEXC_IOC (1 << 0) /* Potential invalid operation flag */ +#define FPEXC_TRAP_MASK (FPEXC_INV|FPEXC_UFC|FPEXC_OFC|FPEXC_IOC) + + +/* MVFR0 register bits */ +#define MVFR0_A_SIMD_BIT (0) +#define MVFR0_A_SIMD_MASK (0xf << MVFR0_A_SIMD_BIT) + + +/* thread switch micro */ +#define THREAD_INIT 0 +#define THREAD_EXIT 1 + +/* + * get VFP register + */ + +#define vmrs(vfp) ({ \ + rt_uint32_t var; \ + asm("vmrs %0, "#vfp"" : "=r" (var) : : "cc"); \ + var; \ + }) + +#define vmsr(vfp, var) \ + asm("vmsr "#vfp", %0" \ + : : "r" (var) : "cc") + + +#endif + + diff --git a/rt-thread/libcpu/arm/common/backtrace.c b/rt-thread/libcpu/arm/common/backtrace.c new file mode 100644 index 0000000..03ee614 --- /dev/null +++ b/rt-thread/libcpu/arm/common/backtrace.c @@ -0,0 +1,67 @@ +/* + * File : backtrace.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 2008 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-07-29 Bernard first version from QiuYi implementation + */ + +#include + +#ifdef __GNUC__ +/* +-->High Address,Stack Top +PC<-----| +LR | +IP | +FP | +...... | +PC<-| | +LR | | +IP | | +FP---|-- | +...... | +PC | +LR | +IP | +FP--- +-->Low Address,Stack Bottom +*/ +void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry) +{ + rt_uint32_t i, pc, func_entry; + + pc = *fp; + rt_kprintf("[0x%x]\n", pc-0xC); + + for(i=0; i<10; i++) + { + fp = (rt_uint32_t *)*(fp - 3); + pc = *fp ; + + func_entry = pc - 0xC; + + if(func_entry <= 0x30000000) break; + + if(func_entry == thread_entry) + { + rt_kprintf("EntryPoint:0x%x\n", func_entry); + + break; + } + + rt_kprintf("[0x%x]\n", func_entry); + } +} +#else +void rt_hw_backtrace(rt_uint32_t *fp, rt_uint32_t thread_entry) +{ + /* old compiler implementation */ +} +#endif diff --git a/rt-thread/libcpu/arm/common/div0.c b/rt-thread/libcpu/arm/common/div0.c new file mode 100644 index 0000000..128a1eb --- /dev/null +++ b/rt-thread/libcpu/arm/common/div0.c @@ -0,0 +1,4 @@ +void __div0 (void) +{ + while (1) ; +} diff --git a/rt-thread/libcpu/arm/common/divsi3.S b/rt-thread/libcpu/arm/common/divsi3.S new file mode 100644 index 0000000..01eac6a --- /dev/null +++ b/rt-thread/libcpu/arm/common/divsi3.S @@ -0,0 +1,393 @@ +/* $NetBSD: divsi3.S,v 1.5 2005/02/26 22:58:56 perry Exp $ */ + +/* + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * stack is aligned as there's a possibility of branching to L_overflow + * which makes a C call + */ + .text + .align 0 + .globl __umodsi3 + .type __umodsi3 , function +__umodsi3: + stmfd sp!, {lr} + sub sp, sp, #4 /* align stack */ + bl .L_udivide + add sp, sp, #4 /* unalign stack */ + mov r0, r1 + ldmfd sp!, {pc} + + .text + .align 0 + .globl __modsi3 + .type __modsi3 , function +__modsi3: + stmfd sp!, {lr} + sub sp, sp, #4 /* align stack */ + bl .L_divide + add sp, sp, #4 /* unalign stack */ + mov r0, r1 + ldmfd sp!, {pc} + +.L_overflow: + /* XXX should cause a fatal error */ + mvn r0, #0 + mov pc, lr + + .text + .align 0 + .globl __udivsi3 + .type __udivsi3 , function +__udivsi3: +.L_udivide: /* r0 = r0 / r1; r1 = r0 % r1 */ + eor r0, r1, r0 + eor r1, r0, r1 + eor r0, r1, r0 + /* r0 = r1 / r0; r1 = r1 % r0 */ + cmp r0, #1 + bcc .L_overflow + beq .L_divide_l0 + mov ip, #0 + movs r1, r1 + bpl .L_divide_l1 + orr ip, ip, #0x20000000 /* ip bit 0x20000000 = -ve r1 */ + movs r1, r1, lsr #1 + orrcs ip, ip, #0x10000000 /* ip bit 0x10000000 = bit 0 of r1 */ + b .L_divide_l1 + +.L_divide_l0: /* r0 == 1 */ + mov r0, r1 + mov r1, #0 + mov pc, lr + + .text + .align 0 + .globl __divsi3 + .type __divsi3 , function +__divsi3: +.L_divide: /* r0 = r0 / r1; r1 = r0 % r1 */ + eor r0, r1, r0 + eor r1, r0, r1 + eor r0, r1, r0 + /* r0 = r1 / r0; r1 = r1 % r0 */ + cmp r0, #1 + bcc .L_overflow + beq .L_divide_l0 + ands ip, r0, #0x80000000 + rsbmi r0, r0, #0 + ands r2, r1, #0x80000000 + eor ip, ip, r2 + rsbmi r1, r1, #0 + orr ip, r2, ip, lsr #1 /* ip bit 0x40000000 = -ve division */ + /* ip bit 0x80000000 = -ve remainder */ + +.L_divide_l1: + mov r2, #1 + mov r3, #0 + + /* + * If the highest bit of the dividend is set, we have to be + * careful when shifting the divisor. Test this. + */ + movs r1,r1 + bpl .L_old_code + + /* + * At this point, the highest bit of r1 is known to be set. + * We abuse this below in the tst instructions. + */ + tst r1, r0 /*, lsl #0 */ + bmi .L_divide_b1 + tst r1, r0, lsl #1 + bmi .L_divide_b2 + tst r1, r0, lsl #2 + bmi .L_divide_b3 + tst r1, r0, lsl #3 + bmi .L_divide_b4 + tst r1, r0, lsl #4 + bmi .L_divide_b5 + tst r1, r0, lsl #5 + bmi .L_divide_b6 + tst r1, r0, lsl #6 + bmi .L_divide_b7 + tst r1, r0, lsl #7 + bmi .L_divide_b8 + tst r1, r0, lsl #8 + bmi .L_divide_b9 + tst r1, r0, lsl #9 + bmi .L_divide_b10 + tst r1, r0, lsl #10 + bmi .L_divide_b11 + tst r1, r0, lsl #11 + bmi .L_divide_b12 + tst r1, r0, lsl #12 + bmi .L_divide_b13 + tst r1, r0, lsl #13 + bmi .L_divide_b14 + tst r1, r0, lsl #14 + bmi .L_divide_b15 + tst r1, r0, lsl #15 + bmi .L_divide_b16 + tst r1, r0, lsl #16 + bmi .L_divide_b17 + tst r1, r0, lsl #17 + bmi .L_divide_b18 + tst r1, r0, lsl #18 + bmi .L_divide_b19 + tst r1, r0, lsl #19 + bmi .L_divide_b20 + tst r1, r0, lsl #20 + bmi .L_divide_b21 + tst r1, r0, lsl #21 + bmi .L_divide_b22 + tst r1, r0, lsl #22 + bmi .L_divide_b23 + tst r1, r0, lsl #23 + bmi .L_divide_b24 + tst r1, r0, lsl #24 + bmi .L_divide_b25 + tst r1, r0, lsl #25 + bmi .L_divide_b26 + tst r1, r0, lsl #26 + bmi .L_divide_b27 + tst r1, r0, lsl #27 + bmi .L_divide_b28 + tst r1, r0, lsl #28 + bmi .L_divide_b29 + tst r1, r0, lsl #29 + bmi .L_divide_b30 + tst r1, r0, lsl #30 + bmi .L_divide_b31 +/* + * instead of: + * tst r1, r0, lsl #31 + * bmi .L_divide_b32 + */ + b .L_divide_b32 + +.L_old_code: + cmp r1, r0 + bcc .L_divide_b0 + cmp r1, r0, lsl #1 + bcc .L_divide_b1 + cmp r1, r0, lsl #2 + bcc .L_divide_b2 + cmp r1, r0, lsl #3 + bcc .L_divide_b3 + cmp r1, r0, lsl #4 + bcc .L_divide_b4 + cmp r1, r0, lsl #5 + bcc .L_divide_b5 + cmp r1, r0, lsl #6 + bcc .L_divide_b6 + cmp r1, r0, lsl #7 + bcc .L_divide_b7 + cmp r1, r0, lsl #8 + bcc .L_divide_b8 + cmp r1, r0, lsl #9 + bcc .L_divide_b9 + cmp r1, r0, lsl #10 + bcc .L_divide_b10 + cmp r1, r0, lsl #11 + bcc .L_divide_b11 + cmp r1, r0, lsl #12 + bcc .L_divide_b12 + cmp r1, r0, lsl #13 + bcc .L_divide_b13 + cmp r1, r0, lsl #14 + bcc .L_divide_b14 + cmp r1, r0, lsl #15 + bcc .L_divide_b15 + cmp r1, r0, lsl #16 + bcc .L_divide_b16 + cmp r1, r0, lsl #17 + bcc .L_divide_b17 + cmp r1, r0, lsl #18 + bcc .L_divide_b18 + cmp r1, r0, lsl #19 + bcc .L_divide_b19 + cmp r1, r0, lsl #20 + bcc .L_divide_b20 + cmp r1, r0, lsl #21 + bcc .L_divide_b21 + cmp r1, r0, lsl #22 + bcc .L_divide_b22 + cmp r1, r0, lsl #23 + bcc .L_divide_b23 + cmp r1, r0, lsl #24 + bcc .L_divide_b24 + cmp r1, r0, lsl #25 + bcc .L_divide_b25 + cmp r1, r0, lsl #26 + bcc .L_divide_b26 + cmp r1, r0, lsl #27 + bcc .L_divide_b27 + cmp r1, r0, lsl #28 + bcc .L_divide_b28 + cmp r1, r0, lsl #29 + bcc .L_divide_b29 + cmp r1, r0, lsl #30 + bcc .L_divide_b30 +.L_divide_b32: + cmp r1, r0, lsl #31 + subhs r1, r1,r0, lsl #31 + addhs r3, r3,r2, lsl #31 +.L_divide_b31: + cmp r1, r0, lsl #30 + subhs r1, r1,r0, lsl #30 + addhs r3, r3,r2, lsl #30 +.L_divide_b30: + cmp r1, r0, lsl #29 + subhs r1, r1,r0, lsl #29 + addhs r3, r3,r2, lsl #29 +.L_divide_b29: + cmp r1, r0, lsl #28 + subhs r1, r1,r0, lsl #28 + addhs r3, r3,r2, lsl #28 +.L_divide_b28: + cmp r1, r0, lsl #27 + subhs r1, r1,r0, lsl #27 + addhs r3, r3,r2, lsl #27 +.L_divide_b27: + cmp r1, r0, lsl #26 + subhs r1, r1,r0, lsl #26 + addhs r3, r3,r2, lsl #26 +.L_divide_b26: + cmp r1, r0, lsl #25 + subhs r1, r1,r0, lsl #25 + addhs r3, r3,r2, lsl #25 +.L_divide_b25: + cmp r1, r0, lsl #24 + subhs r1, r1,r0, lsl #24 + addhs r3, r3,r2, lsl #24 +.L_divide_b24: + cmp r1, r0, lsl #23 + subhs r1, r1,r0, lsl #23 + addhs r3, r3,r2, lsl #23 +.L_divide_b23: + cmp r1, r0, lsl #22 + subhs r1, r1,r0, lsl #22 + addhs r3, r3,r2, lsl #22 +.L_divide_b22: + cmp r1, r0, lsl #21 + subhs r1, r1,r0, lsl #21 + addhs r3, r3,r2, lsl #21 +.L_divide_b21: + cmp r1, r0, lsl #20 + subhs r1, r1,r0, lsl #20 + addhs r3, r3,r2, lsl #20 +.L_divide_b20: + cmp r1, r0, lsl #19 + subhs r1, r1,r0, lsl #19 + addhs r3, r3,r2, lsl #19 +.L_divide_b19: + cmp r1, r0, lsl #18 + subhs r1, r1,r0, lsl #18 + addhs r3, r3,r2, lsl #18 +.L_divide_b18: + cmp r1, r0, lsl #17 + subhs r1, r1,r0, lsl #17 + addhs r3, r3,r2, lsl #17 +.L_divide_b17: + cmp r1, r0, lsl #16 + subhs r1, r1,r0, lsl #16 + addhs r3, r3,r2, lsl #16 +.L_divide_b16: + cmp r1, r0, lsl #15 + subhs r1, r1,r0, lsl #15 + addhs r3, r3,r2, lsl #15 +.L_divide_b15: + cmp r1, r0, lsl #14 + subhs r1, r1,r0, lsl #14 + addhs r3, r3,r2, lsl #14 +.L_divide_b14: + cmp r1, r0, lsl #13 + subhs r1, r1,r0, lsl #13 + addhs r3, r3,r2, lsl #13 +.L_divide_b13: + cmp r1, r0, lsl #12 + subhs r1, r1,r0, lsl #12 + addhs r3, r3,r2, lsl #12 +.L_divide_b12: + cmp r1, r0, lsl #11 + subhs r1, r1,r0, lsl #11 + addhs r3, r3,r2, lsl #11 +.L_divide_b11: + cmp r1, r0, lsl #10 + subhs r1, r1,r0, lsl #10 + addhs r3, r3,r2, lsl #10 +.L_divide_b10: + cmp r1, r0, lsl #9 + subhs r1, r1,r0, lsl #9 + addhs r3, r3,r2, lsl #9 +.L_divide_b9: + cmp r1, r0, lsl #8 + subhs r1, r1,r0, lsl #8 + addhs r3, r3,r2, lsl #8 +.L_divide_b8: + cmp r1, r0, lsl #7 + subhs r1, r1,r0, lsl #7 + addhs r3, r3,r2, lsl #7 +.L_divide_b7: + cmp r1, r0, lsl #6 + subhs r1, r1,r0, lsl #6 + addhs r3, r3,r2, lsl #6 +.L_divide_b6: + cmp r1, r0, lsl #5 + subhs r1, r1,r0, lsl #5 + addhs r3, r3,r2, lsl #5 +.L_divide_b5: + cmp r1, r0, lsl #4 + subhs r1, r1,r0, lsl #4 + addhs r3, r3,r2, lsl #4 +.L_divide_b4: + cmp r1, r0, lsl #3 + subhs r1, r1,r0, lsl #3 + addhs r3, r3,r2, lsl #3 +.L_divide_b3: + cmp r1, r0, lsl #2 + subhs r1, r1,r0, lsl #2 + addhs r3, r3,r2, lsl #2 +.L_divide_b2: + cmp r1, r0, lsl #1 + subhs r1, r1,r0, lsl #1 + addhs r3, r3,r2, lsl #1 +.L_divide_b1: + cmp r1, r0 + subhs r1, r1, r0 + addhs r3, r3, r2 +.L_divide_b0: + + tst ip, #0x20000000 + bne .L_udivide_l1 + mov r0, r3 + cmp ip, #0 + rsbmi r1, r1, #0 + movs ip, ip, lsl #1 + bicmi r0, r0, #0x80000000 /* Fix incase we divided 0x80000000 */ + rsbmi r0, r0, #0 + mov pc, lr + +.L_udivide_l1: + tst ip, #0x10000000 + mov r1, r1, lsl #1 + orrne r1, r1, #1 + mov r3, r3, lsl #1 + cmp r1, r0 + subhs r1, r1, r0 + addhs r3, r3, r2 + mov r0, r3 + mov pc, lr diff --git a/rt-thread/libcpu/arm/common/showmem.c b/rt-thread/libcpu/arm/common/showmem.c new file mode 100644 index 0000000..38f037f --- /dev/null +++ b/rt-thread/libcpu/arm/common/showmem.c @@ -0,0 +1,42 @@ +/* + * File : showmem.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 2008 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-07-29 Bernard first version from QiuYi implementation + */ + +#include + +void rt_hw_show_memory(rt_uint32_t addr, rt_uint32_t size) +{ + int i = 0, j =0; + + RT_ASSERT(addr); + + addr = addr & ~0xF; + size = 4*((size + 3)/4); + + while(i < size) + { + rt_kprintf("0x%08x: ", addr ); + + for(j=0; j<4; j++) + { + rt_kprintf("0x%08x ", *(rt_uint32_t *)addr); + + addr += 4; + i++; + } + + rt_kprintf("\n"); + } + + return; +} diff --git a/rt-thread/libcpu/arm/cortex-a/armv7.h b/rt-thread/libcpu/arm/cortex-a/armv7.h new file mode 100644 index 0000000..69c556e --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/armv7.h @@ -0,0 +1,64 @@ +#ifndef __ARMV7_H__ +#define __ARMV7_H__ + +/* the exception stack without VFP registers */ +struct rt_hw_exp_stack +{ + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long sp; + unsigned long lr; + unsigned long pc; + unsigned long cpsr; +}; + +struct rt_hw_stack +{ + unsigned long cpsr; + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long lr; + unsigned long pc; +}; + +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define MONITORMODE 0x16 +#define ABORTMODE 0x17 +#define HYPMODE 0x1b +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +#define T_Bit (1<<5) +#define F_Bit (1<<6) +#define I_Bit (1<<7) +#define A_Bit (1<<8) +#define E_Bit (1<<9) +#define J_Bit (1<<24) + +#endif diff --git a/rt-thread/libcpu/arm/cortex-a/context_gcc.S b/rt-thread/libcpu/arm/cortex-a/context_gcc.S new file mode 100644 index 0000000..01593a7 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/context_gcc.S @@ -0,0 +1,105 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.section .text, "ax" +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + cpsid i + bx lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + bx lr + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc + +.section .bss.share.isr +_guest_switch_lvl: + .word 0 + +.globl vmm_virq_update + +.section .text.isr, "ax" +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + tst lr, #0x01 + orrne r4, r4, #0x20 @ it's thumb code + + stmfd sp!, {r4} @ push cpsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task cpsr to spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + ldr ip, =rt_interrupt_from_thread @ set rt_interrupt_from_thread + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1 + str r0, [ip] + str r3, [r2] +_reswitch: + ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread + str r1, [r2] + bx lr diff --git a/rt-thread/libcpu/arm/cortex-a/cp15.h b/rt-thread/libcpu/arm/cortex-a/cp15.h new file mode 100644 index 0000000..ebea3f0 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/cp15.h @@ -0,0 +1,12 @@ +#ifndef __CP15_H__ +#define __CP15_H__ + +unsigned long rt_cpu_get_smp_id(void); + +void rt_cpu_mmu_disable(void); +void rt_cpu_mmu_enable(void); +void rt_cpu_tlb_set(volatile unsigned long*); + +void rt_cpu_vector_set_base(unsigned int addr); + +#endif diff --git a/rt-thread/libcpu/arm/cortex-a/cp15_gcc.S b/rt-thread/libcpu/arm/cortex-a/cp15_gcc.S new file mode 100644 index 0000000..f1ed649 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/cp15_gcc.S @@ -0,0 +1,140 @@ +/* + * File : cp15_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * http://www.rt-thread.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.globl rt_cpu_get_smp_id +rt_cpu_get_smp_id: + mrc p15, #0, r0, c0, c0, #5 + bx lr + +.globl rt_cpu_vector_set_base +rt_cpu_vector_set_base: + mcr p15, #0, r0, c12, c0, #0 + dsb + bx lr + +.globl rt_hw_cpu_dcache_enable +rt_hw_cpu_dcache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_hw_cpu_icache_enable +rt_hw_cpu_icache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +_FLD_MAX_WAY: + .word 0x3ff +_FLD_MAX_IDX: + .word 0x7ff + +.globl rt_cpu_dcache_clean_flush +rt_cpu_dcache_clean_flush: + push {r4-r11} + dmb + mrc p15, #1, r0, c0, c0, #1 @ read clid register + ands r3, r0, #0x7000000 @ get level of coherency + mov r3, r3, lsr #23 + beq finished + mov r10, #0 +loop1: + add r2, r10, r10, lsr #1 + mov r1, r0, lsr r2 + and r1, r1, #7 + cmp r1, #2 + blt skip + mcr p15, #2, r10, c0, c0, #0 + isb + mrc p15, #1, r1, c0, c0, #0 + and r2, r1, #7 + add r2, r2, #4 + ldr r4, _FLD_MAX_WAY + ands r4, r4, r1, lsr #3 + clz r5, r4 + ldr r7, _FLD_MAX_IDX + ands r7, r7, r1, lsr #13 +loop2: + mov r9, r4 +loop3: + orr r11, r10, r9, lsl r5 + orr r11, r11, r7, lsl r2 + mcr p15, #0, r11, c7, c14, #2 + subs r9, r9, #1 + bge loop3 + subs r7, r7, #1 + bge loop2 +skip: + add r10, r10, #2 + cmp r3, r10 + bgt loop1 + +finished: + dsb + isb + pop {r4-r11} + bx lr + +.globl rt_hw_cpu_dcache_disable +rt_hw_cpu_dcache_disable: + push {r4-r11, lr} + bl rt_cpu_dcache_clean_flush + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + pop {r4-r11, lr} + bx lr + +.globl rt_hw_cpu_icache_disable +rt_hw_cpu_icache_disable: + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_cpu_mmu_disable +rt_cpu_mmu_disable: + mcr p15, #0, r0, c8, c7, #0 @ invalidate tlb + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #1 + mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit + dsb + bx lr + +.globl rt_cpu_mmu_enable +rt_cpu_mmu_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x001 + mcr p15, #0, r0, c1, c0, #0 @ set mmu enable bit + dsb + bx lr + +.globl rt_cpu_tlb_set +rt_cpu_tlb_set: + mcr p15, #0, r0, c2, c0, #0 + dmb + bx lr diff --git a/rt-thread/libcpu/arm/cortex-a/cpu.c b/rt-thread/libcpu/arm/cortex-a/cpu.c new file mode 100644 index 0000000..7dd426e --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/cpu.c @@ -0,0 +1,37 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop 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 + * 2011-09-15 Bernard first version + */ + +#include +#include +#include + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +/** shutdown CPU */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + while (level) + { + RT_ASSERT(0); + } +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/cortex-a/interrupt.c b/rt-thread/libcpu/arm/cortex-a/interrupt.c new file mode 100644 index 0000000..942c074 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/interrupt.c @@ -0,0 +1,152 @@ +/* + * File : interrupt.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, 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 + * 2013-07-06 Bernard first version + * 2014-04-03 Grissiom port to VMM + */ + +#include +#include + +#include +#include + +#include +#include "cp15.h" + +#define MAX_HANDLERS IMX_INTERRUPT_COUNT + +extern volatile rt_uint8_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +struct rt_irq_desc isr_table[MAX_HANDLERS]; + +rt_uint32_t rt_interrupt_from_thread; +rt_uint32_t rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +extern void rt_cpu_vector_set_base(unsigned int addr); +extern int system_vectors; + +/* keep compatible with platform SDK */ +void register_interrupt_routine(uint32_t irq_id, irq_hdlr_t isr) +{ + rt_hw_interrupt_install(irq_id, (rt_isr_handler_t)isr, NULL, "unknown"); +} + +void enable_interrupt(uint32_t irq_id, uint32_t cpu_id, uint32_t priority) +{ + gic_set_irq_priority(irq_id, priority); + gic_set_irq_security(irq_id, false); // set IRQ as non-secure + gic_set_cpu_target(irq_id, cpu_id, true); + gic_enable_irq(irq_id, true); +} + +void disable_interrupt(uint32_t irq_id, uint32_t cpu_id) +{ + gic_enable_irq(irq_id, false); + gic_set_cpu_target(irq_id, cpu_id, false); +} + +static void rt_hw_vector_init(void) +{ + int sctrl; + unsigned int *src = (unsigned int *)&system_vectors; + + /* C12-C0 is only active when SCTLR.V = 0 */ + asm volatile ("mrc p15, #0, %0, c1, c0, #0" + :"=r" (sctrl)); + sctrl &= ~(1 << 13); + asm volatile ("mcr p15, #0, %0, c1, c0, #0" + : + :"r" (sctrl)); + + asm volatile ("mcr p15, #0, %0, c12, c0, #0" + : + :"r" (src)); +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + rt_hw_vector_init(); + gic_init(); + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + disable_interrupt(vector, 0); +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + enable_interrupt(vector, 0, 0); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if (vector < MAX_HANDLERS) + { + old_handler = isr_table[vector].handler; + + if (handler != RT_NULL) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + // arm_gic_set_cpu(0, vector, 1 << rt_cpu_get_smp_id()); + } + + return old_handler; +} + +/** + * Trigger a software IRQ + * + * Since we are running in single core, the target CPU are always CPU0. + */ +void rt_hw_interrupt_trigger(int vector) +{ + // arm_gic_trigger(0, 1, vector); +} + +void rt_hw_interrupt_clear(int vector) +{ + gic_write_end_of_irq(vector); +} diff --git a/rt-thread/libcpu/arm/cortex-a/mmu.c b/rt-thread/libcpu/arm/cortex-a/mmu.c new file mode 100644 index 0000000..b2503e4 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/mmu.c @@ -0,0 +1,207 @@ +/* + * File : mmu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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 + * 2012-01-10 bernard porting to AM1808 + */ + +#include +#include +#include + +#include "cp15.h" + +#define DESC_SEC (0x2) +#define CB (3<<2) //cache_on, write_back +#define CNB (2<<2) //cache_on, write_through +#define NCB (1<<2) //cache_off,WR_BUF on +#define NCNB (0<<2) //cache_off,WR_BUF off +#define AP_RW (3<<10) //supervisor=RW, user=RW +#define AP_RO (2<<10) //supervisor=RW, user=RO +#define XN (1<<4) // eXecute Never + +#define DOMAIN_FAULT (0x0) +#define DOMAIN_CHK (0x1) +#define DOMAIN_NOTCHK (0x3) +#define DOMAIN0 (0x0<<5) +#define DOMAIN1 (0x1<<5) + +#define DOMAIN0_ATTR (DOMAIN_CHK<<0) +#define DOMAIN1_ATTR (DOMAIN_FAULT<<2) + +/* Read/Write, cache, write back */ +#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) +/* Read/Write, cache, write through */ +#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) +/* Read/Write without cache and write buffer */ +#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) +/* Read/Write without cache and write buffer, no execute */ +#define RW_NCNBXN (AP_RW|DOMAIN0|NCNB|DESC_SEC|XN) +/* Read/Write without cache and write buffer */ +#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) + +/* dump 2nd level page table */ +void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + for (i = 0; i < 256; i++) + { + rt_uint32_t pte2 = ptb[i]; + if ((pte2 & 0x3) == 0) + { + if (fcnt == 0) + rt_kprintf(" "); + rt_kprintf("%04x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf(" %04x: %x: ", i, pte2); + if ((pte2 & 0x3) == 0x1) + { + rt_kprintf("L,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, + (pte2 >> 15) & 0x1, + ((pte2 >> 10) | (pte2 >> 2)) & 0x1f); + } + else + { + rt_kprintf("S,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, pte2 & 0x1, + ((pte2 >> 4) | (pte2 >> 2)) & 0x1f); + } + } +} + +void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + rt_kprintf("page table@%p\n", ptb); + for (i = 0; i < 1024*4; i++) + { + rt_uint32_t pte1 = ptb[i]; + if ((pte1 & 0x3) == 0) + { + rt_kprintf("%03x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf("%03x: %08x: ", i, pte1); + if ((pte1 & 0x3) == 0x3) + { + rt_kprintf("LPAE\n"); + } + else if ((pte1 & 0x3) == 0x1) + { + rt_kprintf("pte,ns:%d,domain:%d\n", + (pte1 >> 3) & 0x1, (pte1 >> 5) & 0xf); + /* + *rt_hw_cpu_dump_page_table_2nd((void*)((pte1 & 0xfffffc000) + * - 0x80000000 + 0xC0000000)); + */ + } + else if (pte1 & (1 << 18)) + { + rt_kprintf("super section,ns:%d,ap:%x,xn:%d,texcb:%02x\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + ((pte1 >> 10) | (pte1 >> 2)) & 0x1f); + } + else + { + rt_kprintf("section,ns:%d,ap:%x," + "xn:%d,texcb:%02x,domain:%d\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + (((pte1 & (0x7 << 12)) >> 10) | + ((pte1 & 0x0c) >> 2)) & 0x1f, + (pte1 >> 5) & 0xf); + } + } +} + +/* level1 page table, each entry for 1MB memory. */ +volatile static unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024))); +void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart, + rt_uint32_t vaddrEnd, + rt_uint32_t paddrStart, + rt_uint32_t attr) +{ + volatile rt_uint32_t *pTT; + volatile int i, nSec; + pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20); + nSec = (vaddrEnd >> 20) - (vaddrStart >> 20); + for(i = 0; i <= nSec; i++) + { + *pTT = attr | (((paddrStart >> 20) + i) << 20); + pTT++; + } +} + +unsigned long rt_hw_set_domain_register(unsigned long domain_val) +{ + unsigned long old_domain; + + asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain)); + asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory"); + + return old_domain; +} + +void rt_hw_mmu_init(void) +{ + rt_hw_cpu_dcache_disable(); + rt_hw_cpu_icache_disable(); + rt_cpu_mmu_disable(); + + /* set page table */ + /* 4G 1:1 memory */ + rt_hw_mmu_setmtt(0, 0xffffffff-1, 0, RW_CB); + /* IO memory region */ + rt_hw_mmu_setmtt(0x44000000, 0x80000000-1, 0x44000000, RW_NCNBXN); + + /*rt_hw_cpu_dump_page_table(MMUTable);*/ + rt_hw_set_domain_register(0x55555555); + + rt_cpu_tlb_set(MMUTable); + + rt_cpu_mmu_enable(); + + rt_hw_cpu_icache_enable(); + rt_hw_cpu_dcache_enable(); +} + diff --git a/rt-thread/libcpu/arm/cortex-a/pmu.c b/rt-thread/libcpu/arm/cortex-a/pmu.c new file mode 100644 index 0000000..07911a2 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/pmu.c @@ -0,0 +1,12 @@ +#include +#include "pmu.h" + +void rt_hw_pmu_dump_feature(void) +{ + unsigned long reg; + + reg = rt_hw_pmu_get_control(); + rt_kprintf("ARM PMU Implementor: %c, ID code: %02x, %d counters\n", + reg >> 24, (reg >> 16) & 0xff, (reg >> 11) & 0x1f); + RT_ASSERT(ARM_PMU_CNTER_NR == ((reg >> 11) & 0x1f)); +} diff --git a/rt-thread/libcpu/arm/cortex-a/pmu.h b/rt-thread/libcpu/arm/cortex-a/pmu.h new file mode 100644 index 0000000..05c1420 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/pmu.h @@ -0,0 +1,151 @@ +#ifndef __PMU_H__ +#define __PMU_H__ + +#include "board.h" + +/* Number of counters */ +#define ARM_PMU_CNTER_NR 4 + +enum rt_hw_pmu_event_type { + ARM_PMU_EVENT_PMNC_SW_INCR = 0x00, + ARM_PMU_EVENT_L1_ICACHE_REFILL = 0x01, + ARM_PMU_EVENT_ITLB_REFILL = 0x02, + ARM_PMU_EVENT_L1_DCACHE_REFILL = 0x03, + ARM_PMU_EVENT_L1_DCACHE_ACCESS = 0x04, + ARM_PMU_EVENT_DTLB_REFILL = 0x05, + ARM_PMU_EVENT_MEM_READ = 0x06, + ARM_PMU_EVENT_MEM_WRITE = 0x07, + ARM_PMU_EVENT_INSTR_EXECUTED = 0x08, + ARM_PMU_EVENT_EXC_TAKEN = 0x09, + ARM_PMU_EVENT_EXC_EXECUTED = 0x0A, + ARM_PMU_EVENT_CID_WRITE = 0x0B, +}; + +/* Enable bit */ +#define ARM_PMU_PMCR_E (0x01 << 0) +/* Event counter reset */ +#define ARM_PMU_PMCR_P (0x01 << 1) +/* Cycle counter reset */ +#define ARM_PMU_PMCR_C (0x01 << 2) +/* Cycle counter divider */ +#define ARM_PMU_PMCR_D (0x01 << 3) + +#ifdef __GNUC__ +rt_inline void rt_hw_pmu_enable_cnt(int divide64) +{ + unsigned long pmcr; + unsigned long pmcntenset; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_E | ARM_PMU_PMCR_P | ARM_PMU_PMCR_C; + if (divide64) + pmcr |= ARM_PMU_PMCR_D; + else + pmcr &= ~ARM_PMU_PMCR_D; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + + /* enable all the counters */ + pmcntenset = ~0; + asm volatile ("mcr p15, 0, %0, c9, c12, 1" :: "r"(pmcntenset)); + /* clear overflows(just in case) */ + asm volatile ("mcr p15, 0, %0, c9, c12, 3" :: "r"(pmcntenset)); +} + +rt_inline unsigned long rt_hw_pmu_get_control(void) +{ + unsigned long pmcr; + asm ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + return pmcr; +} + +rt_inline unsigned long rt_hw_pmu_get_ceid(void) +{ + unsigned long reg; + /* only PMCEID0 is supported, PMCEID1 is RAZ. */ + asm ("mrc p15, 0, %0, c9, c12, 6" : "=r"(reg)); + return reg; +} + +rt_inline unsigned long rt_hw_pmu_get_cnten(void) +{ + unsigned long pmcnt; + asm ("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcnt)); + return pmcnt; +} + +rt_inline void rt_hw_pmu_reset_cycle(void) +{ + unsigned long pmcr; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_C; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + asm volatile ("isb"); +} + +rt_inline void rt_hw_pmu_reset_event(void) +{ + unsigned long pmcr; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_P; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + asm volatile ("isb"); +} + +rt_inline unsigned long rt_hw_pmu_get_cycle(void) +{ + unsigned long cyc; + asm volatile ("isb"); + asm volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r"(cyc)); + return cyc; +} + +rt_inline void rt_hw_pmu_select_counter(int idx) +{ + RT_ASSERT(idx < ARM_PMU_CNTER_NR); + + asm volatile ("mcr p15, 0, %0, c9, c12, 5" : : "r"(idx)); + /* Linux add an isb here, don't know why here. */ + asm volatile ("isb"); +} + +rt_inline void rt_hw_pmu_select_event(int idx, + enum rt_hw_pmu_event_type eve) +{ + RT_ASSERT(idx < ARM_PMU_CNTER_NR); + + rt_hw_pmu_select_counter(idx); + asm volatile ("mcr p15, 0, %0, c9, c13, 1" : : "r"(eve)); +} + +rt_inline unsigned long rt_hw_pmu_read_counter(int idx) +{ + unsigned long reg; + + rt_hw_pmu_select_counter(idx); + asm volatile ("isb"); + asm volatile ("mrc p15, 0, %0, c9, c13, 2" : "=r"(reg)); + return reg; +} + +rt_inline unsigned long rt_hw_pmu_get_ovsr(void) +{ + unsigned long reg; + asm volatile ("isb"); + asm ("mrc p15, 0, %0, c9, c12, 3" : "=r"(reg)); + return reg; +} + +rt_inline void rt_hw_pmu_clear_ovsr(unsigned long reg) +{ + asm ("mcr p15, 0, %0, c9, c12, 3" : : "r"(reg)); + asm volatile ("isb"); +} + +#endif + +void rt_hw_pmu_dump_feature(void); + +#endif /* end of include guard: __PMU_H__ */ + diff --git a/rt-thread/libcpu/arm/cortex-a/stack.c b/rt-thread/libcpu/arm/cortex-a/stack.c new file mode 100644 index 0000000..e60e8c7 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/stack.c @@ -0,0 +1,68 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 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 + * 2011-09-23 Bernard the first version + * 2011-10-05 Bernard add thumb mode + */ +#include +#include +#include + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/cortex-a/start_gcc.S b/rt-thread/libcpu/arm/cortex-a/start_gcc.S new file mode 100644 index 0000000..ca8c1f9 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/start_gcc.S @@ -0,0 +1,249 @@ +/* + * File : start_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.equ Mode_USR, 0x10 +.equ Mode_FIQ, 0x11 +.equ Mode_IRQ, 0x12 +.equ Mode_SVC, 0x13 +.equ Mode_ABT, 0x17 +.equ Mode_UND, 0x1B +.equ Mode_SYS, 0x1F + +.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled +.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled + +.equ UND_Stack_Size, 0x00000000 +.equ SVC_Stack_Size, 0x00000100 +.equ ABT_Stack_Size, 0x00000000 +.equ RT_FIQ_STACK_PGSZ, 0x00000000 +.equ RT_IRQ_STACK_PGSZ, 0x00000100 +.equ USR_Stack_Size, 0x00000100 + +#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ) + +.section .data.share.isr +/* stack */ +.globl stack_start +.globl stack_top + +stack_start: +.rept ISR_Stack_Size +.byte 0 +.endr +stack_top: + +.text +/* reset entry */ +.globl _reset +_reset: + bl rt_cpu_mmu_disable + /* set the cpu to SVC32 mode and disable interrupt */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0x13 + msr cpsr_c, r0 + + /* setup stack */ + bl stack_setup + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop +ctor_end: + + /* start RT-Thread Kernel */ + ldr pc, _rtthread_startup +_rtthread_startup: + .word rtthread_startup + +stack_setup: + ldr r0, =stack_top + + @ Set the startup stack for svc + mov sp, r0 + + @ Enter Undefined Instruction Mode and set its Stack Pointer + msr cpsr_c, #Mode_UND|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #UND_Stack_Size + + @ Enter Abort Mode and set its Stack Pointer + msr cpsr_c, #Mode_ABT|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #ABT_Stack_Size + + @ Enter FIQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #RT_FIQ_STACK_PGSZ + + @ Enter IRQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #RT_IRQ_STACK_PGSZ + + /* come back to SVC mode */ + msr cpsr_c, #Mode_SVC|I_Bit|F_Bit + bx lr + +/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */ +.section .text.isr, "ax" + .align 5 +.globl vector_fiq +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc, lr, #4 + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread + +.globl rt_current_thread +.globl vmm_thread +.globl vmm_virq_check + + .align 5 +.globl vector_irq +vector_irq: + stmfd sp!, {r0-r12,lr} + + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + + @ if rt_thread_switch_interrupt_flag set, jump to + @ rt_hw_context_switch_interrupt_do and don't return + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq rt_hw_context_switch_interrupt_do + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +rt_hw_context_switch_interrupt_do: + mov r1, #0 @ clear flag + str r1, [r0] + + mov r1, sp @ r1 point to {r0-r3} in stack + add sp, sp, #4*4 + ldmfd sp!, {r4-r12,lr}@ reload saved registers + mrs r0, spsr @ get cpsr of interrupt thread + sub r2, lr, #4 @ save old task's pc to r2 + + @ Switch to SVC mode with no interrupt. If the usr mode guest is + @ interrupted, this will just switch to the stack of kernel space. + @ save the registers in kernel space won't trigger data abort. + msr cpsr_c, #I_Bit|F_Bit|Mode_SVC + + stmfd sp!, {r2} @ push old task's pc + stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4 + ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt thread + stmfd sp!, {r1-r4} @ push old task's r0-r3 + stmfd sp!, {r0} @ push old task's cpsr + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] @ store sp in preempted tasks's TCB + + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] @ get new task's stack pointer + + ldmfd sp!, {r4} @ pop new task's cpsr to spsr + msr spsr_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr + +.macro push_svc_reg + sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */ + stmia sp, {r0 - r12} @/* Calling r0-r12 */ + mov r0, sp + mrs r6, spsr @/* Save CPSR */ + str lr, [r0, #15*4] @/* Push PC */ + str r6, [r0, #16*4] @/* Push CPSR */ + cps #Mode_SVC + str sp, [r0, #13*4] @/* Save calling SP */ + str lr, [r0, #14*4] @/* Save calling PC */ +.endm + + .align 5 + .globl vector_swi +vector_swi: + push_svc_reg + bl rt_hw_trap_swi + b . + + .align 5 + .globl vector_undef +vector_undef: + push_svc_reg + bl rt_hw_trap_undef + b . + + .align 5 + .globl vector_pabt +vector_pabt: + push_svc_reg + bl rt_hw_trap_pabt + b . + + .align 5 + .globl vector_dabt +vector_dabt: + push_svc_reg + bl rt_hw_trap_dabt + b . + + .align 5 + .globl vector_resv +vector_resv: + push_svc_reg + bl rt_hw_trap_resv + b . diff --git a/rt-thread/libcpu/arm/cortex-a/trap.c b/rt-thread/libcpu/arm/cortex-a/trap.c new file mode 100644 index 0000000..515f7cb --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/trap.c @@ -0,0 +1,181 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Develop 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 + * 2013-07-20 Bernard first version + */ + +#include +#include +#include + +#include "armv7.h" + +#include "gic.h" + +extern struct rt_thread *rt_current_thread; +#ifdef RT_USING_FINSH +extern long list_thread(void); +#endif + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ +void rt_hw_show_register(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_undef(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("undefined instruction:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("software interrupt:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("prefetch abort:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("data abort:"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("reserved trap:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +void rt_hw_trap_irq(void) +{ + void *param; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + // vectNum = RESERVED[31:13] | CPUID[12:10] | INTERRUPT_ID[9:0] + // send ack and get ID source + uint32_t vectNum = gic_read_irq_ack(); + + // Check that INT_ID isn't 1023 or 1022 (spurious interrupt) + if (vectNum & 0x0200) + { + gic_write_end_of_irq(vectNum); // send end of irq + } + else + { + // copy the local value to the global image of CPUID + unsigned cpu = (vectNum >> 10) & 0x7; + unsigned irq = vectNum & 0x1FF; + + /* skip warning */ + cpu = cpu; + + // Call the service routine stored in the handlers array. If there isn't + // one for this IRQ, then call the default handler. + /* get interrupt service routine */ + isr_func = isr_table[irq].handler; +#ifdef RT_USING_INTERRUPT_INFO + isr_table[irq].counter++; +#endif + if (isr_func) + { + /* Interrupt for myself. */ + param = isr_table[irq].param; + /* turn to interrupt service routine */ + isr_func(irq, param); + } + + // Signal the end of the irq. + gic_write_end_of_irq(vectNum); + } +} + +void rt_hw_trap_fiq(void) +{ + /* TODO */ +} diff --git a/rt-thread/libcpu/arm/cortex-a/vector_gcc.S b/rt-thread/libcpu/arm/cortex-a/vector_gcc.S new file mode 100644 index 0000000..4a44a73 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-a/vector_gcc.S @@ -0,0 +1,65 @@ +/* + * File : vector_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.section .vectors, "ax" +.code 32 + +.globl system_vectors +system_vectors: + ldr pc, _vector_reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + ldr pc, _vector_resv + ldr pc, _vector_irq + ldr pc, _vector_fiq + +.globl _reset +.globl vector_undef +.globl vector_swi +.globl vector_pabt +.globl vector_dabt +.globl vector_resv +.globl vector_irq +.globl vector_fiq + +_vector_reset: + .word _reset +_vector_undef: + .word vector_undef +_vector_swi: + .word vector_swi +_vector_pabt: + .word vector_pabt +_vector_dabt: + .word vector_dabt +_vector_resv: + .word vector_resv +_vector_irq: + .word vector_irq +_vector_fiq: + .word vector_fiq + +.balignl 16,0xdeadbeef diff --git a/rt-thread/libcpu/arm/cortex-m0/context_gcc.S b/rt-thread/libcpu/arm/cortex-m0/context_gcc.S new file mode 100644 index 0000000..227a9aa --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m0/context_gcc.S @@ -0,0 +1,214 @@ +/* + * File : context_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2009 - 2013, 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 + * 2010-01-25 Bernard first version + * 2012-06-01 aozima set pendsv priority to 0xFF. + * 2012-08-17 aozima fixed bug: store r8 - r11. + * 2013-02-20 aozima port to gcc. + * 2013-06-18 aozima add restore MSP feature. + * 2013-11-04 bright fixed hardfault bug for gcc. + */ + + .cpu cortex-m0 + .fpu softvfp + .syntax unified + .thumb + .text + + .equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */ + .equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */ + .equ NVIC_SHPR3, 0xE000ED20 /* system priority register (3) */ + .equ NVIC_PENDSV_PRI, 0x00FF0000 /* PendSV priority value (lowest) */ + .equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */ + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ + .global rt_hw_interrupt_disable + .type rt_hw_interrupt_disable, %function +rt_hw_interrupt_disable: + MRS R0, PRIMASK + CPSID I + BX LR + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ + .global rt_hw_interrupt_enable + .type rt_hw_interrupt_enable, %function +rt_hw_interrupt_enable: + MSR PRIMASK, R0 + BX LR + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * R0 --> from + * R1 --> to + */ + .global rt_hw_context_switch_interrupt + .type rt_hw_context_switch_interrupt, %function + .global rt_hw_context_switch + .type rt_hw_context_switch, %function +rt_hw_context_switch_interrupt: +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 + MOVS 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 + +/* R0 --> switch from thread stack + * R1 --> switch to thread stack + * psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack + */ + .global PendSV_Handler + .type PendSV_Handler, %function +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] + CMP R1, #0x00 + BEQ pendsv_exit /* pendsv aLReady handled */ + + /* clear rt_thread_switch_interrupt_flag to 0 */ + MOVS R1, #0 + STR R1, [R0] + + LDR R0, =rt_interrupt_from_thread + LDR R1, [R0] + CMP R1, #0x00 + BEQ switch_to_thread /* skip register save at the first time */ + + MRS R1, PSP /* get from thread stack pointer */ + + SUBS R1, R1, #0x20 /* space for {R4 - R7} and {R8 - R11} */ + LDR R0, [R0] + STR R1, [R0] /* update from thread stack pointer */ + + STMIA R1!, {R4 - R7} /* push thread {R4 - R7} register to thread stack */ + + MOV R4, R8 /* mov thread {R8 - R11} to {R4 - R7} */ + MOV R5, R9 + MOV R6, R10 + MOV R7, R11 + STMIA R1!, {R4 - R7} /* push thread {R8 - R11} high register to thread stack */ +switch_to_thread: + LDR R1, =rt_interrupt_to_thread + LDR R1, [R1] + LDR R1, [R1] /* load thread stack pointer */ + + LDMIA R1!, {R4 - R7} /* pop thread {R4 - R7} register from thread stack */ + PUSH {R4 - R7} /* push {R4 - R7} to MSP for copy {R8 - R11} */ + + LDMIA R1!, {R4 - R7} /* pop thread {R8 - R11} high register from thread stack to {R4 - R7} */ + MOV R8, R4 /* mov {R4 - R7} to {R8 - R11} */ + MOV R9, R5 + MOV R10, R6 + MOV R11, R7 + + POP {R4 - R7} /* pop {R4 - R7} from MSP */ + + MSR PSP, R1 /* update stack pointer */ + +pendsv_exit: + /* restore interrupt */ + MSR PRIMASK, R2 + + MOVS R0, #0x04 + RSBS R0, R0, #0x00 + BX R0 +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * R0 --> to + */ + .global rt_hw_context_switch_to + .type rt_hw_context_switch_to, %function +rt_hw_context_switch_to: + LDR R1, =rt_interrupt_to_thread + STR R0, [R1] + + /* set from thread to 0 */ + LDR R1, =rt_interrupt_from_thread + MOVS R0, #0 + STR R0, [R1] + + /* set interrupt flag to 1 */ + LDR R1, =rt_thread_switch_interrupt_flag + MOVS R0, #1 + STR R0, [R1] + + /* set the PendSV exception priority */ + LDR R0, =NVIC_SHPR3 + LDR R1, =NVIC_PENDSV_PRI + LDR R2, [R0,#0x00] /* read */ + ORRS R1, R1, R2 /* modify */ + STR R1, [R0] /* write-back */ + + LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */ + LDR R1, =NVIC_PENDSVSET + STR R1, [R0] + NOP + /* restore MSP */ + LDR R0, =SCB_VTOR + LDR R0, [R0] + LDR R0, [R0] + NOP + MSR MSP, R0 + + /* enable interrupts at processor level */ + CPSIE I + + /* never reach here! */ + +/* compatible with old version */ + .global rt_hw_interrupt_thread_switch + .type rt_hw_interrupt_thread_switch, %function +rt_hw_interrupt_thread_switch: + BX LR + NOP + + .global HardFault_Handler + .type HardFault_Handler, %function +HardFault_Handler: + /* get current context */ + MRS R0, PSP /* get fault thread stack pointer */ + PUSH {LR} + BL rt_hw_hard_fault_exception + POP {PC} + + +/* + * rt_uint32_t rt_hw_interrupt_check(void); + * R0 --> state + */ + .global rt_hw_interrupt_check + .type rt_hw_interrupt_check, %function +rt_hw_interrupt_check: + MRS R0, IPSR + BX LR diff --git a/rt-thread/libcpu/arm/cortex-m0/context_iar.S b/rt-thread/libcpu/arm/cortex-m0/context_iar.S new file mode 100644 index 0000000..67ea808 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m0/context_iar.S @@ -0,0 +1,210 @@ +;/* +; * File : context_iar.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 +; * 2010-01-25 Bernard first version +; * 2012-06-01 aozima set pendsv priority to 0xFF. +; * 2012-08-17 aozima fixed bug: store r8 - r11. +; * 2013-06-18 aozima add restore MSP feature. +; */ + +;/** +; * @addtogroup CORTEX-M0 +; */ +;/*@{*/ + +SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register +NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register +NVIC_SHPR3 EQU 0xE000ED20 ; system priority register (2) +NVIC_PENDSV_PRI EQU 0x00FF0000 ; PendSV priority value (lowest) +NVIC_PENDSVSET EQU 0x10000000 ; value to trigger PendSV exception + + SECTION .text:CODE(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(); +; */ + EXPORT rt_hw_interrupt_disable +rt_hw_interrupt_disable: + MRS r0, PRIMASK + CPSID I + BX LR + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ + EXPORT rt_hw_interrupt_enable +rt_hw_interrupt_enable: + MSR PRIMASK, r0 + BX LR + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ + EXPORT rt_hw_context_switch_interrupt + EXPORT rt_hw_context_switch +rt_hw_context_switch_interrupt: +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 + MOVS r3, #0x1 + 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 + +; r0 --> switch from thread stack +; r1 --> switch to thread stack +; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack + EXPORT PendSV_Handler +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] + CMP r1, #0x00 + BEQ pendsv_exit ; pendsv already handled + + ; clear rt_thread_switch_interrupt_flag to 0 + MOVS r1, #0x00 + STR r1, [r0] + + LDR r0, =rt_interrupt_from_thread + LDR r1, [r0] + CMP r1, #0x00 + BEQ switch_to_thread ; skip register save at the first time + + MRS r1, psp ; get from thread stack pointer + + SUBS r1, r1, #0x20 ; space for {r4 - r7} and {r8 - r11} + LDR r0, [r0] + STR r1, [r0] ; update from thread stack pointer + + STMIA r1!, {r4 - r7} ; push thread {r4 - r7} register to thread stack + + MOV r4, r8 ; mov thread {r8 - r11} to {r4 - r7} + MOV r5, r9 + MOV r6, r10 + MOV r7, r11 + STMIA r1!, {r4 - r7} ; push thread {r8 - r11} high register to thread stack + +switch_to_thread + LDR r1, =rt_interrupt_to_thread + LDR r1, [r1] + LDR r1, [r1] ; load thread stack pointer + + LDMIA r1!, {r4 - r7} ; pop thread {r4 - r7} register from thread stack + PUSH {r4 - r7} ; push {r4 - r7} to MSP for copy {r8 - r11} + + LDMIA r1!, {r4 - r7} ; pop thread {r8 - r11} high register from thread stack to {r4 - r7} + MOV r8, r4 ; mov {r4 - r7} to {r8 - r11} + MOV r9, r5 + MOV r10, r6 + MOV r11, r7 + + POP {r4 - r7} ; pop {r4 - r7} from MSP + + MSR psp, r1 ; update stack pointer + +pendsv_exit + ; restore interrupt + MSR PRIMASK, r2 + + MOVS r0, #0x04 + RSBS r0, r0, #0x00 + BX r0 + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; * this fucntion is used to perform the first thread switch +; */ + EXPORT rt_hw_context_switch_to +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 + MOVS r0, #0x0 + STR r0, [r1] + + ; set interrupt flag to 1 + LDR r1, =rt_thread_switch_interrupt_flag + MOVS r0, #1 + STR r0, [r1] + + ; set the PendSV exception priority + LDR r0, =NVIC_SHPR3 + LDR r1, =NVIC_PENDSV_PRI + LDR r2, [r0,#0x00] ; read + ORRS 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] + NOP + + ; restore MSP + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + NOP + MSR msp, r0 + + ; enable interrupts at processor level + CPSIE I + + ; never reach here! + +; compatible with old version + EXPORT rt_hw_interrupt_thread_switch +rt_hw_interrupt_thread_switch: + BX lr + + IMPORT rt_hw_hard_fault_exception + EXPORT HardFault_Handler +HardFault_Handler: + + ; get current context + MRS r0, psp ; get fault thread stack pointer + PUSH {lr} + BL rt_hw_hard_fault_exception + POP {pc} + + END diff --git a/rt-thread/libcpu/arm/cortex-m0/context_rvds.S b/rt-thread/libcpu/arm/cortex-m0/context_rvds.S new file mode 100644 index 0000000..bf68592 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m0/context_rvds.S @@ -0,0 +1,219 @@ +;/* +; * 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 +; * 2010-01-25 Bernard first version +; * 2012-06-01 aozima set pendsv priority to 0xFF. +; * 2012-08-17 aozima fixed bug: store r8 - r11. +; * 2013-06-18 aozima add restore MSP feature. +; */ + +;/** +; * @addtogroup CORTEX-M0 +; */ +;/*@{*/ + +SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register +NVIC_INT_CTRL EQU 0xE000ED04 ; interrupt control state register +NVIC_SHPR3 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 + MOVS r3, #0x01 + 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 --> switch from thread stack +; r1 --> switch 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] + CMP r1, #0x00 + BEQ pendsv_exit ; pendsv already handled + + ; clear rt_thread_switch_interrupt_flag to 0 + MOVS r1, #0x00 + STR r1, [r0] + + LDR r0, =rt_interrupt_from_thread + LDR r1, [r0] + CMP r1, #0x00 + BEQ switch_to_thread ; skip register save at the first time + + MRS r1, psp ; get from thread stack pointer + + SUBS r1, r1, #0x20 ; space for {r4 - r7} and {r8 - r11} + LDR r0, [r0] + STR r1, [r0] ; update from thread stack pointer + + STMIA r1!, {r4 - r7} ; push thread {r4 - r7} register to thread stack + + MOV r4, r8 ; mov thread {r8 - r11} to {r4 - r7} + MOV r5, r9 + MOV r6, r10 + MOV r7, r11 + STMIA r1!, {r4 - r7} ; push thread {r8 - r11} high register to thread stack + +switch_to_thread + LDR r1, =rt_interrupt_to_thread + LDR r1, [r1] + LDR r1, [r1] ; load thread stack pointer + + LDMIA r1!, {r4 - r7} ; pop thread {r4 - r7} register from thread stack + PUSH {r4 - r7} ; push {r4 - r7} to MSP for copy {r8 - r11} + + LDMIA r1!, {r4 - r7} ; pop thread {r8 - r11} high register from thread stack to {r4 - r7} + MOV r8, r4 ; mov {r4 - r7} to {r8 - r11} + MOV r9, r5 + MOV r10, r6 + MOV r11, r7 + + POP {r4 - r7} ; pop {r4 - r7} from MSP + + MSR psp, r1 ; update stack pointer + +pendsv_exit + ; restore interrupt + MSR PRIMASK, r2 + + MOVS r0, #0x04 + RSBS r0, r0, #0x00 + BX r0 + 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 + MOVS r0, #0x0 + STR r0, [r1] + + ; set interrupt flag to 1 + LDR r1, =rt_thread_switch_interrupt_flag + MOVS r0, #1 + STR r0, [r1] + + ; set the PendSV exception priority + LDR r0, =NVIC_SHPR3 + LDR r1, =NVIC_PENDSV_PRI + LDR r2, [r0,#0x00] ; read + ORRS 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] + + ; restore MSP + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + MSR msp, 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 + ENDP + + IMPORT rt_hw_hard_fault_exception + +HardFault_Handler PROC + EXPORT HardFault_Handler + + ; get current context + MRS r0, psp ; get fault thread stack pointer + PUSH {lr} + BL rt_hw_hard_fault_exception + POP {pc} + ENDP + + ALIGN 4 + + END diff --git a/rt-thread/libcpu/arm/cortex-m0/cpuport.c b/rt-thread/libcpu/arm/cortex-m0/cpuport.c new file mode 100644 index 0000000..f8d475a --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m0/cpuport.c @@ -0,0 +1,120 @@ +/* + * File : cpuport.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, 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 + * 2010-01-25 Bernard first version + * 2012-05-31 aozima Merge all of the C source code into cpuport.c + * 2012-08-17 aozima fixed bug: store r8 - r11. + * 2012-12-23 aozima stack addr align to 8byte. + */ + +#include + +struct exception_stack_frame +{ + 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; +}; + +struct stack_frame +{ + /* r4 ~ r7 low register */ + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + + /* r8 ~ r11 high register */ + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t r11; + + struct exception_stack_frame exception_stack_frame; +}; + +/* flag in interrupt handling */ +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, + void *parameter, + rt_uint8_t *stack_addr, + void *texit) +{ + struct stack_frame *stack_frame; + rt_uint8_t *stk; + unsigned long i; + + stk = stack_addr + sizeof(rt_uint32_t); + stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8); + stk -= sizeof(struct stack_frame); + + stack_frame = (struct stack_frame *)stk; + + /* init all register */ + for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++) + { + ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef; + } + + stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */ + stack_frame->exception_stack_frame.r1 = 0; /* r1 */ + stack_frame->exception_stack_frame.r2 = 0; /* r2 */ + stack_frame->exception_stack_frame.r3 = 0; /* r3 */ + stack_frame->exception_stack_frame.r12 = 0; /* r12 */ + stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */ + stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */ + stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */ + + /* return task's current stack address */ + return stk; +} + +extern long list_thread(void); +extern rt_thread_t rt_current_thread; +/** + * fault exception handling + */ +void rt_hw_hard_fault_exception(struct exception_stack_frame *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); +} diff --git a/rt-thread/libcpu/arm/cortex-m3/context_gcc.S b/rt-thread/libcpu/arm/cortex-m3/context_gcc.S new file mode 100644 index 0000000..2e279c4 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m3/context_gcc.S @@ -0,0 +1,214 @@ +/* + * File : context_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2013, 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-10-11 Bernard First version + * 2010-12-29 onelife Modify for EFM32 + * 2011-06-17 onelife Merge all of the assembly source code into context_gcc.S + * 2011-07-12 onelife Add interrupt context check function + * 2013-06-18 aozima add restore MSP feature. + * 2013-07-09 aozima enhancement hard fault exception handler. + */ + + .cpu cortex-m3 + .fpu softvfp + .syntax unified + .thumb + .text + + .equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */ + .equ ICSR, 0xE000ED04 /* interrupt control state register */ + .equ PENDSVSET_BIT, 0x10000000 /* value to trigger PendSV exception */ + + .equ SHPR3, 0xE000ED20 /* system priority register (3) */ + .equ PENDSV_PRI_LOWEST, 0x00FF0000 /* PendSV priority value (lowest) */ + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ + .global rt_hw_interrupt_disable + .type rt_hw_interrupt_disable, %function +rt_hw_interrupt_disable: + MRS R0, PRIMASK + CPSID I + BX LR + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ + .global rt_hw_interrupt_enable + .type rt_hw_interrupt_enable, %function +rt_hw_interrupt_enable: + MSR PRIMASK, R0 + BX LR + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * R0 --> from + * R1 --> to + */ + .global rt_hw_context_switch_interrupt + .type rt_hw_context_switch_interrupt, %function + .global rt_hw_context_switch + .type rt_hw_context_switch, %function +rt_hw_context_switch_interrupt: +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, =ICSR /* trigger the PendSV exception (causes context switch) */ + LDR R1, =PENDSVSET_BIT + STR R1, [R0] + BX LR + +/* R0 --> switch from thread stack + * R1 --> switch to thread stack + * psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack + */ + .global PendSV_Handler + .type PendSV_Handler, %function +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, #0 + STR R1, [R0] + + LDR R0, =rt_interrupt_from_thread + LDR R1, [R0] + CBZ R1, switch_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 */ + +switch_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 + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * R0 --> to + */ + .global rt_hw_context_switch_to + .type rt_hw_context_switch_to, %function +rt_hw_context_switch_to: + LDR R1, =rt_interrupt_to_thread + STR R0, [R1] + + /* set from thread to 0 */ + LDR R1, =rt_interrupt_from_thread + MOV R0, #0 + 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, =SHPR3 + LDR R1, =PENDSV_PRI_LOWEST + LDR.W R2, [R0,#0] /* read */ + ORR R1, R1, R2 /* modify */ + STR R1, [R0] /* write-back */ + + LDR R0, =ICSR /* trigger the PendSV exception (causes context switch) */ + LDR R1, =PENDSVSET_BIT + STR R1, [R0] + + /* restore MSP */ + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + NOP + MSR msp, r0 + + /* enable interrupts at processor level */ + CPSIE F + CPSIE I + + /* never reach here! */ + +/* compatible with old version */ + .global rt_hw_interrupt_thread_switch + .type rt_hw_interrupt_thread_switch, %function +rt_hw_interrupt_thread_switch: + BX LR + NOP + + .global HardFault_Handler + .type HardFault_Handler, %function +HardFault_Handler: + /* get current context */ + MRS r0, msp /* get fault context from handler. */ + TST lr, #0x04 /* if(!EXC_RETURN[2]) */ + BEQ _get_sp_done + MRS r0, psp /* get fault context from thread. */ +_get_sp_done: + + STMFD r0!, {r4 - r11} /* push r4 - r11 register */ + STMFD r0!, {lr} /* push exec_return register */ + + TST lr, #0x04 /* if(!EXC_RETURN[2]) */ + BEQ _update_msp + MSR psp, r0 /* update stack pointer to PSP. */ + B _update_done +_update_msp: + MSR msp, r0 /* update stack pointer to MSP. */ +_update_done: + + PUSH {LR} + BL rt_hw_hard_fault_exception + POP {LR} + + ORR LR, LR, #0x04 + BX LR + +/* + * rt_uint32_t rt_hw_interrupt_check(void); + * R0 --> state + */ + .global rt_hw_interrupt_check + .type rt_hw_interrupt_check, %function +rt_hw_interrupt_check: + MRS R0, IPSR + BX LR diff --git a/rt-thread/libcpu/arm/cortex-m3/context_iar.S b/rt-thread/libcpu/arm/cortex-m3/context_iar.S new file mode 100644 index 0000000..95dee80 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m3/context_iar.S @@ -0,0 +1,206 @@ +;/* +; * File : context_iar.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2013, 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 +; * 2009-09-27 Bernard add protect when contex switch occurs +; * 2013-06-18 aozima add restore MSP feature. +; * 2013-07-09 aozima enhancement hard fault exception handler. +; */ + +;/** +; * @addtogroup cortex-m3 +; */ +;/*@{*/ + +SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register +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 + + SECTION .text:CODE(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(); +; */ + EXPORT rt_hw_interrupt_disable +rt_hw_interrupt_disable: + MRS r0, PRIMASK + CPSID I + BX LR + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ + EXPORT rt_hw_interrupt_enable +rt_hw_interrupt_enable: + MSR PRIMASK, r0 + BX LR + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ + EXPORT rt_hw_context_switch_interrupt + EXPORT rt_hw_context_switch +rt_hw_context_switch_interrupt: +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 + +; r0 --> switch from thread stack +; r1 --> switch to thread stack +; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack + EXPORT PendSV_Handler +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, switch_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 + +switch_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 + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ + EXPORT rt_hw_context_switch_to +rt_hw_context_switch_to: + 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 + + LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch) + LDR r1, =NVIC_PENDSVSET + STR r1, [r0] + + ; restore MSP + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + NOP + MSR msp, r0 + + ; enable interrupts at processor level + CPSIE F + CPSIE I + + ; never reach here! + +; compatible with old version + EXPORT rt_hw_interrupt_thread_switch +rt_hw_interrupt_thread_switch: + BX lr + + IMPORT rt_hw_hard_fault_exception + EXPORT HardFault_Handler +HardFault_Handler: + + ; get current context + MRS r0, msp ; get fault context from handler. + TST lr, #0x04 ; if(!EXC_RETURN[2]) + BEQ _get_sp_done + MRS r0, psp ; get fault context from thread. +_get_sp_done + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + ;STMFD r0!, {lr} ; push exec_return register + SUB r0, r0, #0x04 + STR lr, [r0] + + TST lr, #0x04 ; if(!EXC_RETURN[2]) + BEQ _update_msp + MSR psp, r0 ; update stack pointer to PSP. + B _update_done +_update_msp + MSR msp, r0 ; update stack pointer to MSP. +_update_done + + PUSH {lr} + BL rt_hw_hard_fault_exception + POP {lr} + + ORR lr, lr, #0x04 + BX lr + + END diff --git a/rt-thread/libcpu/arm/cortex-m3/context_rvds.S b/rt-thread/libcpu/arm/cortex-m3/context_rvds.S new file mode 100644 index 0000000..9a7ff10 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m3/context_rvds.S @@ -0,0 +1,211 @@ +;/* +; * File : context_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2018, 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 +; * 2013-06-18 aozima add restore MSP feature. +; * 2013-07-09 aozima enhancement hard fault exception handler. +; */ + +;/** +; * @addtogroup CORTEX-M3 +; */ +;/*@{*/ + +SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register +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 --> switch from thread stack +; r1 --> switch 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, switch_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 + +switch_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] + + ; restore MSP + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + MSR msp, r0 + + ; enable interrupts at processor level + CPSIE F + CPSIE I + + ; never reach here! + ENDP + +; compatible with old version +rt_hw_interrupt_thread_switch PROC + EXPORT rt_hw_interrupt_thread_switch + BX lr + ENDP + + IMPORT rt_hw_hard_fault_exception + EXPORT HardFault_Handler +HardFault_Handler PROC + + ; get current context + TST lr, #0x04 ; if(!EXC_RETURN[2]) + ITE EQ + MRSEQ r0, msp ; [2]=0 ==> Z=1, get fault context from handler. + MRSNE r0, psp ; [2]=1 ==> Z=0, get fault context from thread. + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + STMFD r0!, {lr} ; push exec_return register + + TST lr, #0x04 ; if(!EXC_RETURN[2]) + ITE EQ + MSREQ msp, r0 ; [2]=0 ==> Z=1, update stack pointer to MSP. + MSRNE psp, r0 ; [2]=1 ==> Z=0, update stack pointer to PSP. + + PUSH {lr} + BL rt_hw_hard_fault_exception + POP {lr} + + ORR lr, lr, #0x04 + BX lr + ENDP + + ALIGN 4 + + END diff --git a/rt-thread/libcpu/arm/cortex-m3/cpuport.c b/rt-thread/libcpu/arm/cortex-m3/cpuport.c new file mode 100644 index 0000000..3c7e0ee --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m3/cpuport.c @@ -0,0 +1,407 @@ +/* + * File : cpuport.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2013, 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-05 Bernard first version + * 2011-02-14 onelife Modify for EFM32 + * 2011-06-17 onelife Merge all of the C source code into cpuport.c + * 2012-12-23 aozima stack addr align to 8byte. + * 2012-12-29 Bernard Add exception hook. + * 2013-07-09 aozima enhancement hard fault exception handler. + */ + +#include + +struct exception_stack_frame +{ + 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; +}; + +struct stack_frame +{ + /* r4 ~ r11 register */ + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t r11; + + struct exception_stack_frame exception_stack_frame; +}; + +/* flag in interrupt handling */ +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; +/* exception hook */ +static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL; + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, + void *parameter, + rt_uint8_t *stack_addr, + void *texit) +{ + struct stack_frame *stack_frame; + rt_uint8_t *stk; + unsigned long i; + + stk = stack_addr + sizeof(rt_uint32_t); + stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8); + stk -= sizeof(struct stack_frame); + + stack_frame = (struct stack_frame *)stk; + + /* init all register */ + for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++) + { + ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef; + } + + stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */ + stack_frame->exception_stack_frame.r1 = 0; /* r1 */ + stack_frame->exception_stack_frame.r2 = 0; /* r2 */ + stack_frame->exception_stack_frame.r3 = 0; /* r3 */ + stack_frame->exception_stack_frame.r12 = 0; /* r12 */ + stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */ + stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */ + stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */ + + /* return task's current stack address */ + return stk; +} + +/** + * This function set the hook, which is invoked on fault exception handling. + * + * @param exception_handle the exception handling hook function. + */ +void rt_hw_exception_install(rt_err_t (*exception_handle)(void* context)) +{ + rt_exception_hook = exception_handle; +} + +#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */ +#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */ +#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */ +#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */ +#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */ +#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */ + +#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */ +#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */ +#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */ + +#ifdef RT_USING_FINSH +static void usage_fault_track(void) +{ + rt_kprintf("usage fault:\n"); + rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR); + + if(SCB_CFSR_UFSR & (1<<0)) + { + /* [0]:UNDEFINSTR */ + rt_kprintf("UNDEFINSTR "); + } + + if(SCB_CFSR_UFSR & (1<<1)) + { + /* [1]:INVSTATE */ + rt_kprintf("INVSTATE "); + } + + if(SCB_CFSR_UFSR & (1<<2)) + { + /* [2]:INVPC */ + rt_kprintf("INVPC "); + } + + if(SCB_CFSR_UFSR & (1<<3)) + { + /* [3]:NOCP */ + rt_kprintf("NOCP "); + } + + if(SCB_CFSR_UFSR & (1<<8)) + { + /* [8]:UNALIGNED */ + rt_kprintf("UNALIGNED "); + } + + if(SCB_CFSR_UFSR & (1<<9)) + { + /* [9]:DIVBYZERO */ + rt_kprintf("DIVBYZERO "); + } + + rt_kprintf("\n"); +} + +static void bus_fault_track(void) +{ + rt_kprintf("bus fault:\n"); + rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR); + + if(SCB_CFSR_BFSR & (1<<0)) + { + /* [0]:IBUSERR */ + rt_kprintf("IBUSERR "); + } + + if(SCB_CFSR_BFSR & (1<<1)) + { + /* [1]:PRECISERR */ + rt_kprintf("PRECISERR "); + } + + if(SCB_CFSR_BFSR & (1<<2)) + { + /* [2]:IMPRECISERR */ + rt_kprintf("IMPRECISERR "); + } + + if(SCB_CFSR_BFSR & (1<<3)) + { + /* [3]:UNSTKERR */ + rt_kprintf("UNSTKERR "); + } + + if(SCB_CFSR_BFSR & (1<<4)) + { + /* [4]:STKERR */ + rt_kprintf("STKERR "); + } + + if(SCB_CFSR_BFSR & (1<<7)) + { + rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR); + } + else + { + rt_kprintf("\n"); + } +} + +static void mem_manage_fault_track(void) +{ + rt_kprintf("mem manage fault:\n"); + rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR); + + if(SCB_CFSR_MFSR & (1<<0)) + { + /* [0]:IACCVIOL */ + rt_kprintf("IACCVIOL "); + } + + if(SCB_CFSR_MFSR & (1<<1)) + { + /* [1]:DACCVIOL */ + rt_kprintf("DACCVIOL "); + } + + if(SCB_CFSR_MFSR & (1<<3)) + { + /* [3]:MUNSTKERR */ + rt_kprintf("MUNSTKERR "); + } + + if(SCB_CFSR_MFSR & (1<<4)) + { + /* [4]:MSTKERR */ + rt_kprintf("MSTKERR "); + } + + if(SCB_CFSR_MFSR & (1<<7)) + { + /* [7]:MMARVALID */ + rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR); + } + else + { + rt_kprintf("\n"); + } +} + +static void hard_fault_track(void) +{ + if(SCB_HFSR & (1UL<<1)) + { + /* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */ + rt_kprintf("failed vector fetch\n"); + } + + if(SCB_HFSR & (1UL<<30)) + { + /* [30]:FORCED, Indicates hard fault is taken because of bus fault, + memory management fault, or usage fault. */ + if(SCB_CFSR_BFSR) + { + bus_fault_track(); + } + + if(SCB_CFSR_MFSR) + { + mem_manage_fault_track(); + } + + if(SCB_CFSR_UFSR) + { + usage_fault_track(); + } + } + + if(SCB_HFSR & (1UL<<31)) + { + /* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */ + rt_kprintf("debug event\n"); + } +} +#endif /* RT_USING_FINSH */ + +struct exception_info +{ + rt_uint32_t exc_return; + struct stack_frame stack_frame; +}; + +/* + * fault exception handler + */ +void rt_hw_hard_fault_exception(struct exception_info * exception_info) +{ + extern long list_thread(void); + struct stack_frame* context = &exception_info->stack_frame; + + if (rt_exception_hook != RT_NULL) + { + rt_err_t result; + + result = rt_exception_hook(exception_info); + if (result == RT_EOK) + return; + } + + rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr); + + rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0); + rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1); + rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2); + rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3); + rt_kprintf("r04: 0x%08x\n", context->r4); + rt_kprintf("r05: 0x%08x\n", context->r5); + rt_kprintf("r06: 0x%08x\n", context->r6); + rt_kprintf("r07: 0x%08x\n", context->r7); + rt_kprintf("r08: 0x%08x\n", context->r8); + rt_kprintf("r09: 0x%08x\n", context->r9); + rt_kprintf("r10: 0x%08x\n", context->r10); + rt_kprintf("r11: 0x%08x\n", context->r11); + rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12); + rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr); + rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc); + + if(exception_info->exc_return & (1 << 2) ) + { + rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif /* RT_USING_FINSH */ + } + else + { + rt_kprintf("hard fault on handler\r\n\r\n"); + } + +#ifdef RT_USING_FINSH + hard_fault_track(); +#endif /* RT_USING_FINSH */ + + while (1); +} + +/** + * shutdown CPU + */ +void rt_hw_cpu_shutdown(void) +{ + rt_kprintf("shutdown...\n"); + + RT_ASSERT(0); +} + +/** + * reset CPU + */ +RT_WEAK void rt_hw_cpu_reset(void) +{ + SCB_AIRCR = SCB_RESET_VALUE; +} + +#ifdef RT_USING_CPU_FFS +/** + * This function finds the first bit set (beginning with the least significant bit) + * in value and return the index of that bit. + * + * Bits are numbered starting at 1 (the least significant bit). A return value of + * zero from any of these functions means that the argument was zero. + * + * @return return the index of the first bit set. If value is 0, then this function + * shall return 0. + */ +#if defined(__CC_ARM) +__asm int __rt_ffs(int value) +{ + CMP r0, #0x00 + BEQ exit + + RBIT r0, r0 + CLZ r0, r0 + ADDS r0, r0, #0x01 + +exit + BX lr +} +#elif defined(__IAR_SYSTEMS_ICC__) +int __rt_ffs(int value) +{ + if (value == 0) return value; + + asm("RBIT %0, %1" : "=r"(value) : "r"(value)); + asm("CLZ %0, %1" : "=r"(value) : "r"(value)); + asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value)); + + return value; +} +#elif defined(__GNUC__) +int __rt_ffs(int value) +{ + return __builtin_ffs(value); +} +#endif + +#endif diff --git a/rt-thread/libcpu/arm/cortex-m4/context_gcc.S b/rt-thread/libcpu/arm/cortex-m4/context_gcc.S new file mode 100644 index 0000000..d003ce0 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m4/context_gcc.S @@ -0,0 +1,249 @@ +/* + * File : context_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, 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-10-11 Bernard first version + * 2012-01-01 aozima support context switch load/store FPU register. + * 2013-06-18 aozima add restore MSP feature. + * 2013-06-23 aozima support lazy stack optimized. + * 2018-07-24 aozima enhancement hard fault exception handler. + */ + +/** + * @addtogroup cortex-m4 + */ +/*@{*/ + +.cpu cortex-m4 +.syntax unified +.thumb +.text + +.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */ +.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */ +.equ NVIC_SYSPRI2, 0xE000ED20 /* system priority register (2) */ +.equ NVIC_PENDSV_PRI, 0x00FF0000 /* PendSV priority value (lowest) */ +.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */ + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.global rt_hw_interrupt_disable +.type rt_hw_interrupt_disable, %function +rt_hw_interrupt_disable: + MRS r0, PRIMASK + CPSID I + BX LR + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.global rt_hw_interrupt_enable +.type rt_hw_interrupt_enable, %function +rt_hw_interrupt_enable: + MSR PRIMASK, r0 + BX LR + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.global rt_hw_context_switch_interrupt +.type rt_hw_context_switch_interrupt, %function +.global rt_hw_context_switch +.type rt_hw_context_switch, %function + +rt_hw_context_switch_interrupt: +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 + +/* r0 --> switch from thread stack + * r1 --> switch to thread stack + * psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack + */ +.global PendSV_Handler +.type PendSV_Handler, %function +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, switch_to_thread /* skip register save at the first time */ + + MRS r1, psp /* get from thread stack pointer */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + TST lr, #0x10 /* if(!EXC_RETURN[4]) */ + VSTMDBEQ r1!, {d8 - d15} /* push FPU register s16~s31 */ +#endif + + STMFD r1!, {r4 - r11} /* push r4 - r11 register */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + MOV r4, #0x00 /* flag = 0 */ + + TST lr, #0x10 /* if(!EXC_RETURN[4]) */ + MOVEQ r4, #0x01 /* flag = 1 */ + + STMFD r1!, {r4} /* push flag */ +#endif + + LDR r0, [r0] + STR r1, [r0] /* update from thread stack pointer */ + +switch_to_thread: + LDR r1, =rt_interrupt_to_thread + LDR r1, [r1] + LDR r1, [r1] /* load thread stack pointer */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + LDMFD r1!, {r3} /* pop flag */ +#endif + + LDMFD r1!, {r4 - r11} /* pop r4 - r11 register */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + CMP r3, #0 /* if(flag_r3 != 0) */ + VLDMIANE r1!, {d8 - d15} /* pop FPU register s16~s31 */ +#endif + + MSR psp, r1 /* update stack pointer */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + ORR lr, lr, #0x10 /* lr |= (1 << 4), clean FPCA. */ + CMP r3, #0 /* if(flag_r3 != 0) */ + BICNE lr, lr, #0x10 /* lr &= ~(1 << 4), set FPCA. */ +#endif + +pendsv_exit: + /* restore interrupt */ + MSR PRIMASK, r2 + + ORR lr, lr, #0x04 + BX lr + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.global rt_hw_context_switch_to +.type rt_hw_context_switch_to, %function +rt_hw_context_switch_to: + LDR r1, =rt_interrupt_to_thread + STR r0, [r1] + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + /* CLEAR CONTROL.FPCA */ + MRS r2, CONTROL /* read */ + BIC r2, #0x04 /* modify */ + MSR CONTROL, r2 /* write-back */ +#endif + + /* 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 */ + + LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */ + LDR r1, =NVIC_PENDSVSET + STR r1, [r0] + + /* restore MSP */ + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + NOP + MSR msp, r0 + + /* enable interrupts at processor level */ + CPSIE F + CPSIE I + + /* never reach here! */ + +/* compatible with old version */ +.global rt_hw_interrupt_thread_switch +.type rt_hw_interrupt_thread_switch, %function +rt_hw_interrupt_thread_switch: + BX lr + NOP + +.global HardFault_Handler +.type HardFault_Handler, %function +HardFault_Handler: + /* get current context */ + MRS r0, msp /* get fault context from handler. */ + TST lr, #0x04 /* if(!EXC_RETURN[2]) */ + BEQ _get_sp_done + MRS r0, psp /* get fault context from thread. */ +_get_sp_done: + + STMFD r0!, {r4 - r11} /* push r4 - r11 register */ +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + STMFD r0!, {lr} /* push dummy for flag */ +#endif + STMFD r0!, {lr} /* push exec_return register */ + + TST lr, #0x04 /* if(!EXC_RETURN[2]) */ + BEQ _update_msp + MSR psp, r0 /* update stack pointer to PSP. */ + B _update_done +_update_msp: + MSR msp, r0 /* update stack pointer to MSP. */ +_update_done: + + PUSH {LR} + BL rt_hw_hard_fault_exception + POP {LR} + + ORR lr, lr, #0x04 + BX lr diff --git a/rt-thread/libcpu/arm/cortex-m4/context_iar.S b/rt-thread/libcpu/arm/cortex-m4/context_iar.S new file mode 100644 index 0000000..bf707d0 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m4/context_iar.S @@ -0,0 +1,257 @@ +;/* +; * File : context_iar.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2018, 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 +; * 2009-09-27 Bernard add protect when contex switch occurs +; * 2012-01-01 aozima support context switch load/store FPU register. +; * 2013-06-18 aozima add restore MSP feature. +; * 2013-06-23 aozima support lazy stack optimized. +; * 2018-07-24 aozima enhancement hard fault exception handler. +; */ + +;/** +; * @addtogroup cortex-m4 +; */ +;/*@{*/ + +SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register +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 + + SECTION .text:CODE(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(); +; */ + EXPORT rt_hw_interrupt_disable +rt_hw_interrupt_disable: + MRS r0, PRIMASK + CPSID I + BX LR + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ + EXPORT rt_hw_interrupt_enable +rt_hw_interrupt_enable: + MSR PRIMASK, r0 + BX LR + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ + EXPORT rt_hw_context_switch_interrupt + EXPORT rt_hw_context_switch +rt_hw_context_switch_interrupt: +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 + +; r0 --> switch from thread stack +; r1 --> switch to thread stack +; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack + EXPORT PendSV_Handler +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, switch_to_thread ; skip register save at the first time + + MRS r1, psp ; get from thread stack pointer + +#if defined ( __ARMVFP__ ) + TST lr, #0x10 ; if(!EXC_RETURN[4]) + BNE skip_push_fpu + VSTMDB r1!, {d8 - d15} ; push FPU register s16~s31 +skip_push_fpu +#endif + + STMFD r1!, {r4 - r11} ; push r4 - r11 register + +#if defined ( __ARMVFP__ ) + MOV r4, #0x00 ; flag = 0 + TST lr, #0x10 ; if(!EXC_RETURN[4]) + BNE push_flag + MOV r4, #0x01 ; flag = 1 +push_flag + ;STMFD r1!, {r4} ; push flag + SUB r1, r1, #0x04 + STR r4, [r1] +#endif + + LDR r0, [r0] + STR r1, [r0] ; update from thread stack pointer + +switch_to_thread + LDR r1, =rt_interrupt_to_thread + LDR r1, [r1] + LDR r1, [r1] ; load thread stack pointer + +#if defined ( __ARMVFP__ ) + LDMFD r1!, {r3} ; pop flag +#endif + + LDMFD r1!, {r4 - r11} ; pop r4 - r11 register + +#if defined ( __ARMVFP__ ) + CBZ r3, skip_pop_fpu + VLDMIA r1!, {d8 - d15} ; pop FPU register s16~s31 +skip_pop_fpu +#endif + + MSR psp, r1 ; update stack pointer + +#if defined ( __ARMVFP__ ) + ORR lr, lr, #0x10 ; lr |= (1 << 4), clean FPCA. + CBZ r3, return_without_fpu ; if(flag_r3 != 0) + BIC lr, lr, #0x10 ; lr &= ~(1 << 4), set FPCA. +return_without_fpu +#endif + +pendsv_exit + ; restore interrupt + MSR PRIMASK, r2 + + ORR lr, lr, #0x04 + BX lr + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ + EXPORT rt_hw_context_switch_to +rt_hw_context_switch_to: + LDR r1, =rt_interrupt_to_thread + STR r0, [r1] + +#if defined ( __ARMVFP__ ) + ; CLEAR CONTROL.FPCA + MRS r2, CONTROL ; read + BIC r2, r2, #0x04 ; modify + MSR CONTROL, r2 ; write-back +#endif + + ; 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 + + LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch) + LDR r1, =NVIC_PENDSVSET + STR r1, [r0] + + ; restore MSP + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + NOP + MSR msp, r0 + + ; enable interrupts at processor level + CPSIE F + CPSIE I + + ; never reach here! + +; compatible with old version + EXPORT rt_hw_interrupt_thread_switch +rt_hw_interrupt_thread_switch: + BX lr + + IMPORT rt_hw_hard_fault_exception + EXPORT HardFault_Handler +HardFault_Handler: + + ; get current context + MRS r0, msp ; get fault context from handler. + TST lr, #0x04 ; if(!EXC_RETURN[2]) + BEQ _get_sp_done + MRS r0, psp ; get fault context from thread. +_get_sp_done + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + ;STMFD r0!, {lr} ; push exec_return register +#if defined ( __ARMVFP__ ) + SUB r0, r0, #0x04 ; push dummy for flag + STR lr, [r0] +#endif + SUB r0, r0, #0x04 + STR lr, [r0] + + TST lr, #0x04 ; if(!EXC_RETURN[2]) + BEQ _update_msp + MSR psp, r0 ; update stack pointer to PSP. + B _update_done +_update_msp + MSR msp, r0 ; update stack pointer to MSP. +_update_done + + PUSH {lr} + BL rt_hw_hard_fault_exception + POP {lr} + + ORR lr, lr, #0x04 + BX lr + + END diff --git a/rt-thread/libcpu/arm/cortex-m4/context_rvds.S b/rt-thread/libcpu/arm/cortex-m4/context_rvds.S new file mode 100644 index 0000000..f6d2447 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m4/context_rvds.S @@ -0,0 +1,251 @@ +;/* +;* Copyright (c) 2006-2018, RT-Thread Development Team +;* +;* SPDX-License-Identifier: Apache-2.0 +;* +; * Change Logs: +; * Date Author Notes +; * 2009-01-17 Bernard first version. +; * 2012-01-01 aozima support context switch load/store FPU register. +; * 2013-06-18 aozima add restore MSP feature. +; * 2013-06-23 aozima support lazy stack optimized. +; * 2018-07-24 aozima enhancement hard fault exception handler. +; */ + +;/** +; * @addtogroup cortex-m4 +; */ +;/*@{*/ + +SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register +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 --> switch from thread stack +; r1 --> switch 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, switch_to_thread ; skip register save at the first time + + MRS r1, psp ; get from thread stack pointer + + IF {FPU} != "SoftVFP" + TST lr, #0x10 ; if(!EXC_RETURN[4]) + VSTMFDEQ r1!, {d8 - d15} ; push FPU register s16~s31 + ENDIF + + STMFD r1!, {r4 - r11} ; push r4 - r11 register + + IF {FPU} != "SoftVFP" + MOV r4, #0x00 ; flag = 0 + + TST lr, #0x10 ; if(!EXC_RETURN[4]) + MOVEQ r4, #0x01 ; flag = 1 + + STMFD r1!, {r4} ; push flag + ENDIF + + LDR r0, [r0] + STR r1, [r0] ; update from thread stack pointer + +switch_to_thread + LDR r1, =rt_interrupt_to_thread + LDR r1, [r1] + LDR r1, [r1] ; load thread stack pointer + + IF {FPU} != "SoftVFP" + LDMFD r1!, {r3} ; pop flag + ENDIF + + LDMFD r1!, {r4 - r11} ; pop r4 - r11 register + + IF {FPU} != "SoftVFP" + CMP r3, #0 ; if(flag_r3 != 0) + VLDMFDNE r1!, {d8 - d15} ; pop FPU register s16~s31 + ENDIF + + MSR psp, r1 ; update stack pointer + + IF {FPU} != "SoftVFP" + ORR lr, lr, #0x10 ; lr |= (1 << 4), clean FPCA. + CMP r3, #0 ; if(flag_r3 != 0) + BICNE lr, lr, #0x10 ; lr &= ~(1 << 4), set FPCA. + ENDIF + +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] + + IF {FPU} != "SoftVFP" + ; CLEAR CONTROL.FPCA + MRS r2, CONTROL ; read + BIC r2, #0x04 ; modify + MSR CONTROL, r2 ; write-back + ENDIF + + ; 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] + + ; restore MSP + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + MSR msp, r0 + + ; enable interrupts at processor level + CPSIE F + CPSIE I + + ; never reach here! + ENDP + +; compatible with old version +rt_hw_interrupt_thread_switch PROC + EXPORT rt_hw_interrupt_thread_switch + BX lr + ENDP + + IMPORT rt_hw_hard_fault_exception + EXPORT HardFault_Handler +HardFault_Handler PROC + + ; get current context + TST lr, #0x04 ; if(!EXC_RETURN[2]) + ITE EQ + MRSEQ r0, msp ; [2]=0 ==> Z=1, get fault context from handler. + MRSNE r0, psp ; [2]=1 ==> Z=0, get fault context from thread. + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + IF {FPU} != "SoftVFP" + STMFD r0!, {lr} ; push dummy for flag + ENDIF + STMFD r0!, {lr} ; push exec_return register + + TST lr, #0x04 ; if(!EXC_RETURN[2]) + ITE EQ + MSREQ msp, r0 ; [2]=0 ==> Z=1, update stack pointer to MSP. + MSRNE psp, r0 ; [2]=1 ==> Z=0, update stack pointer to PSP. + + PUSH {lr} + BL rt_hw_hard_fault_exception + POP {lr} + + ORR lr, lr, #0x04 + BX lr + ENDP + + ALIGN 4 + + END diff --git a/rt-thread/libcpu/arm/cortex-m4/cpuport.c b/rt-thread/libcpu/arm/cortex-m4/cpuport.c new file mode 100644 index 0000000..18f0278 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m4/cpuport.c @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2011-10-21 Bernard the first version. + * 2011-10-27 aozima update for cortex-M4 FPU. + * 2011-12-31 aozima fixed stack align issues. + * 2012-01-01 aozima support context switch load/store FPU register. + * 2012-12-11 lgnq fixed the coding style. + * 2012-12-23 aozima stack addr align to 8byte. + * 2012-12-29 Bernard Add exception hook. + * 2013-06-23 aozima support lazy stack optimized. + * 2018-07-24 aozima enhancement hard fault exception handler. + */ + +#include + +#if /* ARMCC */ ( (defined ( __CC_ARM ) && defined ( __TARGET_FPU_VFP )) \ + /* Clang */ || (defined ( __CLANG_ARM ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) \ + /* IAR */ || (defined ( __ICCARM__ ) && defined ( __ARMVFP__ )) \ + /* GNU */ || (defined ( __GNUC__ ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) ) +#define USE_FPU 1 +#else +#define USE_FPU 0 +#endif + +/* exception and interrupt handler table */ +rt_uint32_t rt_interrupt_from_thread; +rt_uint32_t rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; +/* exception hook */ +static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL; + +struct exception_stack_frame +{ + 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; +}; + +struct stack_frame +{ +#if USE_FPU + rt_uint32_t flag; +#endif /* USE_FPU */ + + /* r4 ~ r11 register */ + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t r11; + + struct exception_stack_frame exception_stack_frame; +}; + +struct exception_stack_frame_fpu +{ + 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; + +#if USE_FPU + /* FPU register */ + rt_uint32_t S0; + rt_uint32_t S1; + rt_uint32_t S2; + rt_uint32_t S3; + rt_uint32_t S4; + rt_uint32_t S5; + rt_uint32_t S6; + rt_uint32_t S7; + rt_uint32_t S8; + rt_uint32_t S9; + rt_uint32_t S10; + rt_uint32_t S11; + rt_uint32_t S12; + rt_uint32_t S13; + rt_uint32_t S14; + rt_uint32_t S15; + rt_uint32_t FPSCR; + rt_uint32_t NO_NAME; +#endif +}; + +struct stack_frame_fpu +{ + rt_uint32_t flag; + + /* r4 ~ r11 register */ + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t r11; + +#if USE_FPU + /* FPU register s16 ~ s31 */ + rt_uint32_t s16; + rt_uint32_t s17; + rt_uint32_t s18; + rt_uint32_t s19; + rt_uint32_t s20; + rt_uint32_t s21; + rt_uint32_t s22; + rt_uint32_t s23; + rt_uint32_t s24; + rt_uint32_t s25; + rt_uint32_t s26; + rt_uint32_t s27; + rt_uint32_t s28; + rt_uint32_t s29; + rt_uint32_t s30; + rt_uint32_t s31; +#endif + + struct exception_stack_frame_fpu exception_stack_frame; +}; + +rt_uint8_t *rt_hw_stack_init(void *tentry, + void *parameter, + rt_uint8_t *stack_addr, + void *texit) +{ + struct stack_frame *stack_frame; + rt_uint8_t *stk; + unsigned long i; + + stk = stack_addr + sizeof(rt_uint32_t); + stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8); + stk -= sizeof(struct stack_frame); + + stack_frame = (struct stack_frame *)stk; + + /* init all register */ + for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++) + { + ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef; + } + + stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */ + stack_frame->exception_stack_frame.r1 = 0; /* r1 */ + stack_frame->exception_stack_frame.r2 = 0; /* r2 */ + stack_frame->exception_stack_frame.r3 = 0; /* r3 */ + stack_frame->exception_stack_frame.r12 = 0; /* r12 */ + stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */ + stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */ + stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */ + +#if USE_FPU + stack_frame->flag = 0; +#endif /* USE_FPU */ + + /* return task's current stack address */ + return stk; +} + +/** + * This function set the hook, which is invoked on fault exception handling. + * + * @param exception_handle the exception handling hook function. + */ +void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context)) +{ + rt_exception_hook = exception_handle; +} + +#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */ +#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */ +#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */ +#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */ +#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */ +#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */ + +#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */ +#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */ +#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */ + +#ifdef RT_USING_FINSH +static void usage_fault_track(void) +{ + rt_kprintf("usage fault:\n"); + rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR); + + if(SCB_CFSR_UFSR & (1<<0)) + { + /* [0]:UNDEFINSTR */ + rt_kprintf("UNDEFINSTR "); + } + + if(SCB_CFSR_UFSR & (1<<1)) + { + /* [1]:INVSTATE */ + rt_kprintf("INVSTATE "); + } + + if(SCB_CFSR_UFSR & (1<<2)) + { + /* [2]:INVPC */ + rt_kprintf("INVPC "); + } + + if(SCB_CFSR_UFSR & (1<<3)) + { + /* [3]:NOCP */ + rt_kprintf("NOCP "); + } + + if(SCB_CFSR_UFSR & (1<<8)) + { + /* [8]:UNALIGNED */ + rt_kprintf("UNALIGNED "); + } + + if(SCB_CFSR_UFSR & (1<<9)) + { + /* [9]:DIVBYZERO */ + rt_kprintf("DIVBYZERO "); + } + + rt_kprintf("\n"); +} + +static void bus_fault_track(void) +{ + rt_kprintf("bus fault:\n"); + rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR); + + if(SCB_CFSR_BFSR & (1<<0)) + { + /* [0]:IBUSERR */ + rt_kprintf("IBUSERR "); + } + + if(SCB_CFSR_BFSR & (1<<1)) + { + /* [1]:PRECISERR */ + rt_kprintf("PRECISERR "); + } + + if(SCB_CFSR_BFSR & (1<<2)) + { + /* [2]:IMPRECISERR */ + rt_kprintf("IMPRECISERR "); + } + + if(SCB_CFSR_BFSR & (1<<3)) + { + /* [3]:UNSTKERR */ + rt_kprintf("UNSTKERR "); + } + + if(SCB_CFSR_BFSR & (1<<4)) + { + /* [4]:STKERR */ + rt_kprintf("STKERR "); + } + + if(SCB_CFSR_BFSR & (1<<7)) + { + rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR); + } + else + { + rt_kprintf("\n"); + } +} + +static void mem_manage_fault_track(void) +{ + rt_kprintf("mem manage fault:\n"); + rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR); + + if(SCB_CFSR_MFSR & (1<<0)) + { + /* [0]:IACCVIOL */ + rt_kprintf("IACCVIOL "); + } + + if(SCB_CFSR_MFSR & (1<<1)) + { + /* [1]:DACCVIOL */ + rt_kprintf("DACCVIOL "); + } + + if(SCB_CFSR_MFSR & (1<<3)) + { + /* [3]:MUNSTKERR */ + rt_kprintf("MUNSTKERR "); + } + + if(SCB_CFSR_MFSR & (1<<4)) + { + /* [4]:MSTKERR */ + rt_kprintf("MSTKERR "); + } + + if(SCB_CFSR_MFSR & (1<<7)) + { + /* [7]:MMARVALID */ + rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR); + } + else + { + rt_kprintf("\n"); + } +} + +static void hard_fault_track(void) +{ + if(SCB_HFSR & (1UL<<1)) + { + /* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */ + rt_kprintf("failed vector fetch\n"); + } + + if(SCB_HFSR & (1UL<<30)) + { + /* [30]:FORCED, Indicates hard fault is taken because of bus fault, + memory management fault, or usage fault. */ + if(SCB_CFSR_BFSR) + { + bus_fault_track(); + } + + if(SCB_CFSR_MFSR) + { + mem_manage_fault_track(); + } + + if(SCB_CFSR_UFSR) + { + usage_fault_track(); + } + } + + if(SCB_HFSR & (1UL<<31)) + { + /* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */ + rt_kprintf("debug event\n"); + } +} +#endif /* RT_USING_FINSH */ + +struct exception_info +{ + rt_uint32_t exc_return; + struct stack_frame stack_frame; +}; + +void rt_hw_hard_fault_exception(struct exception_info *exception_info) +{ + extern long list_thread(void); + struct exception_stack_frame *exception_stack = &exception_info->stack_frame.exception_stack_frame; + struct stack_frame *context = &exception_info->stack_frame; + + if (rt_exception_hook != RT_NULL) + { + rt_err_t result; + + result = rt_exception_hook(exception_stack); + if (result == RT_EOK) return; + } + + rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr); + + rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0); + rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1); + rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2); + rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3); + rt_kprintf("r04: 0x%08x\n", context->r4); + rt_kprintf("r05: 0x%08x\n", context->r5); + rt_kprintf("r06: 0x%08x\n", context->r6); + rt_kprintf("r07: 0x%08x\n", context->r7); + rt_kprintf("r08: 0x%08x\n", context->r8); + rt_kprintf("r09: 0x%08x\n", context->r9); + rt_kprintf("r10: 0x%08x\n", context->r10); + rt_kprintf("r11: 0x%08x\n", context->r11); + rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12); + rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr); + rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc); + + if (exception_info->exc_return & (1 << 2)) + { + rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + } + else + { + rt_kprintf("hard fault on handler\r\n\r\n"); + } + + if ( (exception_info->exc_return & 0x10) == 0) + { + rt_kprintf("FPU active!\r\n"); + } + +#ifdef RT_USING_FINSH + hard_fault_track(); +#endif /* RT_USING_FINSH */ + + while (1); +} + +/** + * shutdown CPU + */ +void rt_hw_cpu_shutdown(void) +{ + rt_kprintf("shutdown...\n"); + + RT_ASSERT(0); +} + +/** + * reset CPU + */ +RT_WEAK void rt_hw_cpu_reset(void) +{ + SCB_AIRCR = SCB_RESET_VALUE; +} + +#ifdef RT_USING_CPU_FFS +/** + * This function finds the first bit set (beginning with the least significant bit) + * in value and return the index of that bit. + * + * Bits are numbered starting at 1 (the least significant bit). A return value of + * zero from any of these functions means that the argument was zero. + * + * @return return the index of the first bit set. If value is 0, then this function + * shall return 0. + */ +#if defined(__CC_ARM) || defined(__CLANG_ARM) +__asm int __rt_ffs(int value) +{ + CMP r0, #0x00 + BEQ exit + + RBIT r0, r0 + CLZ r0, r0 + ADDS r0, r0, #0x01 + +exit + BX lr +} +#elif defined(__IAR_SYSTEMS_ICC__) +int __rt_ffs(int value) +{ + if (value == 0) return value; + + asm("RBIT %0, %1" : "=r"(value) : "r"(value)); + asm("CLZ %0, %1" : "=r"(value) : "r"(value)); + asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value)); + + return value; +} +#elif defined(__GNUC__) +int __rt_ffs(int value) +{ + return __builtin_ffs(value); +} +#endif + +#endif diff --git a/rt-thread/libcpu/arm/cortex-m7/context_gcc.S b/rt-thread/libcpu/arm/cortex-m7/context_gcc.S new file mode 100644 index 0000000..d003ce0 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m7/context_gcc.S @@ -0,0 +1,249 @@ +/* + * File : context_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2018, 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-10-11 Bernard first version + * 2012-01-01 aozima support context switch load/store FPU register. + * 2013-06-18 aozima add restore MSP feature. + * 2013-06-23 aozima support lazy stack optimized. + * 2018-07-24 aozima enhancement hard fault exception handler. + */ + +/** + * @addtogroup cortex-m4 + */ +/*@{*/ + +.cpu cortex-m4 +.syntax unified +.thumb +.text + +.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */ +.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */ +.equ NVIC_SYSPRI2, 0xE000ED20 /* system priority register (2) */ +.equ NVIC_PENDSV_PRI, 0x00FF0000 /* PendSV priority value (lowest) */ +.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */ + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.global rt_hw_interrupt_disable +.type rt_hw_interrupt_disable, %function +rt_hw_interrupt_disable: + MRS r0, PRIMASK + CPSID I + BX LR + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.global rt_hw_interrupt_enable +.type rt_hw_interrupt_enable, %function +rt_hw_interrupt_enable: + MSR PRIMASK, r0 + BX LR + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.global rt_hw_context_switch_interrupt +.type rt_hw_context_switch_interrupt, %function +.global rt_hw_context_switch +.type rt_hw_context_switch, %function + +rt_hw_context_switch_interrupt: +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 + +/* r0 --> switch from thread stack + * r1 --> switch to thread stack + * psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack + */ +.global PendSV_Handler +.type PendSV_Handler, %function +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, switch_to_thread /* skip register save at the first time */ + + MRS r1, psp /* get from thread stack pointer */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + TST lr, #0x10 /* if(!EXC_RETURN[4]) */ + VSTMDBEQ r1!, {d8 - d15} /* push FPU register s16~s31 */ +#endif + + STMFD r1!, {r4 - r11} /* push r4 - r11 register */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + MOV r4, #0x00 /* flag = 0 */ + + TST lr, #0x10 /* if(!EXC_RETURN[4]) */ + MOVEQ r4, #0x01 /* flag = 1 */ + + STMFD r1!, {r4} /* push flag */ +#endif + + LDR r0, [r0] + STR r1, [r0] /* update from thread stack pointer */ + +switch_to_thread: + LDR r1, =rt_interrupt_to_thread + LDR r1, [r1] + LDR r1, [r1] /* load thread stack pointer */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + LDMFD r1!, {r3} /* pop flag */ +#endif + + LDMFD r1!, {r4 - r11} /* pop r4 - r11 register */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + CMP r3, #0 /* if(flag_r3 != 0) */ + VLDMIANE r1!, {d8 - d15} /* pop FPU register s16~s31 */ +#endif + + MSR psp, r1 /* update stack pointer */ + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + ORR lr, lr, #0x10 /* lr |= (1 << 4), clean FPCA. */ + CMP r3, #0 /* if(flag_r3 != 0) */ + BICNE lr, lr, #0x10 /* lr &= ~(1 << 4), set FPCA. */ +#endif + +pendsv_exit: + /* restore interrupt */ + MSR PRIMASK, r2 + + ORR lr, lr, #0x04 + BX lr + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.global rt_hw_context_switch_to +.type rt_hw_context_switch_to, %function +rt_hw_context_switch_to: + LDR r1, =rt_interrupt_to_thread + STR r0, [r1] + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + /* CLEAR CONTROL.FPCA */ + MRS r2, CONTROL /* read */ + BIC r2, #0x04 /* modify */ + MSR CONTROL, r2 /* write-back */ +#endif + + /* 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 */ + + LDR r0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */ + LDR r1, =NVIC_PENDSVSET + STR r1, [r0] + + /* restore MSP */ + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + NOP + MSR msp, r0 + + /* enable interrupts at processor level */ + CPSIE F + CPSIE I + + /* never reach here! */ + +/* compatible with old version */ +.global rt_hw_interrupt_thread_switch +.type rt_hw_interrupt_thread_switch, %function +rt_hw_interrupt_thread_switch: + BX lr + NOP + +.global HardFault_Handler +.type HardFault_Handler, %function +HardFault_Handler: + /* get current context */ + MRS r0, msp /* get fault context from handler. */ + TST lr, #0x04 /* if(!EXC_RETURN[2]) */ + BEQ _get_sp_done + MRS r0, psp /* get fault context from thread. */ +_get_sp_done: + + STMFD r0!, {r4 - r11} /* push r4 - r11 register */ +#if defined (__VFP_FP__) && !defined(__SOFTFP__) + STMFD r0!, {lr} /* push dummy for flag */ +#endif + STMFD r0!, {lr} /* push exec_return register */ + + TST lr, #0x04 /* if(!EXC_RETURN[2]) */ + BEQ _update_msp + MSR psp, r0 /* update stack pointer to PSP. */ + B _update_done +_update_msp: + MSR msp, r0 /* update stack pointer to MSP. */ +_update_done: + + PUSH {LR} + BL rt_hw_hard_fault_exception + POP {LR} + + ORR lr, lr, #0x04 + BX lr diff --git a/rt-thread/libcpu/arm/cortex-m7/context_iar.S b/rt-thread/libcpu/arm/cortex-m7/context_iar.S new file mode 100644 index 0000000..bf707d0 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m7/context_iar.S @@ -0,0 +1,257 @@ +;/* +; * File : context_iar.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2018, 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 +; * 2009-09-27 Bernard add protect when contex switch occurs +; * 2012-01-01 aozima support context switch load/store FPU register. +; * 2013-06-18 aozima add restore MSP feature. +; * 2013-06-23 aozima support lazy stack optimized. +; * 2018-07-24 aozima enhancement hard fault exception handler. +; */ + +;/** +; * @addtogroup cortex-m4 +; */ +;/*@{*/ + +SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register +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 + + SECTION .text:CODE(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(); +; */ + EXPORT rt_hw_interrupt_disable +rt_hw_interrupt_disable: + MRS r0, PRIMASK + CPSID I + BX LR + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ + EXPORT rt_hw_interrupt_enable +rt_hw_interrupt_enable: + MSR PRIMASK, r0 + BX LR + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ + EXPORT rt_hw_context_switch_interrupt + EXPORT rt_hw_context_switch +rt_hw_context_switch_interrupt: +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 + +; r0 --> switch from thread stack +; r1 --> switch to thread stack +; psr, pc, lr, r12, r3, r2, r1, r0 are pushed into [from] stack + EXPORT PendSV_Handler +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, switch_to_thread ; skip register save at the first time + + MRS r1, psp ; get from thread stack pointer + +#if defined ( __ARMVFP__ ) + TST lr, #0x10 ; if(!EXC_RETURN[4]) + BNE skip_push_fpu + VSTMDB r1!, {d8 - d15} ; push FPU register s16~s31 +skip_push_fpu +#endif + + STMFD r1!, {r4 - r11} ; push r4 - r11 register + +#if defined ( __ARMVFP__ ) + MOV r4, #0x00 ; flag = 0 + TST lr, #0x10 ; if(!EXC_RETURN[4]) + BNE push_flag + MOV r4, #0x01 ; flag = 1 +push_flag + ;STMFD r1!, {r4} ; push flag + SUB r1, r1, #0x04 + STR r4, [r1] +#endif + + LDR r0, [r0] + STR r1, [r0] ; update from thread stack pointer + +switch_to_thread + LDR r1, =rt_interrupt_to_thread + LDR r1, [r1] + LDR r1, [r1] ; load thread stack pointer + +#if defined ( __ARMVFP__ ) + LDMFD r1!, {r3} ; pop flag +#endif + + LDMFD r1!, {r4 - r11} ; pop r4 - r11 register + +#if defined ( __ARMVFP__ ) + CBZ r3, skip_pop_fpu + VLDMIA r1!, {d8 - d15} ; pop FPU register s16~s31 +skip_pop_fpu +#endif + + MSR psp, r1 ; update stack pointer + +#if defined ( __ARMVFP__ ) + ORR lr, lr, #0x10 ; lr |= (1 << 4), clean FPCA. + CBZ r3, return_without_fpu ; if(flag_r3 != 0) + BIC lr, lr, #0x10 ; lr &= ~(1 << 4), set FPCA. +return_without_fpu +#endif + +pendsv_exit + ; restore interrupt + MSR PRIMASK, r2 + + ORR lr, lr, #0x04 + BX lr + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ + EXPORT rt_hw_context_switch_to +rt_hw_context_switch_to: + LDR r1, =rt_interrupt_to_thread + STR r0, [r1] + +#if defined ( __ARMVFP__ ) + ; CLEAR CONTROL.FPCA + MRS r2, CONTROL ; read + BIC r2, r2, #0x04 ; modify + MSR CONTROL, r2 ; write-back +#endif + + ; 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 + + LDR r0, =NVIC_INT_CTRL ; trigger the PendSV exception (causes context switch) + LDR r1, =NVIC_PENDSVSET + STR r1, [r0] + + ; restore MSP + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + NOP + MSR msp, r0 + + ; enable interrupts at processor level + CPSIE F + CPSIE I + + ; never reach here! + +; compatible with old version + EXPORT rt_hw_interrupt_thread_switch +rt_hw_interrupt_thread_switch: + BX lr + + IMPORT rt_hw_hard_fault_exception + EXPORT HardFault_Handler +HardFault_Handler: + + ; get current context + MRS r0, msp ; get fault context from handler. + TST lr, #0x04 ; if(!EXC_RETURN[2]) + BEQ _get_sp_done + MRS r0, psp ; get fault context from thread. +_get_sp_done + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + ;STMFD r0!, {lr} ; push exec_return register +#if defined ( __ARMVFP__ ) + SUB r0, r0, #0x04 ; push dummy for flag + STR lr, [r0] +#endif + SUB r0, r0, #0x04 + STR lr, [r0] + + TST lr, #0x04 ; if(!EXC_RETURN[2]) + BEQ _update_msp + MSR psp, r0 ; update stack pointer to PSP. + B _update_done +_update_msp + MSR msp, r0 ; update stack pointer to MSP. +_update_done + + PUSH {lr} + BL rt_hw_hard_fault_exception + POP {lr} + + ORR lr, lr, #0x04 + BX lr + + END diff --git a/rt-thread/libcpu/arm/cortex-m7/context_rvds.S b/rt-thread/libcpu/arm/cortex-m7/context_rvds.S new file mode 100644 index 0000000..1abe477 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m7/context_rvds.S @@ -0,0 +1,257 @@ +;/* +; * File : context_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006 - 2018, 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. +; * 2012-01-01 aozima support context switch load/store FPU register. +; * 2013-06-18 aozima add restore MSP feature. +; * 2013-06-23 aozima support lazy stack optimized. +; * 2018-07-24 aozima enhancement hard fault exception handler. +; */ + +;/** +; * @addtogroup cortex-m4 +; */ +;/*@{*/ + +SCB_VTOR EQU 0xE000ED08 ; Vector Table Offset Register +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 --> switch from thread stack +; r1 --> switch 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, switch_to_thread ; skip register save at the first time + + MRS r1, psp ; get from thread stack pointer + + IF {FPU} != "SoftVFP" + TST lr, #0x10 ; if(!EXC_RETURN[4]) + VSTMFDEQ r1!, {d8 - d15} ; push FPU register s16~s31 + ENDIF + + STMFD r1!, {r4 - r11} ; push r4 - r11 register + + IF {FPU} != "SoftVFP" + MOV r4, #0x00 ; flag = 0 + + TST lr, #0x10 ; if(!EXC_RETURN[4]) + MOVEQ r4, #0x01 ; flag = 1 + + STMFD r1!, {r4} ; push flag + ENDIF + + LDR r0, [r0] + STR r1, [r0] ; update from thread stack pointer + +switch_to_thread + LDR r1, =rt_interrupt_to_thread + LDR r1, [r1] + LDR r1, [r1] ; load thread stack pointer + + IF {FPU} != "SoftVFP" + LDMFD r1!, {r3} ; pop flag + ENDIF + + LDMFD r1!, {r4 - r11} ; pop r4 - r11 register + + IF {FPU} != "SoftVFP" + CMP r3, #0 ; if(flag_r3 != 0) + VLDMFDNE r1!, {d8 - d15} ; pop FPU register s16~s31 + ENDIF + + MSR psp, r1 ; update stack pointer + + IF {FPU} != "SoftVFP" + ORR lr, lr, #0x10 ; lr |= (1 << 4), clean FPCA. + CMP r3, #0 ; if(flag_r3 != 0) + BICNE lr, lr, #0x10 ; lr &= ~(1 << 4), set FPCA. + ENDIF + +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] + + IF {FPU} != "SoftVFP" + ; CLEAR CONTROL.FPCA + MRS r2, CONTROL ; read + BIC r2, #0x04 ; modify + MSR CONTROL, r2 ; write-back + ENDIF + + ; 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] + + ; restore MSP + LDR r0, =SCB_VTOR + LDR r0, [r0] + LDR r0, [r0] + MSR msp, r0 + + ; enable interrupts at processor level + CPSIE F + CPSIE I + + ; never reach here! + ENDP + +; compatible with old version +rt_hw_interrupt_thread_switch PROC + EXPORT rt_hw_interrupt_thread_switch + BX lr + ENDP + + IMPORT rt_hw_hard_fault_exception + EXPORT HardFault_Handler + EXPORT MemManage_Handler +HardFault_Handler PROC +MemManage_Handler + + ; get current context + TST lr, #0x04 ; if(!EXC_RETURN[2]) + ITE EQ + MRSEQ r0, msp ; [2]=0 ==> Z=1, get fault context from handler. + MRSNE r0, psp ; [2]=1 ==> Z=0, get fault context from thread. + + STMFD r0!, {r4 - r11} ; push r4 - r11 register + IF {FPU} != "SoftVFP" + STMFD r0!, {lr} ; push dummy for flag + ENDIF + STMFD r0!, {lr} ; push exec_return register + + TST lr, #0x04 ; if(!EXC_RETURN[2]) + ITE EQ + MSREQ msp, r0 ; [2]=0 ==> Z=1, update stack pointer to MSP. + MSRNE psp, r0 ; [2]=1 ==> Z=0, update stack pointer to PSP. + + PUSH {lr} + BL rt_hw_hard_fault_exception + POP {lr} + + ORR lr, lr, #0x04 + BX lr + ENDP + + ALIGN 4 + + END diff --git a/rt-thread/libcpu/arm/cortex-m7/cpuport.c b/rt-thread/libcpu/arm/cortex-m7/cpuport.c new file mode 100644 index 0000000..18f0278 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-m7/cpuport.c @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2011-10-21 Bernard the first version. + * 2011-10-27 aozima update for cortex-M4 FPU. + * 2011-12-31 aozima fixed stack align issues. + * 2012-01-01 aozima support context switch load/store FPU register. + * 2012-12-11 lgnq fixed the coding style. + * 2012-12-23 aozima stack addr align to 8byte. + * 2012-12-29 Bernard Add exception hook. + * 2013-06-23 aozima support lazy stack optimized. + * 2018-07-24 aozima enhancement hard fault exception handler. + */ + +#include + +#if /* ARMCC */ ( (defined ( __CC_ARM ) && defined ( __TARGET_FPU_VFP )) \ + /* Clang */ || (defined ( __CLANG_ARM ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) \ + /* IAR */ || (defined ( __ICCARM__ ) && defined ( __ARMVFP__ )) \ + /* GNU */ || (defined ( __GNUC__ ) && defined ( __VFP_FP__ ) && !defined(__SOFTFP__)) ) +#define USE_FPU 1 +#else +#define USE_FPU 0 +#endif + +/* exception and interrupt handler table */ +rt_uint32_t rt_interrupt_from_thread; +rt_uint32_t rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; +/* exception hook */ +static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL; + +struct exception_stack_frame +{ + 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; +}; + +struct stack_frame +{ +#if USE_FPU + rt_uint32_t flag; +#endif /* USE_FPU */ + + /* r4 ~ r11 register */ + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t r11; + + struct exception_stack_frame exception_stack_frame; +}; + +struct exception_stack_frame_fpu +{ + 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; + +#if USE_FPU + /* FPU register */ + rt_uint32_t S0; + rt_uint32_t S1; + rt_uint32_t S2; + rt_uint32_t S3; + rt_uint32_t S4; + rt_uint32_t S5; + rt_uint32_t S6; + rt_uint32_t S7; + rt_uint32_t S8; + rt_uint32_t S9; + rt_uint32_t S10; + rt_uint32_t S11; + rt_uint32_t S12; + rt_uint32_t S13; + rt_uint32_t S14; + rt_uint32_t S15; + rt_uint32_t FPSCR; + rt_uint32_t NO_NAME; +#endif +}; + +struct stack_frame_fpu +{ + rt_uint32_t flag; + + /* r4 ~ r11 register */ + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t r11; + +#if USE_FPU + /* FPU register s16 ~ s31 */ + rt_uint32_t s16; + rt_uint32_t s17; + rt_uint32_t s18; + rt_uint32_t s19; + rt_uint32_t s20; + rt_uint32_t s21; + rt_uint32_t s22; + rt_uint32_t s23; + rt_uint32_t s24; + rt_uint32_t s25; + rt_uint32_t s26; + rt_uint32_t s27; + rt_uint32_t s28; + rt_uint32_t s29; + rt_uint32_t s30; + rt_uint32_t s31; +#endif + + struct exception_stack_frame_fpu exception_stack_frame; +}; + +rt_uint8_t *rt_hw_stack_init(void *tentry, + void *parameter, + rt_uint8_t *stack_addr, + void *texit) +{ + struct stack_frame *stack_frame; + rt_uint8_t *stk; + unsigned long i; + + stk = stack_addr + sizeof(rt_uint32_t); + stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8); + stk -= sizeof(struct stack_frame); + + stack_frame = (struct stack_frame *)stk; + + /* init all register */ + for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_uint32_t); i ++) + { + ((rt_uint32_t *)stack_frame)[i] = 0xdeadbeef; + } + + stack_frame->exception_stack_frame.r0 = (unsigned long)parameter; /* r0 : argument */ + stack_frame->exception_stack_frame.r1 = 0; /* r1 */ + stack_frame->exception_stack_frame.r2 = 0; /* r2 */ + stack_frame->exception_stack_frame.r3 = 0; /* r3 */ + stack_frame->exception_stack_frame.r12 = 0; /* r12 */ + stack_frame->exception_stack_frame.lr = (unsigned long)texit; /* lr */ + stack_frame->exception_stack_frame.pc = (unsigned long)tentry; /* entry point, pc */ + stack_frame->exception_stack_frame.psr = 0x01000000L; /* PSR */ + +#if USE_FPU + stack_frame->flag = 0; +#endif /* USE_FPU */ + + /* return task's current stack address */ + return stk; +} + +/** + * This function set the hook, which is invoked on fault exception handling. + * + * @param exception_handle the exception handling hook function. + */ +void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context)) +{ + rt_exception_hook = exception_handle; +} + +#define SCB_CFSR (*(volatile const unsigned *)0xE000ED28) /* Configurable Fault Status Register */ +#define SCB_HFSR (*(volatile const unsigned *)0xE000ED2C) /* HardFault Status Register */ +#define SCB_MMAR (*(volatile const unsigned *)0xE000ED34) /* MemManage Fault Address register */ +#define SCB_BFAR (*(volatile const unsigned *)0xE000ED38) /* Bus Fault Address Register */ +#define SCB_AIRCR (*(volatile unsigned long *)0xE000ED0C) /* Reset control Address Register */ +#define SCB_RESET_VALUE 0x05FA0004 /* Reset value, write to SCB_AIRCR can reset cpu */ + +#define SCB_CFSR_MFSR (*(volatile const unsigned char*)0xE000ED28) /* Memory-management Fault Status Register */ +#define SCB_CFSR_BFSR (*(volatile const unsigned char*)0xE000ED29) /* Bus Fault Status Register */ +#define SCB_CFSR_UFSR (*(volatile const unsigned short*)0xE000ED2A) /* Usage Fault Status Register */ + +#ifdef RT_USING_FINSH +static void usage_fault_track(void) +{ + rt_kprintf("usage fault:\n"); + rt_kprintf("SCB_CFSR_UFSR:0x%02X ", SCB_CFSR_UFSR); + + if(SCB_CFSR_UFSR & (1<<0)) + { + /* [0]:UNDEFINSTR */ + rt_kprintf("UNDEFINSTR "); + } + + if(SCB_CFSR_UFSR & (1<<1)) + { + /* [1]:INVSTATE */ + rt_kprintf("INVSTATE "); + } + + if(SCB_CFSR_UFSR & (1<<2)) + { + /* [2]:INVPC */ + rt_kprintf("INVPC "); + } + + if(SCB_CFSR_UFSR & (1<<3)) + { + /* [3]:NOCP */ + rt_kprintf("NOCP "); + } + + if(SCB_CFSR_UFSR & (1<<8)) + { + /* [8]:UNALIGNED */ + rt_kprintf("UNALIGNED "); + } + + if(SCB_CFSR_UFSR & (1<<9)) + { + /* [9]:DIVBYZERO */ + rt_kprintf("DIVBYZERO "); + } + + rt_kprintf("\n"); +} + +static void bus_fault_track(void) +{ + rt_kprintf("bus fault:\n"); + rt_kprintf("SCB_CFSR_BFSR:0x%02X ", SCB_CFSR_BFSR); + + if(SCB_CFSR_BFSR & (1<<0)) + { + /* [0]:IBUSERR */ + rt_kprintf("IBUSERR "); + } + + if(SCB_CFSR_BFSR & (1<<1)) + { + /* [1]:PRECISERR */ + rt_kprintf("PRECISERR "); + } + + if(SCB_CFSR_BFSR & (1<<2)) + { + /* [2]:IMPRECISERR */ + rt_kprintf("IMPRECISERR "); + } + + if(SCB_CFSR_BFSR & (1<<3)) + { + /* [3]:UNSTKERR */ + rt_kprintf("UNSTKERR "); + } + + if(SCB_CFSR_BFSR & (1<<4)) + { + /* [4]:STKERR */ + rt_kprintf("STKERR "); + } + + if(SCB_CFSR_BFSR & (1<<7)) + { + rt_kprintf("SCB->BFAR:%08X\n", SCB_BFAR); + } + else + { + rt_kprintf("\n"); + } +} + +static void mem_manage_fault_track(void) +{ + rt_kprintf("mem manage fault:\n"); + rt_kprintf("SCB_CFSR_MFSR:0x%02X ", SCB_CFSR_MFSR); + + if(SCB_CFSR_MFSR & (1<<0)) + { + /* [0]:IACCVIOL */ + rt_kprintf("IACCVIOL "); + } + + if(SCB_CFSR_MFSR & (1<<1)) + { + /* [1]:DACCVIOL */ + rt_kprintf("DACCVIOL "); + } + + if(SCB_CFSR_MFSR & (1<<3)) + { + /* [3]:MUNSTKERR */ + rt_kprintf("MUNSTKERR "); + } + + if(SCB_CFSR_MFSR & (1<<4)) + { + /* [4]:MSTKERR */ + rt_kprintf("MSTKERR "); + } + + if(SCB_CFSR_MFSR & (1<<7)) + { + /* [7]:MMARVALID */ + rt_kprintf("SCB->MMAR:%08X\n", SCB_MMAR); + } + else + { + rt_kprintf("\n"); + } +} + +static void hard_fault_track(void) +{ + if(SCB_HFSR & (1UL<<1)) + { + /* [1]:VECTBL, Indicates hard fault is caused by failed vector fetch. */ + rt_kprintf("failed vector fetch\n"); + } + + if(SCB_HFSR & (1UL<<30)) + { + /* [30]:FORCED, Indicates hard fault is taken because of bus fault, + memory management fault, or usage fault. */ + if(SCB_CFSR_BFSR) + { + bus_fault_track(); + } + + if(SCB_CFSR_MFSR) + { + mem_manage_fault_track(); + } + + if(SCB_CFSR_UFSR) + { + usage_fault_track(); + } + } + + if(SCB_HFSR & (1UL<<31)) + { + /* [31]:DEBUGEVT, Indicates hard fault is triggered by debug event. */ + rt_kprintf("debug event\n"); + } +} +#endif /* RT_USING_FINSH */ + +struct exception_info +{ + rt_uint32_t exc_return; + struct stack_frame stack_frame; +}; + +void rt_hw_hard_fault_exception(struct exception_info *exception_info) +{ + extern long list_thread(void); + struct exception_stack_frame *exception_stack = &exception_info->stack_frame.exception_stack_frame; + struct stack_frame *context = &exception_info->stack_frame; + + if (rt_exception_hook != RT_NULL) + { + rt_err_t result; + + result = rt_exception_hook(exception_stack); + if (result == RT_EOK) return; + } + + rt_kprintf("psr: 0x%08x\n", context->exception_stack_frame.psr); + + rt_kprintf("r00: 0x%08x\n", context->exception_stack_frame.r0); + rt_kprintf("r01: 0x%08x\n", context->exception_stack_frame.r1); + rt_kprintf("r02: 0x%08x\n", context->exception_stack_frame.r2); + rt_kprintf("r03: 0x%08x\n", context->exception_stack_frame.r3); + rt_kprintf("r04: 0x%08x\n", context->r4); + rt_kprintf("r05: 0x%08x\n", context->r5); + rt_kprintf("r06: 0x%08x\n", context->r6); + rt_kprintf("r07: 0x%08x\n", context->r7); + rt_kprintf("r08: 0x%08x\n", context->r8); + rt_kprintf("r09: 0x%08x\n", context->r9); + rt_kprintf("r10: 0x%08x\n", context->r10); + rt_kprintf("r11: 0x%08x\n", context->r11); + rt_kprintf("r12: 0x%08x\n", context->exception_stack_frame.r12); + rt_kprintf(" lr: 0x%08x\n", context->exception_stack_frame.lr); + rt_kprintf(" pc: 0x%08x\n", context->exception_stack_frame.pc); + + if (exception_info->exc_return & (1 << 2)) + { + rt_kprintf("hard fault on thread: %s\r\n\r\n", rt_thread_self()->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + } + else + { + rt_kprintf("hard fault on handler\r\n\r\n"); + } + + if ( (exception_info->exc_return & 0x10) == 0) + { + rt_kprintf("FPU active!\r\n"); + } + +#ifdef RT_USING_FINSH + hard_fault_track(); +#endif /* RT_USING_FINSH */ + + while (1); +} + +/** + * shutdown CPU + */ +void rt_hw_cpu_shutdown(void) +{ + rt_kprintf("shutdown...\n"); + + RT_ASSERT(0); +} + +/** + * reset CPU + */ +RT_WEAK void rt_hw_cpu_reset(void) +{ + SCB_AIRCR = SCB_RESET_VALUE; +} + +#ifdef RT_USING_CPU_FFS +/** + * This function finds the first bit set (beginning with the least significant bit) + * in value and return the index of that bit. + * + * Bits are numbered starting at 1 (the least significant bit). A return value of + * zero from any of these functions means that the argument was zero. + * + * @return return the index of the first bit set. If value is 0, then this function + * shall return 0. + */ +#if defined(__CC_ARM) || defined(__CLANG_ARM) +__asm int __rt_ffs(int value) +{ + CMP r0, #0x00 + BEQ exit + + RBIT r0, r0 + CLZ r0, r0 + ADDS r0, r0, #0x01 + +exit + BX lr +} +#elif defined(__IAR_SYSTEMS_ICC__) +int __rt_ffs(int value) +{ + if (value == 0) return value; + + asm("RBIT %0, %1" : "=r"(value) : "r"(value)); + asm("CLZ %0, %1" : "=r"(value) : "r"(value)); + asm("ADDS %0, %1, #0x01" : "=r"(value) : "r"(value)); + + return value; +} +#elif defined(__GNUC__) +int __rt_ffs(int value) +{ + return __builtin_ffs(value); +} +#endif + +#endif diff --git a/rt-thread/libcpu/arm/cortex-r4/armv7.h b/rt-thread/libcpu/arm/cortex-r4/armv7.h new file mode 100644 index 0000000..7dc3471 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/armv7.h @@ -0,0 +1,48 @@ +#ifndef __ARMV7_H__ +#define __ARMV7_H__ + +#ifndef VFP_DATA_NR +#define VFP_DATA_NR 32 +#endif + +/* the exception stack without VFP registers */ +struct rt_hw_exp_stack +{ + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long sp; + unsigned long lr; + unsigned long pc; + unsigned long cpsr; +}; + +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define MONITORMODE 0x16 +#define ABORTMODE 0x17 +#define HYPMODE 0x1b +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +#define T_Bit (1<<5) +#define F_Bit (1<<6) +#define I_Bit (1<<7) +#define A_Bit (1<<8) +#define E_Bit (1<<9) +#define J_Bit (1<<24) + +#endif diff --git a/rt-thread/libcpu/arm/cortex-r4/context_ccs.asm b/rt-thread/libcpu/arm/cortex-r4/context_ccs.asm new file mode 100644 index 0000000..2b459f8 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/context_ccs.asm @@ -0,0 +1,264 @@ +;/* +; * File : context_ccs.asm +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, 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-20 Bernard first version +; * 2011-07-22 Bernard added thumb mode porting +; * 2013-05-24 Grissiom port to CCS +; * 2013-05-26 Grissiom optimize for ARMv7 +; */ + + .text + .arm + .ref rt_thread_switch_interrupt_flag + .ref rt_interrupt_from_thread + .ref rt_interrupt_to_thread + .ref rt_interrupt_enter + .ref rt_interrupt_leave + .ref rt_hw_trap_irq + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ + .def rt_hw_interrupt_disable + .asmfunc +rt_hw_interrupt_disable + MRS r0, cpsr + CPSID IF + BX lr + .endasmfunc + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ + .def rt_hw_interrupt_enable + .asmfunc +rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + .endasmfunc + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ + .def rt_hw_context_switch + .asmfunc +rt_hw_context_switch + STMDB sp!, {lr} ; push pc (lr should be pushed in place of PC) + STMDB sp!, {r0-r12, lr} ; push lr & register file + + MRS r4, cpsr + TST lr, #0x01 + ORRNE r4, r4, #0x20 ; it's thumb code + + STMDB sp!, {r4} ; push cpsr + + .if (__TI_VFP_SUPPORT__) + VMRS r4, fpexc + TST r4, #0x40000000 + BEQ __no_vfp_frame1 + VSTMDB sp!, {d0-d15} + VMRS r5, fpscr + ; TODO: add support for Common VFPv3. + ; Save registers like FPINST, FPINST2 + STMDB sp!, {r5} +__no_vfp_frame1 + STMDB sp!, {r4} + .endif + + STR sp, [r0] ; store sp in preempted tasks TCB + LDR sp, [r1] ; get new task stack pointer + + .if (__TI_VFP_SUPPORT__) + LDMIA sp!, {r0} ; get fpexc + VMSR fpexc, r0 ; restore fpexc + TST r0, #0x40000000 + BEQ __no_vfp_frame2 + LDMIA sp!, {r1} ; get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame2 + .endif + + LDMIA sp!, {r4} ; pop new task cpsr to spsr + MSR spsr_cxsf, r4 + + LDMIA sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr + .endasmfunc + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ + .def rt_hw_context_switch_to + .asmfunc +rt_hw_context_switch_to + LDR sp, [r0] ; get new task stack pointer + + .if (__TI_VFP_SUPPORT__) + LDMIA sp!, {r0} ; get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_to + LDMIA sp!, {r1} ; get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_to + .endif + + LDMIA sp!, {r4} ; pop new task cpsr to spsr + MSR spsr_cxsf, r4 + + LDMIA sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr + .endasmfunc + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + + .def rt_hw_context_switch_interrupt + .asmfunc +rt_hw_context_switch_interrupt + LDR r2, pintflag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 1 + STR r3, [r2] + LDR r2, pfromthread ; set rt_interrupt_from_thread + STR r0, [r2] +_reswitch + LDR r2, ptothread ; set rt_interrupt_to_thread + STR r1, [r2] + BX lr + .endasmfunc + + .def IRQ_Handler +IRQ_Handler + STMDB sp!, {r0-r12,lr} + + .if (__TI_VFP_SUPPORT__) + VMRS r0, fpexc + TST r0, #0x40000000 + BEQ __no_vfp_frame_str_irq + VSTMDB sp!, {d0-d15} + VMRS r1, fpscr + ; TODO: add support for Common VFPv3. + ; Save registers like FPINST, FPINST2 + STMDB sp!, {r1} +__no_vfp_frame_str_irq + STMDB sp!, {r0} + .endif + + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; if rt_thread_switch_interrupt_flag set, jump to + ; rt_hw_context_switch_interrupt_do and don't return + LDR r0, pintflag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + + .if (__TI_VFP_SUPPORT__) + LDMIA sp!, {r0} ; get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_ldr_irq + LDMIA sp!, {r1} ; get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_ldr_irq + .endif + + LDMIA sp!, {r0-r12,lr} + SUBS pc, lr, #4 + +; /* +; * void rt_hw_context_switch_interrupt_do(rt_base_t flag) +; */ + .def rt_hw_context_switch_interrupt_do +rt_hw_context_switch_interrupt_do + MOV r1, #0 ; clear flag + STR r1, [r0] + + .if (__TI_VFP_SUPPORT__) + LDMIA sp!, {r0} ; get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_do1 + LDMIA sp!, {r1} ; get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_do1 + .endif + + LDMIA sp!, {r0-r12,lr} ; reload saved registers + STMDB sp, {r0-r3} ; save r0-r3. We will restore r0-r3 in the SVC + ; mode so there is no need to update SP. + SUB r1, sp, #16 ; save the right SP value in r1, so we could restore r0-r3. + SUB r2, lr, #4 ; save old task's pc to r2 + + MRS r3, spsr ; get cpsr of interrupt thread + + ; switch to SVC mode and no interrupt + CPSID IF, #0x13 + + STMDB sp!, {r2} ; push old task's pc + STMDB sp!, {r4-r12,lr} ; push old task's lr,r12-r4 + LDMIA r1!, {r4-r7} ; restore r0-r3 of the interrupted thread + STMDB sp!, {r4-r7} ; push old task's r3-r0. We don't need to push/pop them to + ; r0-r3 because we just want to transfer the data and don't + ; use them here. + STMDB sp!, {r3} ; push old task's cpsr + + .if (__TI_VFP_SUPPORT__) + VMRS r0, fpexc + TST r0, #0x40000000 + BEQ __no_vfp_frame_do2 + VSTMDB sp!, {d0-d15} + VMRS r1, fpscr + ; TODO: add support for Common VFPv3. + ; Save registers like FPINST, FPINST2 + STMDB sp!, {r1} +__no_vfp_frame_do2 + STMDB sp!, {r0} + .endif + + LDR r4, pfromthread + LDR r5, [r4] + STR sp, [r5] ; store sp in preempted tasks's TCB + + LDR r6, ptothread + LDR r6, [r6] + LDR sp, [r6] ; get new task's stack pointer + + .if (__TI_VFP_SUPPORT__) + LDMIA sp!, {r0} ; get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_do3 + LDMIA sp!, {r1} ; get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_do3 + .endif + + LDMIA sp!, {r4} ; pop new task's cpsr to spsr + MSR spsr_cxsf, r4 + + LDMIA sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr + +pintflag .word rt_thread_switch_interrupt_flag +pfromthread .word rt_interrupt_from_thread +ptothread .word rt_interrupt_to_thread diff --git a/rt-thread/libcpu/arm/cortex-r4/context_gcc.S b/rt-thread/libcpu/arm/cortex-r4/context_gcc.S new file mode 100644 index 0000000..5256645 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/context_gcc.S @@ -0,0 +1,255 @@ +/* + * File : context_ccs.asm + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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-20 Bernard first version + * 2011-07-22 Bernard added thumb mode porting + * 2013-05-24 Grissiom port to CCS + * 2013-05-26 Grissiom optimize for ARMv7 + * 2013-10-20 Grissiom port to GCC + */ + +#include + + .text + .arm + .globl rt_thread_switch_interrupt_flag + .globl rt_interrupt_from_thread + .globl rt_interrupt_to_thread + .globl rt_interrupt_enter + .globl rt_interrupt_leave + .globl rt_hw_trap_irq + +/* + * rt_base_t rt_hw_interrupt_disable() + */ + .globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + MRS r0, cpsr + CPSID IF + BX lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level) + */ + .globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + MSR cpsr_c, r0 + BX lr + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to) + * r0 --> from + * r1 --> to + */ + .globl rt_hw_context_switch +rt_hw_context_switch: + STMDB sp!, {lr} @ push pc (lr should be pushed in place of PC) + STMDB sp!, {r0-r12, lr} @ push lr & register file + + MRS r4, cpsr + TST lr, #0x01 + ORRNE r4, r4, #0x20 @ it's thumb code + + STMDB sp!, {r4} @ push cpsr + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING) + VMRS r4, fpexc + TST r4, #0x40000000 + BEQ __no_vfp_frame1 + VSTMDB sp!, {d0-d15} + VMRS r5, fpscr + @ TODO: add support for Common VFPv3. + @ Save registers like FPINST, FPINST2 + STMDB sp!, {r5} +__no_vfp_frame1: + STMDB sp!, {r4} +#endif + + STR sp, [r0] @ store sp in preempted tasks TCB + LDR sp, [r1] @ get new task stack pointer + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING) + LDMIA sp!, {r0} @ get fpexc + VMSR fpexc, r0 @ restore fpexc + TST r0, #0x40000000 + BEQ __no_vfp_frame2 + LDMIA sp!, {r1} @ get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame2: + #endif + + LDMIA sp!, {r4} @ pop new task cpsr to spsr + MSR spsr_cxsf, r4 + + LDMIA sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr + +/* + * void rt_hw_context_switch_to(rt_uint32 to) + * r0 --> to + */ + .globl rt_hw_context_switch_to +rt_hw_context_switch_to: + LDR sp, [r0] @ get new task stack pointer + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING) + LDMIA sp!, {r0} @ get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_to + LDMIA sp!, {r1} @ get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_to: +#endif + + LDMIA sp!, {r4} @ pop new task cpsr to spsr + MSR spsr_cxsf, r4 + + LDMIA sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to)@ + */ + + .globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 @ set rt_thread_switch_interrupt_flag to 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] + BX lr + + .globl IRQ_Handler +IRQ_Handler: + STMDB sp!, {r0-r12,lr} + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING) + VMRS r0, fpexc + TST r0, #0x40000000 + BEQ __no_vfp_frame_str_irq + VSTMDB sp!, {d0-d15} + VMRS r1, fpscr + @ TODO: add support for Common VFPv3. + @ Save registers like FPINST, FPINST2 + STMDB sp!, {r1} +__no_vfp_frame_str_irq: + STMDB sp!, {r0} +#endif + + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + @ if rt_thread_switch_interrupt_flag set, jump to + @ rt_hw_context_switch_interrupt_do and don't return + LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING) + LDMIA sp!, {r0} @ get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_ldr_irq + LDMIA sp!, {r1} @ get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_ldr_irq: +#endif + + LDMIA sp!, {r0-r12,lr} + SUBS pc, lr, #4 + +/* + * void rt_hw_context_switch_interrupt_do(rt_base_t flag) + */ + .globl rt_hw_context_switch_interrupt_do +rt_hw_context_switch_interrupt_do: + MOV r1, #0 @ clear flag + STR r1, [r0] + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING) + LDMIA sp!, {r0} @ get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_do1 + LDMIA sp!, {r1} @ get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_do1: +#endif + + LDMIA sp!, {r0-r12,lr} @ reload saved registers + STMDB sp, {r0-r3} @ save r0-r3. We will restore r0-r3 in the SVC + @ mode so there is no need to update SP. + SUB r1, sp, #16 @ save the right SP value in r1, so we could restore r0-r3. + SUB r2, lr, #4 @ save old task's pc to r2 + + MRS r3, spsr @ get cpsr of interrupt thread + + @ switch to SVC mode and no interrupt + CPSID IF, #0x13 + + STMDB sp!, {r2} @ push old task's pc + STMDB sp!, {r4-r12,lr} @ push old task's lr,r12-r4 + LDMIA r1!, {r4-r7} @ restore r0-r3 of the interrupted thread + STMDB sp!, {r4-r7} @ push old task's r3-r0. We don't need to push/pop them to + @ r0-r3 because we just want to transfer the data and don't + @ use them here. + STMDB sp!, {r3} @ push old task's cpsr + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING) + VMRS r0, fpexc + TST r0, #0x40000000 + BEQ __no_vfp_frame_do2 + VSTMDB sp!, {d0-d15} + VMRS r1, fpscr + @ TODO: add support for Common VFPv3. + @ Save registers like FPINST, FPINST2 + STMDB sp!, {r1} +__no_vfp_frame_do2: + STMDB sp!, {r0} +#endif + + LDR r4, =rt_interrupt_from_thread + LDR r5, [r4] + STR sp, [r5] @ store sp in preempted tasks's TCB + + LDR r6, =rt_interrupt_to_thread + LDR r6, [r6] + LDR sp, [r6] @ get new task's stack pointer + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING) + LDMIA sp!, {r0} @ get fpexc + VMSR fpexc, r0 + TST r0, #0x40000000 + BEQ __no_vfp_frame_do3 + LDMIA sp!, {r1} @ get fpscr + VMSR fpscr, r1 + VLDMIA sp!, {d0-d15} +__no_vfp_frame_do3: +#endif + + LDMIA sp!, {r4} @ pop new task's cpsr to spsr + MSR spsr_cxsf, r4 + + LDMIA sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr + diff --git a/rt-thread/libcpu/arm/cortex-r4/cpu.c b/rt-thread/libcpu/arm/cortex-r4/cpu.c new file mode 100644 index 0000000..89369d5 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/cpu.c @@ -0,0 +1,99 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + * 2013-05-24 Grissiom port to RM48x50 + */ + +#include + +/** + * @addtogroup RM48x50 + */ +/*@{*/ + +/** + * this function will reset CPU + * + */ +void rt_hw_cpu_reset() +{ +} + +/** + * this function will shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_kprintf("shutdown...\n"); + + while (1); +} + +#ifdef __TI_COMPILER_VERSION__ +#ifdef RT_USING_CPU_FFS +int __rt_ffs(int value) +{ + if (value == 0) + return value; + + __asm(" rsb r1, r0, #0"); + __asm(" and r1, r1, r0"); + __asm(" clz r1, r1"); + __asm(" rsb r0, r1, #32"); +} +#endif + +void rt_hw_cpu_icache_enable() +{ + __asm(" MRC p15, #0, r1, c1, c0, #0 ; Read SCTLR configuration data"); + __asm(" ORR r1, r1, #0x1 <<12 ; instruction cache enable"); + __asm(" MCR p15, #0, r0, c7, c5, #0 ; Invalidate entire instruction cache, r0 is ignored"); + __asm(" MCR p15, #0, r1, c1, c0, #0 ; enabled instruction cache"); + __asm(" ISB"); +} + +void rt_hw_cpu_icache_disable() +{ + __asm(" MRC p15, #0, r1, c1, c0, #0 ; Read SCTLR configuration data"); + __asm(" BIC r1, r1, #0x1 <<12 ; instruction cache enable"); + __asm(" MCR p15, #0, r1, c1, c0, #0 ; disabled instruction cache"); + __asm(" ISB"); +} + +void rt_hw_cpu_dcache_enable() +{ + __asm(" MRC p15, #0, R1, c1, c0, #0 ; Read SCTLR configuration data"); + __asm(" ORR R1, R1, #0x1 <<2"); + __asm(" DSB"); + __asm(" MCR p15, #0, r0, c15, c5, #0 ; Invalidate entire data cache"); + __asm(" MCR p15, #0, R1, c1, c0, #0 ; enabled data cache"); +} + +void rt_hw_cpu_dcache_disable() +{ + /* FIXME: Clean entire data cache. This routine depends on the data cache + * size. It can be omitted if it is known that the data cache has no dirty + * data. */ + __asm(" MRC p15, #0, r1, c1, c0, #0 ; Read SCTLR configuration data"); + __asm(" BIC r1, r1, #0x1 <<2"); + __asm(" DSB"); + __asm(" MCR p15, #0, r1, c1, c0, #0 ; disabled data cache"); +} + +#elif __GNUC__ +int __rt_ffs(int value) +{ + return __builtin_ffs(value); +} +#endif +/*@}*/ diff --git a/rt-thread/libcpu/arm/cortex-r4/interrupt.c b/rt-thread/libcpu/arm/cortex-r4/interrupt.c new file mode 100644 index 0000000..ba2d99e --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/interrupt.c @@ -0,0 +1,110 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + * 2013-03-29 aozima Modify the interrupt interface implementations. + */ + +#include +#include + +#include +#include + +#include "armv7.h" + +#define MAX_HANDLERS 96 + +/* exception and interrupt handler table */ +struct rt_irq_desc irq_desc[MAX_HANDLERS]; + +extern volatile rt_uint8_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +/** + * @addtogroup RM48x50 + */ + +/*@{*/ + +static void rt_hw_int_not_handle(int vector, void *param) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +#define vimRAM (0xFFF82000U) + +void rt_hw_interrupt_init(void) +{ + register int i; + + rt_uint32_t *vect_addr; + + /* the initialization is done in sys_startup.c */ + + /* init exceptions table */ + rt_memset(irq_desc, 0x00, sizeof(irq_desc)); + for(i=0; i < MAX_HANDLERS; i++) + { + irq_desc[i].handler = rt_hw_int_not_handle; + + vect_addr = (rt_uint32_t *)(vimRAM + i*4); + *vect_addr = (rt_uint32_t)&irq_desc[i]; + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +void rt_hw_interrupt_mask(int vector) +{ + vimDisableInterrupt(vector); +} + +void rt_hw_interrupt_umask(int vector) +{ + vimEnableInterrupt(vector, SYS_IRQ); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param handler the interrupt service routine to be installed + * @param param the parameter for interrupt service routine + * @name unused. + * + * @return the old handler + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if(vector >= 0 && vector < MAX_HANDLERS) + { + old_handler = irq_desc[vector].handler; + if (handler != RT_NULL) + { + irq_desc[vector].handler = handler; + irq_desc[vector].param = param; + } + } + + return old_handler; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/cortex-r4/stack.c b/rt-thread/libcpu/arm/cortex-r4/stack.c new file mode 100644 index 0000000..852c6ea --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/stack.c @@ -0,0 +1,87 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + * 2013-05-24 Grissiom port to RM48x50 + */ +#include + +#include "armv7.h" +/** + * @addtogroup RM48x50 + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + +#if defined(__TI_VFP_SUPPORT__) || (defined (__VFP_FP__) && !defined(__SOFTFP__)) +#ifndef RT_VFP_LAZY_STACKING + { + int i; + + for (i = 0; i < VFP_DATA_NR; i++) + { + *(--stk) = 0; + } + /* FPSCR TODO: do we need to set the values other than 0? */ + *(--stk) = 0; + /* FPEXC. Enable the FVP if no lazy stacking. */ + *(--stk) = 0x40000000; + } +#else + /* FPEXC. Disable the FVP by default. */ + *(--stk) = 0x00000000; +#endif +#endif + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/cortex-r4/start_ccs.asm b/rt-thread/libcpu/arm/cortex-r4/start_ccs.asm new file mode 100644 index 0000000..4334fa9 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/start_ccs.asm @@ -0,0 +1,552 @@ +;------------------------------------------------------------------------------- +; sys_core.asm +; +; (c) Texas Instruments 2009-2013, All rights reserved. +; + + .text + .arm + + .ref _c_int00 + + .def _reset + .asmfunc +_reset +;------------------------------------------------------------------------------- +; Initialize CPU Registers +; After reset, the CPU is in the Supervisor mode (M = 10011) + mov r0, lr + mov r1, #0x0000 + mov r2, #0x0000 + mov r3, #0x0000 + mov r4, #0x0000 + mov r5, #0x0000 + mov r6, #0x0000 + mov r7, #0x0000 + mov r8, #0x0000 + mov r9, #0x0000 + mov r10, #0x0000 + mov r11, #0x0000 + mov r12, #0x0000 + mov r13, #0x0000 + mrs r1, cpsr + msr spsr_cxsf, r1 + ; Switch to FIQ mode (M = 10001) + cps #17 + mov lr, r0 + mov r8, #0x0000 + mov r9, #0x0000 + mov r10, #0x0000 + mov r11, #0x0000 + mov r12, #0x0000 + mrs r1, cpsr + msr spsr_cxsf, r1 + ; Switch to IRQ mode (M = 10010) + cps #18 + mov lr, r0 + mrs r1,cpsr + msr spsr_cxsf, r1 + ; Switch to Abort mode (M = 10111) + cps #23 + mov lr, r0 + mrs r1,cpsr + msr spsr_cxsf, r1 + ; Switch to Undefined Instruction Mode (M = 11011) + cps #27 + mov lr, r0 + mrs r1,cpsr + msr spsr_cxsf, r1 + ; Switch to System Mode ( Shares User Mode registers ) (M = 11111) + cps #31 + mov lr, r0 + mrs r1,cpsr + msr spsr_cxsf, r1 + ; Switch back to Supervisor Mode (M = 10011) + cps #19 + + ; Turn on FPV coprocessor + mrc p15, #0x00, r2, c1, c0, #0x02 + orr r2, r2, #0xF00000 + mcr p15, #0x00, r2, c1, c0, #0x02 + + .if (RT_VFP_LAZY_STACKING) = 0 + fmrx r2, fpexc + orr r2, r2, #0x40000000 + fmxr fpexc, r2 + + fmdrr d0, r1, r1 + fmdrr d1, r1, r1 + fmdrr d2, r1, r1 + fmdrr d3, r1, r1 + fmdrr d4, r1, r1 + fmdrr d5, r1, r1 + fmdrr d6, r1, r1 + fmdrr d7, r1, r1 + fmdrr d8, r1, r1 + fmdrr d9, r1, r1 + fmdrr d10, r1, r1 + fmdrr d11, r1, r1 + fmdrr d12, r1, r1 + fmdrr d13, r1, r1 + fmdrr d14, r1, r1 + fmdrr d15, r1, r1 + .endif + +;------------------------------------------------------------------------------- +; Initialize Stack Pointers + cps #17 + ldr sp, fiqSp + cps #18 + ldr sp, irqSp + cps #23 + ldr sp, abortSp + cps #27 + ldr sp, undefSp + cps #31 + ldr sp, userSp + cps #19 + ldr sp, svcSp + + bl next1 +next1 + bl next2 +next2 + bl next3 +next3 + bl next4 +next4 + ldr lr, int00ad + bx lr + +int00ad .word _c_int00 +userSp .word 0x08000000+0x00001000 +svcSp .word 0x08000000+0x00001000+0x00000100 +fiqSp .word 0x08000000+0x00001000+0x00000100+0x00000100 +irqSp .word 0x08000000+0x00001000+0x00000100+0x00000100+0x00000100 +abortSp .word 0x08000000+0x00001000+0x00000100+0x00000100+0x00000100+0x00000100 +undefSp .word 0x08000000+0x00001000+0x00000100+0x00000100+0x00000100+0x00000100+0x00000100 + + .endasmfunc + +;------------------------------------------------------------------------------- +; Enable RAM ECC Support + + .def _coreEnableRamEcc_ + .asmfunc + +_coreEnableRamEcc_ + + stmfd sp!, {r0} + mrc p15, #0x00, r0, c1, c0, #0x01 + orr r0, r0, #0x0C000000 + mcr p15, #0x00, r0, c1, c0, #0x01 + ldmfd sp!, {r0} + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Disable RAM ECC Support + + .def _coreDisableRamEcc_ + .asmfunc + +_coreDisableRamEcc_ + + stmfd sp!, {r0} + mrc p15, #0x00, r0, c1, c0, #0x01 + bic r0, r0, #0x0C000000 + mcr p15, #0x00, r0, c1, c0, #0x01 + ldmfd sp!, {r0} + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Enable Flash ECC Support + + .def _coreEnableFlashEcc_ + .asmfunc + +_coreEnableFlashEcc_ + + stmfd sp!, {r0} + mrc p15, #0x00, r0, c1, c0, #0x01 + orr r0, r0, #0x02000000 + dmb + mcr p15, #0x00, r0, c1, c0, #0x01 + ldmfd sp!, {r0} + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Disable Flash ECC Support + + .def _coreDisableFlashEcc_ + .asmfunc + +_coreDisableFlashEcc_ + + stmfd sp!, {r0} + mrc p15, #0x00, r0, c1, c0, #0x01 + bic r0, r0, #0x02000000 + mcr p15, #0x00, r0, c1, c0, #0x01 + ldmfd sp!, {r0} + bx lr + + .endasmfunc + +;------------------------------------------------------------------------------- +; Get data fault status register + + .def _coreGetDataFault_ + .asmfunc + +_coreGetDataFault_ + + mrc p15, #0, r0, c5, c0, #0 + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Clear data fault status register + + .def _coreClearDataFault_ + .asmfunc + +_coreClearDataFault_ + + stmfd sp!, {r0} + mov r0, #0 + mcr p15, #0, r0, c5, c0, #0 + ldmfd sp!, {r0} + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Get instruction fault status register + + .def _coreGetInstructionFault_ + .asmfunc + +_coreGetInstructionFault_ + + mrc p15, #0, r0, c5, c0, #1 + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Clear instruction fault status register + + .def _coreClearInstructionFault_ + .asmfunc + +_coreClearInstructionFault_ + + stmfd sp!, {r0} + mov r0, #0 + mcr p15, #0, r0, c5, c0, #1 + ldmfd sp!, {r0} + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Get data fault address register + + .def _coreGetDataFaultAddress_ + .asmfunc + +_coreGetDataFaultAddress_ + + mrc p15, #0, r0, c6, c0, #0 + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Clear data fault address register + + .def _coreClearDataFaultAddress_ + .asmfunc + +_coreClearDataFaultAddress_ + + stmfd sp!, {r0} + mov r0, #0 + mcr p15, #0, r0, c6, c0, #0 + ldmfd sp!, {r0} + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Get instruction fault address register + + .def _coreGetInstructionFaultAddress_ + .asmfunc + +_coreGetInstructionFaultAddress_ + + mrc p15, #0, r0, c6, c0, #2 + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Clear instruction fault address register + + .def _coreClearInstructionFaultAddress_ + .asmfunc + +_coreClearInstructionFaultAddress_ + + stmfd sp!, {r0} + mov r0, #0 + mcr p15, #0, r0, c6, c0, #2 + ldmfd sp!, {r0} + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Get auxiliary data fault status register + + .def _coreGetAuxiliaryDataFault_ + .asmfunc + +_coreGetAuxiliaryDataFault_ + + mrc p15, #0, r0, c5, c1, #0 + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Clear auxiliary data fault status register + + .def _coreClearAuxiliaryDataFault_ + .asmfunc + +_coreClearAuxiliaryDataFault_ + + stmfd sp!, {r0} + mov r0, #0 + mcr p15, #0, r0, c5, c1, #0 + ldmfd sp!, {r0} + bx lr + + .endasmfunc + + +;------------------------------------------------------------------------------- +; Get auxiliary instruction fault status register + + .def _coreGetAuxiliaryInstructionFault_ + .asmfunc + +_coreGetAuxiliaryInstructionFault_ + + mrc p15, #0, r0, c5, c1, #1 + bx lr + + .endasmfunc + +;------------------------------------------------------------------------------- +; Clear auxiliary instruction fault status register + + .def _coreClearAuxiliaryInstructionFault_ + .asmfunc + +_coreClearAuxiliaryInstructionFault_ + + stmfd sp!, {r0} + mov r0, #0 + mrc p15, #0, r0, c5, c1, #1 + ldmfd sp!, {r0} + bx lr + + .endasmfunc + +;------------------------------------------------------------------------------- +; Clear ESM CCM errorss + + .def _esmCcmErrorsClear_ + .asmfunc + +_esmCcmErrorsClear_ + + stmfd sp!, {r0-r2} + ldr r0, ESMSR1_REG ; load the ESMSR1 status register address + ldr r2, ESMSR1_ERR_CLR + str r2, [r0] ; clear the ESMSR1 register + + ldr r0, ESMSR2_REG ; load the ESMSR2 status register address + ldr r2, ESMSR2_ERR_CLR + str r2, [r0] ; clear the ESMSR2 register + + ldr r0, ESMSSR2_REG ; load the ESMSSR2 status register address + ldr r2, ESMSSR2_ERR_CLR + str r2, [r0] ; clear the ESMSSR2 register + + ldr r0, ESMKEY_REG ; load the ESMKEY register address + mov r2, #0x5 ; load R2 with 0x5 + str r2, [r0] ; clear the ESMKEY register + + ldr r0, VIM_INTREQ ; load the INTREQ register address + ldr r2, VIM_INT_CLR + str r2, [r0] ; clear the INTREQ register + ldr r0, CCMR4_STAT_REG ; load the CCMR4 status register address + ldr r2, CCMR4_ERR_CLR + str r2, [r0] ; clear the CCMR4 status register + ldmfd sp!, {r0-r2} + bx lr + +ESMSR1_REG .word 0xFFFFF518 +ESMSR2_REG .word 0xFFFFF51C +ESMSR3_REG .word 0xFFFFF520 +ESMKEY_REG .word 0xFFFFF538 +ESMSSR2_REG .word 0xFFFFF53C +CCMR4_STAT_REG .word 0xFFFFF600 +ERR_CLR_WRD .word 0xFFFFFFFF +CCMR4_ERR_CLR .word 0x00010000 +ESMSR1_ERR_CLR .word 0x80000000 +ESMSR2_ERR_CLR .word 0x00000004 +ESMSSR2_ERR_CLR .word 0x00000004 +VIM_INT_CLR .word 0x00000001 +VIM_INTREQ .word 0xFFFFFE20 + + .endasmfunc + +;------------------------------------------------------------------------------- +; Work Around for Errata CORTEX-R4#57: +; +; Errata Description: +; Conditional VMRS APSR_Nzcv, FPSCR May Evaluate With Incorrect Flags +; Workaround: +; Disable out-of-order single-precision floating point +; multiply-accumulate instruction completion + + .def _errata_CORTEXR4_57_ + .asmfunc + +_errata_CORTEXR4_57_ + + push {r0} + mrc p15, #0, r0, c15, c0, #0 ; Read Secondary Auxiliary Control Register + orr r0, r0, #0x10000 ; Set BIT 16 (Set DOOFMACS) + mcr p15, #0, r0, c15, c0, #0 ; Write Secondary Auxiliary Control Register + pop {r0} + bx lr + .endasmfunc + +;------------------------------------------------------------------------------- +; Work Around for Errata CORTEX-R4#66: +; +; Errata Description: +; Register Corruption During A Load-Multiple Instruction At +; an Exception Vector +; Workaround: +; Disable out-of-order completion for divide instructions in +; Auxiliary Control register + + .def _errata_CORTEXR4_66_ + .asmfunc + +_errata_CORTEXR4_66_ + + push {r0} + mrc p15, #0, r0, c1, c0, #1 ; Read Auxiliary Control register + orr r0, r0, #0x80 ; Set BIT 7 (Disable out-of-order completion + ; for divide instructions.) + mcr p15, #0, r0, c1, c0, #1 ; Write Auxiliary Control register + pop {r0} + bx lr + .endasmfunc + + .def turnon_VFP + .asmfunc +turnon_VFP + ; Enable FPV + STMDB sp!, {r0} + fmrx r0, fpexc + orr r0, r0, #0x40000000 + fmxr fpexc, r0 + LDMIA sp!, {r0} + subs pc, lr, #4 + .endasmfunc + +_push_svc_reg .macro + sub sp, sp, #17 * 4 ;/* Sizeof(struct rt_hw_exp_stack) */ + stmia sp, {r0 - r12} ;/* Calling r0-r12 */ + mov r0, sp + mrs r6, spsr ;/* Save CPSR */ + str lr, [r0, #15*4] ;/* Push PC */ + str r6, [r0, #16*4] ;/* Push CPSR */ + cps #0x13 + str sp, [r0, #13*4] ;/* Save calling SP */ + str lr, [r0, #14*4] ;/* Save calling PC */ + .endm + + .ref rt_hw_trap_svc + .def vector_svc + .asmfunc +vector_svc: + _push_svc_reg + bl rt_hw_trap_svc + sub pc, pc, #-4 + .endasmfunc + + .ref rt_hw_trap_pabt + .def vector_pabort + .asmfunc +vector_pabort: + _push_svc_reg + bl rt_hw_trap_pabt + sub pc, pc, #-4 + .endasmfunc + + .ref rt_hw_trap_dabt + .def vector_dabort + .asmfunc +vector_dabort: + _push_svc_reg + bl rt_hw_trap_dabt + sub pc, pc, #-4 + .endasmfunc + + .ref rt_hw_trap_resv + .def vector_resv + .asmfunc +vector_resv: + _push_svc_reg + bl rt_hw_trap_resv + sub pc, pc, #-4 + .endasmfunc + +;------------------------------------------------------------------------------- +; C++ construct table pointers + + .def __TI_PINIT_Base, __TI_PINIT_Limit + .weak SHT$$INIT_ARRAY$$Base, SHT$$INIT_ARRAY$$Limit + +__TI_PINIT_Base .long SHT$$INIT_ARRAY$$Base +__TI_PINIT_Limit .long SHT$$INIT_ARRAY$$Limit + +;------------------------------------------------------------------------------- diff --git a/rt-thread/libcpu/arm/cortex-r4/start_gcc.S b/rt-thread/libcpu/arm/cortex-r4/start_gcc.S new file mode 100644 index 0000000..1ed1e39 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/start_gcc.S @@ -0,0 +1,478 @@ +@------------------------------------------------------------------------------- +@ sys_core.asm +@ +@ (c) Texas Instruments 2009-2013, All rights reserved. +@ + +#include + +.equ Mode_USR, 0x10 +.equ Mode_FIQ, 0x11 +.equ Mode_IRQ, 0x12 +.equ Mode_SVC, 0x13 +.equ Mode_ABT, 0x17 +.equ Mode_UND, 0x1B +.equ Mode_SYS, 0x1F + +.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled +.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled + +.equ UND_Stack_Size, 0x00000000 +.equ SVC_Stack_Size, 0x00000000 +.equ ABT_Stack_Size, 0x00000000 +.equ FIQ_Stack_Size, 0x00001000 +.equ IRQ_Stack_Size, 0x00001000 + +.section .bss.noinit +/* stack */ +.globl stack_start +.globl stack_top + +stack_start: +.rept (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + FIQ_Stack_Size + IRQ_Stack_Size) +.byte 0 +.endr +stack_top: + +.section .text, "ax" + .text + .arm + + .globl _c_int00 + +.globl _reset +_reset: +@------------------------------------------------------------------------------- +@ Initialize CPU Registers +@ After reset, the CPU is in the Supervisor mode (M = 10011) + cpsid if, #19 + +#if defined (__VFP_FP__) && !defined(__SOFTFP__) && defined(RT_VFP_LAZY_STACKING) + @ Turn on FPV coprocessor + mrc p15, #0x00, r2, c1, c0, #0x02 + orr r2, r2, #0xF00000 + mcr p15, #0x00, r2, c1, c0, #0x02 + + fmrx r2, fpexc + orr r2, r2, #0x40000000 + fmxr fpexc, r2 +#endif + +@------------------------------------------------------------------------------- +@ Initialize Stack Pointers + ldr r0, =stack_top + + @ Set the startup stack for svc + mov sp, r0 + + @ Enter Undefined Instruction Mode and set its Stack Pointer + msr cpsr_c, #Mode_UND|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #UND_Stack_Size + + @ Enter Abort Mode and set its Stack Pointer + msr cpsr_c, #Mode_ABT|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #ABT_Stack_Size + + @ Enter FIQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #FIQ_Stack_Size + + @ Enter IRQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #IRQ_Stack_Size + + @ Switch back to SVC + msr cpsr_c, #Mode_SVC|I_Bit|F_Bit + + bl next1 +next1: + bl next2 +next2: + bl next3 +next3: + bl next4 +next4: + ldr lr, =_c_int00 + bx lr + +.globl data_init +data_init: + /* copy .data to SRAM */ + ldr r1, =_sidata /* .data start in image */ + ldr r2, =_edata /* .data end in image */ + ldr r3, =_sdata /* sram data start */ +data_loop: + ldr r0, [r1, #0] + str r0, [r3] + + add r1, r1, #4 + add r3, r3, #4 + + cmp r3, r2 /* check if data to clear */ + blo data_loop /* loop until done */ + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r3, ip, lr} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r3, ip, lr} + b ctor_loop +ctor_end: + bx lr + +@------------------------------------------------------------------------------- +@ Enable RAM ECC Support + + .globl _coreEnableRamEcc_ +_coreEnableRamEcc_: + + stmfd sp!, {r0} + mrc p15, #0x00, r0, c1, c0, #0x01 + orr r0, r0, #0x0C000000 + mcr p15, #0x00, r0, c1, c0, #0x01 + ldmfd sp!, {r0} + bx lr + +@------------------------------------------------------------------------------- +@ Disable RAM ECC Support + + .globl _coreDisableRamEcc_ +_coreDisableRamEcc_: + + stmfd sp!, {r0} + mrc p15, #0x00, r0, c1, c0, #0x01 + bic r0, r0, #0x0C000000 + mcr p15, #0x00, r0, c1, c0, #0x01 + ldmfd sp!, {r0} + bx lr + + +@------------------------------------------------------------------------------- +@ Enable Flash ECC Support + + .globl _coreEnableFlashEcc_ +_coreEnableFlashEcc_: + + stmfd sp!, {r0} + mrc p15, #0x00, r0, c1, c0, #0x01 + orr r0, r0, #0x02000000 + dmb + mcr p15, #0x00, r0, c1, c0, #0x01 + ldmfd sp!, {r0} + bx lr + +@------------------------------------------------------------------------------- +@ Disable Flash ECC Support + + .globl _coreDisableFlashEcc_ +_coreDisableFlashEcc_: + + stmfd sp!, {r0} + mrc p15, #0x00, r0, c1, c0, #0x01 + bic r0, r0, #0x02000000 + mcr p15, #0x00, r0, c1, c0, #0x01 + ldmfd sp!, {r0} + bx lr + + +@------------------------------------------------------------------------------- +@ Get data fault status register + + .globl _coreGetDataFault_ +_coreGetDataFault_: + + mrc p15, #0, r0, c5, c0, #0 + bx lr + + + +@------------------------------------------------------------------------------- +@ Clear data fault status register + + .globl _coreClearDataFault_ +_coreClearDataFault_: + + stmfd sp!, {r0} + mov r0, #0 + mcr p15, #0, r0, c5, c0, #0 + ldmfd sp!, {r0} + bx lr + + + +@------------------------------------------------------------------------------- +@ Get instruction fault status register + + .globl _coreGetInstructionFault_ +_coreGetInstructionFault_: + + mrc p15, #0, r0, c5, c0, #1 + bx lr + + + +@------------------------------------------------------------------------------- +@ Clear instruction fault status register + + .globl _coreClearInstructionFault_ +_coreClearInstructionFault_: + + stmfd sp!, {r0} + mov r0, #0 + mcr p15, #0, r0, c5, c0, #1 + ldmfd sp!, {r0} + bx lr + + + +@------------------------------------------------------------------------------- +@ Get data fault address register + + .globl _coreGetDataFaultAddress_ +_coreGetDataFaultAddress_: + + mrc p15, #0, r0, c6, c0, #0 + bx lr + + + +@------------------------------------------------------------------------------- +@ Clear data fault address register + + .globl _coreClearDataFaultAddress_ +_coreClearDataFaultAddress_: + + stmfd sp!, {r0} + mov r0, #0 + mcr p15, #0, r0, c6, c0, #0 + ldmfd sp!, {r0} + bx lr + + + +@------------------------------------------------------------------------------- +@ Get instruction fault address register + + .globl _coreGetInstructionFaultAddress_ +_coreGetInstructionFaultAddress_: + + mrc p15, #0, r0, c6, c0, #2 + bx lr + + + +@------------------------------------------------------------------------------- +@ Clear instruction fault address register + + .globl _coreClearInstructionFaultAddress_ +_coreClearInstructionFaultAddress_: + + stmfd sp!, {r0} + mov r0, #0 + mcr p15, #0, r0, c6, c0, #2 + ldmfd sp!, {r0} + bx lr + + + +@------------------------------------------------------------------------------- +@ Get auxiliary data fault status register + + .globl _coreGetAuxiliaryDataFault_ +_coreGetAuxiliaryDataFault_: + + mrc p15, #0, r0, c5, c1, #0 + bx lr + + + +@------------------------------------------------------------------------------- +@ Clear auxiliary data fault status register + + .globl _coreClearAuxiliaryDataFault_ +_coreClearAuxiliaryDataFault_: + + stmfd sp!, {r0} + mov r0, #0 + mcr p15, #0, r0, c5, c1, #0 + ldmfd sp!, {r0} + bx lr + + + +@------------------------------------------------------------------------------- +@ Get auxiliary instruction fault status register + + .globl _coreGetAuxiliaryInstructionFault_ +_coreGetAuxiliaryInstructionFault_: + + mrc p15, #0, r0, c5, c1, #1 + bx lr + + +@------------------------------------------------------------------------------- +@ Clear auxiliary instruction fault status register + + .globl _coreClearAuxiliaryInstructionFault_ +_coreClearAuxiliaryInstructionFault_: + + stmfd sp!, {r0} + mov r0, #0 + mrc p15, #0, r0, c5, c1, #1 + ldmfd sp!, {r0} + bx lr + + +@------------------------------------------------------------------------------- +@ Clear ESM CCM errorss + + .globl _esmCcmErrorsClear_ +_esmCcmErrorsClear_: + + stmfd sp!, {r0-r2} + ldr r0, ESMSR1_REG @ load the ESMSR1 status register address + ldr r2, ESMSR1_ERR_CLR + str r2, [r0] @ clear the ESMSR1 register + + ldr r0, ESMSR2_REG @ load the ESMSR2 status register address + ldr r2, ESMSR2_ERR_CLR + str r2, [r0] @ clear the ESMSR2 register + + ldr r0, ESMSSR2_REG @ load the ESMSSR2 status register address + ldr r2, ESMSSR2_ERR_CLR + str r2, [r0] @ clear the ESMSSR2 register + + ldr r0, ESMKEY_REG @ load the ESMKEY register address + mov r2, #0x5 @ load R2 with 0x5 + str r2, [r0] @ clear the ESMKEY register + + ldr r0, VIM_INTREQ @ load the INTREQ register address + ldr r2, VIM_INT_CLR + str r2, [r0] @ clear the INTREQ register + ldr r0, CCMR4_STAT_REG @ load the CCMR4 status register address + ldr r2, CCMR4_ERR_CLR + str r2, [r0] @ clear the CCMR4 status register + ldmfd sp!, {r0-r2} + bx lr + +ESMSR1_REG: .word 0xFFFFF518 +ESMSR2_REG: .word 0xFFFFF51C +ESMSR3_REG: .word 0xFFFFF520 +ESMKEY_REG: .word 0xFFFFF538 +ESMSSR2_REG: .word 0xFFFFF53C +CCMR4_STAT_REG: .word 0xFFFFF600 +ERR_CLR_WRD: .word 0xFFFFFFFF +CCMR4_ERR_CLR: .word 0x00010000 +ESMSR1_ERR_CLR: .word 0x80000000 +ESMSR2_ERR_CLR: .word 0x00000004 +ESMSSR2_ERR_CLR: .word 0x00000004 +VIM_INT_CLR: .word 0x00000001 +VIM_INTREQ: .word 0xFFFFFE20 + + +@------------------------------------------------------------------------------- +@ Work Around for Errata CORTEX-R4#57: +@ +@ Errata Description: +@ Conditional VMRS APSR_Nzcv, FPSCR May Evaluate With Incorrect Flags +@ Workaround: +@ Disable out-of-order single-precision floating point +@ multiply-accumulate instruction completion + + .globl _errata_CORTEXR4_57_ +_errata_CORTEXR4_57_: + + push {r0} + mrc p15, #0, r0, c15, c0, #0 @ Read Secondary Auxiliary Control Register + orr r0, r0, #0x10000 @ Set BIT 16 (Set DOOFMACS) + mcr p15, #0, r0, c15, c0, #0 @ Write Secondary Auxiliary Control Register + pop {r0} + bx lr + +@------------------------------------------------------------------------------- +@ Work Around for Errata CORTEX-R4#66: +@ +@ Errata Description: +@ Register Corruption During A Load-Multiple Instruction At +@ an Exception Vector +@ Workaround: +@ Disable out-of-order completion for divide instructions in +@ Auxiliary Control register + + .globl _errata_CORTEXR4_66_ +_errata_CORTEXR4_66_: + + push {r0} + mrc p15, #0, r0, c1, c0, #1 @ Read Auxiliary Control register + orr r0, r0, #0x80 @ Set BIT 7 (Disable out-of-order completion + @ for divide instructions.) + mcr p15, #0, r0, c1, c0, #1 @ Write Auxiliary Control register + pop {r0} + bx lr + + .globl turnon_VFP +turnon_VFP: + @ Enable FPV + STMDB sp!, {r0} + fmrx r0, fpexc + orr r0, r0, #0x40000000 + fmxr fpexc, r0 + LDMIA sp!, {r0} + subs pc, lr, #4 + + .macro push_svc_reg + sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */ + stmia sp, {r0 - r12} @/* Calling r0-r12 */ + mov r0, sp + mrs r6, spsr @/* Save CPSR */ + str lr, [r0, #15*4] @/* Push PC */ + str r6, [r0, #16*4] @/* Push CPSR */ + cps #Mode_SVC + str sp, [r0, #13*4] @/* Save calling SP */ + str lr, [r0, #14*4] @/* Save calling PC */ + .endm + + .globl vector_svc +vector_svc: + push_svc_reg + bl rt_hw_trap_svc + b . + + .globl vector_pabort +vector_pabort: + push_svc_reg + bl rt_hw_trap_pabt + b . + + .globl vector_dabort +vector_dabort: + push_svc_reg + bl rt_hw_trap_dabt + b . + + .globl vector_resv +vector_resv: + push_svc_reg + bl rt_hw_trap_resv + b . diff --git a/rt-thread/libcpu/arm/cortex-r4/trap.c b/rt-thread/libcpu/arm/cortex-r4/trap.c new file mode 100644 index 0000000..b72237d --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/trap.c @@ -0,0 +1,152 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + * 2013-05-24 Grissiom port to RM48x50 + */ + +#include +#include + +#include + +#include "armv7.h" + +/** + * @addtogroup RM48x50 + */ +/*@{*/ + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ +void rt_hw_show_register (struct rt_hw_exp_stack *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_udef(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("undefined instruction\n"); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_svc(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("software interrupt\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("prefetch abort\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("Data Abort "); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("Reserved trap\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +extern rt_isr_handler_t isr_table[]; +void rt_hw_trap_irq(void) +{ + int irqno; + struct rt_irq_desc* irq; + extern struct rt_irq_desc irq_desc[]; + + irq = (struct rt_irq_desc*) vimREG->IRQVECREG; + irqno = ((rt_uint32_t) irq - (rt_uint32_t) &irq_desc[0])/sizeof(struct rt_irq_desc); + + /* invoke isr */ + irq->handler(irqno, irq->param); +} + +void rt_hw_trap_fiq(void) +{ + rt_kprintf("fast interrupt request\n"); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/cortex-r4/vector_ccs.asm b/rt-thread/libcpu/arm/cortex-r4/vector_ccs.asm new file mode 100644 index 0000000..df2bcec --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/vector_ccs.asm @@ -0,0 +1,34 @@ +;------------------------------------------------------------------------------- +; sys_intvecs.asm +; +; (c) Texas Instruments 2009-2013, All rights reserved. +; + + .sect ".intvecs" + .arm + +;------------------------------------------------------------------------------- +; import reference for interrupt routines + + .ref _reset + .ref turnon_VFP + .ref vector_svc + .ref vector_pabort + .ref vector_dabort + .ref vector_resv + .ref IRQ_Handler + +;------------------------------------------------------------------------------- +; interrupt vectors + .def resetEntry +resetEntry + b _reset + b turnon_VFP + b vector_svc + b vector_pabort + b vector_dabort + b vector_resv + b IRQ_Handler + ldr pc,[pc,#-0x1b0] + +;------------------------------------------------------------------------------- diff --git a/rt-thread/libcpu/arm/cortex-r4/vector_gcc.S b/rt-thread/libcpu/arm/cortex-r4/vector_gcc.S new file mode 100644 index 0000000..da91421 --- /dev/null +++ b/rt-thread/libcpu/arm/cortex-r4/vector_gcc.S @@ -0,0 +1,31 @@ +@------------------------------------------------------------------------------- +@ sys_intvecs.asm +@ +@ (c) Texas Instruments 2009-2013, All rights reserved. +@ + +.section .vectors, "ax" +.code 32 + +@------------------------------------------------------------------------------- +@ import reference for interrupt routines + + .globl _reset + .globl turnon_VFP + .globl vector_svc + .globl vector_pabort + .globl vector_dabort + .globl vector_resv + .globl IRQ_Handler + + +.globl system_vectors +system_vectors: + b _reset + b turnon_VFP + b vector_svc + b vector_pabort + b vector_dabort + b vector_resv + b IRQ_Handler + ldr pc,[pc,#-0x1b0] diff --git a/rt-thread/libcpu/arm/dm36x/context_gcc.S b/rt-thread/libcpu/arm/dm36x/context_gcc.S new file mode 100644 index 0000000..cfada09 --- /dev/null +++ b/rt-thread/libcpu/arm/dm36x/context_gcc.S @@ -0,0 +1,109 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-01-13 weety + */ + +/*! + * \addtogroup DM36X + */ +/*@{*/ + +#define NOINT 0xc0 + + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + orr r1, r0, #NOINT + msr cpsr_c, r1 + bx lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + bx lr + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + tst lr, #0x01 + orrne r4, r4, #0x20 @ it's thumb code + + stmfd sp!, {r4} @ push cpsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task cpsr to spsr + msr spsr_cxsf, r4 +_do_switch: + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + + bic r4, r4, #0x20 @ must be ARM mode + msr cpsr_cxsf, r4 + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 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] + bx lr diff --git a/rt-thread/libcpu/arm/dm36x/context_rvds.S b/rt-thread/libcpu/arm/dm36x/context_rvds.S new file mode 100644 index 0000000..631da83 --- /dev/null +++ b/rt-thread/libcpu/arm/dm36x/context_rvds.S @@ -0,0 +1,117 @@ +;/* +; * File : context_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; * 2011-08-14 weety copy from mini2440 +; */ + +NOINT EQU 0xc0 ; disable interrupt in psr + + AREA |.text|, CODE, READONLY, ALIGN=2 + ARM + REQUIRE8 + PRESERVE8 + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ +rt_hw_interrupt_disable PROC + EXPORT rt_hw_interrupt_disable + MRS r0, cpsr + ORR r1, r0, #NOINT + MSR cpsr_c, r1 + BX lr + ENDP + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ +rt_hw_interrupt_enable PROC + EXPORT rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + ENDP + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ +rt_hw_context_switch PROC + EXPORT rt_hw_context_switch + STMFD sp!, {lr} ; push pc (lr should be pushed in place of PC) + STMFD sp!, {r0-r12, lr} ; push lr & register file + + MRS r4, cpsr + STMFD sp!, {r4} ; push cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push spsr + + STR sp, [r0] ; store sp in preempted tasks TCB + LDR sp, [r1] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR spsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ +rt_hw_context_switch_to PROC + EXPORT rt_hw_context_switch_to + LDR sp, [r0] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +rt_hw_context_switch_interrupt PROC + EXPORT rt_hw_context_switch_interrupt + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 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] + BX lr + ENDP + + END diff --git a/rt-thread/libcpu/arm/dm36x/cpuport.c b/rt-thread/libcpu/arm/dm36x/cpuport.c new file mode 100644 index 0000000..bf012b1 --- /dev/null +++ b/rt-thread/libcpu/arm/dm36x/cpuport.c @@ -0,0 +1,246 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-01-13 weety first version + */ + +#include +#include + +#define ICACHE_MASK (rt_uint32_t)(1 << 12) +#define DCACHE_MASK (rt_uint32_t)(1 << 2) + +extern void machine_reset(void); +extern void machine_shutdown(void); + +#ifdef __GNUC__ +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + __asm__ __volatile__( \ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "orr r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + __asm__ __volatile__( \ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "bic r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} +#endif + +#ifdef __CC_ARM +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + __asm + { + mrc p15, 0, i, c1, c0, 0 + } + + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} +#endif + +/** + * enable I-Cache + * + */ +void rt_hw_cpu_icache_enable() +{ + cache_enable(ICACHE_MASK); +} + +/** + * disable I-Cache + * + */ +void rt_hw_cpu_icache_disable() +{ + cache_disable(ICACHE_MASK); +} + +/** + * return the status of I-Cache + * + */ +rt_base_t rt_hw_cpu_icache_status() +{ + return (cp15_rd() & ICACHE_MASK); +} + +/** + * enable D-Cache + * + */ +void rt_hw_cpu_dcache_enable() +{ + cache_enable(DCACHE_MASK); +} + +/** + * disable D-Cache + * + */ +void rt_hw_cpu_dcache_disable() +{ + cache_disable(DCACHE_MASK); +} + +/** + * return the status of D-Cache + * + */ +rt_base_t rt_hw_cpu_dcache_status() +{ + return (cp15_rd() & DCACHE_MASK); +} + +/** + * reset cpu by dog's time-out + * + */ +void rt_hw_cpu_reset() +{ + + rt_kprintf("Restarting system...\n"); + machine_reset(); + + while(1); /* loop forever and wait for reset to happen */ + + /* NEVER REACHED */ +} + +/** + * shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + machine_shutdown(); + while (level) + { + RT_ASSERT(0); + } +} + +#ifdef RT_USING_CPU_FFS +/** + * This function finds the first bit set (beginning with the least significant bit) + * in value and return the index of that bit. + * + * Bits are numbered starting at 1 (the least significant bit). A return value of + * zero from any of these functions means that the argument was zero. + * + * @return return the index of the first bit set. If value is 0, then this function + * shall return 0. + */ +#if defined(__CC_ARM) +int __rt_ffs(int value) +{ + register rt_uint32_t x; + + if (value == 0) + return value; + + __asm + { + rsb x, value, #0 + and x, x, value + clz x, x + rsb x, x, #32 + } + + return x; +} +#elif defined(__IAR_SYSTEMS_ICC__) +int __rt_ffs(int value) +{ + if (value == 0) + return value; + + __ASM("RSB r4, r0, #0"); + __ASM("AND r4, r4, r0"); + __ASM("CLZ r4, r4"); + __ASM("RSB r0, r4, #32"); +} +#elif defined(__GNUC__) +int __rt_ffs(int value) +{ + if (value == 0) + return value; + + value &= (-value); + asm ("clz %0, %1": "=r"(value) :"r"(value)); + + return (32 - value); +} +#endif + +#endif + + +/*@}*/ diff --git a/rt-thread/libcpu/arm/dm36x/mmu.c b/rt-thread/libcpu/arm/dm36x/mmu.c new file mode 100644 index 0000000..8c31006 --- /dev/null +++ b/rt-thread/libcpu/arm/dm36x/mmu.c @@ -0,0 +1,560 @@ +/* + * File : mmu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +#include "mmu.h" + +#ifdef __CC_ARM +void mmu_setttbase(rt_uint32_t i) +{ + register rt_uint32_t value; + + /* Invalidates all TLBs.Domain access is selected as + * client by configuring domain access register, + * in that case access controlled by permission value + * set by page table entry + */ + value = 0; + __asm volatile + { + mcr p15, 0, value, c8, c7, 0 + } + + value = 0x55555555; + __asm volatile + { + mcr p15, 0, value, c3, c0, 0 + mcr p15, 0, i, c2, c0, 0 + } +} + +void mmu_set_domain(rt_uint32_t i) +{ + __asm volatile + { + mcr p15,0, i, c3, c0, 0 + } +} + +void mmu_enable() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x01 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x01 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_icache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x1000 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_dcache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x04 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_icache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x1000 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_dcache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x04 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_alignfault() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x02 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_alignfault() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x02 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_clean_invalidated_cache_index(int index) +{ + __asm volatile + { + mcr p15, 0, index, c7, c14, 2 + } +} + +void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while(ptr < buffer + size) + { + __asm volatile + { + MCR p15, 0, ptr, c7, c14, 1 + } + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + __asm volatile + { + MCR p15, 0, ptr, c7, c10, 1 + } + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + __asm volatile + { + MCR p15, 0, ptr, c7, c6, 1 + } + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_tlb() +{ + register rt_uint32_t value; + + value = 0; + __asm volatile + { + mcr p15, 0, value, c8, c7, 0 + } +} + +void mmu_invalidate_icache() +{ + register rt_uint32_t value; + + value = 0; + + __asm volatile + { + mcr p15, 0, value, c7, c5, 0 + } +} + + +void mmu_invalidate_dcache_all() +{ + register rt_uint32_t value; + + value = 0; + + __asm volatile + { + mcr p15, 0, value, c7, c6, 0 + } +} +#elif defined(__GNUC__) +void mmu_setttbase(register rt_uint32_t i) +{ + register rt_uint32_t value; + + /* Invalidates all TLBs.Domain access is selected as + * client by configuring domain access register, + * in that case access controlled by permission value + * set by page table entry + */ + value = 0; + asm volatile ("mcr p15, 0, %0, c8, c7, 0"::"r"(value)); + + value = 0x55555555; + asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(value)); + asm volatile ("mcr p15, 0, %0, c2, c0, 0"::"r"(i)); +} + +void mmu_set_domain(register rt_uint32_t i) +{ + asm volatile ("mcr p15,0, %0, c3, c0, 0": :"r" (i)); +} + +void mmu_enable() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= 0x1; + i |= (1 << 13); /* High exception vectors selected, address range = 0xFFFF0000-0xFFFF001C */ + /* S R bit=1 0 for system protection */ + i |= (1 << 8); + i &= ~(1 << 9); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~0x1; + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_enable_icache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= (1 << 12); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_enable_dcache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= (1 << 2); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable_icache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~(1 << 12); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable_dcache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~(1 << 2); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_enable_alignfault() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= (1 << 1); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable_alignfault() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~(1 << 1); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_clean_invalidated_cache_index(int index) +{ + asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index)); +} + +void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while(ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c14, 1": :"r" (ptr)); + ptr += CACHE_LINE_SIZE; + } +} + + +void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr)); + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size) +{ + unsigned int ptr; + + ptr = buffer & ~(CACHE_LINE_SIZE - 1); + + while (ptr < buffer + size) + { + asm volatile ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr)); + ptr += CACHE_LINE_SIZE; + } +} + +void mmu_invalidate_tlb() +{ + asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0)); +} + +void mmu_invalidate_icache() +{ + asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0)); +} + +void mmu_invalidate_dcache_all() +{ + asm volatile ("mcr p15, 0, %0, c7, c6, 0": :"r" (0)); +} +#endif + +/* level1 page table */ +static volatile unsigned int _pgd_table[4*1024] ALIGN(16*1024); +/* + * level2 page table + * RT_MMU_PTE_SIZE must be 1024*n + */ +static volatile unsigned int _pte_table[RT_MMU_PTE_SIZE] ALIGN(1*1024); + +void mmu_create_pgd(struct mem_desc *mdesc) +{ + volatile rt_uint32_t *pTT; + volatile int i, nSec; + pTT = (rt_uint32_t *)_pgd_table + (mdesc->vaddr_start >> 20); + nSec = (mdesc->vaddr_end >> 20) - (mdesc->vaddr_start >> 20); + for(i = 0; i <= nSec; i++) + { + *pTT = mdesc->sect_attr | (((mdesc->paddr_start >> 20) + i) << 20); + pTT++; + } +} + +void mmu_create_pte(struct mem_desc *mdesc) +{ + volatile rt_uint32_t *pTT; + volatile rt_uint32_t *p_pteentry; + int i; + rt_uint32_t vaddr; + rt_uint32_t total_page = 0; + rt_uint32_t pte_offset = 0; + rt_uint32_t sect_attr = 0; + + total_page = (mdesc->vaddr_end >> 12) - (mdesc->vaddr_start >> 12) + 1; + pte_offset = mdesc->sect_attr & 0xfffffc00; + sect_attr = mdesc->sect_attr & 0x3ff; + vaddr = mdesc->vaddr_start; + + for(i = 0; i < total_page; i++) + { + pTT = (rt_uint32_t *)_pgd_table + (vaddr >> 20); + if (*pTT == 0) /* Level 1 page table item not used, now update pgd item */ + { + *pTT = pte_offset | sect_attr; + p_pteentry = (rt_uint32_t *)pte_offset + + ((vaddr & 0x000ff000) >> 12); + pte_offset += 1024; + } + else /* using old Level 1 page table item */ + { + p_pteentry = (rt_uint32_t *)(*pTT & 0xfffffc00) + + ((vaddr & 0x000ff000) >> 12); + } + + + *p_pteentry = mdesc->page_attr | (((mdesc->paddr_start >> 12) + i) << 12); + vaddr += 0x1000; + } +} + +static void build_pte_mem_desc(struct mem_desc *mdesc, rt_uint32_t size) +{ + rt_uint32_t pte_offset = 0; + rt_uint32_t nsec = 0; + /* set page table */ + for (; size > 0; size--) + { + if (mdesc->mapped_mode == PAGE_MAPPED) + { + nsec = (RT_ALIGN(mdesc->vaddr_end, 0x100000) - RT_ALIGN_DOWN(mdesc->vaddr_start, 0x100000)) >> 20; + mdesc->sect_attr |= (((rt_uint32_t)_pte_table)& 0xfffffc00) + pte_offset; + pte_offset += nsec << 10; + } + if (pte_offset >= RT_MMU_PTE_SIZE) + { + rt_kprintf("PTE table size too little\n"); + RT_ASSERT(0); + } + + mdesc++; + } +} + +void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size) +{ + /* disable I/D cache */ + mmu_disable_dcache(); + mmu_disable_icache(); + mmu_disable(); + mmu_invalidate_tlb(); + + /* clear pgd and pte table */ + rt_memset((void *)_pgd_table, 0, 16*1024); + rt_memset((void *)_pte_table, 0, RT_MMU_PTE_SIZE); + build_pte_mem_desc(mdesc, size); + /* set page table */ + for (; size > 0; size--) + { + if (mdesc->mapped_mode == SECT_MAPPED) + { + mmu_create_pgd(mdesc); + } + else + { + mmu_create_pte(mdesc); + } + + mdesc++; + } + + /* set MMU table address */ + mmu_setttbase((rt_uint32_t)_pgd_table); + + /* enables MMU */ + mmu_enable(); + + /* enable Instruction Cache */ + mmu_enable_icache(); + + /* enable Data Cache */ + mmu_enable_dcache(); + + mmu_invalidate_icache(); + mmu_invalidate_dcache_all(); +} + diff --git a/rt-thread/libcpu/arm/dm36x/mmu.h b/rt-thread/libcpu/arm/dm36x/mmu.h new file mode 100644 index 0000000..9dd802c --- /dev/null +++ b/rt-thread/libcpu/arm/dm36x/mmu.h @@ -0,0 +1,164 @@ +/* + * File : mmu.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + */ + +#ifndef __MMU_H__ +#define __MMU_H__ + +#include + +#define CACHE_LINE_SIZE 32 + +/* + * Hardware page table definitions. + * + * + Level 1 descriptor (PGD) + * - common + */ +#define PGD_TYPE_MASK (3 << 0) +#define PGD_TYPE_FAULT (0 << 0) +#define PGD_TYPE_TABLE (1 << 0) +#define PGD_TYPE_SECT (2 << 0) +#define PGD_BIT4 (1 << 4) +#define PGD_DOMAIN(x) ((x) << 5) +#define PGD_PROTECTION (1 << 9) /* ARMv5 */ +/* + * - section + */ +#define PGD_SECT_BUFFERABLE (1 << 2) +#define PGD_SECT_CACHEABLE (1 << 3) +#define PGD_SECT_XN (1 << 4) /* ARMv6 */ +#define PGD_SECT_AP0 (1 << 10) +#define PGD_SECT_AP1 (1 << 11) +#define PGD_SECT_TEX(x) ((x) << 12) /* ARMv5 */ +#define PGD_SECT_APX (1 << 15) /* ARMv6 */ +#define PGD_SECT_S (1 << 16) /* ARMv6 */ +#define PGD_SECT_nG (1 << 17) /* ARMv6 */ +#define PGD_SECT_SUPER (1 << 18) /* ARMv6 */ + +#define PGD_SECT_UNCACHED (0) +#define PGD_SECT_BUFFERED (PGD_SECT_BUFFERABLE) +#define PGD_SECT_WT (PGD_SECT_CACHEABLE) +#define PGD_SECT_WB (PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE) +#define PGD_SECT_MINICACHE (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE) +#define PGD_SECT_WBWA (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE) +#define PGD_SECT_NONSHARED_DEV (PGD_SECT_TEX(2)) + + +/* + * + Level 2 descriptor (PTE) + * - common + */ +#define PTE_TYPE_MASK (3 << 0) +#define PTE_TYPE_FAULT (0 << 0) +#define PTE_TYPE_LARGE (1 << 0) +#define PTE_TYPE_SMALL (2 << 0) +#define PTE_TYPE_EXT (3 << 0) /* ARMv5 */ +#define PTE_BUFFERABLE (1 << 2) +#define PTE_CACHEABLE (1 << 3) + +/* + * - extended small page/tiny page + */ +#define PTE_EXT_XN (1 << 0) /* ARMv6 */ +#define PTE_EXT_AP_MASK (3 << 4) +#define PTE_EXT_AP0 (1 << 4) +#define PTE_EXT_AP1 (2 << 4) +#define PTE_EXT_AP_UNO_SRO (0 << 4) +#define PTE_EXT_AP_UNO_SRW (PTE_EXT_AP0) +#define PTE_EXT_AP_URO_SRW (PTE_EXT_AP1) +#define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0) +#define PTE_EXT_TEX(x) ((x) << 6) /* ARMv5 */ +#define PTE_EXT_APX (1 << 9) /* ARMv6 */ +#define PTE_EXT_SHARED (1 << 10) /* ARMv6 */ +#define PTE_EXT_NG (1 << 11) /* ARMv6 */ + +/* + * - small page + */ +#define PTE_SMALL_AP_MASK (0xff << 4) +#define PTE_SMALL_AP_UNO_SRO (0x00 << 4) +#define PTE_SMALL_AP_UNO_SRW (0x55 << 4) +#define PTE_SMALL_AP_URO_SRW (0xaa << 4) +#define PTE_SMALL_AP_URW_SRW (0xff << 4) + +/* + * sector table properities + */ +#define SECT_CB (PGD_SECT_CACHEABLE|PGD_SECT_BUFFERABLE) //cache_on, write_back +#define SECT_CNB (PGD_SECT_CACHEABLE) //cache_on, write_through +#define SECT_NCB (PGD_SECT_BUFFERABLE) //cache_off,WR_BUF on +#define SECT_NCNB (0 << 2) //cache_off,WR_BUF off + +#define SECT_AP_RW (PGD_SECT_AP0|PGD_SECT_AP1) //supervisor=RW, user=RW +#define SECT_AP_RO ((0 << 10)|(0 << 11)) //supervisor=RO, user=NO Access(SR=10) + +#define SECT_RW_CB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_BIT4) /* Read/Write, cache, write back */ +#define SECT_RW_CNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_BIT4) /* Read/Write, cache, write through */ +#define SECT_RW_NCNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_BIT4) /* Read/Write without cache and write buffer */ +#define SECT_RW_FAULT (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_BIT4) /* Read/Write without cache and write buffer */ + +#define SECT_RO_CB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_BIT4) /* Read Only, cache, write back */ +#define SECT_RO_CNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_BIT4) /* Read Only, cache, write through */ +#define SECT_RO_NCNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_BIT4) /* Read Only without cache and write buffer */ +#define SECT_RO_FAULT (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_BIT4) /* Read Only without cache and write buffer */ + +#define SECT_TO_PAGE (PGD_DOMAIN(0)|PGD_TYPE_TABLE|PGD_BIT4) /* Level 2 descriptor (PTE) entry properity */ + +/* + * page table properities + */ +#define PAGE_CB (PTE_BUFFERABLE|PTE_CACHEABLE) //cache_on, write_back +#define PAGE_CNB (PTE_CACHEABLE) //cache_on, write_through +#define PAGE_NCB (PTE_BUFFERABLE) //cache_off,WR_BUF on +#define PAGE_NCNB (0 << 2) //cache_off,WR_BUF off + +#define PAGE_AP_RW PTE_SMALL_AP_URW_SRW //supervisor=RW, user=RW +#define PAGE_AP_RO PTE_SMALL_AP_UNO_SRO //supervisor=RO, user=NO Access(SR=10) + +#define PAGE_RW_CB (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL) /* Read/Write, cache, write back */ +#define PAGE_RW_CNB (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL) /* Read/Write, cache, write through */ +#define PAGE_RW_NCNB (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write without cache and write buffer */ +#define PAGE_RW_FAULT (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write without cache and write buffer */ + + +#define PAGE_RO_CB (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL) /* Read Only, cache, write back */ +#define PAGE_RO_CNB (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL) /* Read Only, cache, write through */ +#define PAGE_RO_NCNB (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only without cache and write buffer */ +#define PAGE_RO_FAULT (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only without cache and write buffer */ + +struct mem_desc { + rt_uint32_t vaddr_start; + rt_uint32_t vaddr_end; + rt_uint32_t paddr_start; + rt_uint32_t sect_attr; /* when page mapped */ + rt_uint32_t page_attr; /* only sector mapped valid */ + rt_uint32_t mapped_mode; + #define SECT_MAPPED 0 + #define PAGE_MAPPED 1 +}; + + +void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size); + +#endif + diff --git a/rt-thread/libcpu/arm/dm36x/stack.c b/rt-thread/libcpu/arm/dm36x/stack.c new file mode 100644 index 0000000..fd56e7a --- /dev/null +++ b/rt-thread/libcpu/arm/dm36x/stack.c @@ -0,0 +1,81 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2011-01-13 weety + */ +#include + +/*****************************/ +/* CPU Mode */ +/*****************************/ +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define ABORTMODE 0x17 +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + diff --git a/rt-thread/libcpu/arm/lpc214x/context_gcc.S b/rt-thread/libcpu/arm/lpc214x/context_gcc.S new file mode 100644 index 0000000..0a4b1ce --- /dev/null +++ b/rt-thread/libcpu/arm/lpc214x/context_gcc.S @@ -0,0 +1,102 @@ +.global rt_hw_interrupt_disable +.global rt_hw_interrupt_enable +.global rt_hw_context_switch +.global rt_hw_context_switch_to +.global rt_hw_context_switch_interrupt + +.equ NOINT, 0xc0 + +/* + * rt_base_t rt_hw_interrupt_disable(); + ¹Ø±ÕÖжϣ¬¹Ø±Õǰ·µ»ØCPSR¼Ä´æÆ÷Öµ + */ +rt_hw_interrupt_disable: + //EXPORT rt_hw_interrupt_disable + MRS r0, cpsr + ORR r1, r0, #NOINT + MSR cpsr_c, r1 + BX lr + //ENDP + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + »Ö¸´ÖжÏ״̬ + */ +rt_hw_interrupt_enable: + //EXPORT rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + //ENDP + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + ½øÐÐÏ̵߳ÄÉÏÏÂÎÄÇл» + */ +rt_hw_context_switch: + //EXPORT rt_hw_context_switch + STMFD sp!, {lr} /* push pc (lr should be pushed in place of PC) */ + /* °ÑLR¼Ä´æÆ÷ѹÈëÕ»£¨Õâ¸öº¯Êý·µ»ØºóµÄÏÂÒ»¸öÖ´Ðд¦£© */ + STMFD sp!, {r0-r12, lr} /* push lr & register file */ + /* °ÑR0 ¨C R12ÒÔ¼°LRѹÈëÕ» */ + + MRS r4, cpsr /* ¶ÁÈ¡CPSR¼Ä´æÆ÷µ½R4¼Ä´æÆ÷ */ + STMFD sp!, {r4} /* push cpsr */ + /* °ÑR4¼Ä´æÆ÷ѹջ£¨¼´ÉÏÒ»Ö¸ÁîÈ¡³öµÄCPSR¼Ä´æÆ÷£© */ + MRS r4, spsr /* ¶ÁÈ¡SPSR¼Ä´æÆ÷µ½R4¼Ä´æÆ÷ */ + STMFD sp!, {r4} /* push spsr */ + /* °ÑR4¼Ä´æÆ÷ѹջ£¨¼´SPSR¼Ä´æÆ÷£© */ + + STR sp, [r0] /* store sp in preempted tasks TCB */ + /* °ÑÕ»Ö¸Õë¸üе½TCBµÄsp£¬ÊÇÓÉR0´«Èë´Ëº¯Êý */ + /* µ½ÕâÀï»»³öÏ̵߳ÄÉÏÏÂÎͼ±£´æÔÚÕ»ÖÐ */ + LDR sp, [r1] /* get new task stack pointer */ + /* ÔØÈëÇл»µ½Ï̵߳ÄTCBµÄsp */ + /* ´ÓÇл»µ½Ï̵߳ÄÕ»Öлָ´ÉÏÏÂÎÄ£¬´ÎÐòºÍ±£´æµÄʱºò¸ÕºÃÏà·´ */ + + LDMFD sp!, {r4} /* pop new task spsr */ + /* ³öÕ»µ½R4¼Ä´æÆ÷£¨±£´æÁËSPSR¼Ä´æÆ÷£© */ + MSR spsr_cxsf, r4 /* »Ö¸´SPSR¼Ä´æÆ÷ */ + LDMFD sp!, {r4} /* pop new task cpsr */ + /* ³öÕ»µ½R4¼Ä´æÆ÷£¨±£´æÁËCPSR¼Ä´æÆ÷£© */ + MSR cpsr_cxsf, r4 /* »Ö¸´CPSR¼Ä´æÆ÷ */ + + LDMFD sp!, {r0-r12, lr, pc} /* pop new task r0-r12, lr & pc */ + /* ¶ÔR0 ¨C R12¼°LR¡¢PC½øÐлָ´ */ + //ENDP + +rt_hw_context_switch_to: + //EXPORT rt_hw_context_switch_to + LDR sp, [r0] /* get new task stack pointer */ + /* »ñµÃÇл»µ½Ï̵߳ÄSPÖ¸Õë */ + + LDMFD sp!, {r4} /* pop new task spsr */ + /* ³öÕ»R4¼Ä´æÆ÷£¨±£´æÁËSPSR¼Ä´æÆ÷Öµ£© */ + MSR spsr_cxsf, r4 /* »Ö¸´SPSR¼Ä´æÆ÷ */ + LDMFD sp!, {r4} /* pop new task cpsr */ + /* ³öÕ»R4¼Ä´æÆ÷£¨±£´æÁËCPSR¼Ä´æÆ÷Öµ£© */ + MSR cpsr_cxsf, r4 /* »Ö¸´CPSR¼Ä´æÆ÷ */ + + LDMFD sp!, {r0-r12, lr, pc} /* pop new task r0-r12, lr & pc */ + /* »Ö¸´R0 ¨C R12£¬LR¼°PC¼Ä´æÆ÷ */ + //ENDP + +rt_hw_context_switch_interrupt: + //EXPORT rt_hw_context_switch_interrupt + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] /* ÔØÈëÖжÏÖÐÇл»±êÖµØÖ· */ + CMP r3, #1 /* µÈÓÚ 1 £¿*/ + BEQ _reswitch /* Èç¹ûµÈÓÚ1£¬Ìø×ªµ½_reswitch*/ + MOV r3, #1 /* set rt_thread_switch_interrupt_flag to 1*/ + /* ÉèÖÃÖжÏÖÐÇл»±ê־λ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] /* ±£´æÇл»µ½Ïß³ÌÕ»Ö¸Õë*/ + BX lr + //ENDP + + //END \ No newline at end of file diff --git a/rt-thread/libcpu/arm/lpc214x/context_rvds.S b/rt-thread/libcpu/arm/lpc214x/context_rvds.S new file mode 100644 index 0000000..762b67d --- /dev/null +++ b/rt-thread/libcpu/arm/lpc214x/context_rvds.S @@ -0,0 +1,164 @@ +;/* +; * File : context_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, 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-20 Bernard first version +; * 2011-07-22 Bernard added thumb mode porting +; */ + +Mode_USR EQU 0x10 +Mode_FIQ EQU 0x11 +Mode_IRQ EQU 0x12 +Mode_SVC EQU 0x13 +Mode_ABT EQU 0x17 +Mode_UND EQU 0x1B +Mode_SYS EQU 0x1F + +I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled +F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled + +NOINT EQU 0xc0 ; disable interrupt in psr + + AREA |.text|, CODE, READONLY, ALIGN=2 + ARM + REQUIRE8 + PRESERVE8 + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ +rt_hw_interrupt_disable PROC + EXPORT rt_hw_interrupt_disable + MRS r0, cpsr + ORR r1, r0, #NOINT + MSR cpsr_c, r1 + BX lr + ENDP + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ +rt_hw_interrupt_enable PROC + EXPORT rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + ENDP + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ +rt_hw_context_switch PROC + EXPORT rt_hw_context_switch + STMFD sp!, {lr} ; push pc (lr should be pushed in place of PC) + STMFD sp!, {r0-r12, lr} ; push lr & register file + + MRS r4, cpsr + TST lr, #0x01 + BEQ _ARM_MODE + ORR r4, r4, #0x20 ; it's thumb code +_ARM_MODE + STMFD sp!, {r4} ; push cpsr + + STR sp, [r0] ; store sp in preempted tasks TCB + LDR sp, [r1] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task cpsr to spsr + MSR spsr_cxsf, r4 + BIC r4, r4, #0x20 ; must be ARM mode + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr + ENDP + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ +rt_hw_context_switch_to PROC + EXPORT rt_hw_context_switch_to + LDR sp, [r0] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task cpsr to spsr + MSR spsr_cxsf, r4 + BIC r4, r4, #0x20 ; must be ARM mode + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr + ENDP + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +rt_hw_context_switch_interrupt PROC + EXPORT rt_hw_context_switch_interrupt + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 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] + BX lr + ENDP + +; /* +; * void rt_hw_context_switch_interrupt_do(rt_base_t flag) +; */ +rt_hw_context_switch_interrupt_do PROC + EXPORT rt_hw_context_switch_interrupt_do + MOV r1, #0 ; clear flag + STR r1, [r0] + + LDMFD sp!, {r0-r12,lr}; reload saved registers + STMFD sp!, {r0-r3} ; save r0-r3 + MOV r1, sp + ADD sp, sp, #16 ; restore sp + SUB r2, lr, #4 ; save old task's pc to r2 + + MRS r3, spsr ; get cpsr of interrupt thread + + ; switch to SVC mode and no interrupt + MSR cpsr_c, #I_Bit:OR:F_Bit:OR:Mode_SVC + + STMFD sp!, {r2} ; push old task's pc + STMFD sp!, {r4-r12,lr}; push old task's lr,r12-r4 + MOV r4, r1 ; Special optimised code below + MOV r5, r3 + LDMFD r4!, {r0-r3} + STMFD sp!, {r0-r3} ; push old task's r3-r0 + STMFD sp!, {r5} ; push old task's cpsr + + LDR r4, =rt_interrupt_from_thread + LDR r5, [r4] + STR sp, [r5] ; store sp in preempted tasks's TCB + + LDR r6, =rt_interrupt_to_thread + LDR r6, [r6] + LDR sp, [r6] ; get new task's stack pointer + + LDMFD sp!, {r4} ; pop new task's cpsr to spsr + MSR spsr_cxsf, r4 + BIC r4, r4, #0x20 ; must be ARM mode + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr + ENDP + + END \ No newline at end of file diff --git a/rt-thread/libcpu/arm/lpc214x/cpuport.c b/rt-thread/libcpu/arm/lpc214x/cpuport.c new file mode 100644 index 0000000..1cd33b8 --- /dev/null +++ b/rt-thread/libcpu/arm/lpc214x/cpuport.c @@ -0,0 +1,206 @@ +/* + * 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 + * 2011-06-15 aozima the first version for lpc214x + * 2013-03-29 aozima Modify the interrupt interface implementations. + */ + +#include +#include +#include "lpc214x.h" + +#define MAX_HANDLERS 32 +#define SVCMODE 0x13 + +extern rt_uint32_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +struct rt_irq_desc irq_desc[MAX_HANDLERS]; + +/** + * @addtogroup LPC214x + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +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) = (unsigned long)tentry; /* entry point */ + *(--stk) = (unsigned long)texit; /* lr */ + *(--stk) = 0; /* r12 */ + *(--stk) = 0; /* r11 */ + *(--stk) = 0; /* r10 */ + *(--stk) = 0; /* r9 */ + *(--stk) = 0; /* r8 */ + *(--stk) = 0; /* r7 */ + *(--stk) = 0; /* r6 */ + *(--stk) = 0; /* r5 */ + *(--stk) = 0; /* r4 */ + *(--stk) = 0; /* r3 */ + *(--stk) = 0; /* r2 */ + *(--stk) = 0; /* r1 */ + *(--stk) = (unsigned long)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/* exception and interrupt handler table */ +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +void rt_hw_interrupt_handler(int vector, void *param) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + rt_base_t index; + rt_uint32_t *vect_addr, *vect_ctl; + + /* initialize VIC*/ + VICIntEnClr = 0xffffffff; + VICVectAddr = 0; + /* set all to IRQ */ + VICIntSelect = 0; + + rt_memset(irq_desc, 0x00, sizeof(irq_desc)); + for (index = 0; index < MAX_HANDLERS; index ++) + { + irq_desc[index].handler = rt_hw_interrupt_handler; + + vect_addr = (rt_uint32_t *)(VIC_BASE_ADDR + 0x100 + (index << 2)); + vect_ctl = (rt_uint32_t *)(VIC_BASE_ADDR + 0x200 + (index << 2)); + + *vect_addr = (rt_uint32_t)&irq_desc[index]; + *vect_ctl = 0xF; + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + VICIntEnClr = (1 << vector); +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + VICIntEnable = (1 << vector); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param handler the interrupt service routine to be installed + * @param param the interrupt service function parameter + * @param name the interrupt name + * @return old handler + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if(vector >= 0 && vector < MAX_HANDLERS) + { + rt_uint32_t* vect_ctl = (rt_uint32_t *)(VIC_BASE_ADDR + 0x200 + (vector << 2)); + + /* assign IRQ slot and enable this slot */ + *vect_ctl = 0x20 | (vector & 0x1F); + + old_handler = irq_desc[vector].handler; + if (handler != RT_NULL) + { + irq_desc[vector].handler = handler; + irq_desc[vector].param = param; + } + } + + return old_handler; +} + +/** + * this function will reset CPU + * + */ +void rt_hw_cpu_reset(void) +{ +} + +/** + * this function will shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_kprintf("shutdown...\n"); + + while (1); +} + +void rt_hw_trap_irq(void) +{ + int irqno; + struct rt_irq_desc* irq; + extern struct rt_irq_desc irq_desc[]; + + irq = (struct rt_irq_desc*) VICVectAddr; + irqno = ((rt_uint32_t) irq - (rt_uint32_t) &irq_desc[0])/sizeof(struct rt_irq_desc); + + /* invoke isr */ + irq->handler(irqno, irq->param); + + /* acknowledge Interrupt */ + // VICVectAddr = 0; +} + +void rt_hw_trap_fiq(void) +{ + rt_kprintf("fast interrupt request\n"); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/lpc214x/lpc214x.h b/rt-thread/libcpu/arm/lpc214x/lpc214x.h new file mode 100644 index 0000000..1805bc6 --- /dev/null +++ b/rt-thread/libcpu/arm/lpc214x/lpc214x.h @@ -0,0 +1,393 @@ +/***********************************************************************/ +/* This file is part of the uVision/ARM development tools */ +/* Copyright KEIL ELEKTRONIK GmbH 2002-2005 */ +/***********************************************************************/ +/* */ +/* LPC214X.H: Header file for Philips LPC2141/42/44/46/48 */ +/* */ +/***********************************************************************/ + +#ifndef __LPC214x_H +#define __LPC214x_H + +/* Vectored Interrupt Controller (VIC) */ +#define VICIRQStatus (*((volatile unsigned long *) 0xFFFFF000)) +#define VICFIQStatus (*((volatile unsigned long *) 0xFFFFF004)) +#define VICRawIntr (*((volatile unsigned long *) 0xFFFFF008)) +#define VICIntSelect (*((volatile unsigned long *) 0xFFFFF00C)) +#define VICIntEnable (*((volatile unsigned long *) 0xFFFFF010)) +#define VICIntEnClr (*((volatile unsigned long *) 0xFFFFF014)) +#define VICSoftInt (*((volatile unsigned long *) 0xFFFFF018)) +#define VICSoftIntClr (*((volatile unsigned long *) 0xFFFFF01C)) +#define VICProtection (*((volatile unsigned long *) 0xFFFFF020)) +#define VICVectAddr (*((volatile unsigned long *) 0xFFFFF030)) +#define VICDefVectAddr (*((volatile unsigned long *) 0xFFFFF034)) +#define VICVectAddr0 (*((volatile unsigned long *) 0xFFFFF100)) +#define VICVectAddr1 (*((volatile unsigned long *) 0xFFFFF104)) +#define VICVectAddr2 (*((volatile unsigned long *) 0xFFFFF108)) +#define VICVectAddr3 (*((volatile unsigned long *) 0xFFFFF10C)) +#define VICVectAddr4 (*((volatile unsigned long *) 0xFFFFF110)) +#define VICVectAddr5 (*((volatile unsigned long *) 0xFFFFF114)) +#define VICVectAddr6 (*((volatile unsigned long *) 0xFFFFF118)) +#define VICVectAddr7 (*((volatile unsigned long *) 0xFFFFF11C)) +#define VICVectAddr8 (*((volatile unsigned long *) 0xFFFFF120)) +#define VICVectAddr9 (*((volatile unsigned long *) 0xFFFFF124)) +#define VICVectAddr10 (*((volatile unsigned long *) 0xFFFFF128)) +#define VICVectAddr11 (*((volatile unsigned long *) 0xFFFFF12C)) +#define VICVectAddr12 (*((volatile unsigned long *) 0xFFFFF130)) +#define VICVectAddr13 (*((volatile unsigned long *) 0xFFFFF134)) +#define VICVectAddr14 (*((volatile unsigned long *) 0xFFFFF138)) +#define VICVectAddr15 (*((volatile unsigned long *) 0xFFFFF13C)) +#define VICVectCntl0 (*((volatile unsigned long *) 0xFFFFF200)) +#define VICVectCntl1 (*((volatile unsigned long *) 0xFFFFF204)) +#define VICVectCntl2 (*((volatile unsigned long *) 0xFFFFF208)) +#define VICVectCntl3 (*((volatile unsigned long *) 0xFFFFF20C)) +#define VICVectCntl4 (*((volatile unsigned long *) 0xFFFFF210)) +#define VICVectCntl5 (*((volatile unsigned long *) 0xFFFFF214)) +#define VICVectCntl6 (*((volatile unsigned long *) 0xFFFFF218)) +#define VICVectCntl7 (*((volatile unsigned long *) 0xFFFFF21C)) +#define VICVectCntl8 (*((volatile unsigned long *) 0xFFFFF220)) +#define VICVectCntl9 (*((volatile unsigned long *) 0xFFFFF224)) +#define VICVectCntl10 (*((volatile unsigned long *) 0xFFFFF228)) +#define VICVectCntl11 (*((volatile unsigned long *) 0xFFFFF22C)) +#define VICVectCntl12 (*((volatile unsigned long *) 0xFFFFF230)) +#define VICVectCntl13 (*((volatile unsigned long *) 0xFFFFF234)) +#define VICVectCntl14 (*((volatile unsigned long *) 0xFFFFF238)) +#define VICVectCntl15 (*((volatile unsigned long *) 0xFFFFF23C)) + +/* Pin Connect Block */ +#define PINSEL0 (*((volatile unsigned long *) 0xE002C000)) +#define PINSEL1 (*((volatile unsigned long *) 0xE002C004)) +#define PINSEL2 (*((volatile unsigned long *) 0xE002C014)) + +/* General Purpose Input/Output (GPIO) */ +#define IOPIN0 (*((volatile unsigned long *) 0xE0028000)) +#define IOSET0 (*((volatile unsigned long *) 0xE0028004)) +#define IODIR0 (*((volatile unsigned long *) 0xE0028008)) +#define IOCLR0 (*((volatile unsigned long *) 0xE002800C)) +#define IOPIN1 (*((volatile unsigned long *) 0xE0028010)) +#define IOSET1 (*((volatile unsigned long *) 0xE0028014)) +#define IODIR1 (*((volatile unsigned long *) 0xE0028018)) +#define IOCLR1 (*((volatile unsigned long *) 0xE002801C)) +#define IO0PIN (*((volatile unsigned long *) 0xE0028000)) +#define IO0SET (*((volatile unsigned long *) 0xE0028004)) +#define IO0DIR (*((volatile unsigned long *) 0xE0028008)) +#define IO0CLR (*((volatile unsigned long *) 0xE002800C)) +#define IO1PIN (*((volatile unsigned long *) 0xE0028010)) +#define IO1SET (*((volatile unsigned long *) 0xE0028014)) +#define IO1DIR (*((volatile unsigned long *) 0xE0028018)) +#define IO1CLR (*((volatile unsigned long *) 0xE002801C)) +#define FIO0DIR (*((volatile unsigned long *) 0x3FFFC000)) +#define FIO0MASK (*((volatile unsigned long *) 0x3FFFC010)) +#define FIO0PIN (*((volatile unsigned long *) 0x3FFFC014)) +#define FIO0SET (*((volatile unsigned long *) 0x3FFFC018)) +#define FIO0CLR (*((volatile unsigned long *) 0x3FFFC01C)) +#define FIO1DIR (*((volatile unsigned long *) 0x3FFFC020)) +#define FIO1MASK (*((volatile unsigned long *) 0x3FFFC030)) +#define FIO1PIN (*((volatile unsigned long *) 0x3FFFC034)) +#define FIO1SET (*((volatile unsigned long *) 0x3FFFC038)) +#define FIO1CLR (*((volatile unsigned long *) 0x3FFFC03C)) + +/* Memory Accelerator Module (MAM) */ +#define MAMCR (*((volatile unsigned char *) 0xE01FC000)) +#define MAMTIM (*((volatile unsigned char *) 0xE01FC004)) +#define MEMMAP (*((volatile unsigned char *) 0xE01FC040)) + +/* Phase Locked Loop 0 (PLL0) */ +#define PLL0CON (*((volatile unsigned char *) 0xE01FC080)) +#define PLL0CFG (*((volatile unsigned char *) 0xE01FC084)) +#define PLL0STAT (*((volatile unsigned short*) 0xE01FC088)) +#define PLL0FEED (*((volatile unsigned char *) 0xE01FC08C)) + +/* Phase Locked Loop 1 (PLL1) */ +#define PLL1CON (*((volatile unsigned char *) 0xE01FC0A0)) +#define PLL1CFG (*((volatile unsigned char *) 0xE01FC0A4)) +#define PLL1STAT (*((volatile unsigned short*) 0xE01FC0A8)) +#define PLL1FEED (*((volatile unsigned char *) 0xE01FC0AC)) + +/* VPB Divider */ +#define VPBDIV (*((volatile unsigned char *) 0xE01FC100)) + +/* Power Control */ +#define PCON (*((volatile unsigned char *) 0xE01FC0C0)) +#define PCONP (*((volatile unsigned long *) 0xE01FC0C4)) + +/* External Interrupts */ +#define EXTINT (*((volatile unsigned char *) 0xE01FC140)) +#define INTWAKE (*((volatile unsigned short*) 0xE01FC144)) +#define EXTMODE (*((volatile unsigned char *) 0xE01FC148)) +#define EXTPOLAR (*((volatile unsigned char *) 0xE01FC14C)) + +/* Reset */ +#define RSID (*((volatile unsigned char *) 0xE01FC180)) + +/* Code Security / Debugging */ +#define CSPR (*((volatile unsigned char *) 0xE01FC184)) + +/* System Control Miscellaneous */ +#define SCS (*((volatile unsigned long *) 0xE01FC1A0)) + +/* Timer 0 */ +#define T0IR (*((volatile unsigned long *) 0xE0004000)) +#define T0TCR (*((volatile unsigned long *) 0xE0004004)) +#define T0TC (*((volatile unsigned long *) 0xE0004008)) +#define T0PR (*((volatile unsigned long *) 0xE000400C)) +#define T0PC (*((volatile unsigned long *) 0xE0004010)) +#define T0MCR (*((volatile unsigned long *) 0xE0004014)) +#define T0MR0 (*((volatile unsigned long *) 0xE0004018)) +#define T0MR1 (*((volatile unsigned long *) 0xE000401C)) +#define T0MR2 (*((volatile unsigned long *) 0xE0004020)) +#define T0MR3 (*((volatile unsigned long *) 0xE0004024)) +#define T0CCR (*((volatile unsigned long *) 0xE0004028)) +#define T0CR0 (*((volatile unsigned long *) 0xE000402C)) +#define T0CR1 (*((volatile unsigned long *) 0xE0004030)) +#define T0CR2 (*((volatile unsigned long *) 0xE0004034)) +#define T0CR3 (*((volatile unsigned long *) 0xE0004038)) +#define T0EMR (*((volatile unsigned long *) 0xE000403C)) +#define T0CTCR (*((volatile unsigned long *) 0xE0004070)) + +/* Timer 1 */ +#define T1IR (*((volatile unsigned long *) 0xE0008000)) +#define T1TCR (*((volatile unsigned long *) 0xE0008004)) +#define T1TC (*((volatile unsigned long *) 0xE0008008)) +#define T1PR (*((volatile unsigned long *) 0xE000800C)) +#define T1PC (*((volatile unsigned long *) 0xE0008010)) +#define T1MCR (*((volatile unsigned long *) 0xE0008014)) +#define T1MR0 (*((volatile unsigned long *) 0xE0008018)) +#define T1MR1 (*((volatile unsigned long *) 0xE000801C)) +#define T1MR2 (*((volatile unsigned long *) 0xE0008020)) +#define T1MR3 (*((volatile unsigned long *) 0xE0008024)) +#define T1CCR (*((volatile unsigned long *) 0xE0008028)) +#define T1CR0 (*((volatile unsigned long *) 0xE000802C)) +#define T1CR1 (*((volatile unsigned long *) 0xE0008030)) +#define T1CR2 (*((volatile unsigned long *) 0xE0008034)) +#define T1CR3 (*((volatile unsigned long *) 0xE0008038)) +#define T1EMR (*((volatile unsigned long *) 0xE000803C)) +#define T1CTCR (*((volatile unsigned long *) 0xE0008070)) + +/* Pulse Width Modulator (PWM) */ +#define PWMIR (*((volatile unsigned long *) 0xE0014000)) +#define PWMTCR (*((volatile unsigned long *) 0xE0014004)) +#define PWMTC (*((volatile unsigned long *) 0xE0014008)) +#define PWMPR (*((volatile unsigned long *) 0xE001400C)) +#define PWMPC (*((volatile unsigned long *) 0xE0014010)) +#define PWMMCR (*((volatile unsigned long *) 0xE0014014)) +#define PWMMR0 (*((volatile unsigned long *) 0xE0014018)) +#define PWMMR1 (*((volatile unsigned long *) 0xE001401C)) +#define PWMMR2 (*((volatile unsigned long *) 0xE0014020)) +#define PWMMR3 (*((volatile unsigned long *) 0xE0014024)) +#define PWMMR4 (*((volatile unsigned long *) 0xE0014040)) +#define PWMMR5 (*((volatile unsigned long *) 0xE0014044)) +#define PWMMR6 (*((volatile unsigned long *) 0xE0014048)) +#define PWMPCR (*((volatile unsigned long *) 0xE001404C)) +#define PWMLER (*((volatile unsigned long *) 0xE0014050)) + +/* Universal Asynchronous Receiver Transmitter 0 (UART0) */ +#define U0RBR (*((volatile unsigned char *) 0xE000C000)) +#define U0THR (*((volatile unsigned char *) 0xE000C000)) +#define U0IER (*((volatile unsigned long *) 0xE000C004)) +#define U0IIR (*((volatile unsigned long *) 0xE000C008)) +#define U0FCR (*((volatile unsigned char *) 0xE000C008)) +#define U0LCR (*((volatile unsigned char *) 0xE000C00C)) +#define U0MCR (*((volatile unsigned char *) 0xE000C010)) +#define U0LSR (*((volatile unsigned char *) 0xE000C014)) +#define U0MSR (*((volatile unsigned char *) 0xE000C018)) +#define U0SCR (*((volatile unsigned char *) 0xE000C01C)) +#define U0DLL (*((volatile unsigned char *) 0xE000C000)) +#define U0DLM (*((volatile unsigned char *) 0xE000C004)) +#define U0ACR (*((volatile unsigned long *) 0xE000C020)) +#define U0FDR (*((volatile unsigned long *) 0xE000C028)) +#define U0TER (*((volatile unsigned char *) 0xE000C030)) + +/* Universal Asynchronous Receiver Transmitter 1 (UART1) */ +#define U1RBR (*((volatile unsigned char *) 0xE0010000)) +#define U1THR (*((volatile unsigned char *) 0xE0010000)) +#define U1IER (*((volatile unsigned long *) 0xE0010004)) +#define U1IIR (*((volatile unsigned long *) 0xE0010008)) +#define U1FCR (*((volatile unsigned char *) 0xE0010008)) +#define U1LCR (*((volatile unsigned char *) 0xE001000C)) +#define U1MCR (*((volatile unsigned char *) 0xE0010010)) +#define U1LSR (*((volatile unsigned char *) 0xE0010014)) +#define U1MSR (*((volatile unsigned char *) 0xE0010018)) +#define U1SCR (*((volatile unsigned char *) 0xE001001C)) +#define U1DLL (*((volatile unsigned char *) 0xE0010000)) +#define U1DLM (*((volatile unsigned char *) 0xE0010004)) +#define U1ACR (*((volatile unsigned long *) 0xE0010020)) +#define U1FDR (*((volatile unsigned long *) 0xE0010028)) +#define U1TER (*((volatile unsigned char *) 0xE0010030)) + +/* I2C Interface 0 */ +#define I2C0CONSET (*((volatile unsigned char *) 0xE001C000)) +#define I2C0STAT (*((volatile unsigned char *) 0xE001C004)) +#define I2C0DAT (*((volatile unsigned char *) 0xE001C008)) +#define I2C0ADR (*((volatile unsigned char *) 0xE001C00C)) +#define I2C0SCLH (*((volatile unsigned short*) 0xE001C010)) +#define I2C0SCLL (*((volatile unsigned short*) 0xE001C014)) +#define I2C0CONCLR (*((volatile unsigned char *) 0xE001C018)) + +/* I2C Interface 1 */ +#define I2C1CONSET (*((volatile unsigned char *) 0xE005C000)) +#define I2C1STAT (*((volatile unsigned char *) 0xE005C004)) +#define I2C1DAT (*((volatile unsigned char *) 0xE005C008)) +#define I2C1ADR (*((volatile unsigned char *) 0xE005C00C)) +#define I2C1SCLH (*((volatile unsigned short*) 0xE005C010)) +#define I2C1SCLL (*((volatile unsigned short*) 0xE005C014)) +#define I2C1CONCLR (*((volatile unsigned char *) 0xE005C018)) + +/* SPI0 (Serial Peripheral Interface 0) */ +#define S0SPCR (*((volatile unsigned short*) 0xE0020000)) +#define S0SPSR (*((volatile unsigned char *) 0xE0020004)) +#define S0SPDR (*((volatile unsigned short*) 0xE0020008)) +#define S0SPCCR (*((volatile unsigned char *) 0xE002000C)) +#define S0SPINT (*((volatile unsigned char *) 0xE002001C)) + +/* SSP Controller (SPI1) */ +#define SSPCR0 (*((volatile unsigned short*) 0xE0068000)) +#define SSPCR1 (*((volatile unsigned char *) 0xE0068004)) +#define SSPDR (*((volatile unsigned short*) 0xE0068008)) +#define SSPSR (*((volatile unsigned char *) 0xE006800C)) +#define SSPCPSR (*((volatile unsigned char *) 0xE0068010)) +#define SSPIMSC (*((volatile unsigned char *) 0xE0068014)) +#define SSPRIS (*((volatile unsigned char *) 0xE0068018)) +#define SSPMIS (*((volatile unsigned char *) 0xE006801C)) +#define SSPICR (*((volatile unsigned char *) 0xE0068020)) + +/* Real Time Clock */ +#define ILR (*((volatile unsigned char *) 0xE0024000)) +#define CTC (*((volatile unsigned short*) 0xE0024004)) +#define CCR (*((volatile unsigned char *) 0xE0024008)) +#define CIIR (*((volatile unsigned char *) 0xE002400C)) +#define AMR (*((volatile unsigned char *) 0xE0024010)) +#define CTIME0 (*((volatile unsigned long *) 0xE0024014)) +#define CTIME1 (*((volatile unsigned long *) 0xE0024018)) +#define CTIME2 (*((volatile unsigned long *) 0xE002401C)) +#define SEC (*((volatile unsigned char *) 0xE0024020)) +#define MIN (*((volatile unsigned char *) 0xE0024024)) +#define HOUR (*((volatile unsigned char *) 0xE0024028)) +#define DOM (*((volatile unsigned char *) 0xE002402C)) +#define DOW (*((volatile unsigned char *) 0xE0024030)) +#define DOY (*((volatile unsigned short*) 0xE0024034)) +#define MONTH (*((volatile unsigned char *) 0xE0024038)) +#define YEAR (*((volatile unsigned short*) 0xE002403C)) +#define ALSEC (*((volatile unsigned char *) 0xE0024060)) +#define ALMIN (*((volatile unsigned char *) 0xE0024064)) +#define ALHOUR (*((volatile unsigned char *) 0xE0024068)) +#define ALDOM (*((volatile unsigned char *) 0xE002406C)) +#define ALDOW (*((volatile unsigned char *) 0xE0024070)) +#define ALDOY (*((volatile unsigned short*) 0xE0024074)) +#define ALMON (*((volatile unsigned char *) 0xE0024078)) +#define ALYEAR (*((volatile unsigned short*) 0xE002407C)) +#define PREINT (*((volatile unsigned short*) 0xE0024080)) +#define PREFRAC (*((volatile unsigned short*) 0xE0024084)) + +/* A/D Converter 0 (AD0) */ +#define AD0CR (*((volatile unsigned long *) 0xE0034000)) +#define AD0GDR (*((volatile unsigned long *) 0xE0034004)) +#define AD0STAT (*((volatile unsigned long *) 0xE0034030)) +#define AD0INTEN (*((volatile unsigned long *) 0xE003400C)) +#define AD0DR0 (*((volatile unsigned long *) 0xE0034010)) +#define AD0DR1 (*((volatile unsigned long *) 0xE0034014)) +#define AD0DR2 (*((volatile unsigned long *) 0xE0034018)) +#define AD0DR3 (*((volatile unsigned long *) 0xE003401C)) +#define AD0DR4 (*((volatile unsigned long *) 0xE0034020)) +#define AD0DR5 (*((volatile unsigned long *) 0xE0034024)) +#define AD0DR6 (*((volatile unsigned long *) 0xE0034028)) +#define AD0DR7 (*((volatile unsigned long *) 0xE003402C)) + +/* A/D Converter 1 (AD1) */ +#define AD1CR (*((volatile unsigned long *) 0xE0060000)) +#define AD1GDR (*((volatile unsigned long *) 0xE0060004)) +#define AD1STAT (*((volatile unsigned long *) 0xE0060030)) +#define AD1INTEN (*((volatile unsigned long *) 0xE006000C)) +#define AD1DR0 (*((volatile unsigned long *) 0xE0060010)) +#define AD1DR1 (*((volatile unsigned long *) 0xE0060014)) +#define AD1DR2 (*((volatile unsigned long *) 0xE0060018)) +#define AD1DR3 (*((volatile unsigned long *) 0xE006001C)) +#define AD1DR4 (*((volatile unsigned long *) 0xE0060020)) +#define AD1DR5 (*((volatile unsigned long *) 0xE0060024)) +#define AD1DR6 (*((volatile unsigned long *) 0xE0060028)) +#define AD1DR7 (*((volatile unsigned long *) 0xE006002C)) + +/* A/D Converter Global */ +#define ADGSR (*((volatile unsigned long *) 0xE0034008)) + +/* D/A Converter */ +#define DACR (*((volatile unsigned long *) 0xE006C000)) + +/* Watchdog */ +#define WDMOD (*((volatile unsigned char *) 0xE0000000)) +#define WDTC (*((volatile unsigned long *) 0xE0000004)) +#define WDFEED (*((volatile unsigned char *) 0xE0000008)) +#define WDTV (*((volatile unsigned long *) 0xE000000C)) + +/* USB Controller */ +#define USBIntSt (*((volatile unsigned long *) 0xE01FC1C0)) +#define USBDevIntSt (*((volatile unsigned long *) 0xE0090000)) +#define USBDevIntEn (*((volatile unsigned long *) 0xE0090004)) +#define USBDevIntClr (*((volatile unsigned long *) 0xE0090008)) +#define USBDevIntSet (*((volatile unsigned long *) 0xE009000C)) +#define USBDevIntPri (*((volatile unsigned char *) 0xE009002C)) +#define USBEpIntSt (*((volatile unsigned long *) 0xE0090030)) +#define USBEpIntEn (*((volatile unsigned long *) 0xE0090034)) +#define USBEpIntClr (*((volatile unsigned long *) 0xE0090038)) +#define USBEpIntSet (*((volatile unsigned long *) 0xE009003C)) +#define USBEpIntPri (*((volatile unsigned long *) 0xE0090040)) +#define USBReEp (*((volatile unsigned long *) 0xE0090044)) +#define USBEpInd (*((volatile unsigned long *) 0xE0090048)) +#define USBMaxPSize (*((volatile unsigned long *) 0xE009004C)) +#define USBRxData (*((volatile unsigned long *) 0xE0090018)) +#define USBRxPLen (*((volatile unsigned long *) 0xE0090020)) +#define USBTxData (*((volatile unsigned long *) 0xE009001C)) +#define USBTxPLen (*((volatile unsigned long *) 0xE0090024)) +#define USBCtrl (*((volatile unsigned long *) 0xE0090028)) +#define USBCmdCode (*((volatile unsigned long *) 0xE0090010)) +#define USBCmdData (*((volatile unsigned long *) 0xE0090014)) +#define USBDMARSt (*((volatile unsigned long *) 0xE0090050)) +#define USBDMARClr (*((volatile unsigned long *) 0xE0090054)) +#define USBDMARSet (*((volatile unsigned long *) 0xE0090058)) +#define USBUDCAH (*((volatile unsigned long *) 0xE0090080)) +#define USBEpDMASt (*((volatile unsigned long *) 0xE0090084)) +#define USBEpDMAEn (*((volatile unsigned long *) 0xE0090088)) +#define USBEpDMADis (*((volatile unsigned long *) 0xE009008C)) +#define USBDMAIntSt (*((volatile unsigned long *) 0xE0090090)) +#define USBDMAIntEn (*((volatile unsigned long *) 0xE0090094)) +#define USBEoTIntSt (*((volatile unsigned long *) 0xE00900A0)) +#define USBEoTIntClr (*((volatile unsigned long *) 0xE00900A4)) +#define USBEoTIntSet (*((volatile unsigned long *) 0xE00900A8)) +#define USBNDDRIntSt (*((volatile unsigned long *) 0xE00900AC)) +#define USBNDDRIntClr (*((volatile unsigned long *) 0xE00900B0)) +#define USBNDDRIntSet (*((volatile unsigned long *) 0xE00900B4)) +#define USBSysErrIntSt (*((volatile unsigned long *) 0xE00900B8)) +#define USBSysErrIntClr (*((volatile unsigned long *) 0xE00900BC)) +#define USBSysErrIntSet (*((volatile unsigned long *) 0xE00900C0)) + +#define VIC_BASE_ADDR 0xFFFFF000 + +enum LPC214x_INT +{ + WDT_INT = 0, + SW_INT_reserved, + DbgCommRx_INT, + DbgCommTx_INT, + TIMER0_INT, + TIMER1_INT, + UART0_INT, + UART1_INT, + PWM0_INT, + I2C0_INT, + SP0_INT, + SP1_INT, + PLL_INT, + RTC_INT, + EINT0_INT, + EINT1_INT, + EINT2_INT, + EINT3_INT, + ADC0_INT, + I2C1_INT, + BOD_INT, + ADC1_INT, + USB_INT +}; + +#endif // __LPC214x_H diff --git a/rt-thread/libcpu/arm/lpc214x/start_rvds.S b/rt-thread/libcpu/arm/lpc214x/start_rvds.S new file mode 100644 index 0000000..bef523b --- /dev/null +++ b/rt-thread/libcpu/arm/lpc214x/start_rvds.S @@ -0,0 +1,464 @@ +;/*****************************************************************************/ +;/* STARTUP.S: Startup file for Philips LPC2000 */ +;/*****************************************************************************/ +;/* <<< Use Configuration Wizard in Context Menu >>> */ +;/*****************************************************************************/ +;/* This file is part of the uVision/ARM development tools. */ +;/* Copyright (c) 2005-2007 Keil Software. All rights reserved. */ +;/* This software may only be used under the terms of a valid, current, */ +;/* end user licence from KEIL for a compatible version of KEIL software */ +;/* development tools. Nothing else gives you the right to use this software. */ +;/*****************************************************************************/ + + +;/* +; * The STARTUP.S code is executed after CPU Reset. This file may be +; * translated with the following SET symbols. In uVision these SET +; * symbols are entered under Options - ASM - Define. +; * +; * REMAP: when set the startup code initializes the register MEMMAP +; * which overwrites the settings of the CPU configuration pins. The +; * startup and interrupt vectors are remapped from: +; * 0x00000000 default setting (not remapped) +; * 0x80000000 when EXTMEM_MODE is used +; * 0x40000000 when RAM_MODE is used +; * +; * EXTMEM_MODE: when set the device is configured for code execution +; * from external memory starting at address 0x80000000. +; * +; * RAM_MODE: when set the device is configured for code execution +; * from on-chip RAM starting at address 0x40000000. +; * +; * EXTERNAL_MODE: when set the PIN2SEL values are written that enable +; * the external BUS at startup. +; */ + + +; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs + +Mode_USR EQU 0x10 +Mode_FIQ EQU 0x11 +Mode_IRQ EQU 0x12 +Mode_SVC EQU 0x13 +Mode_ABT EQU 0x17 +Mode_UND EQU 0x1B +Mode_SYS EQU 0x1F + +I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled +F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled + + +;// Stack Configuration (Stack Sizes in Bytes) +;// Undefined Mode <0x0-0xFFFFFFFF:8> +;// Supervisor Mode <0x0-0xFFFFFFFF:8> +;// Abort Mode <0x0-0xFFFFFFFF:8> +;// Fast Interrupt Mode <0x0-0xFFFFFFFF:8> +;// Interrupt Mode <0x0-0xFFFFFFFF:8> +;// User/System Mode <0x0-0xFFFFFFFF:8> +;// + +UND_Stack_Size EQU 0x00000000 +SVC_Stack_Size EQU 0x00000100 +ABT_Stack_Size EQU 0x00000000 +FIQ_Stack_Size EQU 0x00000000 +IRQ_Stack_Size EQU 0x00000100 +USR_Stack_Size EQU 0x00000100 + +ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + FIQ_Stack_Size + IRQ_Stack_Size) + + AREA STACK, NOINIT, READWRITE, ALIGN=3 + +Stack_Mem SPACE USR_Stack_Size +__initial_sp SPACE ISR_Stack_Size + +Stack_Top + + +;// Heap Configuration +;// Heap Size (in Bytes) <0x0-0xFFFFFFFF> +;// + +Heap_Size EQU 0x00000000 + + AREA HEAP, NOINIT, READWRITE, ALIGN=3 +__heap_base +Heap_Mem SPACE Heap_Size +__heap_limit + + +; VPBDIV definitions +VPBDIV EQU 0xE01FC100 ; VPBDIV Address + +;// VPBDIV Setup +;// Peripheral Bus Clock Rate +;// VPBDIV: VPB Clock +;// <0=> VPB Clock = CPU Clock / 4 +;// <1=> VPB Clock = CPU Clock +;// <2=> VPB Clock = CPU Clock / 2 +;// XCLKDIV: XCLK Pin +;// <0=> XCLK Pin = CPU Clock / 4 +;// <1=> XCLK Pin = CPU Clock +;// <2=> XCLK Pin = CPU Clock / 2 +;// +VPBDIV_SETUP EQU 0 +VPBDIV_Val EQU 0x00000000 + + +; Phase Locked Loop (PLL) definitions +PLL_BASE EQU 0xE01FC080 ; PLL Base Address +PLLCON_OFS EQU 0x00 ; PLL Control Offset +PLLCFG_OFS EQU 0x04 ; PLL Configuration Offset +PLLSTAT_OFS EQU 0x08 ; PLL Status Offset +PLLFEED_OFS EQU 0x0C ; PLL Feed Offset +PLLCON_PLLE EQU (1<<0) ; PLL Enable +PLLCON_PLLC EQU (1<<1) ; PLL Connect +PLLCFG_MSEL EQU (0x1F<<0) ; PLL Multiplier +PLLCFG_PSEL EQU (0x03<<5) ; PLL Divider +PLLSTAT_PLOCK EQU (1<<10) ; PLL Lock Status + +;// PLL Setup +;// MSEL: PLL Multiplier Selection +;// <1-32><#-1> +;// M Value +;// PSEL: PLL Divider Selection +;// <0=> 1 <1=> 2 <2=> 4 <3=> 8 +;// P Value +;// +PLL_SETUP EQU 1 +PLLCFG_Val EQU 0x00000024 + + +; Memory Accelerator Module (MAM) definitions +MAM_BASE EQU 0xE01FC000 ; MAM Base Address +MAMCR_OFS EQU 0x00 ; MAM Control Offset +MAMTIM_OFS EQU 0x04 ; MAM Timing Offset + +;// MAM Setup +;// MAM Control +;// <0=> Disabled +;// <1=> Partially Enabled +;// <2=> Fully Enabled +;// Mode +;// MAM Timing +;// <0=> Reserved <1=> 1 <2=> 2 <3=> 3 +;// <4=> 4 <5=> 5 <6=> 6 <7=> 7 +;// Fetch Cycles +;// +MAM_SETUP EQU 1 +MAMCR_Val EQU 0x00000002 +MAMTIM_Val EQU 0x00000004 + + +; External Memory Controller (EMC) definitions +EMC_BASE EQU 0xFFE00000 ; EMC Base Address +BCFG0_OFS EQU 0x00 ; BCFG0 Offset +BCFG1_OFS EQU 0x04 ; BCFG1 Offset +BCFG2_OFS EQU 0x08 ; BCFG2 Offset +BCFG3_OFS EQU 0x0C ; BCFG3 Offset + +;// External Memory Controller (EMC) +EMC_SETUP EQU 0 + +;// Bank Configuration 0 (BCFG0) +;// IDCY: Idle Cycles <0-15> +;// WST1: Wait States 1 <0-31> +;// WST2: Wait States 2 <0-31> +;// RBLE: Read Byte Lane Enable +;// WP: Write Protect +;// BM: Burst ROM +;// MW: Memory Width <0=> 8-bit <1=> 16-bit +;// <2=> 32-bit <3=> Reserved +;// +BCFG0_SETUP EQU 0 +BCFG0_Val EQU 0x0000FBEF + +;// Bank Configuration 1 (BCFG1) +;// IDCY: Idle Cycles <0-15> +;// WST1: Wait States 1 <0-31> +;// WST2: Wait States 2 <0-31> +;// RBLE: Read Byte Lane Enable +;// WP: Write Protect +;// BM: Burst ROM +;// MW: Memory Width <0=> 8-bit <1=> 16-bit +;// <2=> 32-bit <3=> Reserved +;// +BCFG1_SETUP EQU 0 +BCFG1_Val EQU 0x0000FBEF + +;// Bank Configuration 2 (BCFG2) +;// IDCY: Idle Cycles <0-15> +;// WST1: Wait States 1 <0-31> +;// WST2: Wait States 2 <0-31> +;// RBLE: Read Byte Lane Enable +;// WP: Write Protect +;// BM: Burst ROM +;// MW: Memory Width <0=> 8-bit <1=> 16-bit +;// <2=> 32-bit <3=> Reserved +;// +BCFG2_SETUP EQU 0 +BCFG2_Val EQU 0x0000FBEF + +;// Bank Configuration 3 (BCFG3) +;// IDCY: Idle Cycles <0-15> +;// WST1: Wait States 1 <0-31> +;// WST2: Wait States 2 <0-31> +;// RBLE: Read Byte Lane Enable +;// WP: Write Protect +;// BM: Burst ROM +;// MW: Memory Width <0=> 8-bit <1=> 16-bit +;// <2=> 32-bit <3=> Reserved +;// +BCFG3_SETUP EQU 0 +BCFG3_Val EQU 0x0000FBEF + +;// End of EMC + + +; External Memory Pins definitions +PINSEL2 EQU 0xE002C014 ; PINSEL2 Address +PINSEL2_Val EQU 0x0E6149E4 ; CS0..3, OE, WE, BLS0..3, + ; D0..31, A2..23, JTAG Pins + + + PRESERVE8 + + +; Area Definition and Entry Point +; Startup Code must be linked first at Address at which it expects to run. + + AREA RESET, CODE, READONLY + ARM + + +; Exception Vectors +; Mapped to Address 0. +; Absolute addressing mode must be used. +; Dummy Handlers are implemented as infinite loops which can be modified. + +Vectors LDR PC, Reset_Addr + LDR PC, Undef_Addr + LDR PC, SWI_Addr + LDR PC, PAbt_Addr + LDR PC, DAbt_Addr + NOP ; Reserved Vector + LDR PC, IRQ_Addr + LDR PC, FIQ_Addr + +Reset_Addr DCD Reset_Handler +Undef_Addr DCD Undef_Handler +SWI_Addr DCD SWI_Handler +PAbt_Addr DCD PAbt_Handler +DAbt_Addr DCD DAbt_Handler + DCD 0 ; Reserved Address +IRQ_Addr DCD IRQ_Handler +FIQ_Addr DCD FIQ_Handler + +Undef_Handler B Undef_Handler +SWI_Handler B SWI_Handler +PAbt_Handler B PAbt_Handler +DAbt_Handler B DAbt_Handler +FIQ_Handler B FIQ_Handler + + +; Reset Handler + + EXPORT Reset_Handler +Reset_Handler + + +; Setup External Memory Pins + IF :DEF:EXTERNAL_MODE + LDR R0, =PINSEL2 + LDR R1, =PINSEL2_Val + STR R1, [R0] + ENDIF + + +; Setup External Memory Controller + IF EMC_SETUP <> 0 + LDR R0, =EMC_BASE + + IF BCFG0_SETUP <> 0 + LDR R1, =BCFG0_Val + STR R1, [R0, #BCFG0_OFS] + ENDIF + + IF BCFG1_SETUP <> 0 + LDR R1, =BCFG1_Val + STR R1, [R0, #BCFG1_OFS] + ENDIF + + IF BCFG2_SETUP <> 0 + LDR R1, =BCFG2_Val + STR R1, [R0, #BCFG2_OFS] + ENDIF + + IF BCFG3_SETUP <> 0 + LDR R1, =BCFG3_Val + STR R1, [R0, #BCFG3_OFS] + ENDIF + + ENDIF ; EMC_SETUP + + +; Setup VPBDIV + IF VPBDIV_SETUP <> 0 + LDR R0, =VPBDIV + LDR R1, =VPBDIV_Val + STR R1, [R0] + ENDIF + + +; Setup PLL + IF PLL_SETUP <> 0 + LDR R0, =PLL_BASE + MOV R1, #0xAA + MOV R2, #0x55 + +; Configure and Enable PLL + MOV R3, #PLLCFG_Val + STR R3, [R0, #PLLCFG_OFS] + MOV R3, #PLLCON_PLLE + STR R3, [R0, #PLLCON_OFS] + STR R1, [R0, #PLLFEED_OFS] + STR R2, [R0, #PLLFEED_OFS] + +; Wait until PLL Locked +PLL_Loop LDR R3, [R0, #PLLSTAT_OFS] + ANDS R3, R3, #PLLSTAT_PLOCK + BEQ PLL_Loop + +; Switch to PLL Clock + MOV R3, #(PLLCON_PLLE:OR:PLLCON_PLLC) + STR R3, [R0, #PLLCON_OFS] + STR R1, [R0, #PLLFEED_OFS] + STR R2, [R0, #PLLFEED_OFS] + ENDIF ; PLL_SETUP + + +; Setup MAM + IF MAM_SETUP <> 0 + LDR R0, =MAM_BASE + MOV R1, #MAMTIM_Val + STR R1, [R0, #MAMTIM_OFS] + MOV R1, #MAMCR_Val + STR R1, [R0, #MAMCR_OFS] + ENDIF ; MAM_SETUP + + +; Memory Mapping (when Interrupt Vectors are in RAM) +MEMMAP EQU 0xE01FC040 ; Memory Mapping Control + IF :DEF:REMAP + LDR R0, =MEMMAP + IF :DEF:EXTMEM_MODE + MOV R1, #3 + ELIF :DEF:RAM_MODE + MOV R1, #2 + ELSE + MOV R1, #1 + ENDIF + STR R1, [R0] + ENDIF + + +; Initialise Interrupt System +; ... + + +; Setup Stack for each mode + + LDR R0, =Stack_Top + +; Enter Undefined Instruction Mode and set its Stack Pointer + MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #UND_Stack_Size + +; Enter Abort Mode and set its Stack Pointer + MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #ABT_Stack_Size + +; Enter FIQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #FIQ_Stack_Size + +; Enter IRQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #IRQ_Stack_Size + +; Enter Supervisor Mode and set its Stack Pointer + MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit + MOV SP, R0 + ; SUB R0, R0, #SVC_Stack_Size + +; Enter User Mode and set its Stack Pointer + ; RT-Thread does not use user mode + ; MSR CPSR_c, #Mode_USR + IF :DEF:__MICROLIB + + EXPORT __initial_sp + + ELSE + + ; MOV SP, R0 + ; SUB SL, SP, #USR_Stack_Size + + ENDIF + +; Enter the C code + + IMPORT __main + LDR R0, =__main + BX R0 + + IMPORT rt_interrupt_enter + IMPORT rt_interrupt_leave + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + IMPORT rt_hw_trap_irq + IMPORT rt_hw_context_switch_interrupt_do + +IRQ_Handler PROC + EXPORT IRQ_Handler + STMFD sp!, {r0-r12,lr} + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; if rt_thread_switch_interrupt_flag set, jump to + ; rt_hw_context_switch_interrupt_do and don't return + LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD sp!, {r0-r12,lr} + SUBS pc, lr, #4 + ENDP + + IF :DEF:__MICROLIB + + EXPORT __heap_base + EXPORT __heap_limit + + ELSE +; User Initial Stack & Heap + AREA |.text|, CODE, READONLY + + IMPORT __use_two_region_memory + EXPORT __user_initial_stackheap +__user_initial_stackheap + + LDR R0, = Heap_Mem + LDR R1, =(Stack_Mem + USR_Stack_Size) + LDR R2, = (Heap_Mem + Heap_Size) + LDR R3, = Stack_Mem + BX LR + ENDIF + + END diff --git a/rt-thread/libcpu/arm/lpc214x/startup_gcc.S b/rt-thread/libcpu/arm/lpc214x/startup_gcc.S new file mode 100644 index 0000000..ce13d57 --- /dev/null +++ b/rt-thread/libcpu/arm/lpc214x/startup_gcc.S @@ -0,0 +1,312 @@ + .extern main /* ÒýÈëÍⲿCÈë¿Ú */ + + .extern rt_interrupt_enter + .extern rt_interrupt_leave + .extern rt_thread_switch_interrupt_flag + .extern rt_interrupt_from_thread + .extern rt_interrupt_to_thread + .extern rt_hw_trap_irq + + .global start + .global endless_loop + .global rt_hw_context_switch_interrupt_do + + /* Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs */ + .set MODE_USR, 0x10 /* User Mode */ + .set MODE_FIQ, 0x11 /* FIQ Mode */ + .set MODE_IRQ, 0x12 /* IRQ Mode */ + .set MODE_SVC, 0x13 /* Supervisor Mode */ + .set MODE_ABT, 0x17 /* Abort Mode */ + .set MODE_UND, 0x1B /* Undefined Mode */ + .set MODE_SYS, 0x1F /* System Mode */ + + .equ I_BIT, 0x80 /* when I bit is set, IRQ is disabled */ + .equ F_BIT, 0x40 /* when F bit is set, FIQ is disabled */ + .equ I_Bit, 0x80 /* when I bit is set, IRQ is disabled */ + .equ F_Bit, 0x40 /* when F bit is set, FIQ is disabled */ + + /* VPBDIV definitions*/ + .equ VPBDIV, 0xE01FC100 + .set VPBDIV_VALUE, 0x00000000 + + /* Phase Locked Loop (PLL) definitions*/ + .equ PLL_BASE, 0xE01FC080 /* PLL Base Address */ + .equ PLLCON_OFS, 0x00 /* PLL Control Offset */ + .equ PLLCFG_OFS, 0x04 /* PLL Configuration Offset */ + .equ PLLSTAT_OFS, 0x08 /* PLL Status Offset */ + .equ PLLFEED_OFS, 0x0C /* PLL Feed Offset */ + .equ PLLCON_PLLE, (1<<0) /* PLL Enable */ + .equ PLLCON_PLLC, (1<<1) /* PLL Connect */ + .equ PLLCFG_MSEL, (0x1F<<0) /* PLL Multiplier */ + .equ PLLCFG_PSEL, (0x03<<5) /* PLL Divider */ + .equ PLLSTAT_PLOCK, (1<<10) /* PLL Lock Status */ + .equ PLLCFG_Val, 0x00000024 /* MSEL: PLL Multiplier Selection, PSEL: PLL Divider Selection */ + + .equ MEMMAP, 0xE01FC040 /*Memory Mapping Control*/ + + + /* Memory Accelerator Module (MAM) definitions*/ + .equ MAM_BASE, 0xE01FC000 + .equ MAMCR_OFS, 0x00 + .equ MAMTIM_OFS, 0x04 + .equ MAMCR_Val, 0x00000002 + .equ MAMTIM_Val, 0x00000004 + + .equ VICIntEnClr, 0xFFFFF014 + .equ VICIntSelect, 0xFFFFF00C +/************* Ä¿±êÅäÖýáÊø *************/ + + +/* Setup the operating mode & stack.*/ +/* --------------------------------- */ + .global _reset +_reset: + .code 32 + .align 0 + +/************************* PLL_SETUP **********************************/ + ldr r0, =PLL_BASE + mov r1, #0xAA + mov r2, #0x55 + +/* Configure and Enable PLL */ + mov r3, #PLLCFG_Val + str r3, [r0, #PLLCFG_OFS] + mov r3, #PLLCON_PLLE + str r3, [r0, #PLLCON_OFS] + str r1, [r0, #PLLFEED_OFS] + str r2, [r0, #PLLFEED_OFS] + +/* Wait until PLL Locked */ +PLL_Locked_loop: + ldr r3, [r0, #PLLSTAT_OFS] + ands r3, r3, #PLLSTAT_PLOCK + beq PLL_Locked_loop + +/* Switch to PLL Clock */ + mov r3, #(PLLCON_PLLE|PLLCON_PLLC) + str r3, [r0, #PLLCON_OFS] + str r1, [r0, #PLLFEED_OFS] + str R2, [r0, #PLLFEED_OFS] +/************************* PLL_SETUP **********************************/ + +/************************ Setup VPBDIV ********************************/ + ldr r0, =VPBDIV + ldr r1, =VPBDIV_VALUE + str r1, [r0] +/************************ Setup VPBDIV ********************************/ + +/************** Setup MAM **************/ + ldr r0, =MAM_BASE + mov r1, #MAMTIM_Val + str r1, [r0, #MAMTIM_OFS] + mov r1, #MAMCR_Val + str r1, [r0, #MAMCR_OFS] +/************** Setup MAM **************/ + +/************************ setup stack *********************************/ + ldr r0, .undefined_stack_top + sub r0, r0, #4 + msr CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction Mode */ + mov sp, r0 + + ldr r0, .abort_stack_top + sub r0, r0, #4 + msr CPSR_c, #MODE_ABT|I_BIT|F_BIT /* Abort Mode */ + mov sp, r0 + + ldr r0, .fiq_stack_top + sub r0, r0, #4 + msr CPSR_c, #MODE_FIQ|I_BIT|F_BIT /* FIQ Mode */ + mov sp, r0 + + ldr r0, .irq_stack_top + sub r0, r0, #4 + msr CPSR_c, #MODE_IRQ|I_BIT|F_BIT /* IRQ Mode */ + mov sp, r0 + + ldr r0, .svc_stack_top + sub r0, r0, #4 + msr CPSR_c, #MODE_SVC|I_BIT|F_BIT /* Supervisor Mode */ + mov sp, r0 +/************************ setup stack ********************************/ + + /* copy .data to SRAM */ + ldr r1, =_sidata /* .data start in image */ + ldr r2, =_edata /* .data end in image */ + ldr r3, =_sdata /* sram data start */ +data_loop: + ldr r0, [r1, #0] + str r0, [r3] + + add r1, r1, #4 + add r3, r3, #4 + + cmp r3, r2 /* check if data to clear */ + blo data_loop /* loop until done */ + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop +ctor_end: + + /* enter C code */ + bl main + + .align 0 + .undefined_stack_top: + .word _undefined_stack_top + .abort_stack_top: + .word _abort_stack_top + .fiq_stack_top: + .word _fiq_stack_top + .irq_stack_top: + .word _irq_stack_top + .svc_stack_top: + .word _svc_stack_top +/*********************** END Clear BSS ******************************/ + +.section .init,"ax" +.code 32 +.align 0 +.globl _start +_start: + + ldr pc, __start /* reset - _start */ + ldr pc, _undf /* undefined - _undf */ + ldr pc, _swi /* SWI - _swi */ + ldr pc, _pabt /* program abort - _pabt */ + ldr pc, _dabt /* data abort - _dabt */ + .word 0xB8A06F58 /* reserved */ + ldr pc, __IRQ_Handler /* IRQ - read the VIC */ + ldr pc, _fiq /* FIQ - _fiq */ + +__start:.word _reset +_undf: .word __undf /* undefined */ +_swi: .word __swi /* SWI */ +_pabt: .word __pabt /* program abort */ +_dabt: .word __dabt /* data abort */ +temp1: .word 0 +__IRQ_Handler: .word IRQ_Handler +_fiq: .word __fiq /* FIQ */ + +__undf: b . /* undefined */ +__swi : b . +__pabt: b . /* program abort */ +__dabt: b . /* data abort */ +__fiq : b . /* FIQ */ + +/* IRQÈë¿Ú */ +IRQ_Handler : + stmfd sp!, {r0-r12,lr} /* ¶ÔR0 ¨C R12£¬LR¼Ä´æÆ÷ѹջ */ + bl rt_interrupt_enter /* ֪ͨRT-Thread½øÈëÖжÏģʽ */ + bl rt_hw_trap_irq /* ÏàÓ¦ÖжϷþÎñÀý³Ì´¦Àí */ + bl rt_interrupt_leave /* ; ֪ͨRT-ThreadÒªÀ뿪ÖжÏģʽ */ + + /* Èç¹ûÉèÖÃÁËrt_thread_switch_interrupt_flag£¬½øÐÐÖжÏÖеÄÏß³ÌÉÏÏÂÎÄ´¦Àí */ + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq rt_hw_context_switch_interrupt_do /* ÖжÏÖÐÇл»·¢Éú */ + /* Èç¹ûÌø×ªÁË£¬½«²»»á»ØÀ´ */ + ldmfd sp!, {r0-r12,lr} /* »Ö¸´Õ» */ + subs pc, lr, #4 /* ´ÓIRQÖзµ»Ø */ + +/* +* void rt_hw_context_switch_interrupt_do(rt_base_t flag) +* ÖжϽáÊøºóµÄÉÏÏÂÎÄÇл» +*/ +rt_hw_context_switch_interrupt_do: + mov r1, #0 /* clear flag */ + /* Çå³þÖжÏÖÐÇл»±êÖ¾ */ + str r1, [r0] /* */ + + ldmfd sp!, {r0-r12,lr}/* reload saved registers */ + /* ÏȻָ´±»ÖжÏÏ̵߳ÄÉÏÏÂÎÄ */ + stmfd sp!, {r0-r3} /* save r0-r3 */ + /* ¶ÔR0 ¨C R3ѹջ£¬ÒòΪºóÃæ»áÓõ½ */ + mov r1, sp /* °Ñ´Ë´¦µÄÕ»Öµ±£´æµ½R1 */ + add sp, sp, #16 /* restore sp */ + /* »Ö¸´IRQµÄÕ»£¬ºóÃæ»áÌø³öIRQģʽ */ + sub r2, lr, #4 /* save old task's pc to r2 */ + /* ±£´æÇл»³öÏ̵߳ÄPCµ½R2 */ + + mrs r3, spsr /* disable interrupt ±£´æÖжÏǰµÄCPSRµ½R3¼Ä´æÆ÷ */ + /* »ñµÃSPSR¼Ä´æÆ÷Öµ */ + orr r0, r3, #I_BIT|F_BIT + msr spsr_c, r0 /* ¹Ø±ÕSPSRÖеÄIRQ/FIQÖÐ¶Ï */ + + ldr r0, =.+8 /* °Ñµ±Ç°µØÖ·+8ÔØÈëµ½R0¼Ä´æÆ÷ÖÐ switch to interrupted task's stack */ + movs pc, r0 /* Í˳öIRQģʽ£¬ÓÉÓÚSPSR±»ÉèÖóɹØÖжÏģʽ */ + /* ËùÒÔ´ÓIRQ·µ»Øºó£¬Öжϲ¢Ã»Óдò¿ª + ; R0¼Ä´æÆ÷ÖеÄλÖÃʵ¼Ê¾ÍÊÇÏÂÒ»ÌõÖ¸Á + ; ¼´PC¼ÌÐøÍùÏÂ×ß + ; ´Ëʱ + ; ģʽÒѾ­»»³ÉÖжÏǰµÄSVCģʽ£¬ + ; SP¼Ä´æÆ÷Ò²ÊÇSVCģʽϵÄÕ»¼Ä´æÆ÷ + ; R1±£´æIRQģʽϵÄÕ»Ö¸Õë + ; R2±£´æÇл»³öÏ̵߳ÄPC + ; R3±£´æÇл»³öÏ̵߳ÄCPSR */ + stmfd sp!, {r2} /* push old task's pc */ + /* ±£´æÇл»³öÈÎÎñµÄPC */ + stmfd sp!, {r4-r12,lr}/* push old task's lr,r12-r4 */ + /* ±£´æR4 ¨C R12£¬LR¼Ä´æÆ÷ */ + mov r4, r1 /* Special optimised code below */ + /* R1±£´æÓÐѹջR0 ¨C R3´¦µÄջλÖà */ + mov r5, r3 /* R3Çл»³öÏ̵߳ÄCPSR */ + ldmfd r4!, {r0-r3} /* »Ö¸´R0 ¨C R3 */ + stmfd sp!, {r0-r3} /* push old task's r3-r0 */ + /* R0 ¨C R3ѹջµ½Çл»³öÏß³Ì */ + stmfd sp!, {r5} /* push old task's psr */ + /* Çл»³öÏß³ÌCPSRѹջ */ + mrs r4, spsr + stmfd sp!, {r4} /* push old task's spsr */ + /* Çл»³öÏß³ÌSPSRѹջ */ + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] /* store sp in preempted tasks's TCB */ + /* ±£´æÇл»³öÏ̵߳ÄSPÖ¸Õë */ + + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] /* get new task's stack pointer */ + /* »ñµÃÇл»µ½Ï̵߳ÄÕ» */ + + ldmfd sp!, {r4} /* pop new task's spsr */ + /* »Ö¸´SPSR */ + msr SPSR_cxsf, r4 + ldmfd sp!, {r4} /* pop new task's psr */ + /* »Ö¸´CPSR */ + msr CPSR_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc} /* pop new task's r0-r12,lr & pc */ + /* »Ö¸´R0 ¨C R12£¬LR¼°PC¼Ä´æÆ÷ */ + +/* ´úÂë¼ÓÃܹ¦ÄÜ */ +#if defined(CODE_PROTECTION) +.org 0x01FC +.word 0x87654321 +#endif + diff --git a/rt-thread/libcpu/arm/lpc24xx/LPC24xx.h b/rt-thread/libcpu/arm/lpc24xx/LPC24xx.h new file mode 100644 index 0000000..7c70fd1 --- /dev/null +++ b/rt-thread/libcpu/arm/lpc24xx/LPC24xx.h @@ -0,0 +1,1201 @@ +/* + * File : LPC2478.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 xuxinming first version + */ + +#ifndef __LPC24xx_H +#define __LPC24xx_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define ABORTMODE 0x17 +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +#define MCLK (72000000) + +/* Vectored Interrupt Controller (VIC) */ +#define VIC_BASE_ADDR 0xFFFFF000 +#define VICIRQStatus (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x000)) +#define VICFIQStatus (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x004)) +#define VICRawIntr (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x008)) +#define VICIntSelect (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x00C)) +#define VICIntEnable (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x010)) +#define VICIntEnClr (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x014)) +#define VICSoftInt (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x018)) +#define VICSoftIntClr (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x01C)) +#define VICProtection (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x020)) +#define VICSWPrioMask (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x024)) + +#define VICVectAddr0 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x100)) +#define VICVectAddr1 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x104)) +#define VICVectAddr2 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x108)) +#define VICVectAddr3 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x10C)) +#define VICVectAddr4 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x110)) +#define VICVectAddr5 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x114)) +#define VICVectAddr6 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x118)) +#define VICVectAddr7 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x11C)) +#define VICVectAddr8 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x120)) +#define VICVectAddr9 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x124)) +#define VICVectAddr10 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x128)) +#define VICVectAddr11 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x12C)) +#define VICVectAddr12 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x130)) +#define VICVectAddr13 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x134)) +#define VICVectAddr14 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x138)) +#define VICVectAddr15 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x13C)) +#define VICVectAddr16 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x140)) +#define VICVectAddr17 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x144)) +#define VICVectAddr18 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x148)) +#define VICVectAddr19 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x14C)) +#define VICVectAddr20 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x150)) +#define VICVectAddr21 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x154)) +#define VICVectAddr22 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x158)) +#define VICVectAddr23 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x15C)) +#define VICVectAddr24 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x160)) +#define VICVectAddr25 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x164)) +#define VICVectAddr26 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x168)) +#define VICVectAddr27 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x16C)) +#define VICVectAddr28 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x170)) +#define VICVectAddr29 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x174)) +#define VICVectAddr30 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x178)) +#define VICVectAddr31 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x17C)) + +/* The name convention below is from previous LPC2000 family MCUs, in LPC23xx/24xx, +these registers are known as "VICVectPriority(x)". */ +#define VICVectCntl0 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x200)) +#define VICVectCntl1 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x204)) +#define VICVectCntl2 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x208)) +#define VICVectCntl3 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x20C)) +#define VICVectCntl4 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x210)) +#define VICVectCntl5 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x214)) +#define VICVectCntl6 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x218)) +#define VICVectCntl7 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x21C)) +#define VICVectCntl8 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x220)) +#define VICVectCntl9 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x224)) +#define VICVectCntl10 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x228)) +#define VICVectCntl11 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x22C)) +#define VICVectCntl12 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x230)) +#define VICVectCntl13 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x234)) +#define VICVectCntl14 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x238)) +#define VICVectCntl15 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x23C)) +#define VICVectCntl16 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x240)) +#define VICVectCntl17 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x244)) +#define VICVectCntl18 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x248)) +#define VICVectCntl19 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x24C)) +#define VICVectCntl20 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x250)) +#define VICVectCntl21 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x254)) +#define VICVectCntl22 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x258)) +#define VICVectCntl23 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x25C)) +#define VICVectCntl24 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x260)) +#define VICVectCntl25 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x264)) +#define VICVectCntl26 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x268)) +#define VICVectCntl27 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x26C)) +#define VICVectCntl28 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x270)) +#define VICVectCntl29 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x274)) +#define VICVectCntl30 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x278)) +#define VICVectCntl31 (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x27C)) + +#define VICVectAddr (*(volatile unsigned long *)(VIC_BASE_ADDR + 0xF00)) + + +/* Pin Connect Block */ +#define PINSEL_BASE_ADDR 0xE002C000 +#define PINSEL0 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x00)) +#define PINSEL1 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x04)) +#define PINSEL2 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x08)) +#define PINSEL3 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x0C)) +#define PINSEL4 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x10)) +#define PINSEL5 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x14)) +#define PINSEL6 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x18)) +#define PINSEL7 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x1C)) +#define PINSEL8 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x20)) +#define PINSEL9 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x24)) +#define PINSEL10 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x28)) +#define PINSEL11 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x2C)) + +#define PINMODE0 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x40)) +#define PINMODE1 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x44)) +#define PINMODE2 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x48)) +#define PINMODE3 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x4C)) +#define PINMODE4 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x50)) +#define PINMODE5 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x54)) +#define PINMODE6 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x58)) +#define PINMODE7 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x5C)) +#define PINMODE8 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x60)) +#define PINMODE9 (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x64)) + +/* General Purpose Input/Output (GPIO) */ +#define GPIO_BASE_ADDR 0xE0028000 +#define IOPIN0 (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x00)) +#define IOSET0 (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x04)) +#define IODIR0 (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x08)) +#define IOCLR0 (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x0C)) +#define IOPIN1 (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x10)) +#define IOSET1 (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x14)) +#define IODIR1 (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x18)) +#define IOCLR1 (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x1C)) + +/* GPIO Interrupt Registers */ +#define IO0_INT_EN_R (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x90)) +#define IO0_INT_EN_F (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x94)) +#define IO0_INT_STAT_R (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x84)) +#define IO0_INT_STAT_F (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x88)) +#define IO0_INT_CLR (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x8C)) + +#define IO2_INT_EN_R (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0xB0)) +#define IO2_INT_EN_F (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0xB4)) +#define IO2_INT_STAT_R (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0xA4)) +#define IO2_INT_STAT_F (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0xA8)) +#define IO2_INT_CLR (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0xAC)) + +#define IO_INT_STAT (*(volatile unsigned long *)(GPIO_BASE_ADDR + 0x80)) + +#define PARTCFG_BASE_ADDR 0x3FFF8000 +#define PARTCFG (*(volatile unsigned long *)(PARTCFG_BASE_ADDR + 0x00)) + +/* Fast I/O setup */ +#define FIO_BASE_ADDR 0x3FFFC000 +#define FIO0DIR (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x00)) +#define FIO0MASK (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x10)) +#define FIO0PIN (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x14)) +#define FIO0SET (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x18)) +#define FIO0CLR (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x1C)) + +#define FIO1DIR (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x20)) +#define FIO1MASK (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x30)) +#define FIO1PIN (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x34)) +#define FIO1SET (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x38)) +#define FIO1CLR (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x3C)) + +#define FIO2DIR (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x40)) +#define FIO2MASK (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x50)) +#define FIO2PIN (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x54)) +#define FIO2SET (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x58)) +#define FIO2CLR (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x5C)) + +#define FIO3DIR (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x60)) +#define FIO3MASK (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x70)) +#define FIO3PIN (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x74)) +#define FIO3SET (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x78)) +#define FIO3CLR (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x7C)) + +#define FIO4DIR (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x80)) +#define FIO4MASK (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x90)) +#define FIO4PIN (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x94)) +#define FIO4SET (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x98)) +#define FIO4CLR (*(volatile unsigned long *)(FIO_BASE_ADDR + 0x9C)) + +/* FIOs can be accessed through WORD, HALF-WORD or BYTE. */ +#define FIO0DIR0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x00)) +#define FIO1DIR0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x20)) +#define FIO2DIR0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x40)) +#define FIO3DIR0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x60)) +#define FIO4DIR0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x80)) + +#define FIO0DIR1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x01)) +#define FIO1DIR1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x21)) +#define FIO2DIR1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x41)) +#define FIO3DIR1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x61)) +#define FIO4DIR1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x81)) + +#define FIO0DIR2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x02)) +#define FIO1DIR2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x22)) +#define FIO2DIR2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x42)) +#define FIO3DIR2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x62)) +#define FIO4DIR2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x82)) + +#define FIO0DIR3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x03)) +#define FIO1DIR3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x23)) +#define FIO2DIR3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x43)) +#define FIO3DIR3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x63)) +#define FIO4DIR3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x83)) + +#define FIO0DIRL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x00)) +#define FIO1DIRL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x20)) +#define FIO2DIRL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x40)) +#define FIO3DIRL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x60)) +#define FIO4DIRL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x80)) + +#define FIO0DIRU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x02)) +#define FIO1DIRU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x22)) +#define FIO2DIRU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x42)) +#define FIO3DIRU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x62)) +#define FIO4DIRU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x82)) + +#define FIO0MASK0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x10)) +#define FIO1MASK0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x30)) +#define FIO2MASK0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x50)) +#define FIO3MASK0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x70)) +#define FIO4MASK0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x90)) + +#define FIO0MASK1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x11)) +#define FIO1MASK1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x21)) +#define FIO2MASK1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x51)) +#define FIO3MASK1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x71)) +#define FIO4MASK1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x91)) + +#define FIO0MASK2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x12)) +#define FIO1MASK2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x32)) +#define FIO2MASK2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x52)) +#define FIO3MASK2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x72)) +#define FIO4MASK2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x92)) + +#define FIO0MASK3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x13)) +#define FIO1MASK3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x33)) +#define FIO2MASK3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x53)) +#define FIO3MASK3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x73)) +#define FIO4MASK3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x93)) + +#define FIO0MASKL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x10)) +#define FIO1MASKL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x30)) +#define FIO2MASKL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x50)) +#define FIO3MASKL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x70)) +#define FIO4MASKL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x90)) + +#define FIO0MASKU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x12)) +#define FIO1MASKU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x32)) +#define FIO2MASKU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x52)) +#define FIO3MASKU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x72)) +#define FIO4MASKU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x92)) + +#define FIO0PIN0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x14)) +#define FIO1PIN0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x34)) +#define FIO2PIN0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x54)) +#define FIO3PIN0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x74)) +#define FIO4PIN0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x94)) + +#define FIO0PIN1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x15)) +#define FIO1PIN1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x35)) +#define FIO2PIN1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x55)) +#define FIO3PIN1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x75)) +#define FIO4PIN1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x95)) + +#define FIO0PIN2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x16)) +#define FIO1PIN2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x36)) +#define FIO2PIN2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x56)) +#define FIO3PIN2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x76)) +#define FIO4PIN2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x96)) + +#define FIO0PIN3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x17)) +#define FIO1PIN3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x37)) +#define FIO2PIN3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x57)) +#define FIO3PIN3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x77)) +#define FIO4PIN3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x97)) + +#define FIO0PINL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x14)) +#define FIO1PINL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x34)) +#define FIO2PINL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x54)) +#define FIO3PINL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x74)) +#define FIO4PINL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x94)) + +#define FIO0PINU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x16)) +#define FIO1PINU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x36)) +#define FIO2PINU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x56)) +#define FIO3PINU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x76)) +#define FIO4PINU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x96)) + +#define FIO0SET0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x18)) +#define FIO1SET0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x38)) +#define FIO2SET0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x58)) +#define FIO3SET0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x78)) +#define FIO4SET0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x98)) + +#define FIO0SET1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x19)) +#define FIO1SET1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x29)) +#define FIO2SET1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x59)) +#define FIO3SET1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x79)) +#define FIO4SET1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x99)) + +#define FIO0SET2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x1A)) +#define FIO1SET2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x3A)) +#define FIO2SET2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x5A)) +#define FIO3SET2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x7A)) +#define FIO4SET2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x9A)) + +#define FIO0SET3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x1B)) +#define FIO1SET3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x3B)) +#define FIO2SET3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x5B)) +#define FIO3SET3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x7B)) +#define FIO4SET3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x9B)) + +#define FIO0SETL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x18)) +#define FIO1SETL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x38)) +#define FIO2SETL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x58)) +#define FIO3SETL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x78)) +#define FIO4SETL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x98)) + +#define FIO0SETU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x1A)) +#define FIO1SETU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x3A)) +#define FIO2SETU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x5A)) +#define FIO3SETU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x7A)) +#define FIO4SETU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x9A)) + +#define FIO0CLR0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x1C)) +#define FIO1CLR0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x3C)) +#define FIO2CLR0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x5C)) +#define FIO3CLR0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x7C)) +#define FIO4CLR0 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x9C)) + +#define FIO0CLR1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x1D)) +#define FIO1CLR1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x2D)) +#define FIO2CLR1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x5D)) +#define FIO3CLR1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x7D)) +#define FIO4CLR1 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x9D)) + +#define FIO0CLR2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x1E)) +#define FIO1CLR2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x3E)) +#define FIO2CLR2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x5E)) +#define FIO3CLR2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x7E)) +#define FIO4CLR2 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x9E)) + +#define FIO0CLR3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x1F)) +#define FIO1CLR3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x3F)) +#define FIO2CLR3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x5F)) +#define FIO3CLR3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x7F)) +#define FIO4CLR3 (*(volatile unsigned char *)(FIO_BASE_ADDR + 0x9F)) + +#define FIO0CLRL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x1C)) +#define FIO1CLRL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x3C)) +#define FIO2CLRL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x5C)) +#define FIO3CLRL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x7C)) +#define FIO4CLRL (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x9C)) + +#define FIO0CLRU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x1E)) +#define FIO1CLRU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x3E)) +#define FIO2CLRU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x5E)) +#define FIO3CLRU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x7E)) +#define FIO4CLRU (*(volatile unsigned short *)(FIO_BASE_ADDR + 0x9E)) + + +/* System Control Block(SCB) modules include Memory Accelerator Module, +Phase Locked Loop, VPB divider, Power Control, External Interrupt, +Reset, and Code Security/Debugging */ +#define SCB_BASE_ADDR 0xE01FC000 + +/* Memory Accelerator Module (MAM) */ +#define MAMCR (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x000)) +#define MAMTIM (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x004)) +#define MEMMAP (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x040)) + +/* Phase Locked Loop (PLL) */ +#define PLLCON (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x080)) +#define PLLCFG (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x084)) +#define PLLSTAT (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x088)) +#define PLLFEED (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x08C)) + +/* Power Control */ +#define PCON (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x0C0)) +#define PCONP (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x0C4)) + +/* Clock Divider */ +#define CCLKCFG (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x104)) +#define USBCLKCFG (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x108)) +#define CLKSRCSEL (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x10C)) +#define PCLKSEL0 (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x1A8)) +#define PCLKSEL1 (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x1AC)) + +/* External Interrupts */ +#define EXTINT (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x140)) +#define INTWAKE (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x144)) +#define EXTMODE (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x148)) +#define EXTPOLAR (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x14C)) + +/* Reset, reset source identification */ +#define RSIR (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x180)) + +/* RSID, code security protection */ +#define CSPR (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x184)) + +/* AHB configuration */ +#define AHBCFG1 (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x188)) +#define AHBCFG2 (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x18C)) + +/* System Controls and Status */ +#define SCS (*(volatile unsigned long *)(SCB_BASE_ADDR + 0x1A0)) + +/* MPMC(EMC) registers, note: all the external memory controller(EMC) registers +are for LPC24xx only. */ +#define STATIC_MEM0_BASE 0x80000000 +#define STATIC_MEM1_BASE 0x81000000 +#define STATIC_MEM2_BASE 0x82000000 +#define STATIC_MEM3_BASE 0x83000000 + +#define DYNAMIC_MEM0_BASE 0xA0000000 +#define DYNAMIC_MEM1_BASE 0xB0000000 +#define DYNAMIC_MEM2_BASE 0xC0000000 +#define DYNAMIC_MEM3_BASE 0xD0000000 + +/* External Memory Controller (EMC) */ +#define EMC_BASE_ADDR 0xFFE08000 +#define EMC_CTRL (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x000)) +#define EMC_STAT (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x004)) +#define EMC_CONFIG (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x008)) + +/* Dynamic RAM access registers */ +#define EMC_DYN_CTRL (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x020)) +#define EMC_DYN_RFSH (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x024)) +#define EMC_DYN_RD_CFG (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x028)) +#define EMC_DYN_RP (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x030)) +#define EMC_DYN_RAS (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x034)) +#define EMC_DYN_SREX (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x038)) +#define EMC_DYN_APR (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x03C)) +#define EMC_DYN_DAL (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x040)) +#define EMC_DYN_WR (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x044)) +#define EMC_DYN_RC (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x048)) +#define EMC_DYN_RFC (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x04C)) +#define EMC_DYN_XSR (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x050)) +#define EMC_DYN_RRD (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x054)) +#define EMC_DYN_MRD (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x058)) + +#define EMC_DYN_CFG0 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x100)) +#define EMC_DYN_RASCAS0 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x104)) +#define EMC_DYN_CFG1 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x140)) +#define EMC_DYN_RASCAS1 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x144)) +#define EMC_DYN_CFG2 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x160)) +#define EMC_DYN_RASCAS2 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x164)) +#define EMC_DYN_CFG3 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x180)) +#define EMC_DYN_RASCAS3 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x184)) + +/* static RAM access registers */ +#define EMC_STA_CFG0 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x200)) +#define EMC_STA_WAITWEN0 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x204)) +#define EMC_STA_WAITOEN0 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x208)) +#define EMC_STA_WAITRD0 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x20C)) +#define EMC_STA_WAITPAGE0 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x210)) +#define EMC_STA_WAITWR0 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x214)) +#define EMC_STA_WAITTURN0 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x218)) + +#define EMC_STA_CFG1 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x220)) +#define EMC_STA_WAITWEN1 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x224)) +#define EMC_STA_WAITOEN1 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x228)) +#define EMC_STA_WAITRD1 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x22C)) +#define EMC_STA_WAITPAGE1 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x230)) +#define EMC_STA_WAITWR1 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x234)) +#define EMC_STA_WAITTURN1 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x238)) + +#define EMC_STA_CFG2 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x240)) +#define EMC_STA_WAITWEN2 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x244)) +#define EMC_STA_WAITOEN2 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x248)) +#define EMC_STA_WAITRD2 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x24C)) +#define EMC_STA_WAITPAGE2 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x250)) +#define EMC_STA_WAITWR2 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x254)) +#define EMC_STA_WAITTURN2 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x258)) + +#define EMC_STA_CFG3 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x260)) +#define EMC_STA_WAITWEN3 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x264)) +#define EMC_STA_WAITOEN3 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x268)) +#define EMC_STA_WAITRD3 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x26C)) +#define EMC_STA_WAITPAGE3 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x270)) +#define EMC_STA_WAITWR3 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x274)) +#define EMC_STA_WAITTURN3 (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x278)) + +#define EMC_STA_EXT_WAIT (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x880)) + + +/* Timer 0 */ +#define TMR0_BASE_ADDR 0xE0004000 +#define T0IR (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x00)) +#define T0TCR (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x04)) +#define T0TC (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x08)) +#define T0PR (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x0C)) +#define T0PC (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x10)) +#define T0MCR (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x14)) +#define T0MR0 (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x18)) +#define T0MR1 (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x1C)) +#define T0MR2 (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x20)) +#define T0MR3 (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x24)) +#define T0CCR (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x28)) +#define T0CR0 (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x2C)) +#define T0CR1 (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x30)) +#define T0CR2 (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x34)) +#define T0CR3 (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x38)) +#define T0EMR (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x3C)) +#define T0CTCR (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x70)) + +/* Timer 1 */ +#define TMR1_BASE_ADDR 0xE0008000 +#define T1IR (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x00)) +#define T1TCR (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x04)) +#define T1TC (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x08)) +#define T1PR (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x0C)) +#define T1PC (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x10)) +#define T1MCR (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x14)) +#define T1MR0 (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x18)) +#define T1MR1 (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x1C)) +#define T1MR2 (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x20)) +#define T1MR3 (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x24)) +#define T1CCR (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x28)) +#define T1CR0 (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x2C)) +#define T1CR1 (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x30)) +#define T1CR2 (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x34)) +#define T1CR3 (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x38)) +#define T1EMR (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x3C)) +#define T1CTCR (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x70)) + +/* Timer 2 */ +#define TMR2_BASE_ADDR 0xE0070000 +#define T2IR (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x00)) +#define T2TCR (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x04)) +#define T2TC (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x08)) +#define T2PR (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x0C)) +#define T2PC (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x10)) +#define T2MCR (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x14)) +#define T2MR0 (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x18)) +#define T2MR1 (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x1C)) +#define T2MR2 (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x20)) +#define T2MR3 (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x24)) +#define T2CCR (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x28)) +#define T2CR0 (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x2C)) +#define T2CR1 (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x30)) +#define T2CR2 (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x34)) +#define T2CR3 (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x38)) +#define T2EMR (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x3C)) +#define T2CTCR (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x70)) + +/* Timer 3 */ +#define TMR3_BASE_ADDR 0xE0074000 +#define T3IR (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x00)) +#define T3TCR (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x04)) +#define T3TC (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x08)) +#define T3PR (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x0C)) +#define T3PC (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x10)) +#define T3MCR (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x14)) +#define T3MR0 (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x18)) +#define T3MR1 (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x1C)) +#define T3MR2 (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x20)) +#define T3MR3 (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x24)) +#define T3CCR (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x28)) +#define T3CR0 (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x2C)) +#define T3CR1 (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x30)) +#define T3CR2 (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x34)) +#define T3CR3 (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x38)) +#define T3EMR (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x3C)) +#define T3CTCR (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x70)) + + +/* Pulse Width Modulator (PWM) */ +#define PWM0_BASE_ADDR 0xE0014000 +#define PWM0IR (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x00)) +#define PWM0TCR (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x04)) +#define PWM0TC (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x08)) +#define PWM0PR (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x0C)) +#define PWM0PC (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x10)) +#define PWM0MCR (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x14)) +#define PWM0MR0 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x18)) +#define PWM0MR1 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x1C)) +#define PWM0MR2 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x20)) +#define PWM0MR3 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x24)) +#define PWM0CCR (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x28)) +#define PWM0CR0 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x2C)) +#define PWM0CR1 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x30)) +#define PWM0CR2 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x34)) +#define PWM0CR3 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x38)) +#define PWM0EMR (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x3C)) +#define PWM0MR4 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x40)) +#define PWM0MR5 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x44)) +#define PWM0MR6 (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x48)) +#define PWM0PCR (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x4C)) +#define PWM0LER (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x50)) +#define PWM0CTCR (*(volatile unsigned long *)(PWM0_BASE_ADDR + 0x70)) + +#define PWM1_BASE_ADDR 0xE0018000 +#define PWM1IR (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x00)) +#define PWM1TCR (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x04)) +#define PWM1TC (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x08)) +#define PWM1PR (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x0C)) +#define PWM1PC (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x10)) +#define PWM1MCR (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x14)) +#define PWM1MR0 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x18)) +#define PWM1MR1 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x1C)) +#define PWM1MR2 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x20)) +#define PWM1MR3 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x24)) +#define PWM1CCR (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x28)) +#define PWM1CR0 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x2C)) +#define PWM1CR1 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x30)) +#define PWM1CR2 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x34)) +#define PWM1CR3 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x38)) +#define PWM1EMR (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x3C)) +#define PWM1MR4 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x40)) +#define PWM1MR5 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x44)) +#define PWM1MR6 (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x48)) +#define PWM1PCR (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x4C)) +#define PWM1LER (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x50)) +#define PWM1CTCR (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x70)) + + +/* Universal Asynchronous Receiver Transmitter 0 (UART0) */ +#define UART0_BASE_ADDR 0xE000C000 +#define U0RBR (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x00)) +#define U0THR (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x00)) +#define U0DLL (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x00)) +#define U0DLM (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x04)) +#define U0IER (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x04)) +#define U0IIR (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x08)) +#define U0FCR (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x08)) +#define U0LCR (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x0C)) +#define U0LSR (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x14)) +#define U0SCR (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x1C)) +#define U0ACR (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x20)) +#define U0ICR (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x24)) +#define U0FDR (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x28)) +#define U0TER (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x30)) + +/* Universal Asynchronous Receiver Transmitter 1 (UART1) */ +#define UART1_BASE_ADDR 0xE0010000 +#define U1RBR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x00)) +#define U1THR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x00)) +#define U1DLL (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x00)) +#define U1DLM (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x04)) +#define U1IER (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x04)) +#define U1IIR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x08)) +#define U1FCR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x08)) +#define U1LCR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x0C)) +#define U1MCR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x10)) +#define U1LSR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x14)) +#define U1MSR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x18)) +#define U1SCR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x1C)) +#define U1ACR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x20)) +#define U1FDR (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x28)) +#define U1TER (*(volatile unsigned long *)(UART1_BASE_ADDR + 0x30)) + +/* Universal Asynchronous Receiver Transmitter 2 (UART2) */ +#define UART2_BASE_ADDR 0xE0078000 +#define U2RBR (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x00)) +#define U2THR (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x00)) +#define U2DLL (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x00)) +#define U2DLM (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x04)) +#define U2IER (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x04)) +#define U2IIR (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x08)) +#define U2FCR (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x08)) +#define U2LCR (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x0C)) +#define U2LSR (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x14)) +#define U2SCR (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x1C)) +#define U2ACR (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x20)) +#define U2ICR (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x24)) +#define U2FDR (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x28)) +#define U2TER (*(volatile unsigned long *)(UART2_BASE_ADDR + 0x30)) + +/* Universal Asynchronous Receiver Transmitter 3 (UART3) */ +#define UART3_BASE_ADDR 0xE007C000 +#define U3RBR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x00)) +#define U3THR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x00)) +#define U3DLL (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x00)) +#define U3DLM (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x04)) +#define U3IER (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x04)) +#define U3IIR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x08)) +#define U3FCR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x08)) +#define U3LCR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x0C)) +#define U3LSR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x14)) +#define U3SCR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x1C)) +#define U3ACR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x20)) +#define U3ICR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x24)) +#define U3FDR (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x28)) +#define U3TER (*(volatile unsigned long *)(UART3_BASE_ADDR + 0x30)) + +/* I2C Interface 0 */ +#define I2C0_BASE_ADDR 0xE001C000 +#define I20CONSET (*(volatile unsigned long *)(I2C0_BASE_ADDR + 0x00)) +#define I20STAT (*(volatile unsigned long *)(I2C0_BASE_ADDR + 0x04)) +#define I20DAT (*(volatile unsigned long *)(I2C0_BASE_ADDR + 0x08)) +#define I20ADR (*(volatile unsigned long *)(I2C0_BASE_ADDR + 0x0C)) +#define I20SCLH (*(volatile unsigned long *)(I2C0_BASE_ADDR + 0x10)) +#define I20SCLL (*(volatile unsigned long *)(I2C0_BASE_ADDR + 0x14)) +#define I20CONCLR (*(volatile unsigned long *)(I2C0_BASE_ADDR + 0x18)) + +/* I2C Interface 1 */ +#define I2C1_BASE_ADDR 0xE005C000 +#define I21CONSET (*(volatile unsigned long *)(I2C1_BASE_ADDR + 0x00)) +#define I21STAT (*(volatile unsigned long *)(I2C1_BASE_ADDR + 0x04)) +#define I21DAT (*(volatile unsigned long *)(I2C1_BASE_ADDR + 0x08)) +#define I21ADR (*(volatile unsigned long *)(I2C1_BASE_ADDR + 0x0C)) +#define I21SCLH (*(volatile unsigned long *)(I2C1_BASE_ADDR + 0x10)) +#define I21SCLL (*(volatile unsigned long *)(I2C1_BASE_ADDR + 0x14)) +#define I21CONCLR (*(volatile unsigned long *)(I2C1_BASE_ADDR + 0x18)) + +/* I2C Interface 2 */ +#define I2C2_BASE_ADDR 0xE0080000 +#define I22CONSET (*(volatile unsigned long *)(I2C2_BASE_ADDR + 0x00)) +#define I22STAT (*(volatile unsigned long *)(I2C2_BASE_ADDR + 0x04)) +#define I22DAT (*(volatile unsigned long *)(I2C2_BASE_ADDR + 0x08)) +#define I22ADR (*(volatile unsigned long *)(I2C2_BASE_ADDR + 0x0C)) +#define I22SCLH (*(volatile unsigned long *)(I2C2_BASE_ADDR + 0x10)) +#define I22SCLL (*(volatile unsigned long *)(I2C2_BASE_ADDR + 0x14)) +#define I22CONCLR (*(volatile unsigned long *)(I2C2_BASE_ADDR + 0x18)) + +/* SPI0 (Serial Peripheral Interface 0) */ +#define SPI0_BASE_ADDR 0xE0020000 +#define S0SPCR (*(volatile unsigned long *)(SPI0_BASE_ADDR + 0x00)) +#define S0SPSR (*(volatile unsigned long *)(SPI0_BASE_ADDR + 0x04)) +#define S0SPDR (*(volatile unsigned long *)(SPI0_BASE_ADDR + 0x08)) +#define S0SPCCR (*(volatile unsigned long *)(SPI0_BASE_ADDR + 0x0C)) +#define S0SPINT (*(volatile unsigned long *)(SPI0_BASE_ADDR + 0x1C)) + +/* SSP0 Controller */ +#define SSP0_BASE_ADDR 0xE0068000 +#define SSP0CR0 (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x00)) +#define SSP0CR1 (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x04)) +#define SSP0DR (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x08)) +#define SSP0SR (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x0C)) +#define SSP0CPSR (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x10)) +#define SSP0IMSC (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x14)) +#define SSP0RIS (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x18)) +#define SSP0MIS (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x1C)) +#define SSP0ICR (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x20)) +#define SSP0DMACR (*(volatile unsigned long *)(SSP0_BASE_ADDR + 0x24)) + +/* SSP1 Controller */ +#define SSP1_BASE_ADDR 0xE0030000 +#define SSP1CR0 (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x00)) +#define SSP1CR1 (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x04)) +#define SSP1DR (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x08)) +#define SSP1SR (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x0C)) +#define SSP1CPSR (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x10)) +#define SSP1IMSC (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x14)) +#define SSP1RIS (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x18)) +#define SSP1MIS (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x1C)) +#define SSP1ICR (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x20)) +#define SSP1DMACR (*(volatile unsigned long *)(SSP1_BASE_ADDR + 0x24)) + + +/* Real Time Clock */ +#define RTC_BASE_ADDR 0xE0024000 +#define RTC_ILR (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x00)) +#define RTC_CTC (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x04)) +#define RTC_CCR (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x08)) +#define RTC_CIIR (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x0C)) +#define RTC_AMR (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x10)) +#define RTC_CTIME0 (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x14)) +#define RTC_CTIME1 (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x18)) +#define RTC_CTIME2 (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x1C)) +#define RTC_SEC (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x20)) +#define RTC_MIN (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x24)) +#define RTC_HOUR (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x28)) +#define RTC_DOM (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x2C)) +#define RTC_DOW (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x30)) +#define RTC_DOY (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x34)) +#define RTC_MONTH (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x38)) +#define RTC_YEAR (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x3C)) +#define RTC_CISS (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x40)) +#define RTC_ALSEC (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x60)) +#define RTC_ALMIN (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x64)) +#define RTC_ALHOUR (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x68)) +#define RTC_ALDOM (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x6C)) +#define RTC_ALDOW (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x70)) +#define RTC_ALDOY (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x74)) +#define RTC_ALMON (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x78)) +#define RTC_ALYEAR (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x7C)) +#define RTC_PREINT (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x80)) +#define RTC_PREFRAC (*(volatile unsigned long *)(RTC_BASE_ADDR + 0x84)) + + +/* A/D Converter 0 (AD0) */ +#define AD0_BASE_ADDR 0xE0034000 +#define AD0CR (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x00)) +#define AD0GDR (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x04)) +#define AD0INTEN (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x0C)) +#define AD0DR0 (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x10)) +#define AD0DR1 (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x14)) +#define AD0DR2 (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x18)) +#define AD0DR3 (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x1C)) +#define AD0DR4 (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x20)) +#define AD0DR5 (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x24)) +#define AD0DR6 (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x28)) +#define AD0DR7 (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x2C)) +#define AD0STAT (*(volatile unsigned long *)(AD0_BASE_ADDR + 0x30)) + + +/* D/A Converter */ +#define DAC_BASE_ADDR 0xE006C000 +#define DACR (*(volatile unsigned long *)(DAC_BASE_ADDR + 0x00)) + + +/* Watchdog */ +#define WDG_BASE_ADDR 0xE0000000 +#define WDMOD (*(volatile unsigned long *)(WDG_BASE_ADDR + 0x00)) +#define WDTC (*(volatile unsigned long *)(WDG_BASE_ADDR + 0x04)) +#define WDFEED (*(volatile unsigned long *)(WDG_BASE_ADDR + 0x08)) +#define WDTV (*(volatile unsigned long *)(WDG_BASE_ADDR + 0x0C)) +#define WDCLKSEL (*(volatile unsigned long *)(WDG_BASE_ADDR + 0x10)) + +/* CAN CONTROLLERS AND ACCEPTANCE FILTER */ +#define CAN_ACCEPT_BASE_ADDR 0xE003C000 +#define CAN_AFMR (*(volatile unsigned long *)(CAN_ACCEPT_BASE_ADDR + 0x00)) +#define CAN_SFF_SA (*(volatile unsigned long *)(CAN_ACCEPT_BASE_ADDR + 0x04)) +#define CAN_SFF_GRP_SA (*(volatile unsigned long *)(CAN_ACCEPT_BASE_ADDR + 0x08)) +#define CAN_EFF_SA (*(volatile unsigned long *)(CAN_ACCEPT_BASE_ADDR + 0x0C)) +#define CAN_EFF_GRP_SA (*(volatile unsigned long *)(CAN_ACCEPT_BASE_ADDR + 0x10)) +#define CAN_EOT (*(volatile unsigned long *)(CAN_ACCEPT_BASE_ADDR + 0x14)) +#define CAN_LUT_ERR_ADR (*(volatile unsigned long *)(CAN_ACCEPT_BASE_ADDR + 0x18)) +#define CAN_LUT_ERR (*(volatile unsigned long *)(CAN_ACCEPT_BASE_ADDR + 0x1C)) + +#define CAN_CENTRAL_BASE_ADDR 0xE0040000 +#define CAN_TX_SR (*(volatile unsigned long *)(CAN_CENTRAL_BASE_ADDR + 0x00)) +#define CAN_RX_SR (*(volatile unsigned long *)(CAN_CENTRAL_BASE_ADDR + 0x04)) +#define CAN_MSR (*(volatile unsigned long *)(CAN_CENTRAL_BASE_ADDR + 0x08)) + +#define CAN1_BASE_ADDR 0xE0044000 +#define CAN1MOD (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x00)) +#define CAN1CMR (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x04)) +#define CAN1GSR (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x08)) +#define CAN1ICR (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x0C)) +#define CAN1IER (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x10)) +#define CAN1BTR (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x14)) +#define CAN1EWL (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x18)) +#define CAN1SR (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x1C)) +#define CAN1RFS (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x20)) +#define CAN1RID (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x24)) +#define CAN1RDA (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x28)) +#define CAN1RDB (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x2C)) + +#define CAN1TFI1 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x30)) +#define CAN1TID1 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x34)) +#define CAN1TDA1 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x38)) +#define CAN1TDB1 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x3C)) +#define CAN1TFI2 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x40)) +#define CAN1TID2 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x44)) +#define CAN1TDA2 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x48)) +#define CAN1TDB2 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x4C)) +#define CAN1TFI3 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x50)) +#define CAN1TID3 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x54)) +#define CAN1TDA3 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x58)) +#define CAN1TDB3 (*(volatile unsigned long *)(CAN1_BASE_ADDR + 0x5C)) + +#define CAN2_BASE_ADDR 0xE0048000 +#define CAN2MOD (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x00)) +#define CAN2CMR (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x04)) +#define CAN2GSR (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x08)) +#define CAN2ICR (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x0C)) +#define CAN2IER (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x10)) +#define CAN2BTR (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x14)) +#define CAN2EWL (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x18)) +#define CAN2SR (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x1C)) +#define CAN2RFS (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x20)) +#define CAN2RID (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x24)) +#define CAN2RDA (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x28)) +#define CAN2RDB (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x2C)) + +#define CAN2TFI1 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x30)) +#define CAN2TID1 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x34)) +#define CAN2TDA1 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x38)) +#define CAN2TDB1 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x3C)) +#define CAN2TFI2 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x40)) +#define CAN2TID2 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x44)) +#define CAN2TDA2 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x48)) +#define CAN2TDB2 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x4C)) +#define CAN2TFI3 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x50)) +#define CAN2TID3 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x54)) +#define CAN2TDA3 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x58)) +#define CAN2TDB3 (*(volatile unsigned long *)(CAN2_BASE_ADDR + 0x5C)) + + +/* MultiMedia Card Interface(MCI) Controller */ +#define MCI_BASE_ADDR 0xE008C000 +#define MCI_POWER (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x00)) +#define MCI_CLOCK (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x04)) +#define MCI_ARGUMENT (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x08)) +#define MCI_COMMAND (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x0C)) +#define MCI_RESP_CMD (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x10)) +#define MCI_RESP0 (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x14)) +#define MCI_RESP1 (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x18)) +#define MCI_RESP2 (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x1C)) +#define MCI_RESP3 (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x20)) +#define MCI_DATA_TMR (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x24)) +#define MCI_DATA_LEN (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x28)) +#define MCI_DATA_CTRL (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x2C)) +#define MCI_DATA_CNT (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x30)) +#define MCI_STATUS (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x34)) +#define MCI_CLEAR (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x38)) +#define MCI_MASK0 (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x3C)) +#define MCI_MASK1 (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x40)) +#define MCI_FIFO_CNT (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x48)) +#define MCI_FIFO (*(volatile unsigned long *)(MCI_BASE_ADDR + 0x80)) + + +/* I2S Interface Controller (I2S) */ +#define I2S_BASE_ADDR 0xE0088000 +#define I2S_DAO (*(volatile unsigned long *)(I2S_BASE_ADDR + 0x00)) +#define I2S_DAI (*(volatile unsigned long *)(I2S_BASE_ADDR + 0x04)) +#define I2S_TX_FIFO (*(volatile unsigned long *)(I2S_BASE_ADDR + 0x08)) +#define I2S_RX_FIFO (*(volatile unsigned long *)(I2S_BASE_ADDR + 0x0C)) +#define I2S_STATE (*(volatile unsigned long *)(I2S_BASE_ADDR + 0x10)) +#define I2S_DMA1 (*(volatile unsigned long *)(I2S_BASE_ADDR + 0x14)) +#define I2S_DMA2 (*(volatile unsigned long *)(I2S_BASE_ADDR + 0x18)) +#define I2S_IRQ (*(volatile unsigned long *)(I2S_BASE_ADDR + 0x1C)) +#define I2S_TXRATE (*(volatile unsigned long *)(I2S_BASE_ADDR + 0x20)) +#define I2S_RXRATE (*(volatile unsigned long *)(I2S_BASE_ADDR + 0x24)) + + +/* General-purpose DMA Controller */ +#define DMA_BASE_ADDR 0xFFE04000 +#define GPDMA_INT_STAT (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x000)) +#define GPDMA_INT_TCSTAT (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x004)) +#define GPDMA_INT_TCCLR (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x008)) +#define GPDMA_INT_ERR_STAT (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x00C)) +#define GPDMA_INT_ERR_CLR (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x010)) +#define GPDMA_RAW_INT_TCSTAT (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x014)) +#define GPDMA_RAW_INT_ERR_STAT (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x018)) +#define GPDMA_ENABLED_CHNS (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x01C)) +#define GPDMA_SOFT_BREQ (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x020)) +#define GPDMA_SOFT_SREQ (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x024)) +#define GPDMA_SOFT_LBREQ (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x028)) +#define GPDMA_SOFT_LSREQ (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x02C)) +#define GPDMA_CONFIG (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x030)) +#define GPDMA_SYNC (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x034)) + +/* DMA channel 0 registers */ +#define GPDMA_CH0_SRC (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x100)) +#define GPDMA_CH0_DEST (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x104)) +#define GPDMA_CH0_LLI (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x108)) +#define GPDMA_CH0_CTRL (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x10C)) +#define GPDMA_CH0_CFG (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x110)) + +/* DMA channel 1 registers */ +#define GPDMA_CH1_SRC (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x120)) +#define GPDMA_CH1_DEST (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x124)) +#define GPDMA_CH1_LLI (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x128)) +#define GPDMA_CH1_CTRL (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x12C)) +#define GPDMA_CH1_CFG (*(volatile unsigned long *)(DMA_BASE_ADDR + 0x130)) + + +/* USB Controller */ +#define USB_INT_BASE_ADDR 0xE01FC1C0 +#define USB_BASE_ADDR 0xFFE0C200 /* USB Base Address */ + +#define USB_INT_STAT (*(volatile unsigned long *)(USB_INT_BASE_ADDR + 0x00)) + +/* USB Device Interrupt Registers */ +#define DEV_INT_STAT (*(volatile unsigned long *)(USB_BASE_ADDR + 0x00)) +#define DEV_INT_EN (*(volatile unsigned long *)(USB_BASE_ADDR + 0x04)) +#define DEV_INT_CLR (*(volatile unsigned long *)(USB_BASE_ADDR + 0x08)) +#define DEV_INT_SET (*(volatile unsigned long *)(USB_BASE_ADDR + 0x0C)) +#define DEV_INT_PRIO (*(volatile unsigned long *)(USB_BASE_ADDR + 0x2C)) + +/* USB Device Endpoint Interrupt Registers */ +#define EP_INT_STAT (*(volatile unsigned long *)(USB_BASE_ADDR + 0x30)) +#define EP_INT_EN (*(volatile unsigned long *)(USB_BASE_ADDR + 0x34)) +#define EP_INT_CLR (*(volatile unsigned long *)(USB_BASE_ADDR + 0x38)) +#define EP_INT_SET (*(volatile unsigned long *)(USB_BASE_ADDR + 0x3C)) +#define EP_INT_PRIO (*(volatile unsigned long *)(USB_BASE_ADDR + 0x40)) + +/* USB Device Endpoint Realization Registers */ +#define REALIZE_EP (*(volatile unsigned long *)(USB_BASE_ADDR + 0x44)) +#define EP_INDEX (*(volatile unsigned long *)(USB_BASE_ADDR + 0x48)) +#define MAXPACKET_SIZE (*(volatile unsigned long *)(USB_BASE_ADDR + 0x4C)) + +/* USB Device Command Reagisters */ +#define CMD_CODE (*(volatile unsigned long *)(USB_BASE_ADDR + 0x10)) +#define CMD_DATA (*(volatile unsigned long *)(USB_BASE_ADDR + 0x14)) + +/* USB Device Data Transfer Registers */ +#define RX_DATA (*(volatile unsigned long *)(USB_BASE_ADDR + 0x18)) +#define TX_DATA (*(volatile unsigned long *)(USB_BASE_ADDR + 0x1C)) +#define RX_PLENGTH (*(volatile unsigned long *)(USB_BASE_ADDR + 0x20)) +#define TX_PLENGTH (*(volatile unsigned long *)(USB_BASE_ADDR + 0x24)) +#define USB_CTRL (*(volatile unsigned long *)(USB_BASE_ADDR + 0x28)) + +/* USB Device DMA Registers */ +#define DMA_REQ_STAT (*(volatile unsigned long *)(USB_BASE_ADDR + 0x50)) +#define DMA_REQ_CLR (*(volatile unsigned long *)(USB_BASE_ADDR + 0x54)) +#define DMA_REQ_SET (*(volatile unsigned long *)(USB_BASE_ADDR + 0x58)) +#define UDCA_HEAD (*(volatile unsigned long *)(USB_BASE_ADDR + 0x80)) +#define EP_DMA_STAT (*(volatile unsigned long *)(USB_BASE_ADDR + 0x84)) +#define EP_DMA_EN (*(volatile unsigned long *)(USB_BASE_ADDR + 0x88)) +#define EP_DMA_DIS (*(volatile unsigned long *)(USB_BASE_ADDR + 0x8C)) +#define DMA_INT_STAT (*(volatile unsigned long *)(USB_BASE_ADDR + 0x90)) +#define DMA_INT_EN (*(volatile unsigned long *)(USB_BASE_ADDR + 0x94)) +#define EOT_INT_STAT (*(volatile unsigned long *)(USB_BASE_ADDR + 0xA0)) +#define EOT_INT_CLR (*(volatile unsigned long *)(USB_BASE_ADDR + 0xA4)) +#define EOT_INT_SET (*(volatile unsigned long *)(USB_BASE_ADDR + 0xA8)) +#define NDD_REQ_INT_STAT (*(volatile unsigned long *)(USB_BASE_ADDR + 0xAC)) +#define NDD_REQ_INT_CLR (*(volatile unsigned long *)(USB_BASE_ADDR + 0xB0)) +#define NDD_REQ_INT_SET (*(volatile unsigned long *)(USB_BASE_ADDR + 0xB4)) +#define SYS_ERR_INT_STAT (*(volatile unsigned long *)(USB_BASE_ADDR + 0xB8)) +#define SYS_ERR_INT_CLR (*(volatile unsigned long *)(USB_BASE_ADDR + 0xBC)) +#define SYS_ERR_INT_SET (*(volatile unsigned long *)(USB_BASE_ADDR + 0xC0)) + +/* USB Host and OTG registers are for LPC24xx only */ +/* USB Host Controller */ +#define USBHC_BASE_ADDR 0xFFE0C000 +#define HC_REVISION (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x00)) +#define HC_CONTROL (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x04)) +#define HC_CMD_STAT (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x08)) +#define HC_INT_STAT (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x0C)) +#define HC_INT_EN (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x10)) +#define HC_INT_DIS (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x14)) +#define HC_HCCA (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x18)) +#define HC_PERIOD_CUR_ED (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x1C)) +#define HC_CTRL_HEAD_ED (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x20)) +#define HC_CTRL_CUR_ED (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x24)) +#define HC_BULK_HEAD_ED (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x28)) +#define HC_BULK_CUR_ED (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x2C)) +#define HC_DONE_HEAD (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x30)) +#define HC_FM_INTERVAL (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x34)) +#define HC_FM_REMAINING (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x38)) +#define HC_FM_NUMBER (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x3C)) +#define HC_PERIOD_START (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x40)) +#define HC_LS_THRHLD (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x44)) +#define HC_RH_DESCA (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x48)) +#define HC_RH_DESCB (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x4C)) +#define HC_RH_STAT (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x50)) +#define HC_RH_PORT_STAT1 (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x54)) +#define HC_RH_PORT_STAT2 (*(volatile unsigned long *)(USBHC_BASE_ADDR + 0x58)) + +/* USB OTG Controller */ +#define USBOTG_BASE_ADDR 0xFFE0C100 +#define OTG_INT_STAT (*(volatile unsigned long *)(USBOTG_BASE_ADDR + 0x00)) +#define OTG_INT_EN (*(volatile unsigned long *)(USBOTG_BASE_ADDR + 0x04)) +#define OTG_INT_SET (*(volatile unsigned long *)(USBOTG_BASE_ADDR + 0x08)) +#define OTG_INT_CLR (*(volatile unsigned long *)(USBOTG_BASE_ADDR + 0x0C)) +/* On LPC23xx, the name is USBPortSel, on LPC24xx, the name is OTG_STAT_CTRL */ +#define OTG_STAT_CTRL (*(volatile unsigned long *)(USBOTG_BASE_ADDR + 0x10)) +#define OTG_TIMER (*(volatile unsigned long *)(USBOTG_BASE_ADDR + 0x14)) + +#define USBOTG_I2C_BASE_ADDR 0xFFE0C300 +#define OTG_I2C_RX (*(volatile unsigned long *)(USBOTG_I2C_BASE_ADDR + 0x00)) +#define OTG_I2C_TX (*(volatile unsigned long *)(USBOTG_I2C_BASE_ADDR + 0x00)) +#define OTG_I2C_STS (*(volatile unsigned long *)(USBOTG_I2C_BASE_ADDR + 0x04)) +#define OTG_I2C_CTL (*(volatile unsigned long *)(USBOTG_I2C_BASE_ADDR + 0x08)) +#define OTG_I2C_CLKHI (*(volatile unsigned long *)(USBOTG_I2C_BASE_ADDR + 0x0C)) +#define OTG_I2C_CLKLO (*(volatile unsigned long *)(USBOTG_I2C_BASE_ADDR + 0x10)) + +/* On LPC23xx, the names are USBClkCtrl and USBClkSt; on LPC24xx, the names are +OTG_CLK_CTRL and OTG_CLK_STAT respectively. */ +#define USBOTG_CLK_BASE_ADDR 0xFFE0CFF0 +#define OTG_CLK_CTRL (*(volatile unsigned long *)(USBOTG_CLK_BASE_ADDR + 0x04)) +#define OTG_CLK_STAT (*(volatile unsigned long *)(USBOTG_CLK_BASE_ADDR + 0x08)) + +/* Note: below three register name convention is for LPC23xx USB device only, match +with the spec. update in USB Device Section. */ +#define USBPortSel (*(volatile unsigned long *)(USBOTG_BASE_ADDR + 0x10)) +#define USBClkCtrl (*(volatile unsigned long *)(USBOTG_CLK_BASE_ADDR + 0x04)) +#define USBClkSt (*(volatile unsigned long *)(USBOTG_CLK_BASE_ADDR + 0x08)) + +/* Ethernet MAC (32 bit data bus) -- all registers are RW unless indicated in parentheses */ +#define MAC_BASE_ADDR 0xFFE00000 /* AHB Peripheral # 0 */ +#define MAC_MAC1 (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x000)) /* MAC config reg 1 */ +#define MAC_MAC2 (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x004)) /* MAC config reg 2 */ +#define MAC_IPGT (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x008)) /* b2b InterPacketGap reg */ +#define MAC_IPGR (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x00C)) /* non b2b InterPacketGap reg */ +#define MAC_CLRT (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x010)) /* CoLlision window/ReTry reg */ +#define MAC_MAXF (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x014)) /* MAXimum Frame reg */ +#define MAC_SUPP (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x018)) /* PHY SUPPort reg */ +#define MAC_TEST (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x01C)) /* TEST reg */ +#define MAC_MCFG (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x020)) /* MII Mgmt ConFiG reg */ +#define MAC_MCMD (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x024)) /* MII Mgmt CoMmanD reg */ +#define MAC_MADR (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x028)) /* MII Mgmt ADdRess reg */ +#define MAC_MWTD (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x02C)) /* MII Mgmt WriTe Data reg (WO) */ +#define MAC_MRDD (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x030)) /* MII Mgmt ReaD Data reg (RO) */ +#define MAC_MIND (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x034)) /* MII Mgmt INDicators reg (RO) */ + +#define MAC_SA0 (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x040)) /* Station Address 0 reg */ +#define MAC_SA1 (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x044)) /* Station Address 1 reg */ +#define MAC_SA2 (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x048)) /* Station Address 2 reg */ + +#define MAC_COMMAND (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x100)) /* Command reg */ +#define MAC_STATUS (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x104)) /* Status reg (RO) */ +#define MAC_RXDESCRIPTOR (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x108)) /* Rx descriptor base address reg */ +#define MAC_RXSTATUS (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x10C)) /* Rx status base address reg */ +#define MAC_RXDESCRIPTORNUM (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x110)) /* Rx number of descriptors reg */ +#define MAC_RXPRODUCEINDEX (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x114)) /* Rx produce index reg (RO) */ +#define MAC_RXCONSUMEINDEX (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x118)) /* Rx consume index reg */ +#define MAC_TXDESCRIPTOR (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x11C)) /* Tx descriptor base address reg */ +#define MAC_TXSTATUS (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x120)) /* Tx status base address reg */ +#define MAC_TXDESCRIPTORNUM (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x124)) /* Tx number of descriptors reg */ +#define MAC_TXPRODUCEINDEX (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x128)) /* Tx produce index reg */ +#define MAC_TXCONSUMEINDEX (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x12C)) /* Tx consume index reg (RO) */ + +#define MAC_TSV0 (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x158)) /* Tx status vector 0 reg (RO) */ +#define MAC_TSV1 (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x15C)) /* Tx status vector 1 reg (RO) */ +#define MAC_RSV (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x160)) /* Rx status vector reg (RO) */ + +#define MAC_FLOWCONTROLCNT (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x170)) /* Flow control counter reg */ +#define MAC_FLOWCONTROLSTS (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x174)) /* Flow control status reg */ + +#define MAC_RXFILTERCTRL (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x200)) /* Rx filter ctrl reg */ +#define MAC_RXFILTERWOLSTS (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x204)) /* Rx filter WoL status reg (RO) */ +#define MAC_RXFILTERWOLCLR (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x208)) /* Rx filter WoL clear reg (WO) */ + +#define MAC_HASHFILTERL (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x210)) /* Hash filter LSBs reg */ +#define MAC_HASHFILTERH (*(volatile unsigned long *)(MAC_BASE_ADDR + 0x214)) /* Hash filter MSBs reg */ + +#define MAC_INTSTATUS (*(volatile unsigned long *)(MAC_BASE_ADDR + 0xFE0)) /* Interrupt status reg (RO) */ +#define MAC_INTENABLE (*(volatile unsigned long *)(MAC_BASE_ADDR + 0xFE4)) /* Interrupt enable reg */ +#define MAC_INTCLEAR (*(volatile unsigned long *)(MAC_BASE_ADDR + 0xFE8)) /* Interrupt clear reg (WO) */ +#define MAC_INTSET (*(volatile unsigned long *)(MAC_BASE_ADDR + 0xFEC)) /* Interrupt set reg (WO) */ + +#define MAC_POWERDOWN (*(volatile unsigned long *)(MAC_BASE_ADDR + 0xFF4)) /* Power-down reg */ +#define MAC_MODULEID (*(volatile unsigned long *)(MAC_BASE_ADDR + 0xFFC)) /* Module ID reg (RO) */ + +/* LCD Controller registers */ +#define LCD_BASE_ADDR 0xFFE10000 /* AHB Peripheral # 4 */ +#define LCD_CFG (*(volatile unsigned long *)(0xE01FC1B8)) +#define LCD_TIMH (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x000)) +#define LCD_TIMV (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x004)) +#define LCD_POL (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x008)) +#define LCD_LE (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x00C)) +#define LCD_UPBASE (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x010)) +#define LCD_LPBASE (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x014)) +#define LCD_CTRL (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x018)) +#define LCD_INTMSK (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x01C)) +#define LCD_INTRAW (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x020)) +#define LCD_INTSTAT (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x024)) +#define LCD_INTCLR (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x028)) +#define LCD_UPCURR (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x02C)) +#define LCD_LPCURR (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x030)) +#define LCD_PAL (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x200)) +#define CRSR_IMG (*(volatile unsigned long *)(LCD_BASE_ADDR + 0x800)) +#define CRSR_CTRL (*(volatile unsigned long *)(LCD_BASE_ADDR + 0xC00)) +#define CRSR_CFG (*(volatile unsigned long *)(LCD_BASE_ADDR + 0xC04)) +#define CRSR_PAL0 (*(volatile unsigned long *)(LCD_BASE_ADDR + 0xC08)) +#define CRSR_PAL1 (*(volatile unsigned long *)(LCD_BASE_ADDR + 0xC0C)) +#define CRSR_XY (*(volatile unsigned long *)(LCD_BASE_ADDR + 0xC10)) +#define CRSR_CLIP (*(volatile unsigned long *)(LCD_BASE_ADDR + 0xC14)) +#define CRSR_INTMSK (*(volatile unsigned long *)(LCD_BASE_ADDR + 0xC20)) +#define CRSR_INTCLR (*(volatile unsigned long *)(LCD_BASE_ADDR + 0xC24)) +#define CRSR_INTRAW (*(volatile unsigned long *)(LCD_BASE_ADDR + 0xC28)) +#define CRSR_INTSTAT (*(volatile unsigned long *)(LCD_BASE_ADDR + 0xC2C)) + +struct rt_hw_register +{ + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long sp; + unsigned long lr; + unsigned long pc; + unsigned long cpsr; + unsigned long ORIG_r0; +}; + +#ifdef __cplusplus +} +#endif + +#endif // __LPC24xx_H + diff --git a/rt-thread/libcpu/arm/lpc24xx/context_gcc.S b/rt-thread/libcpu/arm/lpc24xx/context_gcc.S new file mode 100644 index 0000000..df22aac --- /dev/null +++ b/rt-thread/libcpu/arm/lpc24xx/context_gcc.S @@ -0,0 +1,99 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + */ + +/*! + * \addtogroup LPC2478 + */ +/*@{*/ + +#define NOINT 0xc0 + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + orr r1, r0, #NOINT + msr cpsr_c, r1 + mov pc, lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + mov pc, lr + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + stmfd sp!, {r4} @ push cpsr + mrs r4, spsr + stmfd sp!, {r4} @ push spsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r4} @ pop new task cpsr + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r4} @ pop new task cpsr + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 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] + mov pc, lr diff --git a/rt-thread/libcpu/arm/lpc24xx/context_rvds.S b/rt-thread/libcpu/arm/lpc24xx/context_rvds.S new file mode 100644 index 0000000..ecd20e4 --- /dev/null +++ b/rt-thread/libcpu/arm/lpc24xx/context_rvds.S @@ -0,0 +1,111 @@ +;/* +; * File : context_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, 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-20 Bernard first version +; * 2011-07-22 Bernard added thumb mode porting +; */ + +NOINT EQU 0xc0 ; disable interrupt in psr + + AREA |.text|, CODE, READONLY, ALIGN=2 + ARM + REQUIRE8 + PRESERVE8 + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ +rt_hw_interrupt_disable PROC + EXPORT rt_hw_interrupt_disable + MRS r0, cpsr + ORR r1, r0, #NOINT + MSR cpsr_c, r1 + BX lr + ENDP + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ +rt_hw_interrupt_enable PROC + EXPORT rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + ENDP + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ +rt_hw_context_switch PROC + EXPORT rt_hw_context_switch + STMFD sp!, {lr} ; push pc (lr should be pushed in place of PC) + STMFD sp!, {r0-r12, lr} ; push lr & register file + + MRS r4, cpsr + TST lr, #0x01 + BEQ _ARM_MODE + ORR r4, r4, #0x20 ; it's thumb code + +_ARM_MODE + STMFD sp!, {r4} ; push cpsr + + STR sp, [r0] ; store sp in preempted tasks TCB + LDR sp, [r1] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task cpsr to spsr + MSR spsr_cxsf, r4 + BIC r4, r4, #0x20 ; must be ARM mode + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr + ENDP + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ +rt_hw_context_switch_to PROC + EXPORT rt_hw_context_switch_to + LDR sp, [r0] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task cpsr to spsr + MSR spsr_cxsf, r4 + BIC r4, r4, #0x20 ; must be ARM mode + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc, copy spsr to cpsr + ENDP + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +rt_hw_context_switch_interrupt PROC + EXPORT rt_hw_context_switch_interrupt + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 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] + BX lr + ENDP + + END \ No newline at end of file diff --git a/rt-thread/libcpu/arm/lpc24xx/cpu.c b/rt-thread/libcpu/arm/lpc24xx/cpu.c new file mode 100644 index 0000000..0265ed9 --- /dev/null +++ b/rt-thread/libcpu/arm/lpc24xx/cpu.c @@ -0,0 +1,42 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + */ + +#include +#include "LPC24xx.h" + +/** + * @addtogroup LPC2478 + */ +/*@{*/ + +/** + * this function will reset CPU + * + */ +void rt_hw_cpu_reset() +{ +} + +/** + * this function will shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_kprintf("shutdown...\n"); + + while (1); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/lpc24xx/interrupt.c b/rt-thread/libcpu/arm/lpc24xx/interrupt.c new file mode 100644 index 0000000..16d1dd7 --- /dev/null +++ b/rt-thread/libcpu/arm/lpc24xx/interrupt.c @@ -0,0 +1,107 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + * 2013-03-29 aozima Modify the interrupt interface implementations. + */ + +#include +#include +#include "LPC24xx.h" + +#define MAX_HANDLERS 32 + +/* exception and interrupt handler table */ +struct rt_irq_desc irq_desc[MAX_HANDLERS]; + +extern rt_uint32_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +/** + * @addtogroup LPC2478 + */ +/*@{*/ +void rt_hw_interrupt_handler(int vector, void *param) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +void rt_hw_interrupt_init(void) +{ + register int i; + + rt_uint32_t *vect_addr, *vect_cntl; + + /* initialize VIC*/ + VICIntEnClr = 0xffffffff; + VICVectAddr = 0; + VICIntSelect = 0; + + /* init exceptions table */ + rt_memset(irq_desc, 0x00, sizeof(irq_desc)); + for(i=0; i < MAX_HANDLERS; i++) + { + irq_desc[i].handler = rt_hw_interrupt_handler; + + vect_addr = (rt_uint32_t *)(VIC_BASE_ADDR + 0x100 + i*4); + vect_cntl = (rt_uint32_t *)(VIC_BASE_ADDR + 0x200 + i*4); + *vect_addr = (rt_uint32_t)&irq_desc[i]; + *vect_cntl = 0xF; + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +void rt_hw_interrupt_mask(int vector) +{ + VICIntEnClr = (1 << vector); +} + +void rt_hw_interrupt_umask(int vector) +{ + VICIntEnable = (1 << vector); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param handler the interrupt service routine to be installed + * @param param the parameter for interrupt service routine + * @name unused. + * + * @return the old handler + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if(vector >= 0 && vector < MAX_HANDLERS) + { + old_handler = irq_desc[vector].handler; + if (handler != RT_NULL) + { + irq_desc[vector].handler = handler; + irq_desc[vector].param = param; + } + } + + return old_handler; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/lpc24xx/stack.c b/rt-thread/libcpu/arm/lpc24xx/stack.c new file mode 100644 index 0000000..f160e9c --- /dev/null +++ b/rt-thread/libcpu/arm/lpc24xx/stack.c @@ -0,0 +1,67 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + */ +#include +#include "LPC24xx.h" + +/** + * @addtogroup LPC2478 + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/lpc24xx/start_gcc.S b/rt-thread/libcpu/arm/lpc24xx/start_gcc.S new file mode 100644 index 0000000..feab6f0 --- /dev/null +++ b/rt-thread/libcpu/arm/lpc24xx/start_gcc.S @@ -0,0 +1,286 @@ +/* + * File : start.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + * 2011-03-17 Bernard update to 0.4.x + */ + +#define WDMOD (0xE0000000 + 0x00) +#define VICIntEnClr (0xFFFFF000 + 0x014) +#define VICVectAddr (0xFFFFF000 + 0xF00) +#define VICIntSelect (0xFFFFF000 + 0x00C) +#define PLLCFG (0xE01FC000 + 0x084) +#define PLLCON (0xE01FC000 + 0x080) +#define PLLFEED (0xE01FC000 + 0x08C) +#define PLLSTAT (0xE01FC000 + 0x088) +#define CCLKCFG (0xE01FC000 + 0x104) +#define MEMMAP (0xE01FC000 + 0x040) +#define SCS (0xE01FC000 + 0x1A0) +#define CLKSRCSEL (0xE01FC000 + 0x10C) +#define MAMCR (0xE01FC000 + 0x000) +#define MAMTIM (0xE01FC000 + 0x004) + +/* stack memory */ +.section .bss.noinit +.equ IRQ_STACK_SIZE, 0x00000200 +.equ FIQ_STACK_SIZE, 0x00000100 +.equ UDF_STACK_SIZE, 0x00000004 +.equ ABT_STACK_SIZE, 0x00000004 +.equ SVC_STACK_SIZE, 0x00000200 + +.space IRQ_STACK_SIZE +IRQ_STACK: + +.space FIQ_STACK_SIZE +FIQ_STACK: + +.space UDF_STACK_SIZE +UDF_STACK: + +.space ABT_STACK_SIZE +ABT_STACK: + +.space SVC_STACK_SIZE +SVC_STACK: + +.section .init, "ax" +.code 32 +.globl _start +_start: + b reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + ldr pc, _vector_resv + ldr pc, _vector_irq + ldr pc, _vector_fiq + +_vector_undef: .word vector_undef +_vector_swi: .word vector_swi +_vector_pabt: .word vector_pabt +_vector_dabt: .word vector_dabt +_vector_resv: .word vector_resv +_vector_irq: .word vector_irq +_vector_fiq: .word vector_fiq + +.balignl 16,0xdeadbeef + +/* + * rtthread kernel start and end + * which are defined in linker script + */ +.globl _rtthread_start +_rtthread_start: + .word _start + +.globl _rtthread_end +_rtthread_end: + .word _end + +/* + * rtthread bss start and end which are defined in linker script + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word __bss_end + +.text +.code 32 + +/* the system entry */ +reset: + /* enter svc mode */ + msr cpsr_c, #SVCMODE|NOINT + + /*watch dog disable */ + ldr r0,=WDMOD + ldr r1,=0x0 + str r1,[r0] + + /* all interrupt disable */ + ldr r0,=VICIntEnClr + ldr r1,=0xffffffff + str r1,[r0] + + ldr r1, =VICVectAddr + ldr r0, =0x00 + str r0, [r1] + + ldr r1, =VICIntSelect + ldr r0, =0x00 + str r0, [r1] + + /* setup stack */ + bl stack_setup + + /* copy .data to SRAM */ + ldr r1, =_sidata /* .data start in image */ + ldr r2, =_edata /* .data end in image */ + ldr r3, =_sdata /* sram data start */ +data_loop: + ldr r0, [r1, #0] + str r0, [r3] + + add r1, r1, #4 + add r3, r3, #4 + + cmp r3, r2 /* check if data to clear */ + blo data_loop /* loop until done */ + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop +ctor_end: + + /* start RT-Thread Kernel */ + ldr pc, _rtthread_startup + +_rtthread_startup: + .word rtthread_startup + + .equ USERMODE, 0x10 + .equ FIQMODE, 0x11 + .equ IRQMODE, 0x12 + .equ SVCMODE, 0x13 + .equ ABORTMODE, 0x17 + .equ UNDEFMODE, 0x1b + .equ MODEMASK, 0x1f + .equ NOINT, 0xc0 + +/* exception handlers */ +vector_undef: bl rt_hw_trap_udef +vector_swi: bl rt_hw_trap_swi +vector_pabt: bl rt_hw_trap_pabt +vector_dabt: bl rt_hw_trap_dabt +vector_resv: bl rt_hw_trap_resv + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +vector_irq: + stmfd sp!, {r0-r12,lr} + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + + /* if rt_thread_switch_interrupt_flag set, + * jump to _interrupt_thread_switch and don't return + */ + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq _interrupt_thread_switch + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + + .align 5 +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc,lr,#4 + +_interrupt_thread_switch: + mov r1, #0 /* clear rt_thread_switch_interrupt_flag */ + str r1, [r0] + + ldmfd sp!, {r0-r12,lr} /* reload saved registers */ + stmfd sp!, {r0-r3} /* save r0-r3 */ + mov r1, sp + add sp, sp, #16 /* restore sp */ + sub r2, lr, #4 /* save old task's pc to r2 */ + + mrs r3, spsr /* disable interrupt */ + orr r0, r3, #NOINT + msr spsr_c, r0 + + ldr r0, =.+8 /* switch to interrupted task's stack */ + movs pc, r0 + + stmfd sp!, {r2} /* push old task's pc */ + stmfd sp!, {r4-r12,lr} /* push old task's lr,r12-r4 */ + mov r4, r1 /* Special optimised code below */ + mov r5, r3 + ldmfd r4!, {r0-r3} + stmfd sp!, {r0-r3} /* push old task's r3-r0 */ + stmfd sp!, {r5} /* push old task's psr */ + mrs r4, spsr + stmfd sp!, {r4} /* push old task's spsr */ + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] /* store sp in preempted tasks's TCB */ + + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] /* get new task's stack pointer */ + + ldmfd sp!, {r4} /* pop new task's spsr */ + msr SPSR_cxsf, r4 + ldmfd sp!, {r4} /* pop new task's psr */ + msr CPSR_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc} /* pop new task's r0-r12,lr & pc */ + +stack_setup: + mrs r0, cpsr + bic r0, r0, #MODEMASK + orr r1, r0, #UNDEFMODE|NOINT + msr cpsr_cxsf, r1 /* undef mode */ + ldr sp, =UDF_STACK + + orr r1,r0,#ABORTMODE|NOINT + msr cpsr_cxsf,r1 /* abort mode */ + ldr sp, =ABT_STACK + + orr r1,r0,#IRQMODE|NOINT + msr cpsr_cxsf,r1 /* IRQ mode */ + ldr sp, =IRQ_STACK + + orr r1,r0,#FIQMODE|NOINT + msr cpsr_cxsf,r1 /* FIQ mode */ + ldr sp, =FIQ_STACK + + bic r0,r0,#MODEMASK + orr r1,r0,#SVCMODE|NOINT + msr cpsr_cxsf,r1 /* SVC mode */ + ldr sp, =SVC_STACK + + /* USER mode is not initialized. */ + mov pc,lr /* The LR register may be not valid for the mode changes.*/ diff --git a/rt-thread/libcpu/arm/lpc24xx/start_rvds.S b/rt-thread/libcpu/arm/lpc24xx/start_rvds.S new file mode 100644 index 0000000..e49cf2d --- /dev/null +++ b/rt-thread/libcpu/arm/lpc24xx/start_rvds.S @@ -0,0 +1,1632 @@ +;/*****************************************************************************/ +;/* LPC2400.S: Startup file for Philips LPC2400 device series */ +;/*****************************************************************************/ +;/* <<< Use Configuration Wizard in Context Menu >>> */ +;/*****************************************************************************/ +;/* This file is part of the uVision/ARM development tools. */ +;/* Copyright (c) 2007-2008 Keil - An ARM Company. All rights reserved. */ +;/* This software may only be used under the terms of a valid, current, */ +;/* end user licence from KEIL for a compatible version of KEIL software */ +;/* development tools. Nothing else gives you the right to use this software. */ +;/*****************************************************************************/ + +;/* +; * The LPC2400.S code is executed after CPU Reset. This file may be +; * translated with the following SET symbols. In uVision these SET +; * symbols are entered under Options - ASM - Define. +; * +; * NO_CLOCK_SETUP: when set the startup code will not initialize Clock +; * (used mostly when clock is already initialized from script .ini +; * file). +; * +; * NO_EMC_SETUP: when set the startup code will not initialize +; * External Bus Controller. +; * +; * RAM_INTVEC: when set the startup code copies exception vectors +; * from on-chip Flash to on-chip RAM. +; * +; * REMAP: when set the startup code initializes the register MEMMAP +; * which overwrites the settings of the CPU configuration pins. The +; * startup and interrupt vectors are remapped from: +; * 0x00000000 default setting (not remapped) +; * 0x40000000 when RAM_MODE is used +; * 0x80000000 when EXTMEM_MODE is used +; * +; * EXTMEM_MODE: when set the device is configured for code execution +; * from external memory starting at address 0x80000000. +; * +; * RAM_MODE: when set the device is configured for code execution +; * from on-chip RAM starting at address 0x40000000. +; */ + + +; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs + +Mode_USR EQU 0x10 +Mode_FIQ EQU 0x11 +Mode_IRQ EQU 0x12 +Mode_SVC EQU 0x13 +Mode_ABT EQU 0x17 +Mode_UND EQU 0x1B +Mode_SYS EQU 0x1F +I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled +F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled + +;----------------------- Memory Definitions ------------------------------------ + +; Internal Memory Base Addresses +FLASH_BASE EQU 0x00000000 +RAM_BASE EQU 0x40000000 +EXTMEM_BASE EQU 0x80000000 + +; External Memory Base Addresses +STA_MEM0_BASE EQU 0x80000000 +STA_MEM1_BASE EQU 0x81000000 +STA_MEM2_BASE EQU 0x82000000 +STA_MEM3_BASE EQU 0x83000000 +DYN_MEM0_BASE EQU 0xA0000000 +DYN_MEM1_BASE EQU 0xB0000000 +DYN_MEM2_BASE EQU 0xC0000000 +DYN_MEM3_BASE EQU 0xD0000000 + + +;----------------------- Stack and Heap Definitions ---------------------------- + +;// Stack Configuration (Stack Sizes in Bytes) +;// Undefined Mode <0x0-0xFFFFFFFF:8> +;// Supervisor Mode <0x0-0xFFFFFFFF:8> +;// Abort Mode <0x0-0xFFFFFFFF:8> +;// Fast Interrupt Mode <0x0-0xFFFFFFFF:8> +;// Interrupt Mode <0x0-0xFFFFFFFF:8> +;// User/System Mode <0x0-0xFFFFFFFF:8> +;// + +UND_Stack_Size EQU 0x00000000 +SVC_Stack_Size EQU 0x00000100 +ABT_Stack_Size EQU 0x00000000 +FIQ_Stack_Size EQU 0x00000000 +IRQ_Stack_Size EQU 0x00000100 +USR_Stack_Size EQU 0x00000100 + +ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + FIQ_Stack_Size + IRQ_Stack_Size) + + AREA STACK, NOINIT, READWRITE, ALIGN=3 + +Stack_Mem SPACE USR_Stack_Size +__initial_sp SPACE ISR_Stack_Size + +Stack_Top + + +;// Heap Configuration +;// Heap Size (in Bytes) <0x0-0xFFFFFFFF> +;// + +Heap_Size EQU 0x00000000 + + AREA HEAP, NOINIT, READWRITE, ALIGN=3 +__heap_base +Heap_Mem SPACE Heap_Size +__heap_limit + + +;----------------------- Clock Definitions ------------------------------------- + +; System Control Block (SCB) Module Definitions +SCB_BASE EQU 0xE01FC000 ; SCB Base Address +PLLCON_OFS EQU 0x80 ; PLL Control Offset +PLLCFG_OFS EQU 0x84 ; PLL Configuration Offset +PLLSTAT_OFS EQU 0x88 ; PLL Status Offset +PLLFEED_OFS EQU 0x8C ; PLL Feed Offset +CCLKCFG_OFS EQU 0x104 ; CPU Clock Divider Reg Offset +USBCLKCFG_OFS EQU 0x108 ; USB Clock Divider Reg Offset +CLKSRCSEL_OFS EQU 0x10C ; Clock Source Sel Reg Offset +SCS_OFS EQU 0x1A0 ; Sys Control and Status Reg Offset +PCLKSEL0_OFS EQU 0x1A8 ; Periph Clock Sel Reg 0 Offset +PCLKSEL1_OFS EQU 0x1AC ; Periph Clock Sel Reg 0 Offset + +PCON_OFS EQU 0x0C0 ; Power Mode Control Reg Offset +PCONP_OFS EQU 0x0C4 ; Power Control for Periphs Reg Offset + +; Constants +OSCRANGE EQU (1<<4) ; Oscillator Range Select +OSCEN EQU (1<<5) ; Main oscillator Enable +OSCSTAT EQU (1<<6) ; Main Oscillator Status +PLLCON_PLLE EQU (1<<0) ; PLL Enable +PLLCON_PLLC EQU (1<<1) ; PLL Connect +PLLSTAT_M EQU (0x7FFF<<0) ; PLL M Value +PLLSTAT_N EQU (0xFF<<16) ; PLL N Value +PLLSTAT_PLOCK EQU (1<<26) ; PLL Lock Status + +;// Clock Setup +;// System Controls and Status Register (SYS) +;// OSCRANGE: Main Oscillator Range Select +;// <0=> 1 MHz to 20 MHz +;// <1=> 15 MHz to 24 MHz +;// OSCEN: Main Oscillator Enable +;// +;// +;// +;// PLL Clock Source Select Register (CLKSRCSEL) +;// CLKSRC: PLL Clock Source Selection +;// <0=> Internal RC oscillator +;// <1=> Main oscillator +;// <2=> RTC oscillator +;// +;// +;// PLL Configuration Register (PLLCFG) +;// PLL_clk = (2* M * PLL_clk_src) / N +;// MSEL: PLL Multiplier Selection +;// <1-32768><#-1> +;// M Value +;// NSEL: PLL Divider Selection +;// <1-256><#-1> +;// N Value +;// +;// +;// CPU Clock Configuration Register (CCLKCFG) +;// CCLKSEL: Divide Value for CPU Clock from PLL +;// <1-256><#-1> +;// +;// +;// USB Clock Configuration Register (USBCLKCFG) +;// USBSEL: Divide Value for USB Clock from PLL +;// <1-16><#-1> +;// +;// +;// Peripheral Clock Selection Register 0 (PCLKSEL0) +;// PCLK_WDT: Peripheral Clock Selection for WDT +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_TIMER0: Peripheral Clock Selection for TIMER0 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_TIMER1: Peripheral Clock Selection for TIMER1 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_UART0: Peripheral Clock Selection for UART0 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_UART1: Peripheral Clock Selection for UART1 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_PWM0: Peripheral Clock Selection for PWM0 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_PWM1: Peripheral Clock Selection for PWM1 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_I2C0: Peripheral Clock Selection for I2C0 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_SPI: Peripheral Clock Selection for SPI +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_RTC: Peripheral Clock Selection for RTC +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_SSP1: Peripheral Clock Selection for SSP1 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_DAC: Peripheral Clock Selection for DAC +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_ADC: Peripheral Clock Selection for ADC +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_CAN1: Peripheral Clock Selection for CAN1 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 6 +;// PCLK_CAN2: Peripheral Clock Selection for CAN2 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 6 +;// PCLK_ACF: Peripheral Clock Selection for ACF +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 6 +;// +;// +;// Peripheral Clock Selection Register 1 (PCLKSEL1) +;// PCLK_BAT_RAM: Peripheral Clock Selection for the Battery Supported RAM +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_GPIO: Peripheral Clock Selection for GPIOs +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_PCB: Peripheral Clock Selection for Pin Connect Block +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_I2C1: Peripheral Clock Selection for I2C1 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_SSP0: Peripheral Clock Selection for SSP0 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_TIMER2: Peripheral Clock Selection for TIMER2 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_TIMER3: Peripheral Clock Selection for TIMER3 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_UART2: Peripheral Clock Selection for UART2 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_UART3: Peripheral Clock Selection for UART3 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_I2C2: Peripheral Clock Selection for I2C2 +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_I2S: Peripheral Clock Selection for I2S +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_MCI: Peripheral Clock Selection for MCI +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// PCLK_SYSCON: Peripheral Clock Selection for System Control Block +;// <0=> Pclk = Cclk / 4 +;// <1=> Pclk = Cclk +;// <2=> Pclk = Cclk / 2 +;// <3=> Pclk = Cclk / 8 +;// +;// +CLOCK_SETUP EQU 1 +SCS_Val EQU 0x00000020 +CLKSRCSEL_Val EQU 0x00000001 +PLLCFG_Val EQU 0x0000000B +CCLKCFG_Val EQU 0x00000004 +USBCLKCFG_Val EQU 0x00000005 +PCLKSEL0_Val EQU 0x00000000 +PCLKSEL1_Val EQU 0x00000000 + + +;----------------------- Memory Accelerator Module (MAM) Definitions ----------- + +MAM_BASE EQU 0xE01FC000 ; MAM Base Address +MAMCR_OFS EQU 0x00 ; MAM Control Offset +MAMTIM_OFS EQU 0x04 ; MAM Timing Offset + +;// MAM Setup +;// MAM Control +;// <0=> Disabled +;// <1=> Partially Enabled +;// <2=> Fully Enabled +;// Mode +;// MAM Timing +;// <0=> Reserved <1=> 1 <2=> 2 <3=> 3 +;// <4=> 4 <5=> 5 <6=> 6 <7=> 7 +;// Fetch Cycles +;// +MAM_SETUP EQU 1 +MAMCR_Val EQU 0x00000002 +MAMTIM_Val EQU 0x00000004 + + +;----------------------- Pin Connect Block Definitions ------------------------- + +PCB_BASE EQU 0xE002C000 ; PCB Base Address +PINSEL0_OFS EQU 0x00 ; PINSEL0 Address Offset +PINSEL1_OFS EQU 0x04 ; PINSEL1 Address Offset +PINSEL2_OFS EQU 0x08 ; PINSEL2 Address Offset +PINSEL3_OFS EQU 0x0C ; PINSEL3 Address Offset +PINSEL4_OFS EQU 0x10 ; PINSEL4 Address Offset +PINSEL5_OFS EQU 0x14 ; PINSEL5 Address Offset +PINSEL6_OFS EQU 0x18 ; PINSEL6 Address Offset +PINSEL7_OFS EQU 0x1C ; PINSEL7 Address Offset +PINSEL8_OFS EQU 0x20 ; PINSEL8 Address Offset +PINSEL9_OFS EQU 0x24 ; PINSEL9 Address Offset +PINSEL10_OFS EQU 0x28 ; PINSEL10 Address Offset + + +;----------------------- External Memory Controller (EMC) Definitons ----------- + +EMC_BASE EQU 0xFFE08000 ; EMC Base Address + +EMC_CTRL_OFS EQU 0x000 +EMC_STAT_OFS EQU 0x004 +EMC_CONFIG_OFS EQU 0x008 +EMC_DYN_CTRL_OFS EQU 0x020 +EMC_DYN_RFSH_OFS EQU 0x024 +EMC_DYN_RD_CFG_OFS EQU 0x028 +EMC_DYN_RP_OFS EQU 0x030 +EMC_DYN_RAS_OFS EQU 0x034 +EMC_DYN_SREX_OFS EQU 0x038 +EMC_DYN_APR_OFS EQU 0x03C +EMC_DYN_DAL_OFS EQU 0x040 +EMC_DYN_WR_OFS EQU 0x044 +EMC_DYN_RC_OFS EQU 0x048 +EMC_DYN_RFC_OFS EQU 0x04C +EMC_DYN_XSR_OFS EQU 0x050 +EMC_DYN_RRD_OFS EQU 0x054 +EMC_DYN_MRD_OFS EQU 0x058 +EMC_DYN_CFG0_OFS EQU 0x100 +EMC_DYN_RASCAS0_OFS EQU 0x104 +EMC_DYN_CFG1_OFS EQU 0x140 +EMC_DYN_RASCAS1_OFS EQU 0x144 +EMC_DYN_CFG2_OFS EQU 0x160 +EMC_DYN_RASCAS2_OFS EQU 0x164 +EMC_DYN_CFG3_OFS EQU 0x180 +EMC_DYN_RASCAS3_OFS EQU 0x184 +EMC_STA_CFG0_OFS EQU 0x200 +EMC_STA_WWEN0_OFS EQU 0x204 +EMC_STA_WOEN0_OFS EQU 0x208 +EMC_STA_WRD0_OFS EQU 0x20C +EMC_STA_WPAGE0_OFS EQU 0x210 +EMC_STA_WWR0_OFS EQU 0x214 +EMC_STA_WTURN0_OFS EQU 0x218 +EMC_STA_CFG1_OFS EQU 0x220 +EMC_STA_WWEN1_OFS EQU 0x224 +EMC_STA_WOEN1_OFS EQU 0x228 +EMC_STA_WRD1_OFS EQU 0x22C +EMC_STA_WPAGE1_OFS EQU 0x230 +EMC_STA_WWR1_OFS EQU 0x234 +EMC_STA_WTURN1_OFS EQU 0x238 +EMC_STA_CFG2_OFS EQU 0x240 +EMC_STA_WWEN2_OFS EQU 0x244 +EMC_STA_WOEN2_OFS EQU 0x248 +EMC_STA_WRD2_OFS EQU 0x24C +EMC_STA_WPAGE2_OFS EQU 0x250 +EMC_STA_WWR2_OFS EQU 0x254 +EMC_STA_WTURN2_OFS EQU 0x258 +EMC_STA_CFG3_OFS EQU 0x260 +EMC_STA_WWEN3_OFS EQU 0x264 +EMC_STA_WOEN3_OFS EQU 0x268 +EMC_STA_WRD3_OFS EQU 0x26C +EMC_STA_WPAGE3_OFS EQU 0x270 +EMC_STA_WWR3_OFS EQU 0x274 +EMC_STA_WTURN3_OFS EQU 0x278 +EMC_STA_EXT_W_OFS EQU 0x880 + +; Constants +NORMAL_CMD EQU (0x0 << 7) ; NORMAL Command +MODE_CMD EQU (0x1 << 7) ; MODE Command +PALL_CMD EQU (0x2 << 7) ; Precharge All Command +NOP_CMD EQU (0x3 << 7) ; NOP Command + +BUFEN_Const EQU (1 << 19) ; Buffer enable bit +EMC_PCONP_Const EQU (1 << 11) ; PCONP val to enable power for EMC + +; External Memory Pins definitions +; pin functions for SDRAM, NOR and NAND flash interfacing +EMC_PINSEL5_Val EQU 0x05010115 ; !CAS, !RAS, CLKOUT0, !DYCS0, DQMOUT0, DQMOUT1 +EMC_PINSEL6_Val EQU 0x55555555 ; D0 .. D15 +EMC_PINSEL8_Val EQU 0x55555555 ; A0 .. A15 +EMC_PINSEL9_Val EQU 0x50055555; ; A16 .. A23, !OE, !WE, !CS0, !CS1 + +;// External Memory Controller Setup (EMC) --------------------------------- +;// External Memory Controller Setup (EMC) +EMC_SETUP EQU 0 + +;// EMC Control Register (EMCControl) +;// Controls operation of the memory controller +;// L: Low-power mode enable +;// M: Address mirror enable +;// E: EMC enable +;// +EMC_CTRL_Val EQU 0x00000001 + +;// EMC Configuration Register (EMCConfig) +;// Configures operation of the memory controller +;// CCLK: CLKOUT ratio +;// <0=> 1:1 +;// <1=> 1:2 +;// Endian mode +;// <0=> Little-endian +;// <1=> Big-endian +;// +EMC_CONFIG_Val EQU 0x00000000 + +;// Dynamic Memory Interface Setup --------------------------------------- +;// Dynamic Memory Interface Setup +EMC_DYNAMIC_SETUP EQU 1 + +;// Dynamic Memory Refresh Timer Register (EMCDynamicRefresh) +;// Configures dynamic memory refresh operation +;// REFRESH: Refresh timer <0x000-0x7FF> +;// 0 = refresh disabled, 0x01-0x7FF: value * 16 CCLKS +;// +EMC_DYN_RFSH_Val EQU 0x0000001C + +;// Dynamic Memory Read Configuration Register (EMCDynamicReadConfig) +;// Configures the dynamic memory read strategy +;// RD: Read data strategy +;// <0=> Clock out delayed strategy +;// <1=> Command delayed strategy +;// <2=> Command delayed strategy plus one clock cycle +;// <3=> Command delayed strategy plus two clock cycles +;// +EMC_DYN_RD_CFG_Val EQU 0x00000001 + +;// Dynamic Memory Timings +;// Dynamic Memory Percentage Command Period Register (EMCDynamictRP) +;// tRP: Precharge command period <1-16> <#-1> +;// The delay is in EMCCLK cycles +;// This value is normally found in SDRAM data sheets as tRP +;// +;// Dynamic Memory Active to Precharge Command Period Register (EMCDynamictRAS) +;// tRAS: Active to precharge command period <1-16> <#-1> +;// The delay is in EMCCLK cycles +;// This value is normally found in SDRAM data sheets as tRAS +;// +;// Dynamic Memory Self-refresh Exit Time Register (EMCDynamictSREX) +;// tSREX: Self-refresh exit time <1-16> <#-1> +;// The delay is in CCLK cycles +;// This value is normally found in SDRAM data sheets as tSREX, +;// for devices without this parameter you use the same value as tXSR +;// +;// Dynamic Memory Last Data Out to Active Time Register (EMCDynamictAPR) +;// tAPR: Last-data-out to active command time <1-16> <#-1> +;// The delay is in CCLK cycles +;// This value is normally found in SDRAM data sheets as tAPR +;// +;// Dynamic Memory Data-in to Active Command Time Register (EMCDynamictDAL) +;// tDAL: Data-in to active command time <1-16> <#-1> +;// The delay is in CCLK cycles +;// This value is normally found in SDRAM data sheets as tDAL or tAPW +;// +;// Dynamic Memory Write Recovery Time Register (EMCDynamictWR) +;// tWR: Write recovery time <1-16> <#-1> +;// The delay is in CCLK cycles +;// This value is normally found in SDRAM data sheets as tWR, tDPL, tRWL, or tRDL +;// +;// Dynamic Memory Active to Active Command Period Register (EMCDynamictRC) +;// tRC: Active to active command period <1-32> <#-1> +;// The delay is in CCLK cycles +;// This value is normally found in SDRAM data sheets as tRC +;// +;// Dynamic Memory Auto-refresh Period Register (EMCDynamictRFC) +;// tRFC: Auto-refresh period and auto-refresh to active command period <1-32> <#-1> +;// The delay is in CCLK cycles +;// This value is normally found in SDRAM data sheets as tRFC or tRC +;// +;// Dynamic Memory Exit Self-refresh Register (EMCDynamictXSR) +;// tXSR: Exit self-refresh to active command time <1-32> <#-1> +;// The delay is in CCLK cycles +;// This value is normally found in SDRAM data sheets as tXSR +;// +;// Dynamic Memory Active Bank A to Active Bank B Time Register (EMCDynamicRRD) +;// tRRD: Active bank A to active bank B latency <1-16> <#-1> +;// The delay is in CCLK cycles +;// This value is normally found in SDRAM data sheets as tRRD +;// +;// Dynamic Memory Load Mode Register to Active Command Time (EMCDynamictMRD) +;// tMRD: Load mode register to active command time <1-16> <#-1> +;// The delay is in CCLK cycles +;// This value is normally found in SDRAM data sheets as tMRD or tRSA +;// +;// +EMC_DYN_RP_Val EQU 0x00000002 +EMC_DYN_RAS_Val EQU 0x00000003 +EMC_DYN_SREX_Val EQU 0x00000007 +EMC_DYN_APR_Val EQU 0x00000002 +EMC_DYN_DAL_Val EQU 0x00000005 +EMC_DYN_WR_Val EQU 0x00000001 +EMC_DYN_RC_Val EQU 0x00000005 +EMC_DYN_RFC_Val EQU 0x00000005 +EMC_DYN_XSR_Val EQU 0x00000007 +EMC_DYN_RRD_Val EQU 0x00000001 +EMC_DYN_MRD_Val EQU 0x00000002 + +;// Configure External Bus Behaviour for Dynamic CS0 Area +EMC_DYNCS0_SETUP EQU 1 + +;// Dynamic Memory Configuration Register (EMCDynamicConfig0) +;// Defines the configuration information for the dynamic memory CS0 +;// P: Write protect +;// B: Buffer enable +;// AM 14: External bus data width +;// <0=> 16 bit +;// <1=> 32 bit +;// AM 12: External bus memory type +;// <0=> High-performance +;// <1=> Low-power SDRAM +;// AM 11..7: External bus address mapping (Row, Bank, Column) +;// <0x00=> 16 Mb = 2MB (2Mx8), 2 banks, row length = 11, column length = 9 +;// <0x01=> 16 Mb = 2MB (1Mx16), 2 banks, row length = 11, column length = 8 +;// <0x04=> 64 Mb = 8MB (8Mx8), 4 banks, row length = 12, column length = 9 +;// <0x05=> 64 Mb = 8MB (4Mx16), 4 banks, row length = 12, column length = 8 +;// <0x08=> 128 Mb = 16MB (16Mx8), 4 banks, row length = 12, column length = 10 +;// <0x09=> 128 Mb = 16MB (8Mx16), 4 banks, row length = 12, column length = 9 +;// <0x0C=> 256 Mb = 32MB (32Mx8), 4 banks, row length = 13, column length = 10 +;// <0x0D=> 256 Mb = 32MB (16Mx16), 4 banks, row length = 13, column length = 9 +;// <0x10=> 512 Mb = 64MB (64Mx8), 4 banks, row length = 13, column length = 11 +;// <0x11=> 512 Mb = 64MB (32Mx16), 4 banks, row length = 13, column length = 10 +;// MD: Memory device +;// <0=> SDRAM +;// <1=> Low-power SDRAM +;// <2=> Micron SyncFlash +;// +EMC_DYN_CFG0_Val EQU 0x00080680 + +;// Dynamic Memory RAS & CAS Delay register (EMCDynamicRASCAS0) +;// Controls the RAS and CAS latencies for the dynamic memory CS0 +;// CAS: CAS latency +;// <1=> One CCLK cycle +;// <2=> Two CCLK cycles +;// <3=> Three CCLK cycles +;// RAS: RAS latency (active to read/write delay) +;// <1=> One CCLK cycle +;// <2=> Two CCLK cycles +;// <3=> Three CCLK cycles +;// +EMC_DYN_RASCAS0_Val EQU 0x00000303 + +;// End of Dynamic Setup for CS0 Area + + +;// Configure External Bus Behaviour for Dynamic CS1 Area +EMC_DYNCS1_SETUP EQU 0 + +;// Dynamic Memory Configuration Register (EMCDynamicConfig1) +;// Defines the configuration information for the dynamic memory CS1 +;// P: Write protect +;// B: Buffer enable +;// AM 14: External bus data width +;// <0=> 16 bit +;// <1=> 32 bit +;// AM 12: External bus memory type +;// <0=> High-performance +;// <1=> Low-power SDRAM +;// AM 11..7: External bus address mapping (Row, Bank, Column) +;// <0x00=> 16 Mb = 2MB (2Mx8), 2 banks, row length = 11, column length = 9 +;// <0x01=> 16 Mb = 2MB (1Mx16), 2 banks, row length = 11, column length = 8 +;// <0x04=> 64 Mb = 8MB (8Mx8), 4 banks, row length = 12, column length = 9 +;// <0x05=> 64 Mb = 8MB (4Mx16), 4 banks, row length = 12, column length = 8 +;// <0x08=> 128 Mb = 16MB (16Mx8), 4 banks, row length = 12, column length = 10 +;// <0x09=> 128 Mb = 16MB (8Mx16), 4 banks, row length = 12, column length = 9 +;// <0x0C=> 256 Mb = 32MB (32Mx8), 4 banks, row length = 13, column length = 10 +;// <0x0D=> 256 Mb = 32MB (16Mx16), 4 banks, row length = 13, column length = 9 +;// <0x10=> 512 Mb = 64MB (64Mx8), 4 banks, row length = 13, column length = 11 +;// <0x11=> 512 Mb = 64MB (32Mx16), 4 banks, row length = 13, column length = 10 +;// MD: Memory device +;// <0=> SDRAM +;// <1=> Low-power SDRAM +;// <2=> Micron SyncFlash +;// +EMC_DYN_CFG1_Val EQU 0x00000000 + +;// Dynamic Memory RAS & CAS Delay register (EMCDynamicRASCAS1) +;// Controls the RAS and CAS latencies for the dynamic memory CS1 +;// CAS: CAS latency +;// <1=> One CCLK cycle +;// <2=> Two CCLK cycles +;// <3=> Three CCLK cycles +;// RAS: RAS latency (active to read/write delay) +;// <1=> One CCLK cycle +;// <2=> Two CCLK cycles +;// <3=> Three CCLK cycles +;// +EMC_DYN_RASCAS1_Val EQU 0x00000303 + +;// End of Dynamic Setup for CS1 Area + +;// Configure External Bus Behaviour for Dynamic CS2 Area +EMC_DYNCS2_SETUP EQU 0 + +;// Dynamic Memory Configuration Register (EMCDynamicConfig2) +;// Defines the configuration information for the dynamic memory CS2 +;// P: Write protect +;// B: Buffer enable +;// AM 14: External bus data width +;// <0=> 16 bit +;// <1=> 32 bit +;// AM 12: External bus memory type +;// <0=> High-performance +;// <1=> Low-power SDRAM +;// AM 11..7: External bus address mapping (Row, Bank, Column) +;// <0x00=> 16 Mb = 2MB (2Mx8), 2 banks, row length = 11, column length = 9 +;// <0x01=> 16 Mb = 2MB (1Mx16), 2 banks, row length = 11, column length = 8 +;// <0x04=> 64 Mb = 8MB (8Mx8), 4 banks, row length = 12, column length = 9 +;// <0x05=> 64 Mb = 8MB (4Mx16), 4 banks, row length = 12, column length = 8 +;// <0x08=> 128 Mb = 16MB (16Mx8), 4 banks, row length = 12, column length = 10 +;// <0x09=> 128 Mb = 16MB (8Mx16), 4 banks, row length = 12, column length = 9 +;// <0x0C=> 256 Mb = 32MB (32Mx8), 4 banks, row length = 13, column length = 10 +;// <0x0D=> 256 Mb = 32MB (16Mx16), 4 banks, row length = 13, column length = 9 +;// <0x10=> 512 Mb = 64MB (64Mx8), 4 banks, row length = 13, column length = 11 +;// <0x11=> 512 Mb = 64MB (32Mx16), 4 banks, row length = 13, column length = 10 +;// MD: Memory device +;// <0=> SDRAM +;// <1=> Low-power SDRAM +;// <2=> Micron SyncFlash +;// +EMC_DYN_CFG2_Val EQU 0x00000000 + +;// Dynamic Memory RAS & CAS Delay register (EMCDynamicRASCAS2) +;// Controls the RAS and CAS latencies for the dynamic memory CS2 +;// CAS: CAS latency +;// <1=> One CCLK cycle +;// <2=> Two CCLK cycles +;// <3=> Three CCLK cycles +;// RAS: RAS latency (active to read/write delay) +;// <1=> One CCLK cycle +;// <2=> Two CCLK cycles +;// <3=> Three CCLK cycles +;// +EMC_DYN_RASCAS2_Val EQU 0x00000303 + +;// End of Dynamic Setup for CS2 Area + +;// Configure External Bus Behaviour for Dynamic CS3 Area +EMC_DYNCS3_SETUP EQU 0 + +;// Dynamic Memory Configuration Register (EMCDynamicConfig3) +;// Defines the configuration information for the dynamic memory CS3 +;// P: Write protect +;// B: Buffer enable +;// AM 14: External bus data width +;// <0=> 16 bit +;// <1=> 32 bit +;// AM 12: External bus memory type +;// <0=> High-performance +;// <1=> Low-power SDRAM +;// AM 11..7: External bus address mapping (Row, Bank, Column) +;// <0x00=> 16 Mb = 2MB (2Mx8), 2 banks, row length = 11, column length = 9 +;// <0x01=> 16 Mb = 2MB (1Mx16), 2 banks, row length = 11, column length = 8 +;// <0x04=> 64 Mb = 8MB (8Mx8), 4 banks, row length = 12, column length = 9 +;// <0x05=> 64 Mb = 8MB (4Mx16), 4 banks, row length = 12, column length = 8 +;// <0x08=> 128 Mb = 16MB (16Mx8), 4 banks, row length = 12, column length = 10 +;// <0x09=> 128 Mb = 16MB (8Mx16), 4 banks, row length = 12, column length = 9 +;// <0x0C=> 256 Mb = 32MB (32Mx8), 4 banks, row length = 13, column length = 10 +;// <0x0D=> 256 Mb = 32MB (16Mx16), 4 banks, row length = 13, column length = 9 +;// <0x10=> 512 Mb = 64MB (64Mx8), 4 banks, row length = 13, column length = 11 +;// <0x11=> 512 Mb = 64MB (32Mx16), 4 banks, row length = 13, column length = 10 +;// MD: Memory device +;// <0=> SDRAM +;// <1=> Low-power SDRAM +;// <2=> Micron SyncFlash +;// +EMC_DYN_CFG3_Val EQU 0x00000000 + +;// Dynamic Memory RAS & CAS Delay register (EMCDynamicRASCAS3) +;// Controls the RAS and CAS latencies for the dynamic memory CS3 +;// CAS: CAS latency +;// <1=> One CCLK cycle +;// <2=> Two CCLK cycles +;// <3=> Three CCLK cycles +;// RAS: RAS latency (active to read/write delay) +;// <1=> One CCLK cycle +;// <2=> Two CCLK cycles +;// <3=> Three CCLK cycles +;// +EMC_DYN_RASCAS3_Val EQU 0x00000303 + +;// End of Dynamic Setup for CS3 Area + +;// End of Dynamic Setup + +;// Static Memory Interface Setup ---------------------------------------- +;// Static Memory Interface Setup +EMC_STATIC_SETUP EQU 1 + +;// Configure External Bus Behaviour for Static CS0 Area --------------- +;// Configure External Bus Behaviour for Static CS0 Area +EMC_STACS0_SETUP EQU 1 + +;// Static Memory Configuration Register (EMCStaticConfig0) +;// Defines the configuration information for the static memory CS0 +;// WP: Write protect +;// B: Buffer enable +;// EW: Extended wait enable +;// PB: Byte lane state +;// <0=> For reads BLSn are HIGH, for writes BLSn are LOW +;// <1=> For reads BLSn are LOW, for writes BLSn are LOW +;// PC: Chip select polarity +;// <0=> Active LOW chip select +;// <1=> Active HIGH chip select +;// PM: Page mode enable +;// MW: Memory width +;// <0=> 8 bit +;// <1=> 16 bit +;// <2=> 32 bit +;// +EMC_STA_CFG0_Val EQU 0x00000081 + +;// Static Memory Write Enable Delay Register (EMCStaticWaitWen0) +;// Selects the delay from CS0 to write enable +;// WAITWEN: Wait write enable <1-16> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WWEN0_Val EQU 0x00000002 + +;// Static Memory Output Enable Delay register (EMCStaticWaitOen0) +;// Selects the delay from CS0 or address change, whichever is later, to output enable +;// WAITOEN: Wait output enable <0-15> +;// The delay is in CCLK cycles +;// +EMC_STA_WOEN0_Val EQU 0x00000002 + +;// Static Memory Read Delay Register (EMCStaticWaitRd0) +;// Selects the delay from CS0 to a read access +;// WAITRD: Non-page mode read wait states or asynchronous page mode read first access wait states <1-32> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WRD0_Val EQU 0x0000001F + +;// Static Memory Page Mode Read Delay Register (EMCStaticWaitPage0) +;// Selects the delay for asynchronous page mode sequential accesses for CS0 +;// WAITPAGE: Asynchronous page mode read after the first read wait states <1-32> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WPAGE0_Val EQU 0x0000001F + +;// Static Memory Write Delay Register (EMCStaticWaitWr0) +;// Selects the delay from CS0 to a write access +;// WAITWR: Write wait states <2-33> <#-2> +;// The delay is in CCLK cycles +;// +EMC_STA_WWR0_Val EQU 0x0000001F + +;// Static Memory Turn Round Delay Register (EMCStaticWaitTurn0) +;// Selects the number of bus turnaround cycles for CS0 +;// WAITTURN: Bus turnaround cycles <1-16> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WTURN0_Val EQU 0x0000000F + +;// End of Static Setup for Static CS0 Area + +;// Configure External Bus Behaviour for Static CS1 Area --------------- +;// Configure External Bus Behaviour for Static CS1 Area +EMC_STACS1_SETUP EQU 0 + +;// Static Memory Configuration Register (EMCStaticConfig1) +;// Defines the configuration information for the static memory CS1 +;// WP: Write protect +;// B: Buffer enable +;// EW: Extended wait enable +;// PB: Byte lane state +;// <0=> For reads BLSn are HIGH, for writes BLSn are LOW +;// <1=> For reads BLSn are LOW, for writes BLSn are LOW +;// PC: Chip select polarity +;// <0=> Active LOW chip select +;// <1=> Active HIGH chip select +;// PM: Page mode enable +;// MW: Memory width +;// <0=> 8 bit +;// <1=> 16 bit +;// <2=> 32 bit +;// +EMC_STA_CFG1_Val EQU 0x00000000 + +;// Static Memory Write Enable Delay Register (EMCStaticWaitWen1) +;// Selects the delay from CS1 to write enable +;// WAITWEN: Wait write enable <1-16> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WWEN1_Val EQU 0x00000000 + +;// Static Memory Output Enable Delay register (EMCStaticWaitOen1) +;// Selects the delay from CS1 or address change, whichever is later, to output enable +;// WAITOEN: Wait output enable <0-15> +;// The delay is in CCLK cycles +;// +EMC_STA_WOEN1_Val EQU 0x00000000 + +;// Static Memory Read Delay Register (EMCStaticWaitRd1) +;// Selects the delay from CS1 to a read access +;// WAITRD: Non-page mode read wait states or asynchronous page mode read first access wait states <1-32> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WRD1_Val EQU 0x0000001F + +;// Static Memory Page Mode Read Delay Register (EMCStaticWaitPage0) +;// Selects the delay for asynchronous page mode sequential accesses for CS1 +;// WAITPAGE: Asynchronous page mode read after the first read wait states <1-32> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WPAGE1_Val EQU 0x0000001F + +;// Static Memory Write Delay Register (EMCStaticWaitWr1) +;// Selects the delay from CS1 to a write access +;// WAITWR: Write wait states <2-33> <#-2> +;// The delay is in CCLK cycles +;// +EMC_STA_WWR1_Val EQU 0x0000001F + +;// Static Memory Turn Round Delay Register (EMCStaticWaitTurn1) +;// Selects the number of bus turnaround cycles for CS1 +;// WAITTURN: Bus turnaround cycles <1-16> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WTURN1_Val EQU 0x0000000F + +;// End of Static Setup for Static CS1 Area + +;// Configure External Bus Behaviour for Static CS2 Area --------------- +;// Configure External Bus Behaviour for Static CS2 Area +EMC_STACS2_SETUP EQU 0 + +;// Static Memory Configuration Register (EMCStaticConfig2) +;// Defines the configuration information for the static memory CS2 +;// WP: Write protect +;// B: Buffer enable +;// EW: Extended wait enable +;// PB: Byte lane state +;// <0=> For reads BLSn are HIGH, for writes BLSn are LOW +;// <1=> For reads BLSn are LOW, for writes BLSn are LOW +;// PC: Chip select polarity +;// <0=> Active LOW chip select +;// <1=> Active HIGH chip select +;// PM: Page mode enable +;// MW: Memory width +;// <0=> 8 bit +;// <1=> 16 bit +;// <2=> 32 bit +;// +EMC_STA_CFG2_Val EQU 0x00000000 + +;// Static Memory Write Enable Delay Register (EMCStaticWaitWen2) +;// Selects the delay from CS2 to write enable +;// WAITWEN: Wait write enable <1-16> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WWEN2_Val EQU 0x00000000 + +;// Static Memory Output Enable Delay register (EMCStaticWaitOen2) +;// Selects the delay from CS2 or address change, whichever is later, to output enable +;// WAITOEN: Wait output enable <0-15> +;// The delay is in CCLK cycles +;// +EMC_STA_WOEN2_Val EQU 0x00000000 + +;// Static Memory Read Delay Register (EMCStaticWaitRd2) +;// Selects the delay from CS2 to a read access +;// WAITRD: Non-page mode read wait states or asynchronous page mode read first access wait states <1-32> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WRD2_Val EQU 0x0000001F + +;// Static Memory Page Mode Read Delay Register (EMCStaticWaitPage2) +;// Selects the delay for asynchronous page mode sequential accesses for CS2 +;// WAITPAGE: Asynchronous page mode read after the first read wait states <1-32> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WPAGE2_Val EQU 0x0000001F + +;// Static Memory Write Delay Register (EMCStaticWaitWr2) +;// Selects the delay from CS2 to a write access +;// WAITWR: Write wait states <2-33> <#-2> +;// The delay is in CCLK cycles +;// +EMC_STA_WWR2_Val EQU 0x0000001F + +;// Static Memory Turn Round Delay Register (EMCStaticWaitTurn2) +;// Selects the number of bus turnaround cycles for CS2 +;// WAITTURN: Bus turnaround cycles <1-16> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WTURN2_Val EQU 0x0000000F + +;// End of Static Setup for Static CS2 Area + +;// Configure External Bus Behaviour for Static CS3 Area --------------- +;// Configure External Bus Behaviour for Static CS3 Area +EMC_STACS3_SETUP EQU 0 + +;// Static Memory Configuration Register (EMCStaticConfig3) +;// Defines the configuration information for the static memory CS3 +;// WP: Write protect +;// B: Buffer enable +;// EW: Extended wait enable +;// PB: Byte lane state +;// <0=> For reads BLSn are HIGH, for writes BLSn are LOW +;// <1=> For reads BLSn are LOW, for writes BLSn are LOW +;// PC: Chip select polarity +;// <0=> Active LOW chip select +;// <1=> Active HIGH chip select +;// PM: Page mode enable +;// MW: Memory width +;// <0=> 8 bit +;// <1=> 16 bit +;// <2=> 32 bit +;// +EMC_STA_CFG3_Val EQU 0x00000000 + +;// Static Memory Write Enable Delay Register (EMCStaticWaitWen3) +;// Selects the delay from CS3 to write enable +;// WAITWEN: Wait write enable <1-16> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WWEN3_Val EQU 0x00000000 + +;// Static Memory Output Enable Delay register (EMCStaticWaitOen3) +;// Selects the delay from CS3 or address change, whichever is later, to output enable +;// WAITOEN: Wait output enable <0-15> +;// The delay is in CCLK cycles +;// +EMC_STA_WOEN3_Val EQU 0x00000000 + +;// Static Memory Read Delay Register (EMCStaticWaitRd3) +;// Selects the delay from CS3 to a read access +;// WAITRD: Non-page mode read wait states or asynchronous page mode read first access wait states <1-32> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WRD3_Val EQU 0x0000001F + +;// Static Memory Page Mode Read Delay Register (EMCStaticWaitPage3) +;// Selects the delay for asynchronous page mode sequential accesses for CS3 +;// WAITPAGE: Asynchronous page mode read after the first read wait states <1-32> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WPAGE3_Val EQU 0x0000001F + +;// Static Memory Write Delay Register (EMCStaticWaitWr3) +;// Selects the delay from CS3 to a write access +;// WAITWR: Write wait states <2-33> <#-2> +;// The delay is in CCLK cycles +;// +EMC_STA_WWR3_Val EQU 0x0000001F + +;// Static Memory Turn Round Delay Register (EMCStaticWaitTurn3) +;// Selects the number of bus turnaround cycles for CS3 +;// WAITTURN: Bus turnaround cycles <1-16> <#-1> +;// The delay is in CCLK cycles +;// +EMC_STA_WTURN3_Val EQU 0x0000000F + +;// End of Static Setup for Static CS3 Area + +;// Static Memory Extended Wait Register (EMCStaticExtendedWait) +;// Time long static memory read and write transfers +;// EXTENDEDWAIT: Extended wait time out <0-1023> +;// The delay is in (16 * CCLK) cycles +;// +EMC_STA_EXT_W_Val EQU 0x00000000 + +;// End of Static Setup + +;// End of EMC Setup + + + PRESERVE8 + +; Area Definition and Entry Point +; Startup Code must be linked first at Address at which it expects to run. + + AREA RESET, CODE, READONLY + ARM + + +; Exception Vectors +; Mapped to Address 0. +; Absolute addressing mode must be used. +; Dummy Handlers are implemented as infinite loops which can be modified. + +Vectors LDR PC, Reset_Addr + LDR PC, Undef_Addr + LDR PC, SWI_Addr + LDR PC, PAbt_Addr + LDR PC, DAbt_Addr + NOP ; Reserved Vector + LDR PC, IRQ_Addr + LDR PC, FIQ_Addr + +Reset_Addr DCD Reset_Handler +Undef_Addr DCD Undef_Handler +SWI_Addr DCD SWI_Handler +PAbt_Addr DCD PAbt_Handler +DAbt_Addr DCD DAbt_Handler + DCD 0 ; Reserved Address +IRQ_Addr DCD IRQ_Handler +FIQ_Addr DCD FIQ_Handler + + +; Exception Handler + IMPORT rt_hw_trap_udef + IMPORT rt_hw_trap_swi + IMPORT rt_hw_trap_pabt + IMPORT rt_hw_trap_dabt + IMPORT rt_hw_trap_fiq + +; Prepare Fatal Context + MACRO + prepare_fatal + STMFD sp!, {r0-r3} + MOV r1, sp + ADD sp, sp, #16 + SUB r2, lr, #4 + MRS r3, spsr + + ; switch to SVC mode and no interrupt + MSR cpsr_c, #I_Bit :OR: F_Bit :OR: Mode_SVC + + STMFD sp!, {r0} ; old r0 + ; get sp + ADD r0, sp, #4 + STMFD sp!, {r3} ; cpsr + STMFD sp!, {r2} ; pc + STMFD sp!, {lr} ; lr + STMFD sp!, {r0} ; sp + STMFD sp!, {r4-r12} + + MOV r4, r1 + + LDMFD r4!, {r0-r3} + STMFD sp!, {r0-r3} + + MOV r0, sp + MEND + +Undef_Handler + prepare_fatal + BL rt_hw_trap_irq + B . + +SWI_Handler + prepare_fatal + BL rt_hw_trap_swi + B . + +PAbt_Handler + prepare_fatal + BL rt_hw_trap_pabt + B . + +DAbt_Handler + prepare_fatal + BL rt_hw_trap_dabt + B . + +FIQ_Handler + prepare_fatal + BL rt_hw_trap_fiq + B . + +; Reset Handler + + EXPORT Reset_Handler +Reset_Handler + + +; Clock Setup ------------------------------------------------------------------ + + IF (:LNOT:(:DEF:NO_CLOCK_SETUP)):LAND:(CLOCK_SETUP != 0) + LDR R0, =SCB_BASE + MOV R1, #0xAA + MOV R2, #0x55 + +; Configure and Enable PLL + LDR R3, =SCS_Val ; Enable main oscillator + STR R3, [R0, #SCS_OFS] + + IF (SCS_Val:AND:OSCEN) != 0 +OSC_Loop LDR R3, [R0, #SCS_OFS] ; Wait for main osc stabilize + ANDS R3, R3, #OSCSTAT + BEQ OSC_Loop + ENDIF + + LDR R3, =CLKSRCSEL_Val ; Select PLL source clock + STR R3, [R0, #CLKSRCSEL_OFS] + LDR R3, =PLLCFG_Val + STR R3, [R0, #PLLCFG_OFS] + STR R1, [R0, #PLLFEED_OFS] + STR R2, [R0, #PLLFEED_OFS] + MOV R3, #PLLCON_PLLE + STR R3, [R0, #PLLCON_OFS] + STR R1, [R0, #PLLFEED_OFS] + STR R2, [R0, #PLLFEED_OFS] + + IF (CLKSRCSEL_Val:AND:3) != 2 +; Wait until PLL Locked (if source is not RTC oscillator) +PLL_Loop LDR R3, [R0, #PLLSTAT_OFS] + ANDS R3, R3, #PLLSTAT_PLOCK + BEQ PLL_Loop + ELSE +; Wait at least 200 cycles (if source is RTC oscillator) + MOV R3, #(200/4) +PLL_Loop SUBS R3, R3, #1 + BNE PLL_Loop + ENDIF + +M_N_Lock LDR R3, [R0, #PLLSTAT_OFS] + LDR R4, =(PLLSTAT_M:OR:PLLSTAT_N) + AND R3, R3, R4 + LDR R4, =PLLCFG_Val + EORS R3, R3, R4 + BNE M_N_Lock + +; Setup CPU clock divider + MOV R3, #CCLKCFG_Val + STR R3, [R0, #CCLKCFG_OFS] + +; Setup USB clock divider + LDR R3, =USBCLKCFG_Val + STR R3, [R0, #USBCLKCFG_OFS] + +; Setup Peripheral Clock + LDR R3, =PCLKSEL0_Val + STR R3, [R0, #PCLKSEL0_OFS] + LDR R3, =PCLKSEL1_Val + STR R3, [R0, #PCLKSEL1_OFS] + +; Switch to PLL Clock + MOV R3, #(PLLCON_PLLE:OR:PLLCON_PLLC) + STR R3, [R0, #PLLCON_OFS] + STR R1, [R0, #PLLFEED_OFS] + STR R2, [R0, #PLLFEED_OFS] + ENDIF ; CLOCK_SETUP + + +; Setup Memory Accelerator Module ---------------------------------------------- + + IF MAM_SETUP != 0 + LDR R0, =MAM_BASE + MOV R1, #MAMTIM_Val + STR R1, [R0, #MAMTIM_OFS] + MOV R1, #MAMCR_Val + STR R1, [R0, #MAMCR_OFS] + ENDIF ; MAM_SETUP + + +; Setup External Memory Controller --------------------------------------------- + + IF (:LNOT:(:DEF:NO_EMC_SETUP)):LAND:(EMC_SETUP != 0) + LDR R0, =EMC_BASE + LDR R1, =SCB_BASE + LDR R2, =PCB_BASE + + LDR R4, =EMC_PCONP_Const ; Enable EMC + LDR R3, [R1, #PCONP_OFS] + ORR R4, R4, R3 + STR R4, [R1, #PCONP_OFS] + + LDR R4, =EMC_CTRL_Val + STR R4, [R0, #EMC_CTRL_OFS] + LDR R4, =EMC_CONFIG_Val + STR R4, [R0, #EMC_CONFIG_OFS] + +; Setup pin functions for External Bus functionality + LDR R4, =EMC_PINSEL5_Val + STR R4, [R2, #PINSEL5_OFS] + LDR R4, =EMC_PINSEL6_Val + STR R4, [R2, #PINSEL6_OFS] + LDR R4, =EMC_PINSEL8_Val + STR R4, [R2, #PINSEL8_OFS] + LDR R4, =EMC_PINSEL9_Val + STR R4, [R2, #PINSEL9_OFS] + +; Setup Dynamic Memory Interface + IF (EMC_DYNAMIC_SETUP != 0) + + LDR R4, =EMC_DYN_RP_Val + STR R4, [R0, #EMC_DYN_RP_OFS] + LDR R4, =EMC_DYN_RAS_Val + STR R4, [R0, #EMC_DYN_RAS_OFS] + LDR R4, =EMC_DYN_SREX_Val + STR R4, [R0, #EMC_DYN_SREX_OFS] + LDR R4, =EMC_DYN_APR_Val + STR R4, [R0, #EMC_DYN_APR_OFS] + LDR R4, =EMC_DYN_DAL_Val + STR R4, [R0, #EMC_DYN_DAL_OFS] + LDR R4, =EMC_DYN_WR_Val + STR R4, [R0, #EMC_DYN_WR_OFS] + LDR R4, =EMC_DYN_RC_Val + STR R4, [R0, #EMC_DYN_RC_OFS] + LDR R4, =EMC_DYN_RFC_Val + STR R4, [R0, #EMC_DYN_RFC_OFS] + LDR R4, =EMC_DYN_XSR_Val + STR R4, [R0, #EMC_DYN_XSR_OFS] + LDR R4, =EMC_DYN_RRD_Val + STR R4, [R0, #EMC_DYN_RRD_OFS] + LDR R4, =EMC_DYN_MRD_Val + STR R4, [R0, #EMC_DYN_MRD_OFS] + + LDR R4, =EMC_DYN_RD_CFG_Val + STR R4, [R0, #EMC_DYN_RD_CFG_OFS] + + IF (EMC_DYNCS0_SETUP != 0) + LDR R4, =EMC_DYN_RASCAS0_Val + STR R4, [R0, #EMC_DYN_RASCAS0_OFS] + LDR R4, =EMC_DYN_CFG0_Val + MVN R5, #BUFEN_Const + AND R4, R4, R5 + STR R4, [R0, #EMC_DYN_CFG0_OFS] + ENDIF + IF (EMC_DYNCS1_SETUP != 0) + LDR R4, =EMC_DYN_RASCAS1_Val + STR R4, [R0, #EMC_DYN_RASCAS1_OFS] + LDR R4, =EMC_DYN_CFG1_Val + MVN R5, =BUFEN_Const + AND R4, R4, R5 + STR R4, [R0, #EMC_DYN_CFG1_OFS] + ENDIF + IF (EMC_DYNCS2_SETUP != 0) + LDR R4, =EMC_DYN_RASCAS2_Val + STR R4, [R0, #EMC_DYN_RASCAS2_OFS] + LDR R4, =EMC_DYN_CFG2_Val + MVN R5, =BUFEN_Const + AND R4, R4, R5 + STR R4, [R0, #EMC_DYN_CFG2_OFS] + ENDIF + IF (EMC_DYNCS3_SETUP != 0) + LDR R4, =EMC_DYN_RASCAS3_Val + STR R4, [R0, #EMC_DYN_RASCAS3_OFS] + LDR R4, =EMC_DYN_CFG3_Val + MVN R5, =BUFEN_Const + AND R4, R4, R5 + STR R4, [R0, #EMC_DYN_CFG3_OFS] + ENDIF + + LDR R6, =1440000 ; Number of cycles to delay +Wait_0 SUBS R6, R6, #1 ; Delay ~100 ms proc clk 57.6 MHz + BNE Wait_0 ; BNE (3 cyc) + SUBS (1 cyc) = 4 cyc + + LDR R4, =(NOP_CMD:OR:0x03) ; Write NOP Command + STR R4, [R0, #EMC_DYN_CTRL_OFS] + + LDR R6, =2880000 ; Number of cycles to delay +Wait_1 SUBS R6, R6, #1 ; Delay ~200 ms proc clk 57.6 MHz + BNE Wait_1 + + LDR R4, =(PALL_CMD:OR:0x03) ; Write Precharge All Command + STR R4, [R0, #EMC_DYN_CTRL_OFS] + + MOV R4, #2 + STR R4, [R0, #EMC_DYN_RFSH_OFS] + + MOV R6, #64 ; Number of cycles to delay +Wait_2 SUBS R6, R6, #1 ; Delay + BNE Wait_2 + + LDR R4, =EMC_DYN_RFSH_Val + STR R4, [R0, #EMC_DYN_RFSH_OFS] + + LDR R4, =(MODE_CMD:OR:0x03) ; Write MODE Command + STR R4, [R0, #EMC_DYN_CTRL_OFS] + + ; Dummy read + IF (EMC_DYNCS0_SETUP != 0) + LDR R4, =DYN_MEM0_BASE + MOV R5, #(0x33 << 12) + ADD R4, R4, R5 + LDR R4, [R4, #0] + ENDIF + IF (EMC_DYNCS1_SETUP != 0) + LDR R4, =DYN_MEM1_BASE + MOV R5, #(0x33 << 12) + ADD R4, R4, R5 + LDR R4, [R4, #0] + ENDIF + IF (EMC_DYNCS2_SETUP != 0) + LDR R4, =DYN_MEM2_BASE + MOV R5, #(0x33 << 12) + ADD R4, R4, R5 + LDR R4, [R4, #0] + ENDIF + IF (EMC_DYNCS3_SETUP != 0) + LDR R4, =DYN_MEM3_BASE + MOV R5, #(0x33 << 12) + ADD R4, R4, R5 + LDR R4, [R4, #0] + ENDIF + + LDR R4, =NORMAL_CMD ; Write NORMAL Command + STR R4, [R0, #EMC_DYN_CTRL_OFS] + + ; Enable buffer if requested by settings + IF (EMC_DYNCS0_SETUP != 0):LAND:((EMC_DYN_CFG0_Val:AND:BUFEN_Const) != 0) + LDR R4, =EMC_DYN_CFG0_Val + STR R4, [R0, #EMC_DYN_CFG0_OFS] + ENDIF + IF (EMC_DYNCS1_SETUP != 0):LAND:((EMC_DYN_CFG1_Val:AND:BUFEN_Const) != 0) + LDR R4, =EMC_DYN_CFG1_Val + STR R4, [R0, #EMC_DYN_CFG1_OFS] + ENDIF + IF (EMC_DYNCS2_SETUP != 0):LAND:((EMC_DYN_CFG2_Val:AND:BUFEN_Const) != 0) + LDR R4, =EMC_DYN_CFG2_Val + STR R4, [R0, #EMC_DYN_CFG2_OFS] + ENDIF + IF (EMC_DYNCS3_SETUP != 0):LAND:((EMC_DYN_CFG3_Val:AND:BUFEN_Const) != 0) + LDR R4, =EMC_DYN_CFG3_Val + STR R4, [R0, #EMC_DYN_CFG3_OFS] + ENDIF + + LDR R6, =14400 ; Number of cycles to delay +Wait_3 SUBS R6, R6, #1 ; Delay ~1 ms @ proc clk 57.6 MHz + BNE Wait_3 + + ENDIF ; EMC_DYNAMIC_SETUP + +; Setup Static Memory Interface + IF (EMC_STATIC_SETUP != 0) + + LDR R6, =1440000 ; Number of cycles to delay +Wait_4 SUBS R6, R6, #1 ; Delay ~100 ms @ proc clk 57.6 MHz + BNE Wait_4 + + IF (EMC_STACS0_SETUP != 0) + LDR R4, =EMC_STA_CFG0_Val + STR R4, [R0, #EMC_STA_CFG0_OFS] + LDR R4, =EMC_STA_WWEN0_Val + STR R4, [R0, #EMC_STA_WWEN0_OFS] + LDR R4, =EMC_STA_WOEN0_Val + STR R4, [R0, #EMC_STA_WOEN0_OFS] + LDR R4, =EMC_STA_WRD0_Val + STR R4, [R0, #EMC_STA_WRD0_OFS] + LDR R4, =EMC_STA_WPAGE0_Val + STR R4, [R0, #EMC_STA_WPAGE0_OFS] + LDR R4, =EMC_STA_WWR0_Val + STR R4, [R0, #EMC_STA_WWR0_OFS] + LDR R4, =EMC_STA_WTURN0_Val + STR R4, [R0, #EMC_STA_WTURN0_OFS] + ENDIF + + IF (EMC_STACS1_SETUP != 0) + LDR R4, =EMC_STA_CFG1_Val + STR R4, [R0, #EMC_STA_CFG1_OFS] + LDR R4, =EMC_STA_WWEN1_Val + STR R4, [R0, #EMC_STA_WWEN1_OFS] + LDR R4, =EMC_STA_WOEN1_Val + STR R4, [R0, #EMC_STA_WOEN1_OFS] + LDR R4, =EMC_STA_WRD1_Val + STR R4, [R0, #EMC_STA_WRD1_OFS] + LDR R4, =EMC_STA_WPAGE1_Val + STR R4, [R0, #EMC_STA_WPAGE1_OFS] + LDR R4, =EMC_STA_WWR1_Val + STR R4, [R0, #EMC_STA_WWR1_OFS] + LDR R4, =EMC_STA_WTURN1_Val + STR R4, [R0, #EMC_STA_WTURN1_OFS] + ENDIF + + IF (EMC_STACS2_SETUP != 0) + LDR R4, =EMC_STA_CFG2_Val + STR R4, [R0, #EMC_STA_CFG2_OFS] + LDR R4, =EMC_STA_WWEN2_Val + STR R4, [R0, #EMC_STA_WWEN2_OFS] + LDR R4, =EMC_STA_WOEN2_Val + STR R4, [R0, #EMC_STA_WOEN2_OFS] + LDR R4, =EMC_STA_WRD2_Val + STR R4, [R0, #EMC_STA_WRD2_OFS] + LDR R4, =EMC_STA_WPAGE2_Val + STR R4, [R0, #EMC_STA_WPAGE2_OFS] + LDR R4, =EMC_STA_WWR2_Val + STR R4, [R0, #EMC_STA_WWR2_OFS] + LDR R4, =EMC_STA_WTURN2_Val + STR R4, [R0, #EMC_STA_WTURN2_OFS] + ENDIF + + IF (EMC_STACS3_SETUP != 0) + LDR R4, =EMC_STA_CFG3_Val + STR R4, [R0, #EMC_STA_CFG3_OFS] + LDR R4, =EMC_STA_WWEN3_Val + STR R4, [R0, #EMC_STA_WWEN3_OFS] + LDR R4, =EMC_STA_WOEN3_Val + STR R4, [R0, #EMC_STA_WOEN3_OFS] + LDR R4, =EMC_STA_WRD3_Val + STR R4, [R0, #EMC_STA_WRD3_OFS] + LDR R4, =EMC_STA_WPAGE3_Val + STR R4, [R0, #EMC_STA_WPAGE3_OFS] + LDR R4, =EMC_STA_WWR3_Val + STR R4, [R0, #EMC_STA_WWR3_OFS] + LDR R4, =EMC_STA_WTURN3_Val + STR R4, [R0, #EMC_STA_WTURN3_OFS] + ENDIF + + LDR R6, =144000 ; Number of cycles to delay +Wait_5 SUBS R6, R6, #1 ; Delay ~10 ms @ proc clk 57.6 MHz + BNE Wait_5 + + LDR R4, =EMC_STA_EXT_W_Val + LDR R5, =EMC_STA_EXT_W_OFS + ADD R5, R5, R0 + STR R4, [R5, #0] + + ENDIF ; EMC_STATIC_SETUP + + ENDIF ; EMC_SETUP + + +; Copy Exception Vectors to Internal RAM --------------------------------------- + + IF :DEF:RAM_INTVEC + ADR R8, Vectors ; Source + LDR R9, =RAM_BASE ; Destination + LDMIA R8!, {R0-R7} ; Load Vectors + STMIA R9!, {R0-R7} ; Store Vectors + LDMIA R8!, {R0-R7} ; Load Handler Addresses + STMIA R9!, {R0-R7} ; Store Handler Addresses + ENDIF + + +; Memory Mapping (when Interrupt Vectors are in RAM) --------------------------- + +MEMMAP EQU 0xE01FC040 ; Memory Mapping Control + IF :DEF:REMAP + LDR R0, =MEMMAP + IF :DEF:EXTMEM_MODE + MOV R1, #3 + ELIF :DEF:RAM_MODE + MOV R1, #2 + ELSE + MOV R1, #1 + ENDIF + STR R1, [R0] + ENDIF + + +; Setup Stack for each mode ---------------------------------------------------- + + LDR R0, =Stack_Top + +; Enter Undefined Instruction Mode and set its Stack Pointer + MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #UND_Stack_Size + +; Enter Abort Mode and set its Stack Pointer + MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #ABT_Stack_Size + +; Enter FIQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #FIQ_Stack_Size + +; Enter IRQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #IRQ_Stack_Size + +; Enter Supervisor Mode and set its Stack Pointer + MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #SVC_Stack_Size + + IF :DEF:__MICROLIB + EXPORT __initial_sp + ELSE + ENDIF + +; Enter the C code ------------------------------------------------------------- + + IMPORT __main + LDR R0, =__main + BX R0 + + IMPORT rt_interrupt_enter + IMPORT rt_interrupt_leave + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + IMPORT rt_hw_trap_irq + +IRQ_Handler PROC + EXPORT IRQ_Handler + STMFD sp!, {r0-r12,lr} + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; if rt_thread_switch_interrupt_flag set, jump to + ; rt_hw_context_switch_interrupt_do and don't return + LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD sp!, {r0-r12,lr} + SUBS pc, lr, #4 + ENDP + +; /* +; * void rt_hw_context_switch_interrupt_do(rt_base_t flag) +; */ +rt_hw_context_switch_interrupt_do PROC + EXPORT rt_hw_context_switch_interrupt_do + MOV r1, #0 ; clear flag + STR r1, [r0] + + LDMFD sp!, {r0-r12,lr}; reload saved registers + STMFD sp!, {r0-r3} ; save r0-r3 + MOV r1, sp + ADD sp, sp, #16 ; restore sp + SUB r2, lr, #4 ; save old task's pc to r2 + + MRS r3, spsr ; get cpsr of interrupt thread + + ; switch to SVC mode and no interrupt + MSR cpsr_c, #I_Bit :OR: F_Bit :OR: Mode_SVC + + STMFD sp!, {r2} ; push old task's pc + STMFD sp!, {r4-r12,lr}; push old task's lr,r12-r4 + MOV r4, r1 ; Special optimised code below + MOV r5, r3 + LDMFD r4!, {r0-r3} + STMFD sp!, {r0-r3} ; push old task's r3-r0 + STMFD sp!, {r5} ; push old task's cpsr + + LDR r4, =rt_interrupt_from_thread + LDR r5, [r4] + STR sp, [r5] ; store sp in preempted tasks's TCB + + LDR r6, =rt_interrupt_to_thread + LDR r6, [r6] + LDR sp, [r6] ; get new task's stack pointer + + LDMFD sp!, {r4} ; pop new task's cpsr to spsr + MSR spsr_cxsf, r4 + BIC r4, r4, #0x20 ; must be ARM mode + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12,lr,pc}^ ; pop new task's r0-r12,lr & pc, copy spsr to cpsr + ENDP + + IF :DEF:__MICROLIB + + EXPORT __heap_base + EXPORT __heap_limit + + ELSE +; User Initial Stack & Heap + AREA |.text|, CODE, READONLY + + IMPORT __use_two_region_memory + EXPORT __user_initial_stackheap +__user_initial_stackheap + + LDR R0, = Heap_Mem + LDR R1, =(Stack_Mem + USR_Stack_Size) + LDR R2, = (Heap_Mem + Heap_Size) + LDR R3, = Stack_Mem + BX LR + ENDIF + + + END diff --git a/rt-thread/libcpu/arm/lpc24xx/trap.c b/rt-thread/libcpu/arm/lpc24xx/trap.c new file mode 100644 index 0000000..71d8810 --- /dev/null +++ b/rt-thread/libcpu/arm/lpc24xx/trap.c @@ -0,0 +1,147 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-12-11 XuXinming first version + */ + +#include +#include + +#include "LPC24xx.h" + +//#define BSP_INT_DEBUG + +/** + * @addtogroup LPC2478 + */ +/*@{*/ + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ +void rt_hw_show_register (struct rt_hw_register *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When ARM7TDMI comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_udef(struct rt_hw_register *regs) +{ + rt_kprintf("undefined instruction\n"); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_register *regs) +{ + rt_kprintf("software interrupt\n"); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_register *regs) +{ + rt_kprintf("prefetch abort\n"); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_register *regs) +{ + rt_kprintf("Data Abort "); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_register *regs) +{ + rt_kprintf("not used\n"); + rt_hw_show_register(regs); + if (rt_thread_self() != RT_NULL) + rt_kprintf("Current Thread: %s\n", rt_thread_self()->name); + rt_hw_cpu_shutdown(); +} + +extern rt_isr_handler_t isr_table[]; +void rt_hw_trap_irq(void) +{ + int irqno; + struct rt_irq_desc* irq; + extern struct rt_irq_desc irq_desc[]; + + irq = (struct rt_irq_desc*) VICVectAddr; + irqno = ((rt_uint32_t) irq - (rt_uint32_t) &irq_desc[0])/sizeof(struct rt_irq_desc); + + /* invoke isr */ + irq->handler(irqno, irq->param); +} + +void rt_hw_trap_fiq(void) +{ + rt_kprintf("fast interrupt request\n"); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/SConscript b/rt-thread/libcpu/arm/realview-a8-vmm/SConscript new file mode 100644 index 0000000..61057c0 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/SConscript @@ -0,0 +1,17 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +if rtconfig.PLATFORM == 'iar': + src += Glob('*_iar.S') +elif rtconfig.PLATFORM == 'gcc': + src += Glob('*_gcc.S') +elif rtconfig.PLATFORM == 'armcc': + src += Glob('*_rvds.S') + +group = DefineGroup('AM335x', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/armv7.h b/rt-thread/libcpu/arm/realview-a8-vmm/armv7.h new file mode 100644 index 0000000..69c556e --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/armv7.h @@ -0,0 +1,64 @@ +#ifndef __ARMV7_H__ +#define __ARMV7_H__ + +/* the exception stack without VFP registers */ +struct rt_hw_exp_stack +{ + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long sp; + unsigned long lr; + unsigned long pc; + unsigned long cpsr; +}; + +struct rt_hw_stack +{ + unsigned long cpsr; + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long lr; + unsigned long pc; +}; + +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define MONITORMODE 0x16 +#define ABORTMODE 0x17 +#define HYPMODE 0x1b +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +#define T_Bit (1<<5) +#define F_Bit (1<<6) +#define I_Bit (1<<7) +#define A_Bit (1<<8) +#define E_Bit (1<<9) +#define J_Bit (1<<24) + +#endif diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/context_gcc.S b/rt-thread/libcpu/arm/realview-a8-vmm/context_gcc.S new file mode 100644 index 0000000..dba0095 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/context_gcc.S @@ -0,0 +1,172 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +#include + +#ifdef RT_USING_VMM +#include +#endif + +.section .text, "ax" +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + cpsid i + bx lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + bx lr + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc + +.section .bss.share.isr +_guest_switch_lvl: + .word 0 + +.globl vmm_virq_update + +.section .text.isr, "ax" +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + tst lr, #0x01 + orrne r4, r4, #0x20 @ it's thumb code + + stmfd sp!, {r4} @ push cpsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + +#ifdef RT_USING_VMM +#ifdef RT_VMM_USING_DOMAIN + @ need to make sure we are in vmm domain as we would use rt_current_thread + ldr r2, =vmm_domain_val + ldr r7, [r2] + mcr p15, 0, r7, c3, c0 +#endif + + /* check whether vmm thread, otherwise, update vIRQ */ + ldr r3, =rt_current_thread + ldr r4, [r3] + ldr r5, =vmm_thread + cmp r4, r5 + beq switch_to_guest + + @ not falling into guest. Simple task ;-) + ldmfd sp!, {r6} @ pop new task cpsr to spsr + msr spsr_cxsf, r6 + ldmfd sp!, {r0-r12, lr, pc}^ + +switch_to_guest: +#ifdef RT_VMM_USING_DOMAIN + @ the stack is saved in the guest domain so we need to + @ come back to the guest domain to get the registers. + ldr r1, =super_domain_val + ldr r0, [r1] + mcr p15, 0, r0, c3, c0 +#endif + /* The user can do nearly anything in rt_thread_idle_excute because it will + call the thread->cleanup. One common thing is sending events and wake up + threads. So the guest thread will be preempted. This is the only point that + the guest thread would call rt_hw_context_switch and "yield". + + More over, rt_schedule will call this function and this function *will* + reentrant. If that happens, we need to make sure that call the + rt_thread_idle_excute and vmm_virq_update again and we are in super domain. + I use a "reference count" to achieve such behaviour. If you have better + idea, tell me. */ + ldr r4, =_guest_switch_lvl + ldr r5, [r4] + add r5, r5, #1 + str r5, [r4] + cmp r5, #1 + bne _switch_through + + bl rt_thread_idle_excute + bl vmm_virq_update + + /* we need _guest_switch_lvl to protect until _switch_through, but it's OK + * to cleanup the reference count here because the code below will not be + * reentrant. */ + sub r5, r5, #1 + str r5, [r4] + +#ifdef RT_VMM_USING_DOMAIN + ldr r1, =guest_domain_val + ldr r0, [r1] + mcr p15, 0, r0, c3, c0 +#endif +_switch_through: +#endif /* RT_USING_VMM */ + ldmfd sp!, {r4} @ pop new task cpsr to spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + ldr ip, =rt_interrupt_from_thread @ set rt_interrupt_from_thread + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1 + str r0, [ip] + str r3, [r2] +_reswitch: + ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread + str r1, [r2] + bx lr diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/cp15.h b/rt-thread/libcpu/arm/realview-a8-vmm/cp15.h new file mode 100644 index 0000000..ebea3f0 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/cp15.h @@ -0,0 +1,12 @@ +#ifndef __CP15_H__ +#define __CP15_H__ + +unsigned long rt_cpu_get_smp_id(void); + +void rt_cpu_mmu_disable(void); +void rt_cpu_mmu_enable(void); +void rt_cpu_tlb_set(volatile unsigned long*); + +void rt_cpu_vector_set_base(unsigned int addr); + +#endif diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/cp15_gcc.S b/rt-thread/libcpu/arm/realview-a8-vmm/cp15_gcc.S new file mode 100644 index 0000000..f1ed649 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/cp15_gcc.S @@ -0,0 +1,140 @@ +/* + * File : cp15_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * http://www.rt-thread.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.globl rt_cpu_get_smp_id +rt_cpu_get_smp_id: + mrc p15, #0, r0, c0, c0, #5 + bx lr + +.globl rt_cpu_vector_set_base +rt_cpu_vector_set_base: + mcr p15, #0, r0, c12, c0, #0 + dsb + bx lr + +.globl rt_hw_cpu_dcache_enable +rt_hw_cpu_dcache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_hw_cpu_icache_enable +rt_hw_cpu_icache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +_FLD_MAX_WAY: + .word 0x3ff +_FLD_MAX_IDX: + .word 0x7ff + +.globl rt_cpu_dcache_clean_flush +rt_cpu_dcache_clean_flush: + push {r4-r11} + dmb + mrc p15, #1, r0, c0, c0, #1 @ read clid register + ands r3, r0, #0x7000000 @ get level of coherency + mov r3, r3, lsr #23 + beq finished + mov r10, #0 +loop1: + add r2, r10, r10, lsr #1 + mov r1, r0, lsr r2 + and r1, r1, #7 + cmp r1, #2 + blt skip + mcr p15, #2, r10, c0, c0, #0 + isb + mrc p15, #1, r1, c0, c0, #0 + and r2, r1, #7 + add r2, r2, #4 + ldr r4, _FLD_MAX_WAY + ands r4, r4, r1, lsr #3 + clz r5, r4 + ldr r7, _FLD_MAX_IDX + ands r7, r7, r1, lsr #13 +loop2: + mov r9, r4 +loop3: + orr r11, r10, r9, lsl r5 + orr r11, r11, r7, lsl r2 + mcr p15, #0, r11, c7, c14, #2 + subs r9, r9, #1 + bge loop3 + subs r7, r7, #1 + bge loop2 +skip: + add r10, r10, #2 + cmp r3, r10 + bgt loop1 + +finished: + dsb + isb + pop {r4-r11} + bx lr + +.globl rt_hw_cpu_dcache_disable +rt_hw_cpu_dcache_disable: + push {r4-r11, lr} + bl rt_cpu_dcache_clean_flush + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + pop {r4-r11, lr} + bx lr + +.globl rt_hw_cpu_icache_disable +rt_hw_cpu_icache_disable: + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_cpu_mmu_disable +rt_cpu_mmu_disable: + mcr p15, #0, r0, c8, c7, #0 @ invalidate tlb + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #1 + mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit + dsb + bx lr + +.globl rt_cpu_mmu_enable +rt_cpu_mmu_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x001 + mcr p15, #0, r0, c1, c0, #0 @ set mmu enable bit + dsb + bx lr + +.globl rt_cpu_tlb_set +rt_cpu_tlb_set: + mcr p15, #0, r0, c2, c0, #0 + dmb + bx lr diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/cpu.c b/rt-thread/libcpu/arm/realview-a8-vmm/cpu.c new file mode 100644 index 0000000..7dd426e --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/cpu.c @@ -0,0 +1,37 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop 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 + * 2011-09-15 Bernard first version + */ + +#include +#include +#include + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +/** shutdown CPU */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + while (level) + { + RT_ASSERT(0); + } +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/gic.c b/rt-thread/libcpu/arm/realview-a8-vmm/gic.c new file mode 100644 index 0000000..4cff1ba --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/gic.c @@ -0,0 +1,316 @@ +/* + * File : gic.c, ARM Generic Interrupt Controller + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, RT-Thread Develop 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 + * 2013-07-20 Bernard first version + * 2014-04-03 Grissiom many enhancements + */ + +#include +#include + +#include "gic.h" +#include "cp15.h" + +struct arm_gic +{ + rt_uint32_t offset; + + rt_uint32_t dist_hw_base; + rt_uint32_t cpu_hw_base; +}; +static struct arm_gic _gic_table[ARM_GIC_MAX_NR]; + +#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00) +#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04) +#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08) +#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0c) +#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10) +#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14) +#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18) + +#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000) +#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004) +#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080 + ((n)/32) * 4) +#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100 + ((n)/32) * 4) +#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180 + ((n)/32) * 4) +#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200 + ((n)/32) * 4) +#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280 + ((n)/32) * 4) +#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300 + ((n)/32) * 4) +#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380 + ((n)/32) * 4) +#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400 + ((n)/4) * 4) +#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800 + ((n)/4) * 4) +#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00 + ((n)/16) * 4) +#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00) +#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10 + ((n)/4) * 4) +#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8) + +static unsigned int _gic_max_irq; + +int arm_gic_get_active_irq(rt_uint32_t index) +{ + int irq; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = GIC_CPU_INTACK(_gic_table[index].cpu_hw_base); + irq += _gic_table[index].offset; + return irq; +} + +void arm_gic_ack(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; + GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq; + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_mask(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_clear_pending(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_clear_active(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask) +{ + rt_uint32_t old_tgt; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq); + + old_tgt &= ~(0x0FFUL << ((irq % 4)*8)); + old_tgt |= cpumask << ((irq % 4)*8); + + GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt; +} + +void arm_gic_umask(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_dump_type(rt_uint32_t index) +{ + unsigned int gic_type; + + gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base); + rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n", + (GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4) & 0xf, + _gic_table[index].dist_hw_base, + _gic_max_irq, + gic_type & (1 << 10) ? "has" : "no", + gic_type); +} + +void arm_gic_dump(rt_uint32_t index) +{ + unsigned int i, k; + + k = GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base); + rt_kprintf("--- high pending priority: %d(%08x)\n", k, k); + rt_kprintf("--- hw mask ---\n"); + for (i = 0; i < _gic_max_irq / 32; i++) + { + rt_kprintf("0x%08x, ", + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, + i * 32)); + } + rt_kprintf("\n--- hw pending ---\n"); + for (i = 0; i < _gic_max_irq / 32; i++) + { + rt_kprintf("0x%08x, ", + GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, + i * 32)); + } + rt_kprintf("\n--- hw active ---\n"); + for (i = 0; i < _gic_max_irq / 32; i++) + { + rt_kprintf("0x%08x, ", + GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, + i * 32)); + } + rt_kprintf("\n"); +} +#ifdef RT_USING_FINSH +#include +FINSH_FUNCTION_EXPORT_ALIAS(arm_gic_dump, gic, show gic status); +#endif + +int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start) +{ + unsigned int gic_type, i; + rt_uint32_t cpumask = 1 << 0; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + _gic_table[index].dist_hw_base = dist_base; + _gic_table[index].offset = irq_start; + + /* Find out how many interrupts are supported. */ + gic_type = GIC_DIST_TYPE(dist_base); + _gic_max_irq = ((gic_type & 0x1f) + 1) * 32; + + /* + * The GIC only supports up to 1020 interrupt sources. + * Limit this to either the architected maximum, or the + * platform maximum. + */ + if (_gic_max_irq > 1020) + _gic_max_irq = 1020; + if (_gic_max_irq > ARM_GIC_NR_IRQS) + _gic_max_irq = ARM_GIC_NR_IRQS; + +#ifndef RT_PRETENT_AS_CPU0 + /* If we are run on the second core, the GIC should have already been setup + * by BootStrapProcessor. */ + if ((rt_cpu_get_smp_id() & 0xF) != 0) + return 0; +#endif +#ifdef RT_USING_VMM + return 0; +#endif + + cpumask |= cpumask << 8; + cpumask |= cpumask << 16; + + GIC_DIST_CTRL(dist_base) = 0x0; + + /* Set all global interrupts to be level triggered, active low. */ + for (i = 32; i < _gic_max_irq; i += 16) + GIC_DIST_CONFIG(dist_base, i) = 0x0; + + /* Set all global interrupts to this CPU only. */ + for (i = 32; i < _gic_max_irq; i += 4) + GIC_DIST_TARGET(dist_base, i) = cpumask; + + /* Set priority on all interrupts. */ + for (i = 0; i < _gic_max_irq; i += 4) + GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0; + + /* Disable all interrupts. */ + for (i = 0; i < _gic_max_irq; i += 32) + GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffff; + /* All interrupts defaults to IGROUP1(IRQ). */ + for (i = 0; i < _gic_max_irq; i += 32) + GIC_DIST_IGROUP(dist_base, i) = 0xffffffff; + + /* Enable group0 and group1 interrupt forwarding. */ + GIC_DIST_CTRL(dist_base) = 0x03; + + return 0; +} + +int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + _gic_table[index].cpu_hw_base = cpu_base; + +#ifndef RT_PRETENT_AS_CPU0 + /* If we are run on the second core, the GIC should have already been setup + * by BootStrapProcessor. */ + if ((rt_cpu_get_smp_id() & 0xF) != 0) + return 0; +#endif +#ifdef RT_USING_VMM + return 0; +#endif + + GIC_CPU_PRIMASK(cpu_base) = 0xf0; + /* Enable CPU interrupt */ + GIC_CPU_CTRL(cpu_base) = 0x01; + + return 0; +} + +void arm_gic_set_group(rt_uint32_t index, int vector, int group) +{ + /* As for GICv2, there are only group0 and group1. */ + RT_ASSERT(group <= 1); + RT_ASSERT(vector < _gic_max_irq); + + if (group == 0) + { + GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, + vector) &= ~(1 << (vector % 32)); + } + else if (group == 1) + { + GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, + vector) |= (1 << (vector % 32)); + } +} + +void arm_gic_trigger(rt_uint32_t index, int target_cpu, int irq) +{ + unsigned int reg; + + RT_ASSERT(irq <= 15); + RT_ASSERT(target_cpu <= 255); + + reg = (target_cpu << 16) | irq; + GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = reg; +} + +void arm_gic_clear_sgi(rt_uint32_t index, int target_cpu, int irq) +{ + RT_ASSERT(irq <= 15); + RT_ASSERT(target_cpu <= 255); + + GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = target_cpu << (irq % 4); +} diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/gic.h b/rt-thread/libcpu/arm/realview-a8-vmm/gic.h new file mode 100644 index 0000000..41a7727 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/gic.h @@ -0,0 +1,35 @@ +/* + * File : gic.h, ARM Generic Interrupt Controller + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Develop 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 + * 2013-07-20 Bernard first version + */ + +#ifndef __GIC_H__ +#define __GIC_H__ + +int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start); +int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base); + +void arm_gic_mask(rt_uint32_t index, int irq); +void arm_gic_umask(rt_uint32_t index, int irq); +void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask); +void arm_gic_set_group(rt_uint32_t index, int vector, int group); + +int arm_gic_get_active_irq(rt_uint32_t index); +void arm_gic_ack(rt_uint32_t index, int irq); + +void arm_gic_trigger(rt_uint32_t index, int target_cpu, int irq); +void arm_gic_clear_sgi(rt_uint32_t index, int target_cpu, int irq); + +void arm_gic_dump_type(rt_uint32_t index); + +#endif + diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/interrupt.c b/rt-thread/libcpu/arm/realview-a8-vmm/interrupt.c new file mode 100644 index 0000000..ffb6c10 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/interrupt.c @@ -0,0 +1,144 @@ +/* + * File : interrupt.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, 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 + * 2013-07-06 Bernard first version + * 2014-04-03 Grissiom port to VMM + */ + +#include +#include +#include "realview.h" +#include "gic.h" + +#ifdef RT_USING_VMM +#include +#endif + +#define MAX_HANDLERS NR_IRQS_PBA8 + +extern volatile rt_uint8_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +struct rt_irq_desc isr_table[MAX_HANDLERS]; + +/* Those varibles will be accessed in ISR, so we need to share them. */ +rt_uint32_t rt_interrupt_from_thread SECTION(".bss.share.int"); +rt_uint32_t rt_interrupt_to_thread SECTION(".bss.share.int"); +rt_uint32_t rt_thread_switch_interrupt_flag SECTION(".bss.share.int"); + +const unsigned int VECTOR_BASE = 0x00; +extern void rt_cpu_vector_set_base(unsigned int addr); +extern int system_vectors; + +static void rt_hw_vector_init(void) +{ +#ifndef RT_USING_VMM + unsigned int *dest = (unsigned int *)VECTOR_BASE; + unsigned int *src = (unsigned int *)&system_vectors; + + rt_memcpy(dest, src, 16 * 4); + rt_cpu_vector_set_base(VECTOR_BASE); +#endif +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + rt_uint32_t gic_cpu_base; + rt_uint32_t gic_dist_base; + + /* initialize vector table */ + rt_hw_vector_init(); + + /* initialize exceptions table */ + rt_memset(isr_table, 0x00, sizeof(isr_table)); + + /* initialize ARM GIC */ +#ifdef RT_USING_VMM + gic_dist_base = vmm_find_iomap("GIC_DIST"); + gic_cpu_base = vmm_find_iomap("GIC_CPU"); +#else + gic_dist_base = REALVIEW_GIC_DIST_BASE; + gic_cpu_base = REALVIEW_GIC_CPU_BASE; +#endif + arm_gic_dist_init(0, gic_dist_base, 0); + arm_gic_cpu_init(0, gic_cpu_base); + /*arm_gic_dump_type(0);*/ + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + arm_gic_mask(0, vector); +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + arm_gic_umask(0, vector); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if (vector < MAX_HANDLERS) + { + old_handler = isr_table[vector].handler; + + if (handler != RT_NULL) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + } + + return old_handler; +} + +/** + * Trigger a software IRQ + * + * Since we are running in single core, the target CPU are always CPU0. + */ +void rt_hw_interrupt_trigger(int vector) +{ + arm_gic_trigger(0, 1, vector); +} + +void rt_hw_interrupt_clear(int vector) +{ + arm_gic_clear_sgi(0, 1, vector); +} diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/interrupt.h b/rt-thread/libcpu/arm/realview-a8-vmm/interrupt.h new file mode 100644 index 0000000..d81f1c8 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/interrupt.h @@ -0,0 +1,50 @@ +/* + * File : interrupt.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 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 + * 2013-07-06 Bernard first version + */ + +#ifndef __INTERRUPT_H__ +#define __INTERRUPT_H__ + +#define INT_IRQ 0x00 +#define INT_FIQ 0x01 + +#define INTC_REVISION(hw_base) REG32((hw_base) + 0x0) +#define INTC_SYSCONFIG(hw_base) REG32((hw_base) + 0x10) +#define INTC_SYSSTATUS(hw_base) REG32((hw_base) + 0x14) +#define INTC_SIR_IRQ(hw_base) REG32((hw_base) + 0x40) +#define INTC_SIR_FIQ(hw_base) REG32((hw_base) + 0x44) +#define INTC_CONTROL(hw_base) REG32((hw_base) + 0x48) +#define INTC_PROTECTION(hw_base) REG32((hw_base) + 0x4c) +#define INTC_IDLE(hw_base) REG32((hw_base) + 0x50) +#define INTC_IRQ_PRIORITY(hw_base) REG32((hw_base) + 0x60) +#define INTC_FIQ_PRIORITY(hw_base) REG32((hw_base) + 0x64) +#define INTC_THRESHOLD(hw_base) REG32((hw_base) + 0x68) +#define INTC_SICR(hw_base) REG32((hw_base) + 0x6c) +#define INTC_SCR(hw_base, n) REG32((hw_base) + 0x70 + ((n) * 0x04)) +#define INTC_ITR(hw_base, n) REG32((hw_base) + 0x80 + ((n) * 0x20)) +#define INTC_MIR(hw_base, n) REG32((hw_base) + 0x84 + ((n) * 0x20)) +#define INTC_MIR_CLEAR(hw_base, n) REG32((hw_base) + 0x88 + ((n) * 0x20)) +#define INTC_MIR_SET(hw_base, n) REG32((hw_base) + 0x8c + ((n) * 0x20)) +#define INTC_ISR_SET(hw_base, n) REG32((hw_base) + 0x90 + ((n) * 0x20)) +#define INTC_ISR_CLEAR(hw_base, n) REG32((hw_base) + 0x94 + ((n) * 0x20)) +#define INTC_PENDING_IRQ(hw_base, n) REG32((hw_base) + 0x98 + ((n) * 0x20)) +#define INTC_PENDING_FIQ(hw_base, n) REG32((hw_base) + 0x9c + ((n) * 0x20)) +#define INTC_ILR(hw_base, n) REG32((hw_base) + 0x100 + ((n) * 0x04)) + +void rt_hw_interrupt_control(int vector, int priority, int route); +int rt_hw_interrupt_get_active(int fiq_irq); +void rt_hw_interrupt_ack(int fiq_irq); +void rt_hw_interrupt_trigger(int vector); +void rt_hw_interrupt_clear(int vector); + +#endif diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/mmu.c b/rt-thread/libcpu/arm/realview-a8-vmm/mmu.c new file mode 100644 index 0000000..b2503e4 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/mmu.c @@ -0,0 +1,207 @@ +/* + * File : mmu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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 + * 2012-01-10 bernard porting to AM1808 + */ + +#include +#include +#include + +#include "cp15.h" + +#define DESC_SEC (0x2) +#define CB (3<<2) //cache_on, write_back +#define CNB (2<<2) //cache_on, write_through +#define NCB (1<<2) //cache_off,WR_BUF on +#define NCNB (0<<2) //cache_off,WR_BUF off +#define AP_RW (3<<10) //supervisor=RW, user=RW +#define AP_RO (2<<10) //supervisor=RW, user=RO +#define XN (1<<4) // eXecute Never + +#define DOMAIN_FAULT (0x0) +#define DOMAIN_CHK (0x1) +#define DOMAIN_NOTCHK (0x3) +#define DOMAIN0 (0x0<<5) +#define DOMAIN1 (0x1<<5) + +#define DOMAIN0_ATTR (DOMAIN_CHK<<0) +#define DOMAIN1_ATTR (DOMAIN_FAULT<<2) + +/* Read/Write, cache, write back */ +#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) +/* Read/Write, cache, write through */ +#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) +/* Read/Write without cache and write buffer */ +#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) +/* Read/Write without cache and write buffer, no execute */ +#define RW_NCNBXN (AP_RW|DOMAIN0|NCNB|DESC_SEC|XN) +/* Read/Write without cache and write buffer */ +#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) + +/* dump 2nd level page table */ +void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + for (i = 0; i < 256; i++) + { + rt_uint32_t pte2 = ptb[i]; + if ((pte2 & 0x3) == 0) + { + if (fcnt == 0) + rt_kprintf(" "); + rt_kprintf("%04x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf(" %04x: %x: ", i, pte2); + if ((pte2 & 0x3) == 0x1) + { + rt_kprintf("L,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, + (pte2 >> 15) & 0x1, + ((pte2 >> 10) | (pte2 >> 2)) & 0x1f); + } + else + { + rt_kprintf("S,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, pte2 & 0x1, + ((pte2 >> 4) | (pte2 >> 2)) & 0x1f); + } + } +} + +void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + rt_kprintf("page table@%p\n", ptb); + for (i = 0; i < 1024*4; i++) + { + rt_uint32_t pte1 = ptb[i]; + if ((pte1 & 0x3) == 0) + { + rt_kprintf("%03x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf("%03x: %08x: ", i, pte1); + if ((pte1 & 0x3) == 0x3) + { + rt_kprintf("LPAE\n"); + } + else if ((pte1 & 0x3) == 0x1) + { + rt_kprintf("pte,ns:%d,domain:%d\n", + (pte1 >> 3) & 0x1, (pte1 >> 5) & 0xf); + /* + *rt_hw_cpu_dump_page_table_2nd((void*)((pte1 & 0xfffffc000) + * - 0x80000000 + 0xC0000000)); + */ + } + else if (pte1 & (1 << 18)) + { + rt_kprintf("super section,ns:%d,ap:%x,xn:%d,texcb:%02x\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + ((pte1 >> 10) | (pte1 >> 2)) & 0x1f); + } + else + { + rt_kprintf("section,ns:%d,ap:%x," + "xn:%d,texcb:%02x,domain:%d\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + (((pte1 & (0x7 << 12)) >> 10) | + ((pte1 & 0x0c) >> 2)) & 0x1f, + (pte1 >> 5) & 0xf); + } + } +} + +/* level1 page table, each entry for 1MB memory. */ +volatile static unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024))); +void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart, + rt_uint32_t vaddrEnd, + rt_uint32_t paddrStart, + rt_uint32_t attr) +{ + volatile rt_uint32_t *pTT; + volatile int i, nSec; + pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20); + nSec = (vaddrEnd >> 20) - (vaddrStart >> 20); + for(i = 0; i <= nSec; i++) + { + *pTT = attr | (((paddrStart >> 20) + i) << 20); + pTT++; + } +} + +unsigned long rt_hw_set_domain_register(unsigned long domain_val) +{ + unsigned long old_domain; + + asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain)); + asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory"); + + return old_domain; +} + +void rt_hw_mmu_init(void) +{ + rt_hw_cpu_dcache_disable(); + rt_hw_cpu_icache_disable(); + rt_cpu_mmu_disable(); + + /* set page table */ + /* 4G 1:1 memory */ + rt_hw_mmu_setmtt(0, 0xffffffff-1, 0, RW_CB); + /* IO memory region */ + rt_hw_mmu_setmtt(0x44000000, 0x80000000-1, 0x44000000, RW_NCNBXN); + + /*rt_hw_cpu_dump_page_table(MMUTable);*/ + rt_hw_set_domain_register(0x55555555); + + rt_cpu_tlb_set(MMUTable); + + rt_cpu_mmu_enable(); + + rt_hw_cpu_icache_enable(); + rt_hw_cpu_dcache_enable(); +} + diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/pmu.c b/rt-thread/libcpu/arm/realview-a8-vmm/pmu.c new file mode 100644 index 0000000..07911a2 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/pmu.c @@ -0,0 +1,12 @@ +#include +#include "pmu.h" + +void rt_hw_pmu_dump_feature(void) +{ + unsigned long reg; + + reg = rt_hw_pmu_get_control(); + rt_kprintf("ARM PMU Implementor: %c, ID code: %02x, %d counters\n", + reg >> 24, (reg >> 16) & 0xff, (reg >> 11) & 0x1f); + RT_ASSERT(ARM_PMU_CNTER_NR == ((reg >> 11) & 0x1f)); +} diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/pmu.h b/rt-thread/libcpu/arm/realview-a8-vmm/pmu.h new file mode 100644 index 0000000..05c1420 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/pmu.h @@ -0,0 +1,151 @@ +#ifndef __PMU_H__ +#define __PMU_H__ + +#include "board.h" + +/* Number of counters */ +#define ARM_PMU_CNTER_NR 4 + +enum rt_hw_pmu_event_type { + ARM_PMU_EVENT_PMNC_SW_INCR = 0x00, + ARM_PMU_EVENT_L1_ICACHE_REFILL = 0x01, + ARM_PMU_EVENT_ITLB_REFILL = 0x02, + ARM_PMU_EVENT_L1_DCACHE_REFILL = 0x03, + ARM_PMU_EVENT_L1_DCACHE_ACCESS = 0x04, + ARM_PMU_EVENT_DTLB_REFILL = 0x05, + ARM_PMU_EVENT_MEM_READ = 0x06, + ARM_PMU_EVENT_MEM_WRITE = 0x07, + ARM_PMU_EVENT_INSTR_EXECUTED = 0x08, + ARM_PMU_EVENT_EXC_TAKEN = 0x09, + ARM_PMU_EVENT_EXC_EXECUTED = 0x0A, + ARM_PMU_EVENT_CID_WRITE = 0x0B, +}; + +/* Enable bit */ +#define ARM_PMU_PMCR_E (0x01 << 0) +/* Event counter reset */ +#define ARM_PMU_PMCR_P (0x01 << 1) +/* Cycle counter reset */ +#define ARM_PMU_PMCR_C (0x01 << 2) +/* Cycle counter divider */ +#define ARM_PMU_PMCR_D (0x01 << 3) + +#ifdef __GNUC__ +rt_inline void rt_hw_pmu_enable_cnt(int divide64) +{ + unsigned long pmcr; + unsigned long pmcntenset; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_E | ARM_PMU_PMCR_P | ARM_PMU_PMCR_C; + if (divide64) + pmcr |= ARM_PMU_PMCR_D; + else + pmcr &= ~ARM_PMU_PMCR_D; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + + /* enable all the counters */ + pmcntenset = ~0; + asm volatile ("mcr p15, 0, %0, c9, c12, 1" :: "r"(pmcntenset)); + /* clear overflows(just in case) */ + asm volatile ("mcr p15, 0, %0, c9, c12, 3" :: "r"(pmcntenset)); +} + +rt_inline unsigned long rt_hw_pmu_get_control(void) +{ + unsigned long pmcr; + asm ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + return pmcr; +} + +rt_inline unsigned long rt_hw_pmu_get_ceid(void) +{ + unsigned long reg; + /* only PMCEID0 is supported, PMCEID1 is RAZ. */ + asm ("mrc p15, 0, %0, c9, c12, 6" : "=r"(reg)); + return reg; +} + +rt_inline unsigned long rt_hw_pmu_get_cnten(void) +{ + unsigned long pmcnt; + asm ("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcnt)); + return pmcnt; +} + +rt_inline void rt_hw_pmu_reset_cycle(void) +{ + unsigned long pmcr; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_C; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + asm volatile ("isb"); +} + +rt_inline void rt_hw_pmu_reset_event(void) +{ + unsigned long pmcr; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_P; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + asm volatile ("isb"); +} + +rt_inline unsigned long rt_hw_pmu_get_cycle(void) +{ + unsigned long cyc; + asm volatile ("isb"); + asm volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r"(cyc)); + return cyc; +} + +rt_inline void rt_hw_pmu_select_counter(int idx) +{ + RT_ASSERT(idx < ARM_PMU_CNTER_NR); + + asm volatile ("mcr p15, 0, %0, c9, c12, 5" : : "r"(idx)); + /* Linux add an isb here, don't know why here. */ + asm volatile ("isb"); +} + +rt_inline void rt_hw_pmu_select_event(int idx, + enum rt_hw_pmu_event_type eve) +{ + RT_ASSERT(idx < ARM_PMU_CNTER_NR); + + rt_hw_pmu_select_counter(idx); + asm volatile ("mcr p15, 0, %0, c9, c13, 1" : : "r"(eve)); +} + +rt_inline unsigned long rt_hw_pmu_read_counter(int idx) +{ + unsigned long reg; + + rt_hw_pmu_select_counter(idx); + asm volatile ("isb"); + asm volatile ("mrc p15, 0, %0, c9, c13, 2" : "=r"(reg)); + return reg; +} + +rt_inline unsigned long rt_hw_pmu_get_ovsr(void) +{ + unsigned long reg; + asm volatile ("isb"); + asm ("mrc p15, 0, %0, c9, c12, 3" : "=r"(reg)); + return reg; +} + +rt_inline void rt_hw_pmu_clear_ovsr(unsigned long reg) +{ + asm ("mcr p15, 0, %0, c9, c12, 3" : : "r"(reg)); + asm volatile ("isb"); +} + +#endif + +void rt_hw_pmu_dump_feature(void); + +#endif /* end of include guard: __PMU_H__ */ + diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/stack.c b/rt-thread/libcpu/arm/realview-a8-vmm/stack.c new file mode 100644 index 0000000..94080ae --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/stack.c @@ -0,0 +1,67 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 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 + * 2011-09-23 Bernard the first version + * 2011-10-05 Bernard add thumb mode + */ +#include +#include + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/start_gcc.S b/rt-thread/libcpu/arm/realview-a8-vmm/start_gcc.S new file mode 100644 index 0000000..98f22ca --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/start_gcc.S @@ -0,0 +1,366 @@ +/* + * File : start_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +#include + +#ifdef RT_USING_VMM +#include +.equ orig_irq_isr, LINUX_VECTOR_POS+0x18 +#else +#undef RT_VMM_USING_DOMAIN +#endif + +.equ Mode_USR, 0x10 +.equ Mode_FIQ, 0x11 +.equ Mode_IRQ, 0x12 +.equ Mode_SVC, 0x13 +.equ Mode_ABT, 0x17 +.equ Mode_UND, 0x1B +.equ Mode_SYS, 0x1F + +.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled +.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled + +#ifndef RT_USING_VMM +.equ UND_Stack_Size, 0x00000000 +.equ SVC_Stack_Size, 0x00000100 +.equ ABT_Stack_Size, 0x00000000 +.equ RT_FIQ_STACK_PGSZ, 0x00000000 +.equ RT_IRQ_STACK_PGSZ, 0x00000100 +.equ USR_Stack_Size, 0x00000100 + +#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ) +#else +#define ISR_Stack_Size (RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ) +#endif + +.section .data.share.isr +/* stack */ +.globl stack_start +.globl stack_top + +stack_start: +.rept ISR_Stack_Size +.byte 0 +.endr +stack_top: + +.text +/* reset entry */ +.globl _reset +_reset: +#ifdef RT_USING_VMM + /* save all the parameter and variable registers */ + stmfd sp!, {r0-r12, lr} +#endif + /* set the cpu to SVC32 mode and disable interrupt */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0x13 + msr cpsr_c, r0 + + /* setup stack */ + bl stack_setup + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + +#ifdef RT_USING_VMM + /* clear .bss.share */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_share_start /* bss start */ + ldr r2,=__bss_share_end /* bss end */ + +bss_share_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_share_loop /* loop until done */ +#endif + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop +ctor_end: + + /* start RT-Thread Kernel */ +#ifdef RT_USING_VMM + /* restore the parameter */ + ldmfd sp!, {r0-r3} + bl vmm_entry + ldmfd sp!, {r4-r12, pc} +#else + ldr pc, _rtthread_startup +_rtthread_startup: + .word rtthread_startup +#endif + +stack_setup: + ldr r0, =stack_top +#ifdef RT_USING_VMM + @ Linux use stmia to save r0, lr and spsr. To align to 8 byte boundary, + @ just allocate 16 bytes for it. + sub r0, r0, #16 +#endif + +#ifndef RT_USING_VMM + @ Set the startup stack for svc + mov sp, r0 +#endif + +#ifndef RT_USING_VMM + @ Enter Undefined Instruction Mode and set its Stack Pointer + msr cpsr_c, #Mode_UND|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #UND_Stack_Size + + @ Enter Abort Mode and set its Stack Pointer + msr cpsr_c, #Mode_ABT|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #ABT_Stack_Size +#endif + + @ Enter FIQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #RT_FIQ_STACK_PGSZ + + @ Enter IRQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #RT_IRQ_STACK_PGSZ + + /* come back to SVC mode */ + msr cpsr_c, #Mode_SVC|I_Bit|F_Bit + bx lr + +/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */ +.section .text.isr, "ax" + .align 5 +.globl vector_fiq +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc, lr, #4 + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread + +.globl rt_current_thread +.globl vmm_thread +.globl vmm_virq_check + + .align 5 +.globl vector_irq +vector_irq: + stmfd sp!, {r0-r12,lr} + +#ifdef RT_VMM_USING_DOMAIN + @ save the last domain + mrc p15, 0, r5, c3, c0 + @ switch to vmm domain as we are going to call vmm codes + ldr r1, =vmm_domain_val + ldr r4, [r1] + mcr p15, 0, r4, c3, c0 +#endif + + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + +#ifdef RT_VMM_USING_DOMAIN + @ restore the last domain. It do some redundant work but simplify the + @ logic. It might be the guest domain so rt_thread_switch_interrupt_flag + @ should lay in .bss.share + mcr p15, 0, r5, c3, c0 +#endif + + @ if rt_thread_switch_interrupt_flag set, jump to + @ rt_hw_context_switch_interrupt_do and don't return + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq rt_hw_context_switch_interrupt_do + +#ifndef RT_USING_VMM + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 +#else +#ifdef RT_VMM_USING_DOMAIN + @ r4 is vmm_domain_val + @ back to vmm domain as we need access rt_current_thread + mcr p15, 0, r4, c3, c0 +#endif + /* check whether we need to do IRQ routing + * ensure the int is disabled. Or there will be an infinite loop. */ + ldr r0, =rt_current_thread + ldr r0, [r0] + ldr r1, =vmm_thread + cmp r0, r1 + beq switch_to_guest + +#ifdef RT_VMM_USING_DOMAIN + @ r5 is domain of interrupted context + @ it might be super_domain_val or vmm_domain_val so we need to restore it. + mcr p15, 0, r5, c3, c0 +#endif + @ switch back if the interrupted thread is not vmm + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +switch_to_guest: +#ifdef RT_VMM_USING_DOMAIN + @ We are going to execute rt-thread code but accessing the content of the + @ guest. So switch to super domain. + ldr r1, =super_domain_val + ldr r0, [r1] + mcr p15, 0, r0, c3, c0 +#endif + /* check whether there is a pending interrupt for Guest OS */ + bl vmm_virq_check + +#ifdef RT_VMM_USING_DOMAIN + @ All done, restore the guest domain. + mcr p15, 0, r5, c3, c0 +#endif + + cmp r0, #0x0 + beq route_irq_to_guest + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +route_irq_to_guest: + ldmfd sp!, {r0-r12,lr} + b orig_irq_isr +#endif /* RT_USING_VMM */ + +rt_hw_context_switch_interrupt_do: + mov r1, #0 @ clear flag + str r1, [r0] + + mov r1, sp @ r1 point to {r0-r3} in stack + add sp, sp, #4*4 + ldmfd sp!, {r4-r12,lr}@ reload saved registers + mrs r0, spsr @ get cpsr of interrupt thread + sub r2, lr, #4 @ save old task's pc to r2 + + @ Switch to SVC mode with no interrupt. If the usr mode guest is + @ interrupted, this will just switch to the stack of kernel space. + @ save the registers in kernel space won't trigger data abort. + msr cpsr_c, #I_Bit|F_Bit|Mode_SVC + + stmfd sp!, {r2} @ push old task's pc + stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4 + ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt thread + stmfd sp!, {r1-r4} @ push old task's r0-r3 + stmfd sp!, {r0} @ push old task's cpsr + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] @ store sp in preempted tasks's TCB + +#ifdef RT_VMM_USING_DOMAIN + @ If a thread is wake up by interrupt, it should be RTT thread. + @ Make sure the domain is correct. + ldr r1, =vmm_domain_val + ldr r2, [r1] + mcr p15, 0, r2, c3, c0 +#endif + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] @ get new task's stack pointer + + ldmfd sp!, {r4} @ pop new task's cpsr to spsr + msr spsr_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr + +.macro push_svc_reg + sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */ + stmia sp, {r0 - r12} @/* Calling r0-r12 */ + mov r0, sp + mrs r6, spsr @/* Save CPSR */ + str lr, [r0, #15*4] @/* Push PC */ + str r6, [r0, #16*4] @/* Push CPSR */ + cps #Mode_SVC + str sp, [r0, #13*4] @/* Save calling SP */ + str lr, [r0, #14*4] @/* Save calling PC */ +.endm + + .align 5 + .globl vector_swi +vector_swi: + push_svc_reg + bl rt_hw_trap_swi + b . + + .align 5 + .globl vector_undef +vector_undef: + push_svc_reg + bl rt_hw_trap_undef + b . + + .align 5 + .globl vector_pabt +vector_pabt: + push_svc_reg + bl rt_hw_trap_pabt + b . + + .align 5 + .globl vector_dabt +vector_dabt: + push_svc_reg + bl rt_hw_trap_dabt + b . + + .align 5 + .globl vector_resv +vector_resv: + push_svc_reg + bl rt_hw_trap_resv + b . diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/trap.c b/rt-thread/libcpu/arm/realview-a8-vmm/trap.c new file mode 100644 index 0000000..a6397d2 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/trap.c @@ -0,0 +1,204 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Develop 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 + * 2013-07-20 Bernard first version + */ + +#include +#include +#include + +#include "armv7.h" + +#ifdef RT_USING_VMM +#include +#endif + +#include "gic.h" + +extern struct rt_thread *rt_current_thread; +#ifdef RT_USING_FINSH +extern long list_thread(void); +#endif + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ +void rt_hw_show_register(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_undef(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("undefined instruction:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("software interrupt:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("prefetch abort:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("data abort:"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("reserved trap:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +#define GIC_ACK_INTID_MASK 0x000003ff + +void rt_hw_trap_irq(void) +{ + void *param; + unsigned long ir; + unsigned long fullir; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + fullir = arm_gic_get_active_irq(0); + ir = fullir & GIC_ACK_INTID_MASK; + + if (ir == 1023) + { + /* Spurious interrupt */ + return; + } + + /* get interrupt service routine */ + isr_func = isr_table[ir].handler; +#ifdef RT_USING_INTERRUPT_INFO + isr_table[ir].counter++; +#endif + if (isr_func) + { + /* Interrupt for myself. */ + param = isr_table[ir].param; + /* turn to interrupt service routine */ + isr_func(ir, param); + } +#ifdef RT_USING_VMM + else + { + /* We have to EOI before masking the interrupts */ + arm_gic_ack(0, fullir); + vmm_virq_pending(ir); + return; + } +#endif + + /* end of interrupt */ + arm_gic_ack(0, fullir); +} + +void rt_hw_trap_fiq(void) +{ + void *param; + unsigned long ir; + unsigned long fullir; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + fullir = arm_gic_get_active_irq(0); + ir = fullir & GIC_ACK_INTID_MASK; + + /* get interrupt service routine */ + isr_func = isr_table[ir].handler; + param = isr_table[ir].param; + + /* turn to interrupt service routine */ + isr_func(ir, param); + + /* end of interrupt */ + arm_gic_ack(0, fullir); +} + diff --git a/rt-thread/libcpu/arm/realview-a8-vmm/vector_gcc.S b/rt-thread/libcpu/arm/realview-a8-vmm/vector_gcc.S new file mode 100644 index 0000000..8d0ca27 --- /dev/null +++ b/rt-thread/libcpu/arm/realview-a8-vmm/vector_gcc.S @@ -0,0 +1,66 @@ +/* + * File : vector_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ +#include + +.section .vectors, "ax" +.code 32 + +.globl system_vectors +system_vectors: + ldr pc, _vector_reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + ldr pc, _vector_resv + ldr pc, _vector_irq + ldr pc, _vector_fiq + +.globl _reset +.globl vector_undef +.globl vector_swi +.globl vector_pabt +.globl vector_dabt +.globl vector_resv +.globl vector_irq +.globl vector_fiq + +_vector_reset: + .word _reset +_vector_undef: + .word vector_undef +_vector_swi: + .word vector_swi +_vector_pabt: + .word vector_pabt +_vector_dabt: + .word vector_dabt +_vector_resv: + .word vector_resv +_vector_irq: + .word vector_irq +_vector_fiq: + .word vector_fiq + +.balignl 16,0xdeadbeef diff --git a/rt-thread/libcpu/arm/s3c24x0/context_gcc.S b/rt-thread/libcpu/arm/s3c24x0/context_gcc.S new file mode 100644 index 0000000..06bbd44 --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/context_gcc.S @@ -0,0 +1,99 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-09-06 XuXinming first version + */ + +/*! + * \addtogroup S3C24X0 + */ +/*@{*/ + +#define NOINT 0xc0 + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + orr r1, r0, #NOINT + msr cpsr_c, r1 + mov pc, lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + mov pc, lr + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + stmfd sp!, {r4} @ push cpsr + mrs r4, spsr + stmfd sp!, {r4} @ push spsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r4} @ pop new task cpsr + msr spsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r4} @ pop new task cpsr + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 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] + mov pc, lr diff --git a/rt-thread/libcpu/arm/s3c24x0/context_rvds.S b/rt-thread/libcpu/arm/s3c24x0/context_rvds.S new file mode 100644 index 0000000..54d655a --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/context_rvds.S @@ -0,0 +1,107 @@ +;/* +; * File : context_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, 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-20 Bernard first version +; */ + +NOINT EQU 0xc0 ; disable interrupt in psr + + AREA |.text|, CODE, READONLY, ALIGN=2 + ARM + REQUIRE8 + PRESERVE8 + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ +rt_hw_interrupt_disable PROC + EXPORT rt_hw_interrupt_disable + MRS r0, cpsr + ORR r1, r0, #NOINT + MSR cpsr_c, r1 + BX lr + ENDP + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ +rt_hw_interrupt_enable PROC + EXPORT rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + ENDP + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ +rt_hw_context_switch PROC + EXPORT rt_hw_context_switch + STMFD sp!, {lr} ; push pc (lr should be pushed in place of PC) + STMFD sp!, {r0-r12, lr} ; push lr & register file + + MRS r4, cpsr + STMFD sp!, {r4} ; push cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push spsr + + STR sp, [r0] ; store sp in preempted tasks TCB + LDR sp, [r1] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR spsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ +rt_hw_context_switch_to PROC + EXPORT rt_hw_context_switch_to + LDR sp, [r0] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +rt_hw_context_switch_interrupt PROC + EXPORT rt_hw_context_switch_interrupt + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 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] + BX lr + ENDP + + END \ No newline at end of file diff --git a/rt-thread/libcpu/arm/s3c24x0/cpu.c b/rt-thread/libcpu/arm/s3c24x0/cpu.c new file mode 100644 index 0000000..907f081 --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/cpu.c @@ -0,0 +1,190 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + */ + +#include +#include +#include "s3c24x0.h" + +/** + * @addtogroup S3C24X0 + */ +/*@{*/ + +#define ICACHE_MASK (rt_uint32_t)(1 << 12) +#define DCACHE_MASK (rt_uint32_t)(1 << 2) + +#ifdef __GNUC__ +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + __asm__ __volatile__( \ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "orr r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + __asm__ __volatile__( \ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "bic r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} +#endif + +#ifdef __CC_ARM +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + __asm + { + mrc p15, 0, i, c1, c0, 0 + } + + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} +#endif + +/** + * enable I-Cache + * + */ +void rt_hw_cpu_icache_enable() +{ + cache_enable(ICACHE_MASK); +} + +/** + * disable I-Cache + * + */ +void rt_hw_cpu_icache_disable() +{ + cache_disable(ICACHE_MASK); +} + +/** + * return the status of I-Cache + * + */ +rt_base_t rt_hw_cpu_icache_status() +{ + return (cp15_rd() & ICACHE_MASK); +} + +/** + * enable D-Cache + * + */ +void rt_hw_cpu_dcache_enable() +{ + cache_enable(DCACHE_MASK); +} + +/** + * disable D-Cache + * + */ +void rt_hw_cpu_dcache_disable() +{ + cache_disable(DCACHE_MASK); +} + +/** + * return the status of D-Cache + * + */ +rt_base_t rt_hw_cpu_dcache_status() +{ + return (cp15_rd() & DCACHE_MASK); +} + +/** + * reset cpu by dog's time-out + * + */ +void rt_hw_cpu_reset() +{ + /* Disable all interrupt except the WDT */ + INTMSK = (~((rt_uint32_t)1 << INTWDT)); + + /* Disable watchdog */ + WTCON = 0x0000; + + /* Initialize watchdog timer count register */ + WTCNT = 0x0001; + + /* Enable watchdog timer; assert reset at timer timeout */ + WTCON = 0x0021; + + while(1); /* loop forever and wait for reset to happen */ + + /* NEVER REACHED */ +} + +/** + * shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + while (level) + { + RT_ASSERT(0); + } +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/s3c24x0/interrupt.c b/rt-thread/libcpu/arm/s3c24x0/interrupt.c new file mode 100644 index 0000000..df0c140 --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/interrupt.c @@ -0,0 +1,132 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + * 2013-03-29 aozima Modify the interrupt interface implementations. + */ + +#include +#include +#include "s3c24x0.h" + +#define MAX_HANDLERS 32 + +extern rt_uint32_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +struct rt_irq_desc isr_table[MAX_HANDLERS]; +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +/** + * @addtogroup S3C24X0 + */ +/*@{*/ + +static void rt_hw_interrupt_handle(int vector, void *param) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + register rt_uint32_t idx; + + /* all clear source pending */ + SRCPND = 0x0; + + /* all clear sub source pending */ + SUBSRCPND = 0x0; + + /* all=IRQ mode */ + INTMOD = 0x0; + + /* all interrupt disabled include global bit */ + INTMSK = BIT_ALLMSK; + + /* all sub interrupt disable */ + INTSUBMSK = BIT_SUB_ALLMSK; + + /* all clear interrupt pending */ + INTPND = BIT_ALLMSK; + + /* init exceptions table */ + rt_memset(isr_table, 0x00, sizeof(isr_table)); + for(idx=0; idx < MAX_HANDLERS; idx++) + { + isr_table[idx].handler = rt_hw_interrupt_handle; + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + INTMSK |= 1 << vector; +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + if (vector == INTNOTUSED6) + { + rt_kprintf("Interrupt vec %d is not used!\n", vector); + // while(1); + } + else if (vector == INTGLOBAL) + INTMSK = 0x0; + else + INTMSK &= ~(1 << vector); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if(vector < MAX_HANDLERS) + { + old_handler = isr_table[vector].handler; + + if (handler != RT_NULL) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + } + + return old_handler; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/s3c24x0/mmu.c b/rt-thread/libcpu/arm/s3c24x0/mmu.c new file mode 100644 index 0000000..662ec3d --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/mmu.c @@ -0,0 +1,394 @@ +/* + * File : mmu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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 + * 2008-04-25 Yi.qiu first version + * 2009-12-18 Bernard port to armcc + */ + +#include +#include "s3c24x0.h" + +#define _MMUTT_STARTADDRESS 0x33FF0000 + +#define DESC_SEC (0x2|(1<<4)) +#define CB (3<<2) //cache_on, write_back +#define CNB (2<<2) //cache_on, write_through +#define NCB (1<<2) //cache_off,WR_BUF on +#define NCNB (0<<2) //cache_off,WR_BUF off +#define AP_RW (3<<10) //supervisor=RW, user=RW +#define AP_RO (2<<10) //supervisor=RW, user=RO + +#define DOMAIN_FAULT (0x0) +#define DOMAIN_CHK (0x1) +#define DOMAIN_NOTCHK (0x3) +#define DOMAIN0 (0x0<<5) +#define DOMAIN1 (0x1<<5) + +#define DOMAIN0_ATTR (DOMAIN_CHK<<0) +#define DOMAIN1_ATTR (DOMAIN_FAULT<<2) + +#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) +#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) +#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) +#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) + +#ifdef __GNUC__ +void mmu_setttbase(register rt_uint32_t i) +{ + asm volatile ("mcr p15, 0, %0, c2, c0, 0": :"r" (i)); +} + +void mmu_set_domain(register rt_uint32_t i) +{ + asm volatile ("mcr p15,0, %0, c3, c0, 0": :"r" (i)); +} + +void mmu_enable() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= 0x1; + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~0x1; + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_enable_icache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= (1 << 12); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_enable_dcache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= (1 << 2); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable_icache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~(1 << 12); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable_dcache() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~(1 << 2); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_enable_alignfault() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i |= (1 << 1); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_disable_alignfault() +{ + register rt_uint32_t i; + + /* read control register */ + asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + + i &= ~(1 << 1); + + /* write back to control register */ + asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i)); +} + +void mmu_clean_invalidated_cache_index(int index) +{ + asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index)); +} + +void mmu_invalidate_tlb() +{ + asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0)); +} + +void mmu_invalidate_icache() +{ + asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0)); +} +#endif + +#ifdef __CC_ARM +void mmu_setttbase(rt_uint32_t i) +{ + __asm volatile + { + mcr p15, 0, i, c2, c0, 0 + } +} + +void mmu_set_domain(rt_uint32_t i) +{ + __asm volatile + { + mcr p15,0, i, c3, c0, 0 + } +} + +void mmu_enable() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x01 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x01 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_icache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x1000 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_dcache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x04 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_icache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x1000 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_dcache() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x04 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_enable_alignfault() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, #0x02 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_disable_alignfault() +{ + register rt_uint32_t value; + + __asm volatile + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, #0x02 + mcr p15, 0, value, c1, c0, 0 + } +} + +void mmu_clean_invalidated_cache_index(int index) +{ + __asm volatile + { + mcr p15, 0, index, c7, c14, 2 + } +} + +void mmu_invalidate_tlb() +{ + register rt_uint32_t value; + + value = 0; + __asm volatile + { + mcr p15, 0, value, c8, c7, 0 + } +} + +void mmu_invalidate_icache() +{ + register rt_uint32_t value; + + value = 0; + + __asm volatile + { + mcr p15, 0, value, c7, c5, 0 + } +} +#endif + +void mmu_setmtt(int vaddrStart,int vaddrEnd,int paddrStart,int attr) +{ + volatile rt_uint32_t *pTT; + volatile int i,nSec; + pTT=(rt_uint32_t *)_MMUTT_STARTADDRESS+(vaddrStart>>20); + nSec=(vaddrEnd>>20)-(vaddrStart>>20); + for(i=0;i<=nSec;i++) + { + *pTT = attr |(((paddrStart>>20)+i)<<20); + pTT++; + } +} + +void rt_hw_mmu_init(void) +{ + int i,j; + //========================== IMPORTANT NOTE ========================= + //The current stack and code area can't be re-mapped in this routine. + //If you want memory map mapped freely, your own sophiscated mmu + //initialization code is needed. + //=================================================================== + + mmu_disable_dcache(); + mmu_disable_icache(); + + //If write-back is used,the DCache should be cleared. + for(i=0;i<64;i++) + for(j=0;j<8;j++) + mmu_clean_invalidated_cache_index((i<<26)|(j<<5)); + + mmu_invalidate_icache(); + + //To complete mmu_Init() fast, Icache may be turned on here. + mmu_enable_icache(); + + mmu_disable(); + mmu_invalidate_tlb(); + + //mmu_setmtt(int vaddrStart,int vaddrEnd,int paddrStart,int attr); + mmu_setmtt(0x00000000,0x07f00000,0x00000000,RW_CNB); //bank0 + mmu_setmtt(0x00000000,0x03f00000,(int)0x30000000,RW_CB); //bank0 + mmu_setmtt(0x04000000,0x07f00000,0,RW_NCNB); //bank0 + mmu_setmtt(0x08000000,0x0ff00000,0x08000000,RW_CNB); //bank1 + mmu_setmtt(0x10000000,0x17f00000,0x10000000,RW_NCNB); //bank2 + mmu_setmtt(0x18000000,0x1ff00000,0x18000000,RW_NCNB); //bank3 + //mmu_setmtt(0x20000000,0x27f00000,0x20000000,RW_CB); //bank4 + mmu_setmtt(0x20000000,0x27f00000,0x20000000,RW_NCNB); //bank4 for DM9000 + mmu_setmtt(0x28000000,0x2ff00000,0x28000000,RW_NCNB); //bank5 + //30f00000->30100000, 31000000->30200000 + mmu_setmtt(0x30000000,0x30100000,0x30000000,RW_CB); //bank6-1 + mmu_setmtt(0x30200000,0x33e00000,0x30200000,RW_CB); //bank6-2 + + mmu_setmtt(0x33f00000,0x34000000,0x33f00000,RW_NCNB); //bank6-3 + mmu_setmtt(0x38000000,0x3ff00000,0x38000000,RW_NCNB); //bank7 + + mmu_setmtt(0x40000000,0x47f00000,0x40000000,RW_NCNB); //SFR + mmu_setmtt(0x48000000,0x5af00000,0x48000000,RW_NCNB); //SFR + mmu_setmtt(0x5b000000,0x5b000000,0x5b000000,RW_NCNB); //SFR + mmu_setmtt(0x5b100000,0xfff00000,0x5b100000,RW_FAULT);//not used + mmu_setmtt(0x60000000,0x67f00000,0x60000000,RW_NCNB); //SFR + + mmu_setttbase(_MMUTT_STARTADDRESS); + + /* DOMAIN1: no_access, DOMAIN0,2~15=client(AP is checked) */ + mmu_set_domain(0x55555550|DOMAIN1_ATTR|DOMAIN0_ATTR); + + mmu_enable_alignfault(); + + mmu_enable(); + + /* ICache enable */ + mmu_enable_icache(); + /* DCache should be turned on after mmu is turned on. */ + mmu_enable_dcache(); +} + diff --git a/rt-thread/libcpu/arm/s3c24x0/rtc.c b/rt-thread/libcpu/arm/s3c24x0/rtc.c new file mode 100644 index 0000000..601f3dd --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/rtc.c @@ -0,0 +1,189 @@ +/* + * File : rtc.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2009-04-26 yi.qiu first version + * 2010-03-18 Gary Lee add functions such as GregorianDay + * and rtc_time_to_tm + * 2009-03-20 yi.qiu clean up + */ + +#include +#include +#include + +// #define RTC_DEBUG + +#define RTC_ENABLE RTCCON |= 0x01; /*RTC read and write enable */ +#define RTC_DISABLE RTCCON &= ~0x01; /* RTC read and write disable */ +#define BCD2BIN(n) (((((n) >> 4) & 0x0F) * 10) + ((n) & 0x0F)) +#define BIN2BCD(n) ((((n) / 10) << 4) | ((n) % 10)) + +/** + * This function get rtc time + */ +void rt_hw_rtc_get(struct tm *ti) +{ + rt_uint8_t sec, min, hour, mday, wday, mon, year; + + /* enable access to RTC registers */ + RTCCON |= RTC_ENABLE; + + /* read RTC registers */ + do + { + sec = BCDSEC; + min = BCDMIN; + hour = BCDHOUR; + mday = BCDDATE; + wday = BCDDAY; + mon = BCDMON; + year = BCDYEAR; + } while (sec != BCDSEC); + +#ifdef RTC_DEBUG + rt_kprintf("sec:%x min:%x hour:%x mday:%x wday:%x mon:%x year:%x\n", + sec, min, hour, mday, wday, mon, year); +#endif + + /* disable access to RTC registers */ + RTC_DISABLE + + ti->tm_sec = BCD2BIN(sec & 0x7F); + ti->tm_min = BCD2BIN(min & 0x7F); + ti->tm_hour = BCD2BIN(hour & 0x3F); + ti->tm_mday = BCD2BIN(mday & 0x3F); + ti->tm_mon = BCD2BIN(mon & 0x1F); + ti->tm_year = BCD2BIN(year); + ti->tm_wday = BCD2BIN(wday & 0x07); + ti->tm_yday = 0; + ti->tm_isdst = 0; +} + +/** + * This function set rtc time + */ +void rt_hw_rtc_set(struct tm *ti) +{ + rt_uint8_t sec, min, hour, mday, wday, mon, year; + + year = BIN2BCD(ti->tm_year); + mon = BIN2BCD(ti->tm_mon); + wday = BIN2BCD(ti->tm_wday); + mday = BIN2BCD(ti->tm_mday); + hour = BIN2BCD(ti->tm_hour); + min = BIN2BCD(ti->tm_min); + sec = BIN2BCD(ti->tm_sec); + + /* enable access to RTC registers */ + RTC_ENABLE + + do{ + /* write RTC registers */ + BCDSEC = sec; + BCDMIN = min; + BCDHOUR = hour; + BCDDATE = mday; + BCDDAY = wday; + BCDMON = mon; + BCDYEAR = year; + }while (sec != BCDSEC); + + /* disable access to RTC registers */ + RTC_DISABLE +} + +/** + * This function reset rtc + */ +void rt_hw_rtc_reset (void) +{ + RTCCON = (RTCCON & ~0x06) | 0x08; + RTCCON &= ~(0x08|0x01); +} + +static struct rt_device rtc; +static rt_err_t rtc_open(rt_device_t dev, rt_uint16_t oflag) +{ + RTC_ENABLE + return RT_EOK; +} + +static rt_err_t rtc_close(rt_device_t dev) +{ + RTC_DISABLE + return RT_EOK; +} + +static rt_size_t rtc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + return RT_EOK; +} + +static rt_err_t rtc_control(rt_device_t dev, int cmd, void *args) +{ + struct tm tm, *tm_ptr; + time_t *time; + RT_ASSERT(dev != RT_NULL); + + time = (time_t *)args; + switch (cmd) + { + case RT_DEVICE_CTRL_RTC_GET_TIME: + /* read device */ + rt_hw_rtc_get(&tm); + *((rt_time_t *)args) = mktime(&tm); + break; + + case RT_DEVICE_CTRL_RTC_SET_TIME: + tm_ptr = localtime(time); + /* write device */ + rt_hw_rtc_set(tm_ptr); + break; + } + + return RT_EOK; +} + +void rt_hw_rtc_init(void) +{ + rtc.type = RT_Device_Class_RTC; + + /* register rtc device */ + rtc.init = RT_NULL; + rtc.open = rtc_open; + rtc.close = rtc_close; + rtc.read = rtc_read; + rtc.write = RT_NULL; + rtc.control = rtc_control; + + /* no private */ + rtc.user_data = RT_NULL; + + rt_device_register(&rtc, "rtc", RT_DEVICE_FLAG_RDWR); +} + +#ifdef RT_USING_FINSH +#include +void list_date() +{ + time_t time; + rt_device_t device; + + device = rt_device_find("rtc"); + if (device != RT_NULL) + { + rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time); + + rt_kprintf("%d, %s\n", time, ctime(&time)); + } +} +FINSH_FUNCTION_EXPORT(list_date, list date); +#endif diff --git a/rt-thread/libcpu/arm/s3c24x0/rtc.h b/rt-thread/libcpu/arm/s3c24x0/rtc.h new file mode 100644 index 0000000..f7073e2 --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/rtc.h @@ -0,0 +1,21 @@ +/* + * File : rtc.h + * 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 + * 2010-03-20 yi.qiu the first version + */ + +#ifndef __RTC_H__ +#define __RTC_H__ + +void rt_hw_rtc_init(void); + +#endif + diff --git a/rt-thread/libcpu/arm/s3c24x0/s3c24x0.h b/rt-thread/libcpu/arm/s3c24x0/s3c24x0.h new file mode 100644 index 0000000..8308148 --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/s3c24x0.h @@ -0,0 +1,611 @@ +/* + * File : s3c24x0.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2009-12-11 Bernard first version + */ + +#ifndef __S3C24X0_H__ +#define __S3C24X0_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/** + * @addtogroup S3C24X0 + */ +/*@{*/ + +// Memory control +#define BWSCON (*(volatile unsigned *)0x48000000) //Bus width & wait status +#define BANKCON0 (*(volatile unsigned *)0x48000004) //Boot ROM control +#define BANKCON1 (*(volatile unsigned *)0x48000008) //BANK1 control +#define BANKCON2 (*(volatile unsigned *)0x4800000c) //BANK2 cControl +#define BANKCON3 (*(volatile unsigned *)0x48000010) //BANK3 control +#define BANKCON4 (*(volatile unsigned *)0x48000014) //BANK4 control +#define BANKCON5 (*(volatile unsigned *)0x48000018) //BANK5 control +#define BANKCON6 (*(volatile unsigned *)0x4800001c) //BANK6 control +#define BANKCON7 (*(volatile unsigned *)0x48000020) //BANK7 control +#define REFRESH (*(volatile unsigned *)0x48000024) //DRAM/SDRAM efresh +#define BANKSIZE (*(volatile unsigned *)0x48000028) //Flexible Bank Size +#define MRSRB6 (*(volatile unsigned *)0x4800002c) //Mode egister set for SDRAM +#define MRSRB7 (*(volatile unsigned *)0x48000030) //Mode egister set for SDRAM + + +// USB Host + + +// INTERRUPT +#define SRCPND (*(volatile unsigned *)0x4a000000) //Interrupt request status +#define INTMOD (*(volatile unsigned *)0x4a000004) //Interrupt mode control +#define INTMSK (*(volatile unsigned *)0x4a000008) //Interrupt mask control +#define PRIORITY (*(volatile unsigned *)0x4a00000c) //IRQ priority control +#define INTPND (*(volatile unsigned *)0x4a000010) //Interrupt request status +#define INTOFFSET (*(volatile unsigned *)0x4a000014) //Interruot request source offset +#define SUBSRCPND (*(volatile unsigned *)0x4a000018) //Sub source pending +#define INTSUBMSK (*(volatile unsigned *)0x4a00001c) //Interrupt sub mask + + +// DMA +#define DISRC0 (*(volatile unsigned *)0x4b000000) //DMA 0 Initial source +#define DISRCC0 (*(volatile unsigned *)0x4b000004) //DMA 0 Initial source control +#define DIDST0 (*(volatile unsigned *)0x4b000008) //DMA 0 Initial Destination +#define DIDSTC0 (*(volatile unsigned *)0x4b00000c) //DMA 0 Initial Destination control +#define DCON0 (*(volatile unsigned *)0x4b000010) //DMA 0 Control +#define DSTAT0 (*(volatile unsigned *)0x4b000014) //DMA 0 Status +#define DCSRC0 (*(volatile unsigned *)0x4b000018) //DMA 0 Current source +#define DCDST0 (*(volatile unsigned *)0x4b00001c) //DMA 0 Current destination +#define DMASKTRIG0 (*(volatile unsigned *)0x4b000020) //DMA 0 Mask trigger + +#define DISRC1 (*(volatile unsigned *)0x4b000040) //DMA 1 Initial source +#define DISRCC1 (*(volatile unsigned *)0x4b000044) //DMA 1 Initial source control +#define DIDST1 (*(volatile unsigned *)0x4b000048) //DMA 1 Initial Destination +#define DIDSTC1 (*(volatile unsigned *)0x4b00004c) //DMA 1 Initial Destination control +#define DCON1 (*(volatile unsigned *)0x4b000050) //DMA 1 Control +#define DSTAT1 (*(volatile unsigned *)0x4b000054) //DMA 1 Status +#define DCSRC1 (*(volatile unsigned *)0x4b000058) //DMA 1 Current source +#define DCDST1 (*(volatile unsigned *)0x4b00005c) //DMA 1 Current destination +#define DMASKTRIG1 (*(volatile unsigned *)0x4b000060) //DMA 1 Mask trigger + +#define DISRC2 (*(volatile unsigned *)0x4b000080) //DMA 2 Initial source +#define DISRCC2 (*(volatile unsigned *)0x4b000084) //DMA 2 Initial source control +#define DIDST2 (*(volatile unsigned *)0x4b000088) //DMA 2 Initial Destination +#define DIDSTC2 (*(volatile unsigned *)0x4b00008c) //DMA 2 Initial Destination control +#define DCON2 (*(volatile unsigned *)0x4b000090) //DMA 2 Control +#define DSTAT2 (*(volatile unsigned *)0x4b000094) //DMA 2 Status +#define DCSRC2 (*(volatile unsigned *)0x4b000098) //DMA 2 Current source +#define DCDST2 (*(volatile unsigned *)0x4b00009c) //DMA 2 Current destination +#define DMASKTRIG2 (*(volatile unsigned *)0x4b0000a0) //DMA 2 Mask trigger + +#define DISRC3 (*(volatile unsigned *)0x4b0000c0) //DMA 3 Initial source +#define DISRCC3 (*(volatile unsigned *)0x4b0000c4) //DMA 3 Initial source control +#define DIDST3 (*(volatile unsigned *)0x4b0000c8) //DMA 3 Initial Destination +#define DIDSTC3 (*(volatile unsigned *)0x4b0000cc) //DMA 3 Initial Destination control +#define DCON3 (*(volatile unsigned *)0x4b0000d0) //DMA 3 Control +#define DSTAT3 (*(volatile unsigned *)0x4b0000d4) //DMA 3 Status +#define DCSRC3 (*(volatile unsigned *)0x4b0000d8) //DMA 3 Current source +#define DCDST3 (*(volatile unsigned *)0x4b0000dc) //DMA 3 Current destination +#define DMASKTRIG3 (*(volatile unsigned *)0x4b0000e0) //DMA 3 Mask trigger + + +// CLOCK & POWER MANAGEMENT +#define LOCKTIME (*(volatile unsigned *)0x4c000000) //PLL lock time counter +#define MPLLCON (*(volatile unsigned *)0x4c000004) //MPLL Control +#define UPLLCON (*(volatile unsigned *)0x4c000008) //UPLL Control +#define CLKCON (*(volatile unsigned *)0x4c00000c) //Clock generator control +#define CLKSLOW (*(volatile unsigned *)0x4c000010) //Slow clock control +#define CLKDIVN (*(volatile unsigned *)0x4c000014) //Clock divider control +#define CAMDIVN (*(volatile unsigned *)0x4c000018) //USB, CAM Clock divider control + + +// LCD CONTROLLER +#define LCDCON1 (*(volatile unsigned *)0x4d000000) //LCD control 1 +#define LCDCON2 (*(volatile unsigned *)0x4d000004) //LCD control 2 +#define LCDCON3 (*(volatile unsigned *)0x4d000008) //LCD control 3 +#define LCDCON4 (*(volatile unsigned *)0x4d00000c) //LCD control 4 +#define LCDCON5 (*(volatile unsigned *)0x4d000010) //LCD control 5 +#define LCDSADDR1 (*(volatile unsigned *)0x4d000014) //STN/TFT Frame buffer start address 1 +#define LCDSADDR2 (*(volatile unsigned *)0x4d000018) //STN/TFT Frame buffer start address 2 +#define LCDSADDR3 (*(volatile unsigned *)0x4d00001c) //STN/TFT Virtual screen address set +#define REDLUT (*(volatile unsigned *)0x4d000020) //STN Red lookup table +#define GREENLUT (*(volatile unsigned *)0x4d000024) //STN Green lookup table +#define BLUELUT (*(volatile unsigned *)0x4d000028) //STN Blue lookup table +#define DITHMODE (*(volatile unsigned *)0x4d00004c) //STN Dithering mode +#define TPAL (*(volatile unsigned *)0x4d000050) //TFT Temporary palette +#define LCDINTPND (*(volatile unsigned *)0x4d000054) //LCD Interrupt pending +#define LCDSRCPND (*(volatile unsigned *)0x4d000058) //LCD Interrupt source +#define LCDINTMSK (*(volatile unsigned *)0x4d00005c) //LCD Interrupt mask +#define LPCSEL (*(volatile unsigned *)0x4d000060) //LPC3600 Control +#define PALETTE 0x4d000400 //Palette start address + + +// NAND flash +#define NFCONF (*(volatile unsigned *)0x4e000000) //NAND Flash configuration +#define NFCMD (*(volatile unsigned *)0x4e000004) //NADD Flash command +#define NFADDR (*(volatile unsigned *)0x4e000008) //NAND Flash address +#define NFDATA (*(volatile unsigned *)0x4e00000c) //NAND Flash data +#define NFSTAT (*(volatile unsigned *)0x4e000010) //NAND Flash operation status +#define NFECC (*(volatile unsigned *)0x4e000014) //NAND Flash ECC +#define NFECC0 (*(volatile unsigned *)0x4e000014) +#define NFECC1 (*(volatile unsigned *)0x4e000015) +#define NFECC2 (*(volatile unsigned *)0x4e000016) + +// UART +#define U0BASE (*(volatile unsigned *)0x50000000) //UART 0 Line control +#define ULCON0 (*(volatile unsigned *)0x50000000) //UART 0 Line control +#define UCON0 (*(volatile unsigned *)0x50000004) //UART 0 Control +#define UFCON0 (*(volatile unsigned *)0x50000008) //UART 0 FIFO control +#define UMCON0 (*(volatile unsigned *)0x5000000c) //UART 0 Modem control +#define USTAT0 (*(volatile unsigned *)0x50000010) //UART 0 Tx/Rx status +#define URXB0 (*(volatile unsigned *)0x50000014) //UART 0 Rx error status +#define UFSTAT0 (*(volatile unsigned *)0x50000018) //UART 0 FIFO status +#define UMSTAT0 (*(volatile unsigned *)0x5000001c) //UART 0 Modem status +#define UBRD0 (*(volatile unsigned *)0x50000028) //UART 0 Baud ate divisor + +#define U1BASE (*(volatile unsigned *)0x50004000) //UART 1 Line control +#define ULCON1 (*(volatile unsigned *)0x50004000) //UART 1 Line control +#define UCON1 (*(volatile unsigned *)0x50004004) //UART 1 Control +#define UFCON1 (*(volatile unsigned *)0x50004008) //UART 1 FIFO control +#define UMCON1 (*(volatile unsigned *)0x5000400c) //UART 1 Modem control +#define USTAT1 (*(volatile unsigned *)0x50004010) //UART 1 Tx/Rx status +#define URXB1 (*(volatile unsigned *)0x50004014) //UART 1 Rx error status +#define UFSTAT1 (*(volatile unsigned *)0x50004018) //UART 1 FIFO status +#define UMSTAT1 (*(volatile unsigned *)0x5000401c) //UART 1 Modem status +#define UBRD1 (*(volatile unsigned *)0x50004028) //UART 1 Baud ate divisor + +#define U2BASE *(volatile unsigned *)0x50008000 //UART 2 Line control +#define ULCON2 (*(volatile unsigned *)0x50008000) //UART 2 Line control +#define UCON2 (*(volatile unsigned *)0x50008004) //UART 2 Control +#define UFCON2 (*(volatile unsigned *)0x50008008) //UART 2 FIFO control +#define UMCON2 (*(volatile unsigned *)0x5000800c) //UART 2 Modem control +#define USTAT2 (*(volatile unsigned *)0x50008010) //UART 2 Tx/Rx status +#define URXB2 (*(volatile unsigned *)0x50008014) //UART 2 Rx error status +#define UFSTAT2 (*(volatile unsigned *)0x50008018) //UART 2 FIFO status +#define UMSTAT2 (*(volatile unsigned *)0x5000801c) //UART 2 Modem status +#define UBRD2 (*(volatile unsigned *)0x50008028) //UART 2 Baud ate divisor + +#ifdef __BIG_ENDIAN +#define UTXH0 (*(volatile unsigned char *)0x50000023) //UART 0 Transmission Hold +#define URXH0 (*(volatile unsigned char *)0x50000027) //UART 0 Receive buffer +#define UTXH1 (*(volatile unsigned char *)0x50004023) //UART 1 Transmission Hold +#define URXH1 (*(volatile unsigned char *)0x50004027) //UART 1 Receive buffer +#define UTXH2 (*(volatile unsigned char *)0x50008023) //UART 2 Transmission Hold +#define URXH2 (*(volatile unsigned char *)0x50008027) //UART 2 Receive buffer + +#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000023)=(unsigned char)(ch) +#define RdURXH0() (*(volatile unsigned char *)0x50000027) +#define WrUTXH1(ch) (*(volatile unsigned char *)0x50004023)=(unsigned char)(ch) +#define RdURXH1() (*(volatile unsigned char *)0x50004027) +#define WrUTXH2(ch) (*(volatile unsigned char *)0x50008023)=(unsigned char)(ch) +#define RdURXH2() (*(volatile unsigned char *)0x50008027) + +#else //Little Endian +#define UTXH0 (*(volatile unsigned char *)0x50000020) //UART 0 Transmission Hold +#define URXH0 (*(volatile unsigned char *)0x50000024) //UART 0 Receive buffer +#define UTXH1 (*(volatile unsigned char *)0x50004020) //UART 1 Transmission Hold +#define URXH1 (*(volatile unsigned char *)0x50004024) //UART 1 Receive buffer +#define UTXH2 (*(volatile unsigned char *)0x50008020) //UART 2 Transmission Hold +#define URXH2 (*(volatile unsigned char *)0x50008024) //UART 2 Receive buffer + +#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch) +#define RdURXH0() (*(volatile unsigned char *)0x50000024) +#define WrUTXH1(ch) (*(volatile unsigned char *)0x50004020)=(unsigned char)(ch) +#define RdURXH1() (*(volatile unsigned char *)0x50004024) +#define WrUTXH2(ch) (*(volatile unsigned char *)0x50008020)=(unsigned char)(ch) +#define RdURXH2() (*(volatile unsigned char *)0x50008024) + +#endif + + +// PWM TIMER +#define TCFG0 (*(volatile unsigned *)0x51000000) //Timer 0 configuration +#define TCFG1 (*(volatile unsigned *)0x51000004) //Timer 1 configuration +#define TCON (*(volatile unsigned *)0x51000008) //Timer control +#define TCNTB0 (*(volatile unsigned *)0x5100000c) //Timer count buffer 0 +#define TCMPB0 (*(volatile unsigned *)0x51000010) //Timer compare buffer 0 +#define TCNTO0 (*(volatile unsigned *)0x51000014) //Timer count observation 0 +#define TCNTB1 (*(volatile unsigned *)0x51000018) //Timer count buffer 1 +#define TCMPB1 (*(volatile unsigned *)0x5100001c) //Timer compare buffer 1 +#define TCNTO1 (*(volatile unsigned *)0x51000020) //Timer count observation 1 +#define TCNTB2 (*(volatile unsigned *)0x51000024) //Timer count buffer 2 +#define TCMPB2 (*(volatile unsigned *)0x51000028) //Timer compare buffer 2 +#define TCNTO2 (*(volatile unsigned *)0x5100002c) //Timer count observation 2 +#define TCNTB3 (*(volatile unsigned *)0x51000030) //Timer count buffer 3 +#define TCMPB3 (*(volatile unsigned *)0x51000034) //Timer compare buffer 3 +#define TCNTO3 (*(volatile unsigned *)0x51000038) //Timer count observation 3 +#define TCNTB4 (*(volatile unsigned *)0x5100003c) //Timer count buffer 4 +#define TCNTO4 (*(volatile unsigned *)0x51000040) //Timer count observation 4 + +// Added for 2440 +#define FLTOUT (*(volatile unsigned *)0x560000c0) // Filter output(Read only) +#define DSC0 (*(volatile unsigned *)0x560000c4) // Strength control register 0 +#define DSC1 (*(volatile unsigned *)0x560000c8) // Strength control register 1 +#define MSLCON (*(volatile unsigned *)0x560000cc) // Memory sleep control register + + +// USB DEVICE +#ifdef __BIG_ENDIAN +#define FUNC_ADDR_REG (*(volatile unsigned char *)0x52000143) //Function address +#define PWR_REG (*(volatile unsigned char *)0x52000147) //Power management +#define EP_INT_REG (*(volatile unsigned char *)0x5200014b) //EP Interrupt pending and clear +#define USB_INT_REG (*(volatile unsigned char *)0x5200015b) //USB Interrupt pending and clear +#define EP_INT_EN_REG (*(volatile unsigned char *)0x5200015f) //Interrupt enable +#define USB_INT_EN_REG (*(volatile unsigned char *)0x5200016f) +#define FRAME_NUM1_REG (*(volatile unsigned char *)0x52000173) //Frame number lower byte +#define FRAME_NUM2_REG (*(volatile unsigned char *)0x52000177) //Frame number higher byte +#define INDEX_REG (*(volatile unsigned char *)0x5200017b) //Register index +#define MAXP_REG (*(volatile unsigned char *)0x52000183) //Endpoint max packet +#define EP0_CSR (*(volatile unsigned char *)0x52000187) //Endpoint 0 status +#define IN_CSR1_REG (*(volatile unsigned char *)0x52000187) //In endpoint control status +#define IN_CSR2_REG (*(volatile unsigned char *)0x5200018b) +#define OUT_CSR1_REG (*(volatile unsigned char *)0x52000193) //Out endpoint control status +#define OUT_CSR2_REG (*(volatile unsigned char *)0x52000197) +#define OUT_FIFO_CNT1_REG (*(volatile unsigned char *)0x5200019b) //Endpoint out write count +#define OUT_FIFO_CNT2_REG (*(volatile unsigned char *)0x5200019f) +#define EP0_FIFO (*(volatile unsigned char *)0x520001c3) //Endpoint 0 FIFO +#define EP1_FIFO (*(volatile unsigned char *)0x520001c7) //Endpoint 1 FIFO +#define EP2_FIFO (*(volatile unsigned char *)0x520001cb) //Endpoint 2 FIFO +#define EP3_FIFO (*(volatile unsigned char *)0x520001cf) //Endpoint 3 FIFO +#define EP4_FIFO (*(volatile unsigned char *)0x520001d3) //Endpoint 4 FIFO +#define EP1_DMA_CON (*(volatile unsigned char *)0x52000203) //EP1 DMA interface control +#define EP1_DMA_UNIT (*(volatile unsigned char *)0x52000207) //EP1 DMA Tx unit counter +#define EP1_DMA_FIFO (*(volatile unsigned char *)0x5200020b) //EP1 DMA Tx FIFO counter +#define EP1_DMA_TTC_L (*(volatile unsigned char *)0x5200020f) //EP1 DMA total Tx counter +#define EP1_DMA_TTC_M (*(volatile unsigned char *)0x52000213) +#define EP1_DMA_TTC_H (*(volatile unsigned char *)0x52000217) +#define EP2_DMA_CON (*(volatile unsigned char *)0x5200021b) //EP2 DMA interface control +#define EP2_DMA_UNIT (*(volatile unsigned char *)0x5200021f) //EP2 DMA Tx unit counter +#define EP2_DMA_FIFO (*(volatile unsigned char *)0x52000223) //EP2 DMA Tx FIFO counter +#define EP2_DMA_TTC_L (*(volatile unsigned char *)0x52000227) //EP2 DMA total Tx counter +#define EP2_DMA_TTC_M (*(volatile unsigned char *)0x5200022b) +#define EP2_DMA_TTC_H (*(volatile unsigned char *)0x5200022f) +#define EP3_DMA_CON (*(volatile unsigned char *)0x52000243) //EP3 DMA interface control +#define EP3_DMA_UNIT (*(volatile unsigned char *)0x52000247) //EP3 DMA Tx unit counter +#define EP3_DMA_FIFO (*(volatile unsigned char *)0x5200024b) //EP3 DMA Tx FIFO counter +#define EP3_DMA_TTC_L (*(volatile unsigned char *)0x5200024f) //EP3 DMA total Tx counter +#define EP3_DMA_TTC_M (*(volatile unsigned char *)0x52000253) +#define EP3_DMA_TTC_H (*(volatile unsigned char *)0x52000257) +#define EP4_DMA_CON (*(volatile unsigned char *)0x5200025b) //EP4 DMA interface control +#define EP4_DMA_UNIT (*(volatile unsigned char *)0x5200025f) //EP4 DMA Tx unit counter +#define EP4_DMA_FIFO (*(volatile unsigned char *)0x52000263) //EP4 DMA Tx FIFO counter +#define EP4_DMA_TTC_L (*(volatile unsigned char *)0x52000267) //EP4 DMA total Tx counter +#define EP4_DMA_TTC_M (*(volatile unsigned char *)0x5200026b) +#define EP4_DMA_TTC_H (*(volatile unsigned char *)0x5200026f) + +#else // Little Endian +#define FUNC_ADDR_REG (*(volatile unsigned char *)0x52000140) //Function address +#define PWR_REG (*(volatile unsigned char *)0x52000144) //Power management +#define EP_INT_REG (*(volatile unsigned char *)0x52000148) //EP Interrupt pending and clear +#define USB_INT_REG (*(volatile unsigned char *)0x52000158) //USB Interrupt pending and clear +#define EP_INT_EN_REG (*(volatile unsigned char *)0x5200015c) //Interrupt enable +#define USB_INT_EN_REG (*(volatile unsigned char *)0x5200016c) +#define FRAME_NUM1_REG (*(volatile unsigned char *)0x52000170) //Frame number lower byte +#define FRAME_NUM2_REG (*(volatile unsigned char *)0x52000174) //Frame number higher byte +#define INDEX_REG (*(volatile unsigned char *)0x52000178) //Register index +#define MAXP_REG (*(volatile unsigned char *)0x52000180) //Endpoint max packet +#define EP0_CSR (*(volatile unsigned char *)0x52000184) //Endpoint 0 status +#define IN_CSR1_REG (*(volatile unsigned char *)0x52000184) //In endpoint control status +#define IN_CSR2_REG (*(volatile unsigned char *)0x52000188) +#define OUT_CSR1_REG (*(volatile unsigned char *)0x52000190) //Out endpoint control status +#define OUT_CSR2_REG (*(volatile unsigned char *)0x52000194) +#define OUT_FIFO_CNT1_REG (*(volatile unsigned char *)0x52000198) //Endpoint out write count +#define OUT_FIFO_CNT2_REG (*(volatile unsigned char *)0x5200019c) +#define EP0_FIFO (*(volatile unsigned char *)0x520001c0) //Endpoint 0 FIFO +#define EP1_FIFO (*(volatile unsigned char *)0x520001c4) //Endpoint 1 FIFO +#define EP2_FIFO (*(volatile unsigned char *)0x520001c8) //Endpoint 2 FIFO +#define EP3_FIFO (*(volatile unsigned char *)0x520001cc) //Endpoint 3 FIFO +#define EP4_FIFO (*(volatile unsigned char *)0x520001d0) //Endpoint 4 FIFO +#define EP1_DMA_CON (*(volatile unsigned char *)0x52000200) //EP1 DMA interface control +#define EP1_DMA_UNIT (*(volatile unsigned char *)0x52000204) //EP1 DMA Tx unit counter +#define EP1_DMA_FIFO (*(volatile unsigned char *)0x52000208) //EP1 DMA Tx FIFO counter +#define EP1_DMA_TTC_L (*(volatile unsigned char *)0x5200020c) //EP1 DMA total Tx counter +#define EP1_DMA_TTC_M (*(volatile unsigned char *)0x52000210) +#define EP1_DMA_TTC_H (*(volatile unsigned char *)0x52000214) +#define EP2_DMA_CON (*(volatile unsigned char *)0x52000218) //EP2 DMA interface control +#define EP2_DMA_UNIT (*(volatile unsigned char *)0x5200021c) //EP2 DMA Tx unit counter +#define EP2_DMA_FIFO (*(volatile unsigned char *)0x52000220) //EP2 DMA Tx FIFO counter +#define EP2_DMA_TTC_L (*(volatile unsigned char *)0x52000224) //EP2 DMA total Tx counter +#define EP2_DMA_TTC_M (*(volatile unsigned char *)0x52000228) +#define EP2_DMA_TTC_H (*(volatile unsigned char *)0x5200022c) +#define EP3_DMA_CON (*(volatile unsigned char *)0x52000240) //EP3 DMA interface control +#define EP3_DMA_UNIT (*(volatile unsigned char *)0x52000244) //EP3 DMA Tx unit counter +#define EP3_DMA_FIFO (*(volatile unsigned char *)0x52000248) //EP3 DMA Tx FIFO counter +#define EP3_DMA_TTC_L (*(volatile unsigned char *)0x5200024c) //EP3 DMA total Tx counter +#define EP3_DMA_TTC_M (*(volatile unsigned char *)0x52000250) +#define EP3_DMA_TTC_H (*(volatile unsigned char *)0x52000254) +#define EP4_DMA_CON (*(volatile unsigned char *)0x52000258) //EP4 DMA interface control +#define EP4_DMA_UNIT (*(volatile unsigned char *)0x5200025c) //EP4 DMA Tx unit counter +#define EP4_DMA_FIFO (*(volatile unsigned char *)0x52000260) //EP4 DMA Tx FIFO counter +#define EP4_DMA_TTC_L (*(volatile unsigned char *)0x52000264) //EP4 DMA total Tx counter +#define EP4_DMA_TTC_M (*(volatile unsigned char *)0x52000268) +#define EP4_DMA_TTC_H (*(volatile unsigned char *)0x5200026c) +#endif // __BIG_ENDIAN + + +// WATCH DOG TIMER +#define WTCON (*(volatile unsigned *)0x53000000) //Watch-dog timer mode +#define WTDAT (*(volatile unsigned *)0x53000004) //Watch-dog timer data +#define WTCNT (*(volatile unsigned *)0x53000008) //Eatch-dog timer count + + +// IIC +#define IICCON (*(volatile unsigned *)0x54000000) //IIC control +#define IICSTAT (*(volatile unsigned *)0x54000004) //IIC status +#define IICADD (*(volatile unsigned *)0x54000008) //IIC address +#define IICDS (*(volatile unsigned *)0x5400000c) //IIC data shift + + +// IIS +#define IISCON (*(volatile unsigned *)0x55000000) //IIS Control +#define IISMOD (*(volatile unsigned *)0x55000004) //IIS Mode +#define IISPSR (*(volatile unsigned *)0x55000008) //IIS Prescaler +#define IISFCON (*(volatile unsigned *)0x5500000c) //IIS FIFO control + +#ifdef __BIG_ENDIAN +#define IISFIFO ((volatile unsigned short *)0x55000012) //IIS FIFO entry + +#else //Little Endian +#define IISFIFO ((volatile unsigned short *)0x55000010) //IIS FIFO entry + +#endif + + +// I/O PORT +#define GPACON (*(volatile unsigned *)0x56000000) //Port A control +#define GPADAT (*(volatile unsigned *)0x56000004) //Port A data + +#define GPBCON (*(volatile unsigned *)0x56000010) //Port B control +#define GPBDAT (*(volatile unsigned *)0x56000014) //Port B data +#define GPBUP (*(volatile unsigned *)0x56000018) //Pull-up control B + +#define GPCCON (*(volatile unsigned *)0x56000020) //Port C control +#define GPCDAT (*(volatile unsigned *)0x56000024) //Port C data +#define GPCUP (*(volatile unsigned *)0x56000028) //Pull-up control C + +#define GPDCON (*(volatile unsigned *)0x56000030) //Port D control +#define GPDDAT (*(volatile unsigned *)0x56000034) //Port D data +#define GPDUP (*(volatile unsigned *)0x56000038) //Pull-up control D + +#define GPECON (*(volatile unsigned *)0x56000040) //Port E control +#define GPEDAT (*(volatile unsigned *)0x56000044) //Port E data +#define GPEUP (*(volatile unsigned *)0x56000048) //Pull-up control E + +#define GPFCON (*(volatile unsigned *)0x56000050) //Port F control +#define GPFDAT (*(volatile unsigned *)0x56000054) //Port F data +#define GPFUP (*(volatile unsigned *)0x56000058) //Pull-up control F + +#define GPGCON (*(volatile unsigned *)0x56000060) //Port G control +#define GPGDAT (*(volatile unsigned *)0x56000064) //Port G data +#define GPGUP (*(volatile unsigned *)0x56000068) //Pull-up control G + +#define GPHCON (*(volatile unsigned *)0x56000070) //Port H control +#define GPHDAT (*(volatile unsigned *)0x56000074) //Port H data +#define GPHUP (*(volatile unsigned *)0x56000078) //Pull-up control H + +#define GPJCON (*(volatile unsigned *)0x560000d0) //Port J control +#define GPJDAT (*(volatile unsigned *)0x560000d4) //Port J data +#define GPJUP (*(volatile unsigned *)0x560000d8) //Pull-up control J + +#define MISCCR (*(volatile unsigned *)0x56000080) //Miscellaneous control +#define DCLKCON (*(volatile unsigned *)0x56000084) //DCLK0/1 control +#define EXTINT0 (*(volatile unsigned *)0x56000088) //External interrupt control egister 0 +#define EXTINT1 (*(volatile unsigned *)0x5600008c) //External interrupt control egister 1 +#define EXTINT2 (*(volatile unsigned *)0x56000090) //External interrupt control egister 2 +#define EINTFLT0 (*(volatile unsigned *)0x56000094) //Reserved +#define EINTFLT1 (*(volatile unsigned *)0x56000098) //Reserved +#define EINTFLT2 (*(volatile unsigned *)0x5600009c) //External interrupt filter control egister 2 +#define EINTFLT3 (*(volatile unsigned *)0x560000a0) //External interrupt filter control egister 3 +#define EINTMASK (*(volatile unsigned *)0x560000a4) //External interrupt mask +#define EINTPEND (*(volatile unsigned *)0x560000a8) //External interrupt pending +#define GSTATUS0 (*(volatile unsigned *)0x560000ac) //External pin status +#define GSTATUS1 (*(volatile unsigned *)0x560000b0) //Chip ID(0x32410000) +#define GSTATUS2 (*(volatile unsigned *)0x560000b4) //Reset type +#define GSTATUS3 (*(volatile unsigned *)0x560000b8) //Saved data0(32-bit) before entering POWER_OFF mode +#define GSTATUS4 (*(volatile unsigned *)0x560000bc) //Saved data0(32-bit) before entering POWER_OFF mode + + +// RTC +#ifdef __BIG_ENDIAN +#define RTCCON (*(volatile unsigned char *)0x57000043) //RTC control +#define TICNT (*(volatile unsigned char *)0x57000047) //Tick time count +#define RTCALM (*(volatile unsigned char *)0x57000053) //RTC alarm control +#define ALMSEC (*(volatile unsigned char *)0x57000057) //Alarm second +#define ALMMIN (*(volatile unsigned char *)0x5700005b) //Alarm minute +#define ALMHOUR (*(volatile unsigned char *)0x5700005f) //Alarm Hour +#define ALMDATE (*(volatile unsigned char *)0x57000063) //Alarm day <-- May 06, 2002 SOP +#define ALMMON (*(volatile unsigned char *)0x57000067) //Alarm month +#define ALMYEAR (*(volatile unsigned char *)0x5700006b) //Alarm year +#define RTCRST (*(volatile unsigned char *)0x5700006f) //RTC ound eset +#define BCDSEC (*(volatile unsigned char *)0x57000073) //BCD second +#define BCDMIN (*(volatile unsigned char *)0x57000077) //BCD minute +#define BCDHOUR (*(volatile unsigned char *)0x5700007b) //BCD hour +#define BCDDATE (*(volatile unsigned char *)0x5700007f) //BCD day <-- May 06, 2002 SOP +#define BCDDAY (*(volatile unsigned char *)0x57000083) //BCD date <-- May 06, 2002 SOP +#define BCDMON (*(volatile unsigned char *)0x57000087) //BCD month +#define BCDYEAR (*(volatile unsigned char *)0x5700008b) //BCD year + +#else //Little Endian +#define RTCCON (*(volatile unsigned char *)0x57000040) //RTC control +#define TICNT (*(volatile unsigned char *)0x57000044) //Tick time count +#define RTCALM (*(volatile unsigned char *)0x57000050) //RTC alarm control +#define ALMSEC (*(volatile unsigned char *)0x57000054) //Alarm second +#define ALMMIN (*(volatile unsigned char *)0x57000058) //Alarm minute +#define ALMHOUR (*(volatile unsigned char *)0x5700005c) //Alarm Hour +#define ALMDATE (*(volatile unsigned char *)0x57000060) //Alarm day <-- May 06, 2002 SOP +#define ALMMON (*(volatile unsigned char *)0x57000064) //Alarm month +#define ALMYEAR (*(volatile unsigned char *)0x57000068) //Alarm year +#define RTCRST (*(volatile unsigned char *)0x5700006c) //RTC ound eset +#define BCDSEC (*(volatile unsigned char *)0x57000070) //BCD second +#define BCDMIN (*(volatile unsigned char *)0x57000074) //BCD minute +#define BCDHOUR (*(volatile unsigned char *)0x57000078) //BCD hour +#define BCDDATE (*(volatile unsigned char *)0x5700007c) //BCD day <-- May 06, 2002 SOP +#define BCDDAY (*(volatile unsigned char *)0x57000080) //BCD date <-- May 06, 2002 SOP +#define BCDMON (*(volatile unsigned char *)0x57000084) //BCD month +#define BCDYEAR (*(volatile unsigned char *)0x57000088) //BCD year +#endif //RTC + + +// ADC +#define ADCCON (*(volatile unsigned *)0x58000000) //ADC control +#define ADCTSC (*(volatile unsigned *)0x58000004) //ADC touch screen control +#define ADCDLY (*(volatile unsigned *)0x58000008) //ADC start or Interval Delay +#define ADCDAT0 (*(volatile unsigned *)0x5800000c) //ADC conversion data 0 +#define ADCDAT1 (*(volatile unsigned *)0x58000010) //ADC conversion data 1 + +// SPI +#define SPCON0 (*(volatile unsigned *)0x59000000) //SPI0 control +#define SPSTA0 (*(volatile unsigned *)0x59000004) //SPI0 status +#define SPPIN0 (*(volatile unsigned *)0x59000008) //SPI0 pin control +#define SPPRE0 (*(volatile unsigned *)0x5900000c) //SPI0 baud ate prescaler +#define SPTDAT0 (*(volatile unsigned *)0x59000010) //SPI0 Tx data +#define SPRDAT0 (*(volatile unsigned *)0x59000014) //SPI0 Rx data + +#define SPCON1 (*(volatile unsigned *)0x59000020) //SPI1 control +#define SPSTA1 (*(volatile unsigned *)0x59000024) //SPI1 status +#define SPPIN1 (*(volatile unsigned *)0x59000028) //SPI1 pin control +#define SPPRE1 (*(volatile unsigned *)0x5900002c) //SPI1 baud ate prescaler +#define SPTDAT1 (*(volatile unsigned *)0x59000030) //SPI1 Tx data +#define SPRDAT1 (*(volatile unsigned *)0x59000034) //SPI1 Rx data + + +// SD Interface +#define SDICON (*(volatile unsigned *)0x5a000000) //SDI control +#define SDIPRE (*(volatile unsigned *)0x5a000004) //SDI baud ate prescaler +#define SDICARG (*(volatile unsigned *)0x5a000008) //SDI command argument +#define SDICCON (*(volatile unsigned *)0x5a00000c) //SDI command control +#define SDICSTA (*(volatile unsigned *)0x5a000010) //SDI command status +#define SDIRSP0 (*(volatile unsigned *)0x5a000014) //SDI esponse 0 +#define SDIRSP1 (*(volatile unsigned *)0x5a000018) //SDI esponse 1 +#define SDIRSP2 (*(volatile unsigned *)0x5a00001c) //SDI esponse 2 +#define SDIRSP3 (*(volatile unsigned *)0x5a000020) //SDI esponse 3 +#define SDIDTIMER (*(volatile unsigned *)0x5a000024) //SDI data/busy timer +#define SDIBSIZE (*(volatile unsigned *)0x5a000028) //SDI block size +#define SDIDCON (*(volatile unsigned *)0x5a00002c) //SDI data control +#define SDIDCNT (*(volatile unsigned *)0x5a000030) //SDI data emain counter +#define SDIDSTA (*(volatile unsigned *)0x5a000034) //SDI data status +#define SDIFSTA (*(volatile unsigned *)0x5a000038) //SDI FIFO status +#define SDIIMSK (*(volatile unsigned *)0x5a000040) //SDI interrupt mask + +#ifdef __BIG_ENDIAN /* edited for 2440A */ +#define SDIDAT (*(volatile unsigned *)0x5a00004c) +#else // Little Endian +#define SDIDAT (*(volatile unsigned *)0x5a000040) +#endif //SD Interface + +// PENDING BIT +#define INTEINT0 (0) +#define INTEINT1 (1) +#define INTEINT2 (2) +#define INTEINT3 (3) +#define INTEINT4_7 (4) +#define INTEINT8_23 (5) +#define INTNOTUSED6 (6) +#define INTBAT_FLT (7) +#define INTTICK (8) +#define INTWDT (9) +#define INTTIMER0 (10) +#define INTTIMER1 (11) +#define INTTIMER2 (12) +#define INTTIMER3 (13) +#define INTTIMER4 (14) +#define INTUART2 (15) +#define INTLCD (16) +#define INTDMA0 (17) +#define INTDMA1 (18) +#define INTDMA2 (19) +#define INTDMA3 (20) +#define INTSDI (21) +#define INTSPI0 (22) +#define INTUART1 (23) +//#define INTNOTUSED24 (24) +#define INTNIC (24) +#define INTUSBD (25) +#define INTUSBH (26) +#define INTIIC (27) +#define INTUART0 (28) +#define INTSPI1 (29) +#define INTRTC (30) +#define INTADC (31) +#define BIT_ALLMSK (0xffffffff) + +#define BIT_SUB_ALLMSK (0x7ff) +#define INTSUB_ADC (10) +#define INTSUB_TC (9) +#define INTSUB_ERR2 (8) +#define INTSUB_TXD2 (7) +#define INTSUB_RXD2 (6) +#define INTSUB_ERR1 (5) +#define INTSUB_TXD1 (4) +#define INTSUB_RXD1 (3) +#define INTSUB_ERR0 (2) +#define INTSUB_TXD0 (1) +#define INTSUB_RXD0 (0) + +#define BIT_SUB_ADC (0x1<<10) +#define BIT_SUB_TC (0x1<<9) +#define BIT_SUB_ERR2 (0x1<<8) +#define BIT_SUB_TXD2 (0x1<<7) +#define BIT_SUB_RXD2 (0x1<<6) +#define BIT_SUB_ERR1 (0x1<<5) +#define BIT_SUB_TXD1 (0x1<<4) +#define BIT_SUB_RXD1 (0x1<<3) +#define BIT_SUB_ERR0 (0x1<<2) +#define BIT_SUB_TXD0 (0x1<<1) +#define BIT_SUB_RXD0 (0x1<<0) + +#define ClearPending(bit) {SRCPND = bit;INTPND = bit;INTPND;} +//Wait until INTPND is changed for the case that the ISR is very short. + +#define INTGLOBAL 32 + +/*****************************/ +/* CPU Mode */ +/*****************************/ +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define ABORTMODE 0x17 +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +struct rt_hw_register +{ + rt_uint32_t r0; + rt_uint32_t r1; + rt_uint32_t r2; + rt_uint32_t r3; + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t fp; + rt_uint32_t ip; + rt_uint32_t sp; + rt_uint32_t lr; + rt_uint32_t pc; + rt_uint32_t cpsr; + rt_uint32_t ORIG_r0; +}; + +#ifdef __cplusplus +} +#endif + +/*@}*/ + +#endif diff --git a/rt-thread/libcpu/arm/s3c24x0/serial.c b/rt-thread/libcpu/arm/s3c24x0/serial.c new file mode 100644 index 0000000..ddf303d --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/serial.c @@ -0,0 +1,295 @@ +/* + * File : serial.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + * 2009-04-20 yi.qiu modified according bernard's stm32 version + */ + +#include + +#include "serial.h" + +/** + * @addtogroup S3C24X0 + */ +/*@{*/ + +/* RT-Thread Device Interface */ +/** + * This function initializes serial + */ +static rt_err_t rt_serial_init(rt_device_t dev) +{ + struct serial_device* uart = (struct serial_device*) dev->user_data; + + if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) + { + + if (dev->flag & RT_DEVICE_FLAG_INT_RX) + { + rt_memset(uart->int_rx->rx_buffer, 0, + sizeof(uart->int_rx->rx_buffer)); + uart->int_rx->read_index = uart->int_rx->save_index = 0; + } + + if (dev->flag & RT_DEVICE_FLAG_INT_TX) + { + rt_memset(uart->int_tx->tx_buffer, 0, + sizeof(uart->int_tx->tx_buffer)); + uart->int_tx->write_index = uart->int_tx->save_index = 0; + } + + dev->flag |= RT_DEVICE_FLAG_ACTIVATED; + } + + return RT_EOK; +} + +/* save a char to serial buffer */ +static void rt_serial_savechar(struct serial_device* uart, char ch) +{ + rt_base_t level; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + uart->int_rx->rx_buffer[uart->int_rx->save_index] = ch; + uart->int_rx->save_index ++; + if (uart->int_rx->save_index >= UART_RX_BUFFER_SIZE) + uart->int_rx->save_index = 0; + + /* if the next position is read index, discard this 'read char' */ + if (uart->int_rx->save_index == uart->int_rx->read_index) + { + uart->int_rx->read_index ++; + if (uart->int_rx->read_index >= UART_RX_BUFFER_SIZE) + uart->int_rx->read_index = 0; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); +} + +static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag) +{ + RT_ASSERT(dev != RT_NULL); + + return RT_EOK; +} + +static rt_err_t rt_serial_close(rt_device_t dev) +{ + RT_ASSERT(dev != RT_NULL); + + return RT_EOK; +} + +static rt_size_t rt_serial_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + rt_uint8_t* ptr; + rt_err_t err_code; + struct serial_device* uart; + + ptr = buffer; + err_code = RT_EOK; + uart = (struct serial_device*)dev->user_data; + + if (ptr == RT_NULL) + { + err_code = -RT_ENOMEM; + rt_set_errno(err_code); + return -RT_ENOMEM; + } + if (dev->flag & RT_DEVICE_FLAG_INT_RX) + { + rt_base_t level; + + /* interrupt mode Rx */ + while (size) + { + if (uart->int_rx->read_index != uart->int_rx->save_index) + { + *ptr++ = uart->int_rx->rx_buffer[uart->int_rx->read_index]; + size --; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + uart->int_rx->read_index ++; + if (uart->int_rx->read_index >= UART_RX_BUFFER_SIZE) + uart->int_rx->read_index = 0; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + } + else + { + /* set error code */ + err_code = -RT_EEMPTY; + break; + } + } + } + else + { + /* polling mode */ + while ((rt_uint32_t)ptr - (rt_uint32_t)buffer < size) + { + while (uart->uart_device->ustat & USTAT_RCV_READY) + { + *ptr = uart->uart_device->urxh & 0xff; + ptr ++; + } + } + } + + /* set error code */ + rt_set_errno(err_code); + return (rt_uint32_t)ptr - (rt_uint32_t)buffer; +} + +static rt_size_t rt_serial_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + rt_uint8_t* ptr; + rt_err_t err_code; + struct serial_device* uart; + + err_code = RT_EOK; + ptr = (rt_uint8_t*)buffer; + uart = (struct serial_device*)dev->user_data; + + if (ptr == RT_NULL) + { + err_code = -RT_ENOMEM; + rt_set_errno(err_code); + return -RT_ENOMEM; + } + if (dev->flag & RT_DEVICE_FLAG_INT_TX) + { + /* interrupt mode Tx */ + while (uart->int_tx->save_index != uart->int_tx->write_index) + { + /* save on tx buffer */ + uart->int_tx->tx_buffer[uart->int_tx->save_index] = *ptr++; + + -- size; + + /* move to next position */ + uart->int_tx->save_index ++; + + /* wrap save index */ + if (uart->int_tx->save_index >= UART_TX_BUFFER_SIZE) + uart->int_tx->save_index = 0; + } + + /* set error code */ + if (size > 0) + err_code = -RT_EFULL; + } + else + { + /* polling mode */ + while (size) + { + /* + * to be polite with serial console add a line feed + * to the carriage return character + */ + if (*ptr == '\n' && (dev->flag & RT_DEVICE_FLAG_STREAM)) + { + while (!(uart->uart_device->ustat & USTAT_TXB_EMPTY)); + uart->uart_device->utxh = '\r'; + } + + while (!(uart->uart_device->ustat & USTAT_TXB_EMPTY)); + uart->uart_device->utxh = (*ptr & 0xFF); + + ++ptr; + --size; + } + } + + /* set error code */ + rt_set_errno(err_code); + return (rt_uint32_t)ptr - (rt_uint32_t)buffer; +} + +static rt_err_t rt_serial_control(rt_device_t dev, int cmd, void *args) +{ + RT_ASSERT(dev != RT_NULL); + + switch (cmd) + { + case RT_DEVICE_CTRL_SUSPEND: + /* suspend device */ + dev->flag |= RT_DEVICE_FLAG_SUSPENDED; + break; + + case RT_DEVICE_CTRL_RESUME: + /* resume device */ + dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED; + break; + } + + return RT_EOK; +} + +/* + * serial register + */ +rt_err_t rt_hw_serial_register(rt_device_t device, const char* name, rt_uint32_t flag, struct serial_device *serial) +{ + RT_ASSERT(device != RT_NULL); + + device->type = RT_Device_Class_Char; + device->rx_indicate = RT_NULL; + device->tx_complete = RT_NULL; + device->init = rt_serial_init; + device->open = rt_serial_open; + device->close = rt_serial_close; + device->read = rt_serial_read; + device->write = rt_serial_write; + device->control = rt_serial_control; + device->user_data = serial; + + /* register a character device */ + return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag); +} + +/* ISR for serial interrupt */ +void rt_hw_serial_isr(rt_device_t device) +{ + struct serial_device* uart = (struct serial_device*) device->user_data; + + /* interrupt mode receive */ + RT_ASSERT(device->flag & RT_DEVICE_FLAG_INT_RX); + + /* save on rx buffer */ + while (uart->uart_device->ustat & USTAT_RCV_READY) + { + rt_serial_savechar(uart, uart->uart_device->urxh & 0xff); + } + + /* invoke callback */ + if (device->rx_indicate != RT_NULL) + { + rt_size_t rx_length; + + /* get rx length */ + rx_length = uart->int_rx->read_index > uart->int_rx->save_index ? + UART_RX_BUFFER_SIZE - uart->int_rx->read_index + uart->int_rx->save_index : + uart->int_rx->save_index - uart->int_rx->read_index; + + device->rx_indicate(device, rx_length); + } +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/s3c24x0/serial.h b/rt-thread/libcpu/arm/s3c24x0/serial.h new file mode 100644 index 0000000..e3deb5b --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/serial.h @@ -0,0 +1,58 @@ +#ifndef __RT_HW_SERIAL_H__ +#define __RT_HW_SERIAL_H__ + +#include +#include + +#include "s3c24x0.h" + +#define USTAT_RCV_READY 0x01 /* receive data ready */ +#define USTAT_TXB_EMPTY 0x02 /* tx buffer empty */ +#define BPS 115200 /* serial baudrate */ + +#define UART_RX_BUFFER_SIZE 64 +#define UART_TX_BUFFER_SIZE 64 + +struct serial_int_rx +{ + rt_uint8_t rx_buffer[UART_RX_BUFFER_SIZE]; + rt_uint32_t read_index, save_index; +}; + +struct serial_int_tx +{ + rt_uint8_t tx_buffer[UART_TX_BUFFER_SIZE]; + rt_uint32_t write_index, save_index; +}; + +typedef struct uartport +{ + volatile rt_uint32_t ulcon; + volatile rt_uint32_t ucon; + volatile rt_uint32_t ufcon; + volatile rt_uint32_t umcon; + volatile rt_uint32_t ustat; + volatile rt_uint32_t urxb; + volatile rt_uint32_t ufstat; + volatile rt_uint32_t umstat; + volatile rt_uint32_t utxh; + volatile rt_uint32_t urxh; + volatile rt_uint32_t ubrd; +}uartport; + +struct serial_device +{ + uartport* uart_device; + + /* rx structure */ + struct serial_int_rx* int_rx; + + /* tx structure */ + struct serial_int_tx* int_tx; +}; + +rt_err_t rt_hw_serial_register(rt_device_t device, const char* name, rt_uint32_t flag, struct serial_device *serial); + +void rt_hw_serial_isr(rt_device_t device); + +#endif diff --git a/rt-thread/libcpu/arm/s3c24x0/stack.c b/rt-thread/libcpu/arm/s3c24x0/stack.c new file mode 100644 index 0000000..315091d --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/stack.c @@ -0,0 +1,63 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard the first version + */ +#include +#include "s3c24x0.h" + +/** + * @addtogroup S3C24X0 + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + *(--stk) = SVCMODE; /* cpsr */ + *(--stk) = SVCMODE; /* spsr */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/s3c24x0/start_gcc.S b/rt-thread/libcpu/arm/s3c24x0/start_gcc.S new file mode 100644 index 0000000..142d66e --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/start_gcc.S @@ -0,0 +1,390 @@ +/* + * File : start.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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:/*openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + * 2006-10-05 Alsor.Z for s3c2440 initialize + * 2008-01-29 Yi.Qiu for QEMU emulator + */ + +#define CONFIG_STACKSIZE 512 +#define S_FRAME_SIZE 72 + +#define S_OLD_R0 68 +#define S_PSR 64 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 + +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 + +.equ USERMODE, 0x10 +.equ FIQMODE, 0x11 +.equ IRQMODE, 0x12 +.equ SVCMODE, 0x13 +.equ ABORTMODE, 0x17 +.equ UNDEFMODE, 0x1b +.equ MODEMASK, 0x1f +.equ NOINT, 0xc0 + +.equ RAM_BASE, 0x00000000 /*Start address of RAM */ +.equ ROM_BASE, 0x30000000 /*Start address of Flash */ + +.equ MPLLCON, 0x4c000004 /*Mpll control register */ +.equ M_MDIV, 0x20 +.equ M_PDIV, 0x4 +.equ M_SDIV, 0x2 + +.equ INTMSK, 0x4a000008 +.equ INTSUBMSK, 0x4a00001c +.equ WTCON, 0x53000000 +.equ LOCKTIME, 0x4c000000 +.equ CLKDIVN, 0x4c000014 /*Clock divider control */ +.equ GPHCON, 0x56000070 /*Port H control */ +.equ GPHUP, 0x56000078 /*Pull-up control H */ +.equ BWSCON, 0x48000000 /*Bus width & wait status */ +.equ BANKCON0, 0x48000004 /*Boot ROM control */ +.equ BANKCON1, 0x48000008 /*BANK1 control */ +.equ BANKCON2, 0x4800000c /*BANK2 cControl */ +.equ BANKCON3, 0x48000010 /*BANK3 control */ +.equ BANKCON4, 0x48000014 /*BANK4 control */ +.equ BANKCON5, 0x48000018 /*BANK5 control */ +.equ BANKCON6, 0x4800001c /*BANK6 control */ +.equ BANKCON7, 0x48000020 /*BANK7 control */ +.equ REFRESH, 0x48000024 /*DRAM/SDRAM efresh */ +.equ BANKSIZE, 0x48000028 /*Flexible Bank Size */ +.equ MRSRB6, 0x4800002c /*Mode egister set for SDRAM*/ +.equ MRSRB7, 0x48000030 /*Mode egister set for SDRAM*/ + +/* + ************************************************************************* + * + * Jump vector table + * + ************************************************************************* + */ + +.section .init, "ax" +.code 32 + +.globl _start +_start: + b reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + ldr pc, _vector_resv + ldr pc, _vector_irq + ldr pc, _vector_fiq + +_vector_undef: .word vector_undef +_vector_swi: .word vector_swi +_vector_pabt: .word vector_pabt +_vector_dabt: .word vector_dabt +_vector_resv: .word vector_resv +_vector_irq: .word vector_irq +_vector_fiq: .word vector_fiq + +.balignl 16,0xdeadbeef + +/* + ************************************************************************* + * + * Startup Code (reset vector) + * relocate armboot to ram + * setup stack + * jump to second stage + * + ************************************************************************* + */ + +_TEXT_BASE: + .word TEXT_BASE + +/* + * rtthread kernel start and end + * which are defined in linker script + */ +.globl _rtthread_start +_rtthread_start: + .word _start + +.globl _rtthread_end +_rtthread_end: + .word _end + +/* + * rtthread bss start and end which are defined in linker script + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word __bss_end + +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: + .word _irq_stack_start + 1024 + +.globl FIQ_STACK_START +FIQ_STACK_START: + .word _fiq_stack_start + 1024 + +.globl UNDEFINED_STACK_START +UNDEFINED_STACK_START: + .word _undefined_stack_start + CONFIG_STACKSIZE + +.globl ABORT_STACK_START +ABORT_STACK_START: + .word _abort_stack_start + CONFIG_STACKSIZE + +.globl _STACK_START +_STACK_START: + .word _svc_stack_start + 4096 + +/* ----------------------------------entry------------------------------*/ +reset: + + /* set the cpu to SVC32 mode */ + mrs r0,cpsr + bic r0,r0,#MODEMASK + orr r0,r0,#SVCMODE + msr cpsr,r0 + + /* watch dog disable */ + ldr r0,=WTCON + ldr r1,=0x0 + str r1,[r0] + + /* mask all IRQs by clearing all bits in the INTMRs */ + ldr r1, =INTMSK + ldr r0, =0xffffffff + str r0, [r1] + ldr r1, =INTSUBMSK + ldr r0, =0x7fff /*all sub interrupt disable */ + str r0, [r1] + + /* set interrupt vector */ + ldr r0, _load_address + mov r1, #0x0 /* target address */ + add r2, r0, #0x20 /* size, 32bytes */ + +copy_loop: + ldmia r0!, {r3-r10} /* copy from source address [r0] */ + stmia r1!, {r3-r10} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop + + /* setup stack */ + bl stack_setup + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop + +ctor_end: + + /* start RT-Thread Kernel */ + ldr pc, _rtthread_startup + +_rtthread_startup: + .word rtthread_startup +#if defined (__FLASH_BUILD__) +_load_address: + .word ROM_BASE + _TEXT_BASE +#else +_load_address: + .word RAM_BASE + _TEXT_BASE +#endif + +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ + +/* exception handlers */ + .align 5 +vector_undef: + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} /* Calling r0-r12 */ + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ /* Calling SP, LR */ + str lr, [r8, #0] /* Save calling PC */ + mrs r6, spsr + str r6, [r8, #4] /* Save CPSR */ + str r0, [r8, #8] /* Save OLD_R0 */ + mov r0, sp + + bl rt_hw_trap_udef + + .align 5 +vector_swi: + bl rt_hw_trap_swi + + .align 5 +vector_pabt: + bl rt_hw_trap_pabt + + .align 5 +vector_dabt: + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} /* Calling r0-r12 */ + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ /* Calling SP, LR */ + str lr, [r8, #0] /* Save calling PC */ + mrs r6, spsr + str r6, [r8, #4] /* Save CPSR */ + str r0, [r8, #8] /* Save OLD_R0 */ + mov r0, sp + + bl rt_hw_trap_dabt + + .align 5 +vector_resv: + bl rt_hw_trap_resv + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +vector_irq: + stmfd sp!, {r0-r12,lr} + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + + /* if rt_thread_switch_interrupt_flag set, jump to _interrupt_thread_switch and don't return */ + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq _interrupt_thread_switch + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + + .align 5 +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc,lr,#4 + +_interrupt_thread_switch: + mov r1, #0 /* clear rt_thread_switch_interrupt_flag*/ + str r1, [r0] + + ldmfd sp!, {r0-r12,lr} /* reload saved registers */ + stmfd sp!, {r0-r3} /* save r0-r3 */ + mov r1, sp + add sp, sp, #16 /* restore sp */ + sub r2, lr, #4 /* save old task's pc to r2 */ + + mrs r3, spsr /* disable interrupt */ + orr r0, r3, #NOINT + msr spsr_c, r0 + + ldr r0, =.+8 /* switch to interrupted task's stack*/ + movs pc, r0 + + stmfd sp!, {r2} /* push old task's pc */ + stmfd sp!, {r4-r12,lr} /* push old task's lr,r12-r4 */ + mov r4, r1 /* Special optimised code below */ + mov r5, r3 + ldmfd r4!, {r0-r3} + stmfd sp!, {r0-r3} /* push old task's r3-r0 */ + stmfd sp!, {r5} /* push old task's psr */ + mrs r4, spsr + stmfd sp!, {r4} /* push old task's spsr */ + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] /* store sp in preempted tasks's TCB*/ + + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] /* get new task's stack pointer */ + + ldmfd sp!, {r4} /* pop new task's spsr */ + msr SPSR_cxsf, r4 + ldmfd sp!, {r4} /* pop new task's psr */ + msr CPSR_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc} /* pop new task's r0-r12,lr & pc */ + +stack_setup: + mrs r0, cpsr + bic r0, r0, #MODEMASK + orr r1, r0, #UNDEFMODE|NOINT + msr cpsr_cxsf, r1 /* undef mode */ + ldr sp, UNDEFINED_STACK_START + + orr r1,r0,#ABORTMODE|NOINT + msr cpsr_cxsf,r1 /* abort mode */ + ldr sp, ABORT_STACK_START + + orr r1,r0,#IRQMODE|NOINT + msr cpsr_cxsf,r1 /* IRQ mode */ + ldr sp, IRQ_STACK_START + + orr r1,r0,#FIQMODE|NOINT + msr cpsr_cxsf,r1 /* FIQ mode */ + ldr sp, FIQ_STACK_START + + bic r0,r0,#MODEMASK + orr r1,r0,#SVCMODE|NOINT + msr cpsr_cxsf,r1 /* SVC mode */ + + ldr sp, _STACK_START + + /* USER mode is not initialized. */ + mov pc,lr /* The LR register may be not valid for the mode changes.*/ + +/*/*}*/ + diff --git a/rt-thread/libcpu/arm/s3c24x0/start_rvds.S b/rt-thread/libcpu/arm/s3c24x0/start_rvds.S new file mode 100644 index 0000000..dd5e9cc --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/start_rvds.S @@ -0,0 +1,1190 @@ +;/*****************************************************************************/ +;/* S3C2440.S: Startup file for Samsung S3C440 */ +;/*****************************************************************************/ +;/* <<< Use Configuration Wizard in Context Menu >>> */ +;/*****************************************************************************/ +;/* This file is part of the uVision/ARM development tools. */ +;/* Copyright (c) 2005-2008 Keil Software. All rights reserved. */ +;/* This software may only be used under the terms of a valid, current, */ +;/* end user licence from KEIL for a compatible version of KEIL software */ +;/* development tools. Nothing else gives you the right to use this software. */ +;/*****************************************************************************/ + + +;/* +; * The S3C2440.S code is executed after CPU Reset. This file may be +; * translated with the following SET symbols. In uVision these SET +; * symbols are entered under Options - ASM - Define. +; * +; * NO_CLOCK_SETUP: when set the startup code will not initialize Clock +; * (used mostly when clock is already initialized from script .ini +; * file). +; * +; * NO_MC_SETUP: when set the startup code will not initialize Memory +; * Controller (used mostly when clock is already initialized from script +; * .ini file). +; * +; * NO_GP_SETUP: when set the startup code will not initialize General Ports +; * (used mostly when clock is already initialized from script .ini +; * file). +; * +; * RAM_INTVEC: when set the startup code copies exception vectors +; * from execution address to on-chip RAM. +; */ + + +; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs + +Mode_USR EQU 0x10 +Mode_FIQ EQU 0x11 +Mode_IRQ EQU 0x12 +Mode_SVC EQU 0x13 +Mode_ABT EQU 0x17 +Mode_UND EQU 0x1B +Mode_SYS EQU 0x1F + +I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled +F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled + + +;----------------------- Stack and Heap Definitions ---------------------------- + +;// Stack Configuration (Stack Sizes in Bytes) +;// Undefined Mode <0x0-0xFFFFFFFF:8> +;// Supervisor Mode <0x0-0xFFFFFFFF:8> +;// Abort Mode <0x0-0xFFFFFFFF:8> +;// Fast Interrupt Mode <0x0-0xFFFFFFFF:8> +;// Interrupt Mode <0x0-0xFFFFFFFF:8> +;// User/System Mode <0x0-0xFFFFFFFF:8> +;// + +UND_Stack_Size EQU 0x00000000 +SVC_Stack_Size EQU 0x00000100 +ABT_Stack_Size EQU 0x00000000 +FIQ_Stack_Size EQU 0x00000000 +IRQ_Stack_Size EQU 0x00000100 +USR_Stack_Size EQU 0x00000100 + +ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + FIQ_Stack_Size + IRQ_Stack_Size) + + AREA STACK, NOINIT, READWRITE, ALIGN=3 + +Stack_Mem SPACE USR_Stack_Size +__initial_sp SPACE ISR_Stack_Size +Stack_Top + + +;// Heap Configuration +;// Heap Size (in Bytes) <0x0-0xFFFFFFFF> +;// + +Heap_Size EQU 0x00000000 + + AREA HEAP, NOINIT, READWRITE, ALIGN=3 +__heap_base +Heap_Mem SPACE Heap_Size +__heap_limit + + +;----------------------- Memory Definitions ------------------------------------ + +; Internal Memory Base Addresses +IRAM_BASE EQU 0x40000000 + + +;----------------------- Watchdog Timer Definitions ---------------------------- + +WT_BASE EQU 0x53000000 ; Watchdog Timer Base Address +WTCON_OFS EQU 0x00 ; Watchdog Timer Control Register Offset +WTDAT_OFS EQU 0x04 ; Watchdog Timer Data Register Offset +WTCNT_OFS EQU 0x08 ; Watchdog Timer Count Register Offset + +;// Watchdog Timer Setup +;// Watchdog Timer Control Register (WTCON) +;// Prescaler Value <0-255> +;// Watchdog Timer Enable +;// Clock Division Factor +;// <0=> 16 <1=> 32 <2=> 64 <3=> 128 +;// Interrupt Generation Enable +;// Reset Enable +;// +;// Watchdog Timer Data Register (WTDAT) +;// Count Reload Value <0-65535> +;// +;// Watchdog Timer Setup +WT_SETUP EQU 1 +WTCON_Val EQU 0x00000000 +WTDAT_Val EQU 0x00008000 + + +;----------------------- Clock and Power Management Definitions ---------------- + +CLOCK_BASE EQU 0x4C000000 ; Clock Base Address +LOCKTIME_OFS EQU 0x00 ; PLL Lock Time Count Register Offset +MPLLCON_OFS EQU 0x04 ; MPLL Configuration Register Offset +UPLLCON_OFS EQU 0x08 ; UPLL Configuration Register Offset +CLKCON_OFS EQU 0x0C ; Clock Generator Control Reg Offset +CLKSLOW_OFS EQU 0x10 ; Clock Slow Control Register Offset +CLKDIVN_OFS EQU 0x14 ; Clock Divider Control Register Offset +CAMDIVN_OFS EQU 0x18 ; Camera Clock Divider Register Offset + +;// Clock Setup +;// PLL Lock Time Count Register (LOCKTIME) +;// U_LTIME: UPLL Lock Time Count Value for UCLK <0x0-0xFFFF> +;// M_LTIME: MPLL Lock Time Count Value for FCLK, HCLK and PCLK <0x0-0xFFFF> +;// +;// MPLL Configuration Register (MPLLCON) +;// MPLL = (2 * m * Fin) / (p * 2^s) +;// m: Main Divider m Value <9-256><#-8> +;// m = MDIV + 8 +;// p: Pre-divider p Value <3-64><#-2> +;// p = PDIV + 2 +;// s: Post Divider s Value <0-3> +;// s = SDIV +;// +;// UPLL Configuration Register (UPLLCON) +;// UPLL = ( m * Fin) / (p * 2^s) +;// m: Main Divider m Value <8-263><#-8> +;// m = MDIV + 8 +;// p: Pre-divider p Value <2-65><#-2> +;// p = PDIV + 2 +;// s: Post Divider s Value <0-3> +;// s = SDIV +;// +;// Clock Generation Control Register (CLKCON) +;// AC97 Enable +;// Camera Enable +;// SPI Enable +;// IIS Enable +;// IIC Enable +;// ADC + Touch Screen Enable +;// RTC Enable +;// GPIO Enable +;// UART2 Enable +;// UART1 Enable +;// UART0 Enable +;// SDI Enable +;// PWMTIMER Enable +;// USB Device Enable +;// USB Host Enable +;// LCDC Enable +;// NAND FLASH Controller Enable +;// SLEEP Enable +;// IDLE BIT Enable +;// +;// Clock Slow Control Register (CLKSLOW) +;// UCLK_ON: UCLK ON +;// MPLL_OFF: Turn off PLL +;// SLOW_BIT: Slow Mode Enable +;// SLOW_VAL: Slow Clock Divider <0-7> +;// +;// Clock Divider Control Register (CLKDIVN) +;// DIVN_UPLL: UCLK Select +;// <0=> UCLK = UPLL clock +;// <1=> UCLK = UPLL clock / 2 +;// HDIVN: HCLK Select +;// <0=> HCLK = FCLK +;// <1=> HCLK = FCLK / 2 +;// <2=> HCLK = FCLK / 4 if HCLK4_HALF = 0 in CAMDIVN, else HCLK = FCLK / 8 +;// <3=> HCLK = FCLK / 3 if HCLK3_HALF = 0 in CAMDIVN, else HCLK = FCLK / 6 +;// PDIVN: PCLK Select +;// <0=> PCLK = HCLK +;// <1=> PCLK = HCLK / 2 +;// +;// Camera Clock Divider Control Register (CAMDIVN) +;// DVS_EN: ARM Core Clock Select +;// <0=> ARM core runs at FCLK +;// <1=> ARM core runs at HCLK +;// HCLK4_HALF: HDIVN Division Rate Change Bit +;// <0=> If HDIVN = 2 in CLKDIVN then HCLK = FCLK / 4 +;// <1=> If HDIVN = 2 in CLKDIVN then HCLK = FCLK / 8 +;// HCLK3_HALF: HDIVN Division Rate Change Bit +;// <0=> If HDIVN = 3 in CLKDIVN then HCLK = FCLK / 3 +;// <1=> If HDIVN = 3 in CLKDIVN then HCLK = FCLK / 6 +;// CAMCLK Select +;// <0=> CAMCLK = UPLL +;// <1=> CAMCLK = UPLL / CAMCLK_DIV +;// CAMCLK_DIV: CAMCLK Divider <0-15> +;// Camera Clock = UPLL / (2 * (CAMCLK_DIV + 1)) +;// Divider is used only if CAMCLK_SEL = 1 +;// +;// Clock Setup +CLOCK_SETUP EQU 0 +LOCKTIME_Val EQU 0x0FFF0FFF +MPLLCON_Val EQU 0x00043011 +UPLLCON_Val EQU 0x00038021 +CLKCON_Val EQU 0x001FFFF0 +CLKSLOW_Val EQU 0x00000004 +CLKDIVN_Val EQU 0x0000000F +CAMDIVN_Val EQU 0x00000000 + + +;----------------------- Memory Controller Definitions ------------------------- + +MC_BASE EQU 0x48000000 ; Memory Controller Base Address +BWSCON_OFS EQU 0x00 ; Bus Width and Wait Status Ctrl Offset +BANKCON0_OFS EQU 0x04 ; Bank 0 Control Register Offset +BANKCON1_OFS EQU 0x08 ; Bank 1 Control Register Offset +BANKCON2_OFS EQU 0x0C ; Bank 2 Control Register Offset +BANKCON3_OFS EQU 0x10 ; Bank 3 Control Register Offset +BANKCON4_OFS EQU 0x14 ; Bank 4 Control Register Offset +BANKCON5_OFS EQU 0x18 ; Bank 5 Control Register Offset +BANKCON6_OFS EQU 0x1C ; Bank 6 Control Register Offset +BANKCON7_OFS EQU 0x20 ; Bank 7 Control Register Offset +REFRESH_OFS EQU 0x24 ; SDRAM Refresh Control Register Offset +BANKSIZE_OFS EQU 0x28 ; Flexible Bank Size Register Offset +MRSRB6_OFS EQU 0x2C ; Bank 6 Mode Register Offset +MRSRB7_OFS EQU 0x30 ; Bank 7 Mode Register Offset + +;// Memory Controller Setup +;// Bus Width and Wait Control Register (BWSCON) +;// ST7: Use UB/LB for Bank 7 +;// WS7: Enable Wait Status for Bank 7 +;// DW7: Data Bus Width for Bank 7 +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Reserved +;// ST6: Use UB/LB for Bank 6 +;// WS6: Enable Wait Status for Bank 6 +;// DW6: Data Bus Width for Bank 6 +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Reserved +;// ST5: Use UB/LB for Bank 5 +;// WS5: Enable Wait Status for Bank 5 +;// DW5: Data Bus Width for Bank 5 +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Reserved +;// ST4: Use UB/LB for Bank 4 +;// WS4: Enable Wait Status for Bank 4 +;// DW4: Data Bus Width for Bank 4 +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Reserved +;// ST3: Use UB/LB for Bank 3 +;// WS3: Enable Wait Status for Bank 3 +;// DW3: Data Bus Width for Bank 3 +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Reserved +;// ST2: Use UB/LB for Bank 2 +;// WS2: Enable Wait Status for Bank 2 +;// DW2: Data Bus Width for Bank 2 +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Reserved +;// ST1: Use UB/LB for Bank 1 +;// WS1: Enable Wait Status for Bank 1 +;// DW1: Data Bus Width for Bank 1 +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Reserved +;// DW0: Indicate Data Bus Width for Bank 0 +;// <1=> 16-bit <2=> 32-bit +;// +;// Bank 0 Control Register (BANKCON0) +;// Tacs: Address Set-up Time before nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcos: Chip Selection Set-up Time before nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacc: Access Cycle +;// <0=> 1 clocks <1=> 2 clocks <2=> 3 clocks <3=> 4 clocks +;// <4=> 6 clocks <5=> 8 clocks <6=> 10 clocks <7=> 14 clocks +;// Tcoh: Chip Selection Hold Time after nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcah: Address Hold Time after nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacp: Page Mode Access Cycle at Page Mode +;// <0=> 2 clocks <1=> 3 clocks <2=> 4 clocks <3=> 6 clocks +;// PMC: Page Mode Configuration +;// <0=> normal (1 data) <1=> 4 data <2=> 8 data <3=> 16 data +;// +;// Bank 1 Control Register (BANKCON1) +;// Tacs: Address Set-up Time before nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcos: Chip Selection Set-up Time before nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacc: Access Cycle +;// <0=> 1 clocks <1=> 2 clocks <2=> 3 clocks <3=> 4 clocks +;// <4=> 6 clocks <5=> 8 clocks <6=> 10 clocks <7=> 14 clocks +;// Tcoh: Chip Selection Hold Time after nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcah: Address Hold Time after nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacp: Page Mode Access Cycle at Page Mode +;// <0=> 2 clocks <1=> 3 clocks <2=> 4 clocks <3=> 6 clocks +;// PMC: Page Mode Configuration +;// <0=> normal (1 data) <1=> 4 data <2=> 8 data <3=> 16 data +;// +;// Bank 2 Control Register (BANKCON2) +;// Tacs: Address Set-up Time before nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcos: Chip Selection Set-up Time before nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacc: Access Cycle +;// <0=> 1 clocks <1=> 2 clocks <2=> 3 clocks <3=> 4 clocks +;// <4=> 6 clocks <5=> 8 clocks <6=> 10 clocks <7=> 14 clocks +;// Tcoh: Chip Selection Hold Time after nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcah: Address Hold Time after nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacp: Page Mode Access Cycle at Page Mode +;// <0=> 2 clocks <1=> 3 clocks <2=> 4 clocks <3=> 6 clocks +;// PMC: Page Mode Configuration +;// <0=> normal (1 data) <1=> 4 data <2=> 8 data <3=> 16 data +;// +;// Bank 3 Control Register (BANKCON3) +;// Tacs: Address Set-up Time before nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcos: Chip Selection Set-up Time before nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacc: Access Cycle +;// <0=> 1 clocks <1=> 2 clocks <2=> 3 clocks <3=> 4 clocks +;// <4=> 6 clocks <5=> 8 clocks <6=> 10 clocks <7=> 14 clocks +;// Tcoh: Chip Selection Hold Time after nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcah: Address Hold Time after nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacp: Page Mode Access Cycle at Page Mode +;// <0=> 2 clocks <1=> 3 clocks <2=> 4 clocks <3=> 6 clocks +;// PMC: Page Mode Configuration +;// <0=> normal (1 data) <1=> 4 data <2=> 8 data <3=> 16 data +;// +;// Bank 4 Control Register (BANKCON4) +;// Tacs: Address Set-up Time before nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcos: Chip Selection Set-up Time before nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacc: Access Cycle +;// <0=> 1 clocks <1=> 2 clocks <2=> 3 clocks <3=> 4 clocks +;// <4=> 6 clocks <5=> 8 clocks <6=> 10 clocks <7=> 14 clocks +;// Tcoh: Chip Selection Hold Time after nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcah: Address Hold Time after nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacp: Page Mode Access Cycle at Page Mode +;// <0=> 2 clocks <1=> 3 clocks <2=> 4 clocks <3=> 6 clocks +;// PMC: Page Mode Configuration +;// <0=> normal (1 data) <1=> 4 data <2=> 8 data <3=> 16 data +;// +;// Bank 5 Control Register (BANKCON5) +;// Tacs: Address Set-up Time before nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcos: Chip Selection Set-up Time before nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacc: Access Cycle +;// <0=> 1 clocks <1=> 2 clocks <2=> 3 clocks <3=> 4 clocks +;// <4=> 6 clocks <5=> 8 clocks <6=> 10 clocks <7=> 14 clocks +;// Tcoh: Chip Selection Hold Time after nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcah: Address Hold Time after nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacp: Page Mode Access Cycle at Page Mode +;// <0=> 2 clocks <1=> 3 clocks <2=> 4 clocks <3=> 6 clocks +;// PMC: Page Mode Configuration +;// <0=> normal (1 data) <1=> 4 data <2=> 8 data <3=> 16 data +;// +;// Bank 6 Control Register (BANKCON6) +;// Memory Type Selection +;// <0=> ROM or SRAM <3=> SDRAM +;// Tacs: Address Set-up Time before nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcos: Chip Selection Set-up Time before nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacc: Access Cycle +;// <0=> 1 clocks <1=> 2 clocks <2=> 3 clocks <3=> 4 clocks +;// <4=> 6 clocks <5=> 8 clocks <6=> 10 clocks <7=> 14 clocks +;// Tcoh: Chip Selection Hold Time after nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcah: Address Hold Time after nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacp/Trcd: Page Mode Access Cycle at Page Mode / RAS to CAS Delay +;// Parameter depends on Memory Type: if type SRAM then parameter is Tacp, +;// if type is SDRAM then parameter is Trcd +;// For SDRAM 6 cycles setting is not allowed +;// <0=> 2 clocks <1=> 3 clocks <2=> 4 clocks <3=> 6 clocks +;// PMC/SCAN: Page Mode Configuration / Column Address Number <0-3> +;// Parameter depends on Memory Type: if type SRAM then parameter is PMC, +;// if type is SDRAM then parameter is SCAN +;// +;// Bank 7 Control Register (BANKCON7) +;// Memory Type Selection +;// <0=> ROM or SRAM <3=> SDRAM +;// Tacs: Address Set-up Time before nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcos: Chip Selection Set-up Time before nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacc: Access Cycle +;// <0=> 1 clocks <1=> 2 clocks <2=> 3 clocks <3=> 4 clocks +;// <4=> 6 clocks <5=> 8 clocks <6=> 10 clocks <7=> 14 clocks +;// Tcoh: Chip Selection Hold Time after nOE +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tcah: Address Hold Time after nGCS +;// <0=> 0 clocks <1=> 1 clocks <2=> 2 clocks <3=> 4 clocks +;// Tacp/Trcd: Page Mode Access Cycle at Page Mode / RAS to CAS Delay +;// Parameter depends on Memory Type: if type SRAM then parameter is Tacp, +;// if type is SDRAM then parameter is Trcd +;// For SDRAM 6 cycles setting is not allowed +;// <0=> 2 clocks <1=> 3 clocks <2=> 4 clocks <3=> 6 clocks +;// PMC/SCAN: Page Mode Configuration / Column Address Number <0-3> +;// Parameter depends on Memory Type: if type SRAM then parameter is PMC, +;// if type is SDRAM then parameter is SCAN +;// +;// SDRAM Refresh Control Register (REFRESH) +;// REFEN: SDRAM Refresh Enable +;// TREFMD: SDRAM Refresh Mode +;// <0=> CBR/Auto Refresh <1=> Self Refresh +;// Trp: SDRAM RAS Pre-charge Time +;// <0=> 2 clocks <1=> 3 clocks <2=> 4 clocks <3=> Reserved +;// Tsrc: SDRAM Semi Row Cycle Time +;// SDRAM Row cycle time: Trc = Tsrc + Trp +;// <0=> 4 clocks <1=> 5 clocks <2=> 6 clocks <3=> 7 clocks +;// Refresh Counter <0-1023> +;// Refresh Period = (2048 - Refresh Count + 1) / HCLK +;// +;// Flexible Bank Size Register (BANKSIZE) +;// BURST_EN: ARM Core Burst Operation Enable +;// SCKE_EN: SDRAM Power Down Mode Enable +;// SCLK_EN: SCLK Enabled During SDRAM Access Cycle +;// <0=> SCLK is always active <1=> SCLK is active only during the access +;// BK76MAP: BANK6 and BANK7 Memory Map +;// <0=> 32MB / 32MB <1=> 64MB / 64MB <2=> 128MB / 128MB +;// <4=> 2MB / 2MB <5=> 4MB / 4MB <6=> 8MB / 8MB <7=> 16MB / 16MB +;// Refresh Counter <0-1023> +;// Refresh Period = (2048 - Refresh Count + 1) / HCLK +;// +;// SDRAM Mode Register Set Register 6 (MRSRB6) +;// WBL: Write Burst Length +;// <0=> Burst (Fixed) +;// TM: Test Mode +;// <0=> Mode register set (Fixed) +;// CL: CAS Latency +;// <0=> 1 clocks <1=> 2 clocks <2=> 3 clocks +;// BT: Burst Type +;// <0=> Sequential (Fixed) +;// BL: Burst Length +;// <0=> 1 (Fixed) +;// +;// SDRAM Mode Register Set Register 7 (MRSRB7) +;// WBL: Write Burst Length +;// <0=> Burst (Fixed) +;// TM: Test Mode +;// <0=> Mode register set (Fixed) +;// CL: CAS Latency +;// <0=> 1 clocks <1=> 2 clocks <2=> 3 clocks +;// BT: Burst Type +;// <0=> Sequential (Fixed) +;// BL: Burst Length +;// <0=> 1 (Fixed) +;// +;// Memory Controller Setup +MC_SETUP EQU 0 +BWSCON_Val EQU 0x22000000 +BANKCON0_Val EQU 0x00000700 +BANKCON1_Val EQU 0x00000700 +BANKCON2_Val EQU 0x00000700 +BANKCON3_Val EQU 0x00000700 +BANKCON4_Val EQU 0x00000700 +BANKCON5_Val EQU 0x00000700 +BANKCON6_Val EQU 0x00018005 +BANKCON7_Val EQU 0x00018005 +REFRESH_Val EQU 0x008404F3 +BANKSIZE_Val EQU 0x00000032 +MRSRB6_Val EQU 0x00000020 +MRSRB7_Val EQU 0x00000020 + + +;----------------------- I/O Port Definitions ---------------------------------- + +GPA_BASE EQU 0x56000000 ; GPA Base Address +GPB_BASE EQU 0x56000010 ; GPB Base Address +GPC_BASE EQU 0x56000020 ; GPC Base Address +GPD_BASE EQU 0x56000030 ; GPD Base Address +GPE_BASE EQU 0x56000040 ; GPE Base Address +GPF_BASE EQU 0x56000050 ; GPF Base Address +GPG_BASE EQU 0x56000060 ; GPG Base Address +GPH_BASE EQU 0x56000070 ; GPH Base Address +GPJ_BASE EQU 0x560000D0 ; GPJ Base Address +GPCON_OFS EQU 0x00 ; Control Register Offset +GPDAT_OFS EQU 0x04 ; Data Register Offset +GPUP_OFS EQU 0x08 ; Pull-up Disable Register Offset + +;// I/O Setup +GP_SETUP EQU 1 + +;// Port A Settings +;// Port A Control Register (GPACON) +;// GPA22 <0=> Output <1=> nFCE +;// GPA21 <0=> Output <1=> nRSTOUT +;// GPA20 <0=> Output <1=> nFRE +;// GPA19 <0=> Output <1=> nFWE +;// GPA18 <0=> Output <1=> ALE +;// GPA17 <0=> Output <1=> CLE +;// GPA16 <0=> Output <1=> nGCS[5] +;// GPA15 <0=> Output <1=> nGCS[4] +;// GPA14 <0=> Output <1=> nGCS[3] +;// GPA13 <0=> Output <1=> nGCS[2] +;// GPA12 <0=> Output <1=> nGCS[1] +;// GPA11 <0=> Output <1=> ADDR26 +;// GPA10 <0=> Output <1=> ADDR25 +;// GPA9 <0=> Output <1=> ADDR24 +;// GPA8 <0=> Output <1=> ADDR23 +;// GPA7 <0=> Output <1=> ADDR22 +;// GPA6 <0=> Output <1=> ADDR21 +;// GPA5 <0=> Output <1=> ADDR20 +;// GPA4 <0=> Output <1=> ADDR19 +;// GPA3 <0=> Output <1=> ADDR18 +;// GPA2 <0=> Output <1=> ADDR17 +;// GPA1 <0=> Output <1=> ADDR16 +;// GPA0 <0=> Output <1=> ADDR0 +;// +;// +GPA_SETUP EQU 0 +GPACON_Val EQU 0x000003FF + +;// Port B Settings +;// Port B Control Register (GPBCON) +;// GPB10 <0=> Input <1=> Output <2=> nXDREQ0 <3=> Reserved +;// GPB9 <0=> Input <1=> Output <2=> nXDACK0 <3=> Reserved +;// GPB8 <0=> Input <1=> Output <2=> nXDREQ1 <3=> Reserved +;// GPB7 <0=> Input <1=> Output <2=> nXDACK1 <3=> Reserved +;// GPB6 <0=> Input <1=> Output <2=> nXBREQ <3=> Reserved +;// GPB5 <0=> Input <1=> Output <2=> nXBACK <3=> Reserved +;// GPB4 <0=> Input <1=> Output <2=> TCLK[0] <3=> Reserved +;// GPB3 <0=> Input <1=> Output <2=> TOUT3 <3=> Reserved +;// GPB2 <0=> Input <1=> Output <2=> TOUT2 <3=> Reserved +;// GPB1 <0=> Input <1=> Output <2=> TOUT1 <3=> Reserved +;// GPB0 <0=> Input <1=> Output <2=> TOUT0 <3=> Reserved +;// +;// Port B Pull-up Settings Register (GPBUP) +;// GPB10 Pull-up Disable +;// GPB9 Pull-up Disable +;// GPB8 Pull-up Disable +;// GPB7 Pull-up Disable +;// GPB6 Pull-up Disable +;// GPB5 Pull-up Disable +;// GPB4 Pull-up Disable +;// GPB3 Pull-up Disable +;// GPB2 Pull-up Disable +;// GPB1 Pull-up Disable +;// GPB0 Pull-up Disable +;// +;// +GPB_SETUP EQU 0 +GPBCON_Val EQU 0x00000000 +GPBUP_Val EQU 0x00000000 + +;// Port C Settings +;// Port C Control Register (GPCCON) +;// GPC15 <0=> Input <1=> Output <2=> VD[7] <3=> Reserved +;// GPC14 <0=> Input <1=> Output <2=> VD[6] <3=> Reserved +;// GPC13 <0=> Input <1=> Output <2=> VD[5] <3=> Reserved +;// GPC12 <0=> Input <1=> Output <2=> VD[4] <3=> Reserved +;// GPC11 <0=> Input <1=> Output <2=> VD[3] <3=> Reserved +;// GPC10 <0=> Input <1=> Output <2=> VD[2] <3=> Reserved +;// GPC9 <0=> Input <1=> Output <2=> VD[1] <3=> Reserved +;// GPC8 <0=> Input <1=> Output <2=> VD[0] <3=> Reserved +;// GPC7 <0=> Input <1=> Output <2=> LCD_LPCREVB <3=> Reserved +;// GPC6 <0=> Input <1=> Output <2=> LCD_LPCREV <3=> Reserved +;// GPC5 <0=> Input <1=> Output <2=> LCD_LPCOE <3=> Reserved +;// GPC4 <0=> Input <1=> Output <2=> VM <3=> I2SSDI +;// GPC3 <0=> Input <1=> Output <2=> VFRAME <3=> Reserved +;// GPC2 <0=> Input <1=> Output <2=> VLINE <3=> Reserved +;// GPC1 <0=> Input <1=> Output <2=> VCLK <3=> Reserved +;// GPC0 <0=> Input <1=> Output <2=> LEND <3=> Reserved +;// +;// Port C Pull-up Settings Register (GPCUP) +;// GPC15 Pull-up Disable +;// GPC14 Pull-up Disable +;// GPC13 Pull-up Disable +;// GPC12 Pull-up Disable +;// GPC11 Pull-up Disable +;// GPC10 Pull-up Disable +;// GPC9 Pull-up Disable +;// GPC8 Pull-up Disable +;// GPC7 Pull-up Disable +;// GPC6 Pull-up Disable +;// GPC5 Pull-up Disable +;// GPC4 Pull-up Disable +;// GPC3 Pull-up Disable +;// GPC2 Pull-up Disable +;// GPC1 Pull-up Disable +;// GPC0 Pull-up Disable +;// +;// +GPC_SETUP EQU 0 +GPCCON_Val EQU 0x00000000 +GPCUP_Val EQU 0x00000000 + +;// Port D Settings +;// Port D Control Register (GPDCON) +;// GPD15 <0=> Input <1=> Output <2=> VD[23] <3=> nSS0 +;// GPD14 <0=> Input <1=> Output <2=> VD[22] <3=> nSS1 +;// GPD13 <0=> Input <1=> Output <2=> VD[21] <3=> Reserved +;// GPD12 <0=> Input <1=> Output <2=> VD[20] <3=> Reserved +;// GPD11 <0=> Input <1=> Output <2=> VD[19] <3=> Reserved +;// GPD10 <0=> Input <1=> Output <2=> VD[18] <3=> SPICLK1 +;// GPD9 <0=> Input <1=> Output <2=> VD[17] <3=> SPIMOSI1 +;// GPD8 <0=> Input <1=> Output <2=> VD[16] <3=> SPIMISO1 +;// GPD7 <0=> Input <1=> Output <2=> VD[15] <3=> Reserved +;// GPD6 <0=> Input <1=> Output <2=> VD[14] <3=> Reserved +;// GPD5 <0=> Input <1=> Output <2=> VD[13] <3=> Reserved +;// GPD4 <0=> Input <1=> Output <2=> VD[12] <3=> Reserved +;// GPD3 <0=> Input <1=> Output <2=> VD[11] <3=> Reserved +;// GPD2 <0=> Input <1=> Output <2=> VD[10] <3=> Reserved +;// GPD1 <0=> Input <1=> Output <2=> VD[9] <3=> Reserved +;// GPD0 <0=> Input <1=> Output <2=> VD[8] <3=> Reserved +;// +;// Port D Pull-up Settings Register (GPDUP) +;// GPD15 Pull-up Disable +;// GPD14 Pull-up Disable +;// GPD13 Pull-up Disable +;// GPD12 Pull-up Disable +;// GPD11 Pull-up Disable +;// GPD10 Pull-up Disable +;// GPD9 Pull-up Disable +;// GPD8 Pull-up Disable +;// GPD7 Pull-up Disable +;// GPD6 Pull-up Disable +;// GPD5 Pull-up Disable +;// GPD4 Pull-up Disable +;// GPD3 Pull-up Disable +;// GPD2 Pull-up Disable +;// GPD1 Pull-up Disable +;// GPD0 Pull-up Disable +;// +;// +GPD_SETUP EQU 0 +GPDCON_Val EQU 0x00000000 +GPDUP_Val EQU 0x00000000 + +;// Port E Settings +;// Port E Control Register (GPECON) +;// GPE15 <0=> Input <1=> Output <2=> IICSDA <3=> Reserved +;// This pad is open-drain, and has no pull-up option. +;// GPE14 <0=> Input <1=> Output <2=> IICSCL <3=> Reserved +;// This pad is open-drain, and has no pull-up option. +;// GPE13 <0=> Input <1=> Output <2=> SPICLK0 <3=> Reserved +;// GPE12 <0=> Input <1=> Output <2=> SPIMOSI0 <3=> Reserved +;// GPE11 <0=> Input <1=> Output <2=> SPIMISO0 <3=> Reserved +;// GPE10 <0=> Input <1=> Output <2=> SDDAT3 <3=> Reserved +;// GPE9 <0=> Input <1=> Output <2=> SDDAT2 <3=> Reserved +;// GPE8 <0=> Input <1=> Output <2=> SDDAT1 <3=> Reserved +;// GPE7 <0=> Input <1=> Output <2=> SDDAT0 <3=> Reserved +;// GPE6 <0=> Input <1=> Output <2=> SDCMD <3=> Reserved +;// GPE5 <0=> Input <1=> Output <2=> SDCLK <3=> Reserved +;// GPE4 <0=> Input <1=> Output <2=> I2SDO <3=> AC_SDATA_OUT +;// GPE3 <0=> Input <1=> Output <2=> I2SDI <3=> AC_SDATA_IN +;// GPE2 <0=> Input <1=> Output <2=> CDCLK <3=> AC_nRESET +;// GPE1 <0=> Input <1=> Output <2=> I2SSCLK <3=> AC_BIT_CLK +;// GPE0 <0=> Input <1=> Output <2=> I2SLRCK <3=> AC_SYNC +;// +;// Port E Pull-up Settings Register (GPEUP) +;// GPE13 Pull-up Disable +;// GPE12 Pull-up Disable +;// GPE11 Pull-up Disable +;// GPE10 Pull-up Disable +;// GPE9 Pull-up Disable +;// GPE8 Pull-up Disable +;// GPE7 Pull-up Disable +;// GPE6 Pull-up Disable +;// GPE5 Pull-up Disable +;// GPE4 Pull-up Disable +;// GPE3 Pull-up Disable +;// GPE2 Pull-up Disable +;// GPE1 Pull-up Disable +;// GPE0 Pull-up Disable +;// +;// +GPE_SETUP EQU 0 +GPECON_Val EQU 0x00000000 +GPEUP_Val EQU 0x00000000 + +;// Port F Settings +;// Port F Control Register (GPFCON) +;// GPF7 <0=> Input <1=> Output <2=> EINT[7] <3=> Reserved +;// GPF6 <0=> Input <1=> Output <2=> EINT[6] <3=> Reserved +;// GPF5 <0=> Input <1=> Output <2=> EINT[5] <3=> Reserved +;// GPF4 <0=> Input <1=> Output <2=> EINT[4] <3=> Reserved +;// GPF3 <0=> Input <1=> Output <2=> EINT[3] <3=> Reserved +;// GPF2 <0=> Input <1=> Output <2=> EINT[2] <3=> Reserved +;// GPF1 <0=> Input <1=> Output <2=> EINT[1] <3=> Reserved +;// GPF0 <0=> Input <1=> Output <2=> EINT[0] <3=> Reserved +;// +;// Port F Pull-up Settings Register (GPFUP) +;// GPF7 Pull-up Disable +;// GPF6 Pull-up Disable +;// GPF5 Pull-up Disable +;// GPF4 Pull-up Disable +;// GPF3 Pull-up Disable +;// GPF2 Pull-up Disable +;// GPF1 Pull-up Disable +;// GPF0 Pull-up Disable +;// +;// +GPF_SETUP EQU 1 +GPFCON_Val EQU 0x000000AA +GPFUP_Val EQU 0x0000000F + +;// Port G Settings +;// Port G Control Register (GPGCON) +;// GPG15 <0=> Input <1=> Output <2=> EINT[23] <3=> Reserved +;// GPG14 <0=> Input <1=> Output <2=> EINT[22] <3=> Reserved +;// GPG13 <0=> Input <1=> Output <2=> EINT[21] <3=> Reserved +;// GPG12 <0=> Input <1=> Output <2=> EINT[20] <3=> Reserved +;// GPG11 <0=> Input <1=> Output <2=> EINT[19] <3=> TCLK[1] +;// GPG10 <0=> Input <1=> Output <2=> EINT[18] <3=> nCTS1 +;// GPG9 <0=> Input <1=> Output <2=> EINT[17] <3=> nRTS1 +;// GPG8 <0=> Input <1=> Output <2=> EINT[16] <3=> Reserved +;// GPG7 <0=> Input <1=> Output <2=> EINT[15] <3=> SPICLK1 +;// GPG6 <0=> Input <1=> Output <2=> EINT[14] <3=> SPIMOSI1 +;// GPG5 <0=> Input <1=> Output <2=> EINT[13] <3=> SPIMISO1 +;// GPG4 <0=> Input <1=> Output <2=> EINT[12] <3=> LCD_PWRDN +;// GPG3 <0=> Input <1=> Output <2=> EINT[11] <3=> nSS1 +;// GPG2 <0=> Input <1=> Output <2=> EINT[10] <3=> nSS0 +;// GPG1 <0=> Input <1=> Output <2=> EINT[9] <3=> Reserved +;// GPG0 <0=> Input <1=> Output <2=> EINT[8] <3=> Reserved +;// +;// Port G Pull-up Settings Register (GPGUP) +;// GPG15 Pull-up Disable +;// GPG14 Pull-up Disable +;// GPG13 Pull-up Disable +;// GPG12 Pull-up Disable +;// GPG11 Pull-up Disable +;// GPG10 Pull-up Disable +;// GPG9 Pull-up Disable +;// GPG8 Pull-up Disable +;// GPG7 Pull-up Disable +;// GPG6 Pull-up Disable +;// GPG5 Pull-up Disable +;// GPG4 Pull-up Disable +;// GPG3 Pull-up Disable +;// GPG2 Pull-up Disable +;// GPG1 Pull-up Disable +;// GPG0 Pull-up Disable +;// +;// +GPG_SETUP EQU 0 +GPGCON_Val EQU 0x00000000 +GPGUP_Val EQU 0x00000000 + +;// Port H Settings +;// Port H Control Register (GPHCON) +;// GPH10 <0=> Input <1=> Output <2=> CLKOUT1 <3=> Reserved +;// GPH9 <0=> Input <1=> Output <2=> CLKOUT0 <3=> Reserved +;// GPH8 <0=> Input <1=> Output <2=> UEXTCLK <3=> Reserved +;// GPH7 <0=> Input <1=> Output <2=> RXD[2] <3=> nCTS1 +;// GPH6 <0=> Input <1=> Output <2=> TXD[2] <3=> nRTS1 +;// GPH5 <0=> Input <1=> Output <2=> RXD[1] <3=> Reserved +;// GPH4 <0=> Input <1=> Output <2=> TXD[1] <3=> Reserved +;// GPH3 <0=> Input <1=> Output <2=> RXD[0] <3=> Reserved +;// GPH2 <0=> Input <1=> Output <2=> TXD[0] <3=> Reserved +;// GPH1 <0=> Input <1=> Output <2=> nRTS0 <3=> Reserved +;// GPH0 <0=> Input <1=> Output <2=> nCTS0 <3=> Reserved +;// +;// Port H Pull-up Settings Register (GPHUP) +;// GPH10 Pull-up Disable +;// GPH9 Pull-up Disable +;// GPH8 Pull-up Disable +;// GPH7 Pull-up Disable +;// GPH6 Pull-up Disable +;// GPH5 Pull-up Disable +;// GPH4 Pull-up Disable +;// GPH3 Pull-up Disable +;// GPH2 Pull-up Disable +;// GPH1 Pull-up Disable +;// GPH0 Pull-up Disable +;// +;// +GPH_SETUP EQU 0 +GPHCON_Val EQU 0x00000000 +GPHUP_Val EQU 0x00000000 + +;// Port J Settings +;// Port J Control Register (GPJCON) +;// GPJ12 <0=> Input <1=> Output <2=> CAMRESET <3=> Reserved +;// GPJ11 <0=> Input <1=> Output <2=> CAMCLKOUT <3=> Reserved +;// GPJ10 <0=> Input <1=> Output <2=> CAMHREF <3=> Reserved +;// GPJ9 <0=> Input <1=> Output <2=> CAMVSYNC <3=> Reserved +;// GPJ8 <0=> Input <1=> Output <2=> CAMPCLK <3=> Reserved +;// GPJ7 <0=> Input <1=> Output <2=> CAMDATA[7] <3=> Reserved +;// GPJ6 <0=> Input <1=> Output <2=> CAMDATA[6] <3=> Reserved +;// GPJ5 <0=> Input <1=> Output <2=> CAMDATA[5] <3=> Reserved +;// GPJ4 <0=> Input <1=> Output <2=> CAMDATA[4] <3=> Reserved +;// GPJ3 <0=> Input <1=> Output <2=> CAMDATA[3] <3=> Reserved +;// GPJ2 <0=> Input <1=> Output <2=> CAMDATA[2] <3=> Reserved +;// GPJ1 <0=> Input <1=> Output <2=> CAMDATA[1] <3=> Reserved +;// GPJ0 <0=> Input <1=> Output <2=> CAMDATA[0] <3=> Reserved +;// +;// Port J Pull-up Settings Register (GPJUP) +;// GPJ12 Pull-up Disable +;// GPJ11 Pull-up Disable +;// GPJ10 Pull-up Disable +;// GPJ9 Pull-up Disable +;// GPJ8 Pull-up Disable +;// GPJ7 Pull-up Disable +;// GPJ6 Pull-up Disable +;// GPJ5 Pull-up Disable +;// GPJ4 Pull-up Disable +;// GPJ3 Pull-up Disable +;// GPJ2 Pull-up Disable +;// GPJ1 Pull-up Disable +;// GPJ0 Pull-up Disable +;// +;// +GPJ_SETUP EQU 0 +GPJCON_Val EQU 0x00000000 +GPJUP_Val EQU 0x00000000 + +;// I/O Setup + + +;----------------------- CODE -------------------------------------------------- + + PRESERVE8 + + +; Area Definition and Entry Point +; Startup Code must be linked first at Address at which it expects to run. + + AREA RESET, CODE, READONLY + ARM + +; Exception Vectors +; Mapped to Address 0. +; Absolute addressing mode must be used. +; Dummy Handlers are implemented as infinite loops which can be modified. + + EXPORT Entry_Point +Entry_Point +Vectors LDR PC, Reset_Addr + LDR PC, Undef_Addr + LDR PC, SWI_Addr + LDR PC, PAbt_Addr + LDR PC, DAbt_Addr + NOP + LDR PC, IRQ_Addr + LDR PC, FIQ_Addr + +Reset_Addr DCD Reset_Handler +Undef_Addr DCD Undef_Handler +SWI_Addr DCD SWI_Handler +PAbt_Addr DCD PAbt_Handler +DAbt_Addr DCD DAbt_Handler + DCD 0 ; Reserved Address +IRQ_Addr DCD IRQ_Handler +FIQ_Addr DCD FIQ_Handler + +Undef_Handler B Undef_Handler +SWI_Handler B SWI_Handler +PAbt_Handler B PAbt_Handler +;DAbt_Handler B DAbt_Handler +FIQ_Handler B FIQ_Handler + +;* +;************************************************************************* +;* +;* Interrupt handling +;* +;************************************************************************* +;* +; DAbt Handler +DAbt_Handler + IMPORT rt_hw_trap_dabt + + sub sp, sp, #72 + stmia sp, {r0 - r12} ;/* Calling r0-r12 */ + add r8, sp, #60 + stmdb r8, {sp, lr} ;/* Calling SP, LR */ + str lr, [r8, #0] ;/* Save calling PC */ + mrs r6, spsr + str r6, [r8, #4] ;/* Save CPSR */ + str r0, [r8, #8] ;/* Save OLD_R0 */ + mov r0, sp + + bl rt_hw_trap_dabt + + +;########################################## +; Reset Handler + + EXPORT Reset_Handler +Reset_Handler + + +; Watchdog Setup --------------------------------------------------------------- + + IF WT_SETUP != 0 + LDR R0, =WT_BASE + LDR R1, =WTCON_Val + LDR R2, =WTDAT_Val + STR R2, [R0, #WTCNT_OFS] + STR R2, [R0, #WTDAT_OFS] + STR R1, [R0, #WTCON_OFS] + ENDIF + + +; Clock Setup ------------------------------------------------------------------ + + IF (:LNOT:(:DEF:NO_CLOCK_SETUP)):LAND:(CLOCK_SETUP != 0) + LDR R0, =CLOCK_BASE + LDR R1, =LOCKTIME_Val + STR R1, [R0, #LOCKTIME_OFS] + MOV R1, #CLKDIVN_Val + STR R1, [R0, #CLKDIVN_OFS] + LDR R1, =CAMDIVN_Val + STR R1, [R0, #CAMDIVN_OFS] + LDR R1, =MPLLCON_Val + STR R1, [R0, #MPLLCON_OFS] + LDR R1, =UPLLCON_Val + STR R1, [R0, #UPLLCON_OFS] + MOV R1, #CLKSLOW_Val + STR R1, [R0, #CLKSLOW_OFS] + LDR R1, =CLKCON_Val + STR R1, [R0, #CLKCON_OFS] + ENDIF + + +; Memory Controller Setup ------------------------------------------------------ + + IF (:LNOT:(:DEF:NO_MC_SETUP)):LAND:(CLOCK_SETUP != 0) + LDR R0, =MC_BASE + LDR R1, =BWSCON_Val + STR R1, [R0, #BWSCON_OFS] + LDR R1, =BANKCON0_Val + STR R1, [R0, #BANKCON0_OFS] + LDR R1, =BANKCON1_Val + STR R1, [R0, #BANKCON1_OFS] + LDR R1, =BANKCON2_Val + STR R1, [R0, #BANKCON2_OFS] + LDR R1, =BANKCON3_Val + STR R1, [R0, #BANKCON3_OFS] + LDR R1, =BANKCON4_Val + STR R1, [R0, #BANKCON4_OFS] + LDR R1, =BANKCON5_Val + STR R1, [R0, #BANKCON5_OFS] + LDR R1, =BANKCON6_Val + STR R1, [R0, #BANKCON6_OFS] + LDR R1, =BANKCON7_Val + STR R1, [R0, #BANKCON7_OFS] + LDR R1, =REFRESH_Val + STR R1, [R0, #REFRESH_OFS] + MOV R1, #BANKSIZE_Val + STR R1, [R0, #BANKSIZE_OFS] + MOV R1, #MRSRB6_Val + STR R1, [R0, #MRSRB6_OFS] + MOV R1, #MRSRB7_Val + STR R1, [R0, #MRSRB7_OFS] + ENDIF + + +; I/O Pins Setup --------------------------------------------------------------- + + IF (:LNOT:(:DEF:NO_GP_SETUP)):LAND:(GP_SETUP != 0) + + IF GPA_SETUP != 0 + LDR R0, =GPA_BASE + LDR R1, =GPACON_Val + STR R1, [R0, #GPCON_OFS] + ENDIF + + IF GPB_SETUP != 0 + LDR R0, =GPB_BASE + LDR R1, =GPBCON_Val + STR R1, [R0, #GPCON_OFS] + LDR R1, =GPBUP_Val + STR R1, [R0, #GPUP_OFS] + ENDIF + + IF GPC_SETUP != 0 + LDR R0, =GPC_BASE + LDR R1, =GPCCON_Val + STR R1, [R0, #GPCON_OFS] + LDR R1, =GPCUP_Val + STR R1, [R0, #GPUP_OFS] + ENDIF + + IF GPD_SETUP != 0 + LDR R0, =GPD_BASE + LDR R1, =GPDCON_Val + STR R1, [R0, #GPCON_OFS] + LDR R1, =GPDUP_Val + STR R1, [R0, #GPUP_OFS] + ENDIF + + IF GPE_SETUP != 0 + LDR R0, =GPE_BASE + LDR R1, =GPECON_Val + STR R1, [R0, #GPCON_OFS] + LDR R1, =GPEUP_Val + STR R1, [R0, #GPUP_OFS] + ENDIF + + IF GPF_SETUP != 0 + LDR R0, =GPF_BASE + LDR R1, =GPFCON_Val + STR R1, [R0, #GPCON_OFS] + LDR R1, =GPFUP_Val + STR R1, [R0, #GPUP_OFS] + ENDIF + + IF GPG_SETUP != 0 + LDR R0, =GPG_BASE + LDR R1, =GPGCON_Val + STR R1, [R0, #GPCON_OFS] + LDR R1, =GPGUP_Val + STR R1, [R0, #GPUP_OFS] + ENDIF + + IF GPH_SETUP != 0 + LDR R0, =GPH_BASE + LDR R1, =GPHCON_Val + STR R1, [R0, #GPCON_OFS] + LDR R1, =GPHUP_Val + STR R1, [R0, #GPUP_OFS] + ENDIF + + IF GPJ_SETUP != 0 + LDR R0, =GPJ_BASE + LDR R1, =GPJCON_Val + STR R1, [R0, #GPCON_OFS] + LDR R1, =GPJUP_Val + STR R1, [R0, #GPUP_OFS] + ENDIF + + ENDIF + + +; Copy Exception Vectors to Internal RAM --------------------------------------- + + IF :DEF:RAM_INTVEC + ADR R8, Vectors ; Source + LDR R9, =IRAM_BASE ; Destination + LDMIA R8!, {R0-R7} ; Load Vectors + STMIA R9!, {R0-R7} ; Store Vectors + LDMIA R8!, {R0-R7} ; Load Handler Addresses + STMIA R9!, {R0-R7} ; Store Handler Addresses + ENDIF + + +; Setup Stack for each mode ---------------------------------------------------- + + LDR R0, =Stack_Top + +; Enter Undefined Instruction Mode and set its Stack Pointer + MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #UND_Stack_Size + +; Enter Abort Mode and set its Stack Pointer + MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #ABT_Stack_Size + +; Enter FIQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #FIQ_Stack_Size + +; Enter IRQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #IRQ_Stack_Size + +; Enter Supervisor Mode and set its Stack Pointer + MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #SVC_Stack_Size + +; Enter User Mode and set its Stack Pointer + ; MSR CPSR_c, #Mode_USR + MOV SP, R0 + SUB SL, SP, #USR_Stack_Size + +; Enter the C code ------------------------------------------------------------- + + IMPORT __main + LDR R0, =__main + BX R0 + + IMPORT rt_interrupt_enter + IMPORT rt_interrupt_leave + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + IMPORT rt_hw_trap_irq + +IRQ_Handler PROC + EXPORT IRQ_Handler + STMFD sp!, {r0-r12,lr} + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; if rt_thread_switch_interrupt_flag set, jump to + ; rt_hw_context_switch_interrupt_do and don't return + LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD sp!, {r0-r12,lr} + SUBS pc, lr, #4 + ENDP + +; /* +; * void rt_hw_context_switch_interrupt_do(rt_base_t flag) +; */ +rt_hw_context_switch_interrupt_do PROC + EXPORT rt_hw_context_switch_interrupt_do + MOV r1, #0 ; clear flag + STR r1, [r0] + + LDMFD sp!, {r0-r12,lr}; reload saved registers + STMFD sp!, {r0-r3} ; save r0-r3 + MOV r1, sp + ADD sp, sp, #16 ; restore sp + SUB r2, lr, #4 ; save old task's pc to r2 + + MRS r3, spsr ; get cpsr of interrupt thread + + ; switch to SVC mode and no interrupt + MSR cpsr_c, #I_Bit:OR:F_Bit:OR:Mode_SVC + + STMFD sp!, {r2} ; push old task's pc + STMFD sp!, {r4-r12,lr}; push old task's lr,r12-r4 + MOV r4, r1 ; Special optimised code below + MOV r5, r3 + LDMFD r4!, {r0-r3} + STMFD sp!, {r0-r3} ; push old task's r3-r0 + STMFD sp!, {r5} ; push old task's cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push old task's spsr + + LDR r4, =rt_interrupt_from_thread + LDR r5, [r4] + STR sp, [r5] ; store sp in preempted tasks's TCB + + LDR r6, =rt_interrupt_to_thread + LDR r6, [r6] + LDR sp, [r6] ; get new task's stack pointer + + LDMFD sp!, {r4} ; pop new task's spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task's psr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc + ENDP + + IF :DEF:__MICROLIB + + EXPORT __heap_base + EXPORT __heap_limit + + ELSE +; User Initial Stack & Heap + AREA |.text|, CODE, READONLY + + IMPORT __use_two_region_memory + EXPORT __user_initial_stackheap +__user_initial_stackheap + + LDR R0, = Heap_Mem + LDR R1, =(Stack_Mem + USR_Stack_Size) + LDR R2, = (Heap_Mem + Heap_Size) + LDR R3, = Stack_Mem + BX LR + ENDIF + + + END + diff --git a/rt-thread/libcpu/arm/s3c24x0/system_clock.c b/rt-thread/libcpu/arm/s3c24x0/system_clock.c new file mode 100644 index 0000000..c87c596 --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/system_clock.c @@ -0,0 +1,108 @@ +/* + * File : clock.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2008-04-25 Yi.qiu first version + */ + +#include +#include "s3c24x0.h" + +#define CONFIG_SYS_CLK_FREQ 12000000 // Fin = 12.00MHz + +#if CONFIG_SYS_CLK_FREQ == 12000000 + /* MPLL=2*12*100/6=400MHz */ + #define MPL_MIDV 92 /* m=MPL_MDIV+8=100 */ + #define MPL_PDIV 4 /* p=MPL_PDIV+2=6 */ + #define MPL_SDIV 0 /* s=MPL_SDIV=0 */ + /* UPLL=12*64/8=96MHz */ + #define UPL_MDIV 56 /* m=UPL_MDIV+8=64 */ + #define UPL_PDIV 2 /* p=UPL_PDIV+2=4 */ + #define UPL_SDIV 1 /* s=UPL_SDIV=1 */ + /* System clock divider FCLK:HCLK:PCLK=1:4:8 */ + #define DIVN_UPLL 0x1 /* UCLK = UPLL clock / 2 */ + #define HDIVN 0x2 /* HCLK = FCLK / 4 */ + #define PDIVN 0x1 /* PCLK = HCLK / 2 */ +#endif + +rt_uint32_t PCLK; +rt_uint32_t FCLK; +rt_uint32_t HCLK; +rt_uint32_t UCLK; + +void rt_hw_get_clock(void) +{ + rt_uint32_t val; + rt_uint8_t m, p, s; + + val = MPLLCON; + m = (val>>12)&0xff; + p = (val>>4)&0x3f; + s = val&3; + + FCLK = ((m+8)*(CONFIG_SYS_CLK_FREQ/100)*2)/((p+2)*(1<>1)&3; + p = val&1; + + switch (m) { + case 0: + HCLK = FCLK; + break; + case 1: + HCLK = FCLK>>1; + break; + case 2: + if(s&2) + HCLK = FCLK>>3; + else + HCLK = FCLK>>2; + break; + case 3: + if(s&1) + HCLK = FCLK/6; + else + HCLK = FCLK/3; + break; +} + + if(p) + PCLK = HCLK>>1; + else + PCLK = HCLK; +} + +void rt_hw_set_mpll_clock(rt_uint8_t sdiv, rt_uint8_t pdiv, rt_uint8_t mdiv) +{ + MPLLCON = sdiv | (pdiv<<4) | (mdiv<<12); +} + +void rt_hw_set_upll_clock(rt_uint8_t sdiv, rt_uint8_t pdiv, rt_uint8_t mdiv) +{ + UPLLCON = (mdiv<<12) | (pdiv<<4) | sdiv; +} + +void rt_hw_set_divider(rt_uint8_t hdivn, rt_uint8_t pdivn) +{ + CLKDIVN = (hdivn<<1) | pdivn; +} + +/** + * @brief System Clock Configuration + */ +void rt_hw_clock_init(void) +{ + LOCKTIME = 0xFFFFFFFF; + rt_hw_set_mpll_clock(MPL_SDIV, MPL_PDIV, MPL_MIDV); + rt_hw_set_upll_clock(UPL_SDIV, UPL_PDIV, UPL_MDIV); + rt_hw_set_divider(HDIVN, PDIVN); +} + diff --git a/rt-thread/libcpu/arm/s3c24x0/trap.c b/rt-thread/libcpu/arm/s3c24x0/trap.c new file mode 100644 index 0000000..f1c8176 --- /dev/null +++ b/rt-thread/libcpu/arm/s3c24x0/trap.c @@ -0,0 +1,177 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + * 2006-05-27 Bernard add skyeye support + * 2007-11-19 Yi.Qiu fix rt_hw_trap_irq function + * 2013-03-29 aozima Modify the interrupt interface implementations. + */ + +#include +#include + +#include "s3c24x0.h" + +/** + * @addtogroup S3C24X0 + */ +/*@{*/ + +extern struct rt_thread *rt_current_thread; +#ifdef RT_USING_FINSH +extern long list_thread(void); +#endif + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ + +void rt_hw_show_register (struct rt_hw_register *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When ARM7TDMI comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_udef(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("undefined instruction\n"); + rt_kprintf("thread - %s stack:\n", rt_current_thread->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("software interrupt\n"); + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("prefetch abort\n"); + rt_kprintf("thread - %s stack:\n", rt_current_thread->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("data abort\n"); + rt_kprintf("thread - %s stack:\n", rt_current_thread->name); + +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_register *regs) +{ + rt_kprintf("not used\n"); + rt_hw_show_register(regs); + rt_hw_cpu_shutdown(); +} + +extern struct rt_irq_desc isr_table[]; + +void rt_hw_trap_irq(void) +{ + unsigned long irq; + rt_isr_handler_t isr_func; + void *param; + + irq = INTOFFSET; + + if (irq == INTGLOBAL) return; + + /* get interrupt service routine */ + isr_func = isr_table[irq].handler; + param = isr_table[irq].param; + + /* turn to interrupt service routine */ + isr_func(irq, param); + + /* clear pending register */ + /* note: must be the last, if not, may repeat*/ + ClearPending(1 << irq); + +#ifdef RT_USING_INTERRUPT_INFO + isr_table[irq].counter++; +#endif /* RT_USING_INTERRUPT_INFO */ +} + +void rt_hw_trap_fiq(void) +{ + rt_kprintf("fast interrupt request\n"); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/s3c44b0/context_gcc.S b/rt-thread/libcpu/arm/s3c44b0/context_gcc.S new file mode 100644 index 0000000..bbdc398 --- /dev/null +++ b/rt-thread/libcpu/arm/s3c44b0/context_gcc.S @@ -0,0 +1,99 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-09-06 XuXinming first version + */ + +/*! + * \addtogroup S3C44B0 + */ +/*@{*/ + +#define NOINT 0xc0 + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + orr r1, r0, #NOINT + msr cpsr_c, r1 + mov pc, lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + mov pc, lr + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + stmfd sp!, {r4} @ push cpsr + mrs r4, spsr + stmfd sp!, {r4} @ push spsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r4} @ pop new task cpsr + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r4} @ pop new task cpsr + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 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] + mov pc, lr diff --git a/rt-thread/libcpu/arm/s3c44b0/context_rvds.S b/rt-thread/libcpu/arm/s3c44b0/context_rvds.S new file mode 100644 index 0000000..641ec7a --- /dev/null +++ b/rt-thread/libcpu/arm/s3c44b0/context_rvds.S @@ -0,0 +1,107 @@ +;/* +; * File : context_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, 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-20 Bernard first version +; */ + +NOINT EQU 0xc0 ; disable interrupt in psr + + AREA |.text|, CODE, READONLY, ALIGN=2 + ARM + REQUIRE8 + PRESERVE8 + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ +rt_hw_interrupt_disable PROC + EXPORT rt_hw_interrupt_disable + MRS r0, cpsr + ORR r1, r0, #NOINT + MSR cpsr_c, r1 + BX lr + ENDP + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ +rt_hw_interrupt_enable PROC + EXPORT rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + ENDP + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ +rt_hw_context_switch PROC + EXPORT rt_hw_context_switch + STMFD sp!, {lr} ; push pc (lr should be pushed in place of PC) + STMFD sp!, {r0-r12, lr} ; push lr & register file + + MRS r4, cpsr + STMFD sp!, {r4} ; push cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push spsr + + STR sp, [r0] ; store sp in preempted tasks TCB + LDR sp, [r1] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ +rt_hw_context_switch_to PROC + EXPORT rt_hw_context_switch_to + LDR sp, [r0] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +rt_hw_context_switch_interrupt PROC + EXPORT rt_hw_context_switch_interrupt + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 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] + BX lr + ENDP + + END \ No newline at end of file diff --git a/rt-thread/libcpu/arm/s3c44b0/cpu.c b/rt-thread/libcpu/arm/s3c44b0/cpu.c new file mode 100644 index 0000000..088ca2e --- /dev/null +++ b/rt-thread/libcpu/arm/s3c44b0/cpu.c @@ -0,0 +1,122 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-09-06 XuXinming first version + */ + +#include +#include "s3c44b0.h" + +/** + * @addtogroup S3C44B0 + */ +/*@{*/ + +/** + * This function will enable I-Cache of CPU + * + */ +void rt_hw_cpu_icache_enable() +{ + rt_base_t reg; + + volatile int i; + /* flush cycle */ + for(i = 0x10002000; i < 0x10004800; i+=16) + { + *((int *)i)=0x0; + } + + /* + * Init cache + * Non-cacheable area (everything outside RAM) + * 0x0000:0000 - 0x0C00:0000 + */ + NCACHBE0 = 0xC0000000; + NCACHBE1 = 0x00000000; + + /* + Enable chache + */ + reg = SYSCFG; + reg |= 0x00000006; /* 8kB */ + SYSCFG = reg; +} + +/** + * This function will disable I-Cache of CPU + * + */ +void rt_hw_cpu_icache_disable() +{ + rt_base_t reg; + + reg = SYSCFG; + reg &= ~0x00000006; /* 8kB */ + SYSCFG = reg; +} + +/** + * this function will get the status of I-Cache + * + */ +rt_base_t rt_hw_cpu_icache_status() +{ + return 0; +} + +/** + * this function will enable D-Cache of CPU + * + */ +void rt_hw_cpu_dcache_enable() +{ + rt_hw_cpu_icache_enable(); +} + +/** + * this function will disable D-Cache of CPU + * + */ +void rt_hw_cpu_dcache_disable() +{ + rt_hw_cpu_icache_disable(); +} + +/** + * this function will get the status of D-Cache + * + */ +rt_base_t rt_hw_cpu_dcache_status() +{ + return rt_hw_cpu_icache_status(); +} + +/** + * this function will reset CPU + * + */ +void rt_hw_cpu_reset() +{ +} + +/** + * this function will shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_kprintf("shutdown...\n"); + + while (1); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/s3c44b0/interrupt.c b/rt-thread/libcpu/arm/s3c44b0/interrupt.c new file mode 100644 index 0000000..3fc4f8c --- /dev/null +++ b/rt-thread/libcpu/arm/s3c44b0/interrupt.c @@ -0,0 +1,148 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-09-06 XuXinming first version + * 2006-09-15 Bernard add interrupt bank 0..3 for more effective + * in irq trap + */ + +#include +#include "s3c44b0.h" + +#define MAX_HANDLERS 26 + +extern rt_uint32_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +rt_isr_handler_t isr_table[MAX_HANDLERS]; +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +unsigned char interrupt_bank0[256]; +unsigned char interrupt_bank1[256]; +unsigned char interrupt_bank2[256]; +unsigned char interrupt_bank3[256]; + +/** + * @addtogroup S3C44B0 + */ +/*@{*/ + +void rt_hw_interrupt_handle(int vector) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init() +{ + register int i; + + /* all interrupt disabled include global bit */ + INTMSK = 0x07ffffff; + + /* clear pending register */ + I_ISPC = 0x03ffffff; + + /* non-vector mode IRQ enable */ + INTCON = 0x5; + + /* all IRQ mode */ + INTMOD = 0x0; + + /* init exceptions table */ + for(i=0; i +#include + +#include "s3c44b0.h" + +void rt_serial_init(void); +void rt_console_puts(const char* str); +void rt_serial_putc(const char c); + +#define USTAT_RCV_READY 0x01 /* receive data ready */ +#define USTAT_TXB_EMPTY 0x02 /* tx buffer empty */ + +rt_inline void serial_flush_input(void) +{ + volatile unsigned int tmp; + + /* keep on reading as long as the receiver is not empty */ + while(UTRSTAT0 & USTAT_RCV_READY) tmp = URXH0; +} + +rt_inline void serial_flush_output(void) +{ + /* wait until the transmitter is no longer busy */ + while(!(UTRSTAT0 & USTAT_TXB_EMPTY)) ; +} + +/** + * @addtogroup S3C44B0 + */ +/*@{*/ + +/** + * This function is used to display a string on console, normally, it's + * invoked by rt_kprintf + * + * @param str the displayed string + */ +void rt_console_puts(const char* str) +{ + while (*str) + { + rt_serial_putc (*str++); + } +} + +/** + * This function initializes serial + */ +void rt_serial_init() +{ + rt_uint32_t divisor = 0; + + divisor = 0x20; + + serial_flush_output(); + serial_flush_input(); + + /* UART interrupt off */ + UCON0 = 0; + /* FIFO disable */ + UFCON0 =0x0; + UMCON0 =0x0; + /* set baudrate */ + UBRDIV0 = divisor; + + /* word length=8bit, stop bit = 1, no parity, use external clock */ + ULCON0 = 0x03|0x00|0x00; + + UCON0 = 0x5; +} + +/** + * This function read a character from serial without interrupt enable mode + * + * @return the read char + */ +char rt_serial_getc() +{ + while ((UTRSTAT0 & USTAT_RCV_READY) == 0); + + return URXH0; +} + +/** + * This function will write a character to serial without interrupt enable mode + * + * @param c the char to write + */ +void rt_serial_putc(const char c) +{ + /* + to be polite with serial console add a line feed + to the carriage return character + */ + if (c=='\n')rt_serial_putc('\r'); + + /* wait for room in the transmit FIFO */ + while(!(UTRSTAT0 & USTAT_TXB_EMPTY)); + + UTXH0 = (rt_uint8_t)c; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/s3c44b0/stack.c b/rt-thread/libcpu/arm/s3c44b0/stack.c new file mode 100644 index 0000000..6f838cb --- /dev/null +++ b/rt-thread/libcpu/arm/s3c44b0/stack.c @@ -0,0 +1,62 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-09-06 XuXinming first version + */ +#include +#include "s3c44b0.h" + +/** + * @addtogroup S3C44B0 + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + *(--stk) = SVCMODE; /* cpsr */ + *(--stk) = SVCMODE; /* spsr */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/s3c44b0/start_gcc.S b/rt-thread/libcpu/arm/s3c44b0/start_gcc.S new file mode 100644 index 0000000..17a3d0d --- /dev/null +++ b/rt-thread/libcpu/arm/s3c44b0/start_gcc.S @@ -0,0 +1,257 @@ +/* + * File : start.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-09-06 XuXinming first version + * 2006-09-20 Bernard clean the code + */ + +/** + * @addtogroup S3C44B0 + */ +/*@{*/ + +.section .init, "ax" +.code 32 +.globl _start +_start: + b reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + ldr pc, _vector_resv + ldr pc, _vector_irq + ldr pc, _vector_fiq + +_vector_undef: .word vector_undef +_vector_swi: .word vector_swi +_vector_pabt: .word vector_pabt +_vector_dabt: .word vector_dabt +_vector_resv: .word vector_resv +_vector_irq: .word vector_irq +_vector_fiq: .word vector_fiq + +.text +.code 32 + +/* + * rtthread kernel start and end + * which are defined in linker script + */ +.globl _rtthread_start +_rtthread_start:.word _start +.globl _rtthread_end +_rtthread_end: .word _end + +/* + * rtthread bss start and end + * which are defined in linker script + */ +.globl _bss_start +_bss_start: .word __bss_start +.globl _bss_end +_bss_end: .word __bss_end + +#if defined(__FLASH_BUILD__) +/* + * TEXT_BASE, + * which is defined in macro of make + */ +_TEXT_BASE: .word TEXT_BASE +#endif + + .equ WTCON, 0x1d30000 + .equ INTCON, 0x1e00000 + .equ INTMSK, 0x1e0000c + +/* the system entry */ +reset: + /* enter svc mode */ + msr cpsr_c, #SVCMODE|NOINT + + /*watch dog disable */ + ldr r0,=WTCON + ldr r1,=0x0 + str r1,[r0] + + /* all interrupt disable */ + ldr r0,=INTMSK + ldr r1,=0x07ffffff + str r1,[r0] + + ldr r1, =INTCON + ldr r0, =0x05 + str r0, [r1] + +#if defined(__FLASH_BUILD__) + /* init lowlevel */ + bl lowlevel_init +#endif + + /* setup stack */ + bl stack_setup + +#if defined(__FLASH_BUILD__) + mov r0, #0x0 /* r0 <- flash base address */ + ldr r1, _TEXT_BASE /* r1 <- the taget address */ + + ldr r2, _rtthread_start + ldr r3, _bss_start + sub r2, r3, r2 /* r2 <- size of rtthread kernel */ + add r2, r0, r2 /* r2 <- source end address */ + +copy_loop: + ldmia r0!, {r3-r10} /* copy from source address [r0] */ + stmia r1!, {r3-r10} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop +#endif + + /* start RT-Thread Kernel */ + ldr pc, _rtthread_startup + +_rtthread_startup: .word rtthread_startup + + .equ USERMODE, 0x10 + .equ FIQMODE, 0x11 + .equ IRQMODE, 0x12 + .equ SVCMODE, 0x13 + .equ ABORTMODE, 0x17 + .equ UNDEFMODE, 0x1b + .equ MODEMASK, 0x1f + .equ NOINT, 0xc0 + +/* exception handlers */ +vector_undef: bl rt_hw_trap_udef +vector_swi: bl rt_hw_trap_swi +vector_pabt: bl rt_hw_trap_pabt +vector_dabt: bl rt_hw_trap_dabt +vector_resv: bl rt_hw_trap_resv + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +vector_irq: + stmfd sp!, {r0-r12,lr} + bl led_off + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + + /* if rt_thread_switch_interrupt_flag set, jump to _interrupt_thread_switch and don't return */ + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq _interrupt_thread_switch + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + + .align 5 +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc,lr,#4 + +_interrupt_thread_switch: + mov r1, #0 @ clear rt_thread_switch_interrupt_flag + str r1, [r0] + + ldmfd sp!, {r0-r12,lr} @ reload saved registers + stmfd sp!, {r0-r3} @ save r0-r3 + mov r1, sp + add sp, sp, #16 @ restore sp + sub r2, lr, #4 @ save old task's pc to r2 + + mrs r3, spsr @ disable interrupt + orr r0, r3, #NOINT + msr spsr_c, r0 + + ldr r0, =.+8 @ switch to interrupted task's stack + movs pc, r0 + + stmfd sp!, {r2} @ push old task's pc + stmfd sp!, {r4-r12,lr} @ push old task's lr,r12-r4 + mov r4, r1 @ Special optimised code below + mov r5, r3 + ldmfd r4!, {r0-r3} + stmfd sp!, {r0-r3} @ push old task's r3-r0 + stmfd sp!, {r5} @ push old task's psr + mrs r4, spsr + stmfd sp!, {r4} @ push old task's spsr + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] @ store sp in preempted tasks's TCB + + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] @ get new task's stack pointer + + ldmfd sp!, {r4} @ pop new task's spsr + msr SPSR_cxsf, r4 + ldmfd sp!, {r4} @ pop new task's psr + msr CPSR_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc} @ pop new task's r0-r12,lr & pc + +/* each mode stack memory */ +UNDSTACK_START: .word _undefined_stack_start + 128 +ABTSTACK_START: .word _abort_stack_start + 128 +FIQSTACK_START: .word _fiq_stack_start + 1024 +IRQSTACK_START: .word _irq_stack_start + 1024 +SVCSTACK_START: .word _svc_stack_start + 4096 + +stack_setup: + /* undefined instruction mode */ + msr cpsr_c, #UNDEFMODE|NOINT + ldr sp, UNDSTACK_START + + /* abort mode */ + msr cpsr_c, #ABORTMODE|NOINT + ldr sp, ABTSTACK_START + + /* FIQ mode */ + msr cpsr_c, #FIQMODE|NOINT + ldr sp, FIQSTACK_START + + /* IRQ mode */ + msr cpsr_c, #IRQMODE|NOINT + ldr sp, IRQSTACK_START + + /* supervisor mode */ + msr cpsr_c, #SVCMODE|NOINT + ldr sp, SVCSTACK_START + + mov pc,lr @ The LR register may be not valid for the mode changes. + +.globl led_on +led_on: + ldr r1, =0x1d20014 @ r1<-PDATC + ldr r0, [r1] @ r0<-[r1] + orr r0, r0, #0x0e @ r0=r0 or 0x0e + str r0, [r1] @ r0->[r1] + mov pc, lr + +.globl led_off +led_off: + ldr r1, =0x1d20010 @ r1<-PCONC + ldr r0, =0x5f555555 @ r0<-0x5f555555 + str r0, [r1] @ r0->[r1] + + ldr r1, =0x1d20014 @ r1<-PDATC + ldr r0, =0x0 @ r0<-00 + str r0, [r1] @ r0->[r1] + + mov pc, lr diff --git a/rt-thread/libcpu/arm/s3c44b0/start_rvds.S b/rt-thread/libcpu/arm/s3c44b0/start_rvds.S new file mode 100644 index 0000000..b5c9048 --- /dev/null +++ b/rt-thread/libcpu/arm/s3c44b0/start_rvds.S @@ -0,0 +1,1072 @@ +;/*****************************************************************************/ +;/* S3C44B0X.S: Startup file for Samsung S3C44B0X */ +;/*****************************************************************************/ +;/* <<< Use Configuration Wizard in Context Menu >>> */ +;/*****************************************************************************/ +;/* This file is part of the uVision/ARM development tools. */ +;/* Copyright (c) 2005-2006 Keil Software. All rights reserved. */ +;/* This software may only be used under the terms of a valid, current, */ +;/* end user licence from KEIL for a compatible version of KEIL software */ +;/* development tools. Nothing else gives you the right to use this software. */ +;/*****************************************************************************/ + + +; *** Startup Code (executed after Reset) *** + + +; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs + +Mode_USR EQU 0x10 +Mode_FIQ EQU 0x11 +Mode_IRQ EQU 0x12 +Mode_SVC EQU 0x13 +Mode_ABT EQU 0x17 +Mode_UND EQU 0x1B +Mode_SYS EQU 0x1F + +I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled +F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled + + +;// Stack Configuration (Stack Sizes in Bytes) +;// Undefined Mode <0x0-0xFFFFFFFF:8> +;// Supervisor Mode <0x0-0xFFFFFFFF:8> +;// Abort Mode <0x0-0xFFFFFFFF:8> +;// Fast Interrupt Mode <0x0-0xFFFFFFFF:8> +;// Interrupt Mode <0x0-0xFFFFFFFF:8> +;// User/System Mode <0x0-0xFFFFFFFF:8> +;// + +UND_Stack_Size EQU 0x00000000 +SVC_Stack_Size EQU 0x00000100 +ABT_Stack_Size EQU 0x00000000 +FIQ_Stack_Size EQU 0x00000000 +IRQ_Stack_Size EQU 0x00000100 +USR_Stack_Size EQU 0x00000100 + +ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + FIQ_Stack_Size + IRQ_Stack_Size) + + AREA STACK, NOINIT, READWRITE, ALIGN=3 + +Stack_Mem SPACE USR_Stack_Size +__initial_sp SPACE ISR_Stack_Size +Stack_Top + + +;// Heap Configuration +;// Heap Size (in Bytes) <0x0-0xFFFFFFFF> +;// + +Heap_Size EQU 0x00000000 + + AREA HEAP, NOINIT, READWRITE, ALIGN=3 +__heap_base +Heap_Mem SPACE Heap_Size +__heap_limit + + +; CPU Wrapper and Bus Priorities definitions +CPUW_BASE EQU 0x01C00000 ; CPU Wrapper Base Address +SYSCFG_OFS EQU 0x00 ; SYSCFG Offset +NCACHBE0_OFS EQU 0x04 ; NCACHBE0 Offset +NCACHBE1_OFS EQU 0x08 ; NCACHBE0 Offset +BUSP_BASE EQU 0x01C40000 ; Bus Priority Base Address +SBUSCON_OFS EQU 0x00 ; SBUSCON Offset + +;// CPU Wrapper and Bus Priorities +;// CPU Wrapper +;// SE: Stall Enable +;// CM: Cache Mode +;// <0=> Disable Cache (8kB SRAM) +;// <1=> Half Cache Enable (4kB Cache, 4kB SRAM) +;// <2=> Reserved +;// <3=> Full Cache Enable (8kB Cache) +;// WE: Write Buffer Enable +;// RSE: Read Stall Enable +;// DA: Data Abort <0=> Enable <1=> Disable +;// Non-cacheable Area 0 +;// Start Address <0x0-0x0FFFF000:0x1000><#/0x1000> +;// SA = (Start Address) / 4k +;// End Address + 1 <0x0-0x10000000:0x1000><#/0x1000> +;// SE = (End Address + 1) / 4k +;// +;// Non-cacheable Area 1 +;// Start Address <0x0-0x0FFFF000:0x1000><#/0x1000> +;// SA = (Start Address) / 4k +;// End Address + 1 <0x0-0x10000000:0x1000><#/0x1000> +;// SE = (End Address + 1) / 4k +;// +;// +;// Bus Priorities +;// FIX: Fixed Priorities +;// LCD_DMA <0=> 1st <1=> 2nd <2=> 3rd <3=> 4th +;// ZDMA <0=> 1st <1=> 2nd <2=> 3rd <3=> 4th +;// BDMA <0=> 1st <1=> 2nd <2=> 3rd <3=> 4th +;// nBREQ <0=> 1st <1=> 2nd <2=> 3rd <3=> 4th +;// +;// +SYS_SETUP EQU 0 +SYSCFG_Val EQU 0x00000001 +NCACHBE0_Val EQU 0x00000000 +NCACHBE1_Val EQU 0x00000000 +SBUSCON_Val EQU 0x80001B1B + + +;// Vectored Interrupt Mode (for IRQ) +;// EINT0 External Interrupt 0 +;// EINT1 External Interrupt 1 +;// EINT2 External Interrupt 2 +;// EINT3 External Interrupt 3 +;// EINT4567 External Interrupt 4/5/6/7 +;// TICK RTC Time Tick Interrupt +;// ZDMA0 General DMA0 Interrupt +;// ZDMA1 General DMA1 Interrupt +;// BDMA0 Bridge DMA0 Interrupt +;// BDMA1 Bridge DMA1 Interrupt +;// WDT Watchdog Timer Interrupt +;// UERR01 UART0/1 Error Interrupt +;// TIMER0 Timer0 Interrupt +;// TIMER1 Timer1 Interrupt +;// TIMER2 Timer2 Interrupt +;// TIMER3 Timer3 Interrupt +;// TIMER4 Timer4 Interrupt +;// TIMER5 Timer5 Interrupt +;// URXD0 UART0 Rx Interrupt +;// URXD1 UART1 Rx Interrupt +;// IIC IIC Interrupt +;// SIO SIO Interrupt +;// UTXD0 UART0 Tx Interrupt +;// UTXD1 UART1 Tx Interrupt +;// RTC RTC Alarm Interrupt +;// ADC ADC EOC Interrupt +;// +VIM_SETUP EQU 0 +VIM_CFG EQU 0x00000000 + + +; Clock Management definitions +CLK_BASE EQU 0x01D80000 ; Clock Base Address +PLLCON_OFS EQU 0x00 ; PLLCON Offset +CLKCON_OFS EQU 0x04 ; CLKCON Offset +CLKSLOW_OFS EQU 0x08 ; CLKSLOW Offset +LOCKTIME_OFS EQU 0x0C ; LOCKTIME Offset + +;// Clock Management +;// PLL Settings +;// Fpllo = (m * Fin) / (p * 2^s), 20MHz < Fpllo < 66MHz +;// MDIV: Main divider <0x0-0xFF> +;// m = MDIV + 8 +;// PDIV: Pre-divider <0x0-0x3F> +;// p = PDIV + 2, 1MHz <= Fin/p < 2MHz +;// SDIV: Post Divider <0x0-0x03> +;// s = SDIV, Fpllo * 2^s < 170MHz +;// LTIME CNT: PLL Lock Time Count <0x0-0x0FFF> +;// +;// Master Clock +;// PLL Clock: Fout = Fpllo +;// Slow Clock: Fout = Fin / (2 * SLOW_VAL), SLOW_VAL > 0 +;// Slow Clock: Fout = Fin, SLOW_VAL = 0 +;// PLL_OFF: PLL Off +;// PLL is turned Off only when SLOW_BIT = 1 +;// SLOW_BIT: Slow Clock +;// SLOW_VAL: Slow Clock divider <0x0-0x0F> +;// +;// Clock Generation +;// IIS <0=> Disable <1=> Enable +;// IIC <0=> Disable <1=> Enable +;// ADC <0=> Disable <1=> Enable +;// RTC <0=> Disable <1=> Enable +;// GPIO <0=> Disable <1=> Enable +;// UART1 <0=> Disable <1=> Enable +;// UART0 <0=> Disable <1=> Enable +;// BDMA0,1 <0=> Disable <1=> Enable +;// LCDC <0=> Disable <1=> Enable +;// SIO <0=> Disable <1=> Enable +;// ZDMA0,1 <0=> Disable <1=> Enable +;// PWMTIMER <0=> Disable <1=> Enable +;// +;// +CLK_SETUP EQU 1 +PLLCON_Val EQU 0x00038080 +CLKCON_Val EQU 0x00007FF8 +CLKSLOW_Val EQU 0x00000009 +LOCKTIME_Val EQU 0x00000FFF + + +; Watchdog Timer definitions +WT_BASE EQU 0x01D30000 ; WT Base Address +WTCON_OFS EQU 0x00 ; WTCON Offset +WTDAT_OFS EQU 0x04 ; WTDAT Offset +WTCNT_OFS EQU 0x08 ; WTCNT Offset + +;// Watchdog Timer +;// Watchdog Timer Enable/Disable +;// Reset Enable/Disable +;// Interrupt Enable/Disable +;// Clock Select +;// <0=> 1/16 <1=> 1/32 <2=> 1/64 <3=> 1/128 +;// Clock Division Factor +;// Prescaler Value <0x0-0xFF> +;// Time-out Value <0x0-0xFFFF> +;// +WT_SETUP EQU 1 +WTCON_Val EQU 0x00008000 +WTDAT_Val EQU 0x00008000 + + +; Memory Controller definitions +MC_BASE EQU 0x01C80000 ; Memory Controller Base Address + +;// Memory Controller +MC_SETUP EQU 1 + +;// Bank 0 +;// PMC: Page Mode Configuration +;// <0=> 1 Data <1=> 4 Data <2=> 8 Data <3=> 16 Data +;// Tpac: Page Mode Access Cycle +;// <0=> 2 clks <1=> 3 clks <2=> 4 clks <3=> 6 clks +;// Tcah: Address Holding Time after nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Toch: Chip Select Hold on nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacc: Access Cycle +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// <4=> 6 clk <5=> 8 clks <6=> 10 clks <7=> 14 clks +;// Tcos: Chip Select Set-up nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacs: Address Set-up before nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// +;// +;// Bank 1 +;// DW: Data Bus Width +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Rsrvd +;// WS: WAIT Status +;// <0=> WAIT Disable +;// <1=> WAIT Enable +;// ST: SRAM Type +;// <0=> Not using UB/LB +;// <1=> Using UB/LB +;// PMC: Page Mode Configuration +;// <0=> 1 Data <1=> 4 Data <2=> 8 Data <3=> 16 Data +;// Tpac: Page Mode Access Cycle +;// <0=> 2 clks <1=> 3 clks <2=> 4 clks <3=> 6 clks +;// Tcah: Address Holding Time after nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Toch: Chip Select Hold on nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacc: Access Cycle +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// <4=> 6 clk <5=> 8 clks <6=> 10 clks <7=> 14 clks +;// Tcos: Chip Select Set-up nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacs: Address Set-up before nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// +;// +;// Bank 2 +;// DW: Data Bus Width +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Rsrvd +;// WS: WAIT Status +;// <0=> WAIT Disable +;// <1=> WAIT Enable +;// ST: SRAM Type +;// <0=> Not using UB/LB +;// <1=> Using UB/LB +;// PMC: Page Mode Configuration +;// <0=> 1 Data <1=> 4 Data <2=> 8 Data <3=> 16 Data +;// Tpac: Page Mode Access Cycle +;// <0=> 2 clks <1=> 3 clks <2=> 4 clks <3=> 6 clks +;// Tcah: Address Holding Time after nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Toch: Chip Select Hold on nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacc: Access Cycle +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// <4=> 6 clk <5=> 8 clks <6=> 10 clks <7=> 14 clks +;// Tcos: Chip Select Set-up nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacs: Address Set-up before nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// +;// +;// Bank 3 +;// DW: Data Bus Width +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Rsrvd +;// WS: WAIT Status +;// <0=> WAIT Disable +;// <1=> WAIT Enable +;// ST: SRAM Type +;// <0=> Not using UB/LB +;// <1=> Using UB/LB +;// PMC: Page Mode Configuration +;// <0=> 1 Data <1=> 4 Data <2=> 8 Data <3=> 16 Data +;// Tpac: Page Mode Access Cycle +;// <0=> 2 clks <1=> 3 clks <2=> 4 clks <3=> 6 clks +;// Tcah: Address Holding Time after nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Toch: Chip Select Hold on nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacc: Access Cycle +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// <4=> 6 clk <5=> 8 clks <6=> 10 clks <7=> 14 clks +;// Tcos: Chip Select Set-up nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacs: Address Set-up before nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// +;// +;// Bank 4 +;// DW: Data Bus Width +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Rsrvd +;// WS: WAIT Status +;// <0=> WAIT Disable +;// <1=> WAIT Enable +;// ST: SRAM Type +;// <0=> Not using UB/LB +;// <1=> Using UB/LB +;// PMC: Page Mode Configuration +;// <0=> 1 Data <1=> 4 Data <2=> 8 Data <3=> 16 Data +;// Tpac: Page Mode Access Cycle +;// <0=> 2 clks <1=> 3 clks <2=> 4 clks <3=> 6 clks +;// Tcah: Address Holding Time after nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Toch: Chip Select Hold on nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacc: Access Cycle +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// <4=> 6 clk <5=> 8 clks <6=> 10 clks <7=> 14 clks +;// Tcos: Chip Select Set-up nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacs: Address Set-up before nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// +;// +;// Bank 5 +;// DW: Data Bus Width +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Rsrvd +;// WS: WAIT Status +;// <0=> WAIT Disable +;// <1=> WAIT Enable +;// ST: SRAM Type +;// <0=> Not using UB/LB +;// <1=> Using UB/LB +;// PMC: Page Mode Configuration +;// <0=> 1 Data <1=> 4 Data <2=> 8 Data <3=> 16 Data +;// Tpac: Page Mode Access Cycle +;// <0=> 2 clks <1=> 3 clks <2=> 4 clks <3=> 6 clks +;// Tcah: Address Holding Time after nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Toch: Chip Select Hold on nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacc: Access Cycle +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// <4=> 6 clk <5=> 8 clks <6=> 10 clks <7=> 14 clks +;// Tcos: Chip Select Set-up nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacs: Address Set-up before nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// +;// +;// Bank 6 +;// BK76MAP: Bank 6/7 Memory Map +;// <0=> 32M <4=> 2M <5=> 4M <6=> 8M <7=> 16M +;// DW: Data Bus Width +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Rsrvd +;// WS: WAIT Status +;// <0=> WAIT Disable +;// <1=> WAIT Enable +;// ST: SRAM Type +;// <0=> Not using UB/LB +;// <1=> Using UB/LB +;// MT: Memory Type +;// <0=> ROM or SRAM +;// <1=> FP DRAMP +;// <2=> EDO DRAM +;// <3=> SDRAM +;// ROM or SRAM +;// PMC: Page Mode Configuration +;// <0=> 1 Data <1=> 4 Data <2=> 8 Data <3=> 16 Data +;// Tpac: Page Mode Access Cycle +;// <0=> 2 clks <1=> 3 clks <2=> 4 clks <3=> 6 clks +;// Tcah: Address Holding Time after nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Toch: Chip Select Hold on nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacc: Access Cycle +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// <4=> 6 clk <5=> 8 clks <6=> 10 clks <7=> 14 clks +;// Tcos: Chip Select Set-up nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacs: Address Set-up before nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// +;// FP DRAM or EDO DRAM +;// CAN: Columnn Address Number +;// <0=> 8-bit <1=> 9-bit <2=> 10-bit <3=> 11-bit +;// Tcp: CAS Pre-charge +;// <0=> 1 clk <1=> 2 clks +;// Tcas: CAS Pulse Width +;// <0=> 1 clk <1=> 2 clks +;// Trcd: RAS to CAS Delay +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// +;// SDRAM +;// SCAN: Columnn Address Number +;// <0=> 8-bit <1=> 9-bit <2=> 10-bit <3=> Rsrvd +;// Trcd: RAS to CAS Delay +;// <0=> 2 clks <1=> 3 clks <2=> 4 clks <3=> Rsrvd +;// SCLKEN: SCLK Selection (Bank 6/7) +;// <0=> Normal +;// <1=> Reduced Power +;// BL: Burst Length +;// <0=> 1 +;// BT: Burst Type +;// <0=> Sequential +;// CL: CAS Latency +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks +;// TM: Test Mode +;// <0=> Mode Register Set +;// WBL: Write Burst Length +;// <0=> 0 +;// +;// +;// +;// Bank 7 +;// BK76MAP: Bank 6/7 Memory Map +;// <0=> 32M <4=> 2M <5=> 4M <6=> 8M <7=> 16M +;// DW: Data Bus Width +;// <0=> 8-bit <1=> 16-bit <2=> 32-bit <3=> Rsrvd +;// WS: WAIT Status +;// <0=> WAIT Disable +;// <1=> WAIT Enable +;// ST: SRAM Type +;// <0=> Not using UB/LB +;// <1=> Using UB/LB +;// MT: Memory Type +;// <0=> ROM or SRAM +;// <1=> FP DRAMP +;// <2=> EDO DRAM +;// <3=> SDRAM +;// ROM or SRAM +;// PMC: Page Mode Configuration +;// <0=> 1 Data <1=> 4 Data <2=> 8 Data <3=> 16 Data +;// Tpac: Page Mode Access Cycle +;// <0=> 2 clks <1=> 3 clks <2=> 4 clks <3=> 6 clks +;// Tcah: Address Holding Time after nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Toch: Chip Select Hold on nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacc: Access Cycle +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// <4=> 6 clk <5=> 8 clks <6=> 10 clks <7=> 14 clks +;// Tcos: Chip Select Set-up nOE +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// Tacs: Address Set-up before nGCSn +;// <0=> 0 clk <1=> 1 clk <2=> 2 clks <3=> 4 clks +;// +;// FP DRAM or EDO DRAM +;// CAN: Columnn Address Number +;// <0=> 8-bit <1=> 9-bit <2=> 10-bit <3=> 11-bit +;// Tcp: CAS Pre-charge +;// <0=> 1 clk <1=> 2 clks +;// Tcas: CAS Pulse Width +;// <0=> 1 clk <1=> 2 clks +;// Trcd: RAS to CAS Delay +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// +;// SDRAM +;// SCAN: Columnn Address Number +;// <0=> 8-bit <1=> 9-bit <2=> 10-bit <3=> Rsrvd +;// Trcd: RAS to CAS Delay +;// <0=> 2 clks <1=> 3 clks <2=> 4 clks <3=> Rsrvd +;// SCLKEN: SCLK Selection (Bank 6/7) +;// <0=> Normal +;// <1=> Reduced Power +;// BL: Burst Length +;// <0=> 1 +;// BT: Burst Type +;// <0=> Sequential +;// CL: CAS Latency +;// <0=> 1 clk <1=> 2 clks <2=> 3 clks +;// TM: Test Mode +;// <0=> Mode Register Set +;// WBL: Write Burst Length +;// <0=> 0 +;// +;// +;// +;// Refresh +;// REFEN: DRAM/SDRAM Refresh +;// <0=> Disable <1=> Enable +;// TREFMD: DRAM/SDRAM Refresh Mode +;// <0=> CBR/Auto Refresh +;// <1=> Self Refresh +;// Trp: DRAM/SDRAM RAS Pre-charge Time +;// <0=> 1.5 clks (DRAM) / 2 clks (SDRAM) +;// <1=> 2.5 clks (DRAM) / 3 clks (SDRAM) +;// <2=> 3.5 clks (DRAM) / 4 clks (SDRAM) +;// <3=> 4.5 clks (DRAM) / Rsrvd (SDRAM) +;// Trc: SDRAM RC Min Time +;// <0=> 4 clks <1=> 5 clks <2=> 6 clks <3=> 7 clks +;// Tchr: DRAM CAS Hold Time +;// <0=> 1 clks <1=> 2 clks <2=> 3 clks <3=> 4 clks +;// Refresh Counter <0x0-0x07FF> +;// Refresh Period = (2^11 - Refresh Count + 1) / MCLK +;// +BANKCON0_Val EQU 0x00000700 +BANKCON1_Val EQU 0x00000700 +BANKCON2_Val EQU 0x00000700 +BANKCON3_Val EQU 0x00000700 +BANKCON4_Val EQU 0x00000700 +BANKCON5_Val EQU 0x00000700 +BANKCON6_Val EQU 0x00018008 +BANKCON7_Val EQU 0x00018008 +BWSCON_Val EQU 0x00000000 +REFRESH_Val EQU 0x00AC0000 +BANKSIZE_Val EQU 0x00000000 +MRSRB6_Val EQU 0x00000000 +MRSRB7_Val EQU 0x00000000 + +;// End of MC + + +; I/O Ports definitions +PIO_BASE EQU 0x01D20000 ; PIO Base Address +PCONA_OFS EQU 0x00 ; PCONA Offset +PCONB_OFS EQU 0x08 ; PCONB Offset +PCONC_OFS EQU 0x10 ; PCONC Offset +PCOND_OFS EQU 0x1C ; PCOND Offset +PCONE_OFS EQU 0x28 ; PCONE Offset +PCONF_OFS EQU 0x34 ; PCONF Offset +PCONG_OFS EQU 0x40 ; PCONG Offset +PUPC_OFS EQU 0x18 ; PUPC Offset +PUPD_OFS EQU 0x24 ; PUPD Offset +PUPE_OFS EQU 0x30 ; PUPE Offset +PUPF_OFS EQU 0x3C ; PUPF Offset +PUPG_OFS EQU 0x48 ; PUPG Offset +SPUCR_OFS EQU 0x4C ; SPUCR Offset + +;// I/O Configuration +PIO_SETUP EQU 0 + +;// Port A +;// PA0 <0=> Output <1=> ADDR0 +;// PA1 <0=> Output <1=> ADDR16 +;// PA2 <0=> Output <1=> ADDR17 +;// PA3 <0=> Output <1=> ADDR18 +;// PA4 <0=> Output <1=> ADDR19 +;// PA5 <0=> Output <1=> ADDR20 +;// PA6 <0=> Output <1=> ADDR21 +;// PA7 <0=> Output <1=> ADDR22 +;// PA8 <0=> Output <1=> ADDR23 +;// PA9 <0=> Output <1=> ADDR24 +;// +PIOA_SETUP EQU 1 +PCONA_Val EQU 0x000003FF + +;// Port B +;// PB0 <0=> Output <1=> SCKE +;// PB1 <0=> Output <1=> CKLK +;// PB2 <0=> Output <1=> nSCAS/nCAS2 +;// PB3 <0=> Output <1=> nSRAS/nCAS3 +;// PB4 <0=> Output <1=> nWBE2/nBE2/DQM2 +;// PB5 <0=> Output <1=> nWBE3/nBE3/DQM3 +;// PB6 <0=> Output <1=> nGCS1 +;// PB7 <0=> Output <1=> nGCS2 +;// PB8 <0=> Output <1=> nGCS3 +;// PB9 <0=> Output <1=> nGCS4 +;// PB10 <0=> Output <1=> nGCS5 +;// +PIOB_SETUP EQU 1 +PCONB_Val EQU 0x000007FF + +;// Port C +;// PC0 <0=> Input <1=> Output <2=> DATA16 <3=> IISLRCK +;// PC1 <0=> Input <1=> Output <2=> DATA17 <3=> IISDO +;// PC2 <0=> Input <1=> Output <2=> DATA18 <3=> IISDI +;// PC3 <0=> Input <1=> Output <2=> DATA19 <3=> IISCLK +;// PC4 <0=> Input <1=> Output <2=> DATA20 <3=> VD7 +;// PC5 <0=> Input <1=> Output <2=> DATA21 <3=> VD6 +;// PC6 <0=> Input <1=> Output <2=> DATA22 <3=> VD5 +;// PC7 <0=> Input <1=> Output <2=> DATA23 <3=> VD4 +;// PC8 <0=> Input <1=> Output <2=> DATA24 <3=> nXDACK1 +;// PC9 <0=> Input <1=> Output <2=> DATA25 <3=> nXDREQ1 +;// PC10 <0=> Input <1=> Output <2=> DATA26 <3=> nRTS1 +;// PC11 <0=> Input <1=> Output <2=> DATA27 <3=> nCTS1 +;// PC12 <0=> Input <1=> Output <2=> DATA28 <3=> TxD1 +;// PC13 <0=> Input <1=> Output <2=> DATA29 <3=> RxD1 +;// PC14 <0=> Input <1=> Output <2=> DATA30 <3=> nRTS0 +;// PC15 <0=> Input <1=> Output <2=> DATA31 <3=> nCTS0 +;// Pull-up Resistors +;// PC0 Pull-up <0=> Enabled <1=> Disabled +;// PC1 Pull-up <0=> Enabled <1=> Disabled +;// PC2 Pull-up <0=> Enabled <1=> Disabled +;// PC3 Pull-up <0=> Enabled <1=> Disabled +;// PC4 Pull-up <0=> Enabled <1=> Disabled +;// PC5 Pull-up <0=> Enabled <1=> Disabled +;// PC6 Pull-up <0=> Enabled <1=> Disabled +;// PC7 Pull-up <0=> Enabled <1=> Disabled +;// PC8 Pull-up <0=> Enabled <1=> Disabled +;// PC9 Pull-up <0=> Enabled <1=> Disabled +;// PC10 Pull-up <0=> Enabled <1=> Disabled +;// PC11 Pull-up <0=> Enabled <1=> Disabled +;// PC12 Pull-up <0=> Enabled <1=> Disabled +;// PC13 Pull-up <0=> Enabled <1=> Disabled +;// PC14 Pull-up <0=> Enabled <1=> Disabled +;// PC15 Pull-up <0=> Enabled <1=> Disabled +;// +;// +PIOC_SETUP EQU 1 +PCONC_Val EQU 0xAAAAAAAA +PUPC_Val EQU 0x00000000 + +;// Port D +;// PD0 <0=> Input <1=> Output <2=> VD0 <3=> Reserved +;// PD1 <0=> Input <1=> Output <2=> VD1 <3=> Reserved +;// PD2 <0=> Input <1=> Output <2=> VD2 <3=> Reserved +;// PD3 <0=> Input <1=> Output <2=> VD3 <3=> Reserved +;// PD4 <0=> Input <1=> Output <2=> VCLK <3=> Reserved +;// PD5 <0=> Input <1=> Output <2=> VLINE <3=> Reserved +;// PD6 <0=> Input <1=> Output <2=> VM <3=> Reserved +;// PD7 <0=> Input <1=> Output <2=> VFRAME <3=> Reserved +;// Pull-up Resistors +;// PD0 Pull-up <0=> Enabled <1=> Disabled +;// PD1 Pull-up <0=> Enabled <1=> Disabled +;// PD2 Pull-up <0=> Enabled <1=> Disabled +;// PD3 Pull-up <0=> Enabled <1=> Disabled +;// PD4 Pull-up <0=> Enabled <1=> Disabled +;// PD5 Pull-up <0=> Enabled <1=> Disabled +;// PD6 Pull-up <0=> Enabled <1=> Disabled +;// PD7 Pull-up <0=> Enabled <1=> Disabled +;// +;// +PIOD_SETUP EQU 1 +PCOND_Val EQU 0x00000000 +PUPD_Val EQU 0x00000000 + +;// Port E +;// PE0 <0=> Input <1=> Output <2=> Fpllo <3=> Fout +;// PE1 <0=> Input <1=> Output <2=> TxD0 <3=> Reserved +;// PE2 <0=> Input <1=> Output <2=> RxD0 <3=> Reserved +;// PE3 <0=> Input <1=> Output <2=> TOUT0 <3=> Reserved +;// PE4 <0=> Input <1=> Output <2=> TOUT1 <3=> TCLK +;// PE5 <0=> Input <1=> Output <2=> TOUT2 <3=> TCLK +;// PE6 <0=> Input <1=> Output <2=> TOUT3 <3=> VD6 +;// PE7 <0=> Input <1=> Output <2=> TOUT4 <3=> VD7 +;// PE8 <0=> Input <1=> Output <2=> CODECLK <3=> Reserved +;// Pull-up Resistors +;// PE0 Pull-up <0=> Enabled <1=> Disabled +;// PE1 Pull-up <0=> Enabled <1=> Disabled +;// PE2 Pull-up <0=> Enabled <1=> Disabled +;// PE3 Pull-up <0=> Enabled <1=> Disabled +;// PE4 Pull-up <0=> Enabled <1=> Disabled +;// PE5 Pull-up <0=> Enabled <1=> Disabled +;// PE6 Pull-up <0=> Enabled <1=> Disabled +;// PE7 Pull-up <0=> Enabled <1=> Disabled +;// PE8 Pull-up <0=> Enabled <1=> Disabled +;// +;// +PIOE_SETUP EQU 1 +PCONE_Val EQU 0x00000000 +PUPE_Val EQU 0x00000000 + +;// Port F +;// PF0 <0=> Input <1=> Output <2=> IICSCL <3=> Reserved +;// PF1 <0=> Input <1=> Output <2=> IICSDA <3=> Reserved +;// PF2 <0=> Input <1=> Output <2=> nWAIT <3=> Reserved +;// PF3 <0=> Input <1=> Output <2=> nXBACK <3=> nXDACK0 +;// PF4 <0=> Input <1=> Output <2=> nXBREQ <3=> nXDREQ0 +;// PF5 <0=> Input <1=> Output <2=> nRTS1 <3=> SIOTxD +;// <4=> IISLRCK <5=> Reserved <6=> Reserved <7=> Reserved +;// PF6 <0=> Input <1=> Output <2=> TxD1 <3=> SIORDY +;// <4=> IISDO <5=> Reserved <6=> Reserved <7=> Reserved +;// PF7 <0=> Input <1=> Output <2=> RxD1 <3=> SIORxD +;// <4=> IISDI <5=> Reserved <6=> Reserved <7=> Reserved +;// PF8 <0=> Input <1=> Output <2=> nCTS1 <3=> SIOCLK +;// <4=> IISCLK <5=> Reserved <6=> Reserved <7=> Reserved +;// Pull-up Resistors +;// PF0 Pull-up <0=> Enabled <1=> Disabled +;// PF1 Pull-up <0=> Enabled <1=> Disabled +;// PF2 Pull-up <0=> Enabled <1=> Disabled +;// PF3 Pull-up <0=> Enabled <1=> Disabled +;// PF4 Pull-up <0=> Enabled <1=> Disabled +;// PF5 Pull-up <0=> Enabled <1=> Disabled +;// PF6 Pull-up <0=> Enabled <1=> Disabled +;// PF7 Pull-up <0=> Enabled <1=> Disabled +;// PF8 Pull-up <0=> Enabled <1=> Disabled +;// +;// +PIOF_SETUP EQU 1 +PCONF_Val EQU 0x00000000 +PUPF_Val EQU 0x00000000 + +;// Port G +;// PG0 <0=> Input <1=> Output <2=> VD4 <3=> EINT0 +;// PG1 <0=> Input <1=> Output <2=> VD5 <3=> EINT1 +;// PG2 <0=> Input <1=> Output <2=> nCTS0 <3=> EINT2 +;// PG3 <0=> Input <1=> Output <2=> nRTS0 <3=> EINT3 +;// PG4 <0=> Input <1=> Output <2=> IISCLK <3=> EINT4 +;// PG5 <0=> Input <1=> Output <2=> IISDI <3=> EINT5 +;// PG6 <0=> Input <1=> Output <2=> IISDO <3=> EINT6 +;// PG7 <0=> Input <1=> Output <2=> IISLRCK <3=> EINT7 +;// Pull-up Resistors +;// PG0 Pull-up <0=> Enabled <1=> Disabled +;// PG1 Pull-up <0=> Enabled <1=> Disabled +;// PG2 Pull-up <0=> Enabled <1=> Disabled +;// PG3 Pull-up <0=> Enabled <1=> Disabled +;// PG4 Pull-up <0=> Enabled <1=> Disabled +;// PG5 Pull-up <0=> Enabled <1=> Disabled +;// PG6 Pull-up <0=> Enabled <1=> Disabled +;// PG7 Pull-up <0=> Enabled <1=> Disabled +;// +;// +PIOG_SETUP EQU 1 +PCONG_Val EQU 0x00000000 +PUPG_Val EQU 0x00000000 + +;// Special Pull-up +;// SPUCR0: DATA[7:0] Pull-up Resistor +;// <0=> Enabled <1=> Disabled +;// SPUCR1: DATA[15:8] Pull-up Resistor +;// <0=> Enabled <1=> Disabled +;// HZ@STOP +;// <0=> Prevoius state of PAD +;// <1=> HZ @ Stop +;// +PSPU_SETUP EQU 1 +SPUCR_Val EQU 0x00000004 + +;// + + + PRESERVE8 + + +; Area Definition and Entry Point +; Startup Code must be linked first at Address at which it expects to run. + + AREA RESET, CODE, READONLY + ARM + + +; Exception Vectors +; Mapped to Address 0. +; Absolute addressing mode must be used. +; Dummy Handlers are implemented as infinite loops which can be modified. + +Vectors LDR PC, Reset_Addr + LDR PC, Undef_Addr + LDR PC, SWI_Addr + LDR PC, PAbt_Addr + LDR PC, DAbt_Addr + NOP ; Reserved Vector + LDR PC, IRQ_Addr + LDR PC, FIQ_Addr + +Reset_Addr DCD Reset_Handler +Undef_Addr DCD Undef_Handler +SWI_Addr DCD SWI_Handler +PAbt_Addr DCD PAbt_Handler +DAbt_Addr DCD DAbt_Handler + DCD 0 ; Reserved Address +IRQ_Addr DCD IRQ_Handler +FIQ_Addr DCD FIQ_Handler + +Undef_Handler B Undef_Handler +SWI_Handler B SWI_Handler +PAbt_Handler B PAbt_Handler +DAbt_Handler B DAbt_Handler +FIQ_Handler B FIQ_Handler + + +; CPU Wrapper and Bus Priorities Configuration + IF SYS_SETUP <> 0 +SYS_CFG + DCD CPUW_BASE + DCD BUSP_BASE + DCD SYSCFG_Val + DCD NCACHBE0_Val + DCD NCACHBE1_Val + DCD SBUSCON_Val + ENDIF + + +; Memory Controller Configuration + IF MC_SETUP <> 0 +MC_CFG + DCD BWSCON_Val + DCD BANKCON0_Val + DCD BANKCON1_Val + DCD BANKCON2_Val + DCD BANKCON3_Val + DCD BANKCON4_Val + DCD BANKCON5_Val + DCD BANKCON6_Val + DCD BANKCON7_Val + DCD REFRESH_Val + DCD BANKSIZE_Val + DCD MRSRB6_Val + DCD MRSRB7_Val + ENDIF + + +; Clock Management Configuration + IF CLK_SETUP <> 0 +CLK_CFG + DCD CLK_BASE + DCD PLLCON_Val + DCD CLKCON_Val + DCD CLKSLOW_Val + DCD LOCKTIME_Val + ENDIF + + +; I/O Configuration + IF PIO_SETUP <> 0 +PIO_CFG + DCD PCONA_Val + DCD PCONB_Val + DCD PCONC_Val + DCD PCOND_Val + DCD PCONE_Val + DCD PCONF_Val + DCD PCONG_Val + DCD PUPC_Val + DCD PUPD_Val + DCD PUPE_Val + DCD PUPF_Val + DCD PUPG_Val + DCD SPUCR_Val + ENDIF + + +; Reset Handler + + EXPORT Reset_Handler +Reset_Handler + + + IF SYS_SETUP <> 0 + ADR R8, SYS_CFG + LDMIA R8, {R0-R5} + STMIA R0, {R2-R4} + STR R5, [R1] + ENDIF + + + IF MC_SETUP <> 0 + ADR R14, MC_CFG + LDMIA R14, {R0-R12} + LDR R14, =MC_BASE + STMIA R14, {R0-R12} + ENDIF + + + IF CLK_SETUP <> 0 + ADR R8, CLK_CFG + LDMIA R8, {R0-R4} + STR R4, [R0, #LOCKTIME_OFS] + STR R1, [R0, #PLLCON_OFS] + STR R3, [R0, #CLKSLOW_OFS] + STR R2, [R0, #CLKCON_OFS] + ENDIF + + + IF WT_SETUP <> 0 + LDR R0, =WT_BASE + LDR R1, =WTCON_Val + LDR R2, =WTDAT_Val + STR R2, [R0, #WTCNT_OFS] + STR R2, [R0, #WTDAT_OFS] + STR R1, [R0, #WTCON_OFS] + ENDIF + + + IF PIO_SETUP <> 0 + ADR R14, PIO_CFG + LDMIA R14, {R0-R12} + LDR R14, =PIO_BASE + + IF PIOA_SETUP <> 0 + STR R0, [R14, #PCONA_OFS] + ENDIF + + IF PIOB_SETUP <> 0 + STR R1, [R14, #PCONB_OFS] + ENDIF + + IF PIOC_SETUP <> 0 + STR R2, [R14, #PCONC_OFS] + STR R7, [R14, #PUPC_OFS] + ENDIF + + IF PIOD_SETUP <> 0 + STR R3, [R14, #PCOND_OFS] + STR R8, [R14, #PUPD_OFS] + ENDIF + + IF PIOE_SETUP <> 0 + STR R4, [R14, #PCONE_OFS] + STR R9, [R14, #PUPE_OFS] + ENDIF + + IF PIOF_SETUP <> 0 + STR R5, [R14, #PCONF_OFS] + STR R10,[R14, #PUPF_OFS] + ENDIF + + IF PIOG_SETUP <> 0 + STR R6, [R14, #PCONG_OFS] + STR R11,[R14, #PUPG_OFS] + ENDIF + + IF PSPU_SETUP <> 0 + STR R12,[R14, #SPUCR_OFS] + ENDIF + + ENDIF + + +; Setup Stack for each mode + + LDR R0, =Stack_Top + +; Enter Undefined Instruction Mode and set its Stack Pointer + MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #UND_Stack_Size + +; Enter Abort Mode and set its Stack Pointer + MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #ABT_Stack_Size + +; Enter FIQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #FIQ_Stack_Size + +; Enter IRQ Mode and set its Stack Pointer + MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #IRQ_Stack_Size + +; Enter Supervisor Mode and set its Stack Pointer + MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit + MOV SP, R0 + SUB R0, R0, #SVC_Stack_Size + +; Enter User Mode and set its Stack Pointer + ; MSR CPSR_c, #Mode_USR + IF :DEF:__MICROLIB + + EXPORT __initial_sp + + ELSE + + ; MOV SP, R0 + ; SUB SL, SP, #USR_Stack_Size + + ENDIF + + +; Enter the C code + + IMPORT __main + LDR R0, =__main + BX R0 + + IMPORT rt_interrupt_enter + IMPORT rt_interrupt_leave + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + IMPORT rt_hw_trap_irq + +IRQ_Handler PROC + EXPORT IRQ_Handler + STMFD sp!, {r0-r12,lr} + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; if rt_thread_switch_interrupt_flag set, jump to + ; rt_hw_context_switch_interrupt_do and don't return + LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD sp!, {r0-r12,lr} + SUBS pc, lr, #4 + ENDP + +; /* +; * void rt_hw_context_switch_interrupt_do(rt_base_t flag) +; */ +rt_hw_context_switch_interrupt_do PROC + EXPORT rt_hw_context_switch_interrupt_do + MOV r1, #0 ; clear flag + STR r1, [r0] + + LDMFD sp!, {r0-r12,lr}; reload saved registers + STMFD sp!, {r0-r3} ; save r0-r3 + MOV r1, sp + ADD sp, sp, #16 ; restore sp + SUB r2, lr, #4 ; save old task's pc to r2 + + MRS r3, spsr ; get cpsr of interrupt thread + + ; switch to SVC mode and no interrupt + MSR cpsr_c, #I_Bit|F_Bit|Mode_SVC + + STMFD sp!, {r2} ; push old task's pc + STMFD sp!, {r4-r12,lr}; push old task's lr,r12-r4 + MOV r4, r1 ; Special optimised code below + MOV r5, r3 + LDMFD r4!, {r0-r3} + STMFD sp!, {r0-r3} ; push old task's r3-r0 + STMFD sp!, {r5} ; push old task's cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push old task's spsr + + LDR r4, =rt_interrupt_from_thread + LDR r5, [r4] + STR sp, [r5] ; store sp in preempted tasks's TCB + + LDR r6, =rt_interrupt_to_thread + LDR r6, [r6] + LDR sp, [r6] ; get new task's stack pointer + + LDMFD sp!, {r4} ; pop new task's spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task's psr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc + ENDP + + IF :DEF:__MICROLIB + + EXPORT __heap_base + EXPORT __heap_limit + + ELSE +; User Initial Stack & Heap + AREA |.text|, CODE, READONLY + + IMPORT __use_two_region_memory + EXPORT __user_initial_stackheap +__user_initial_stackheap + + LDR R0, = Heap_Mem + LDR R1, =(Stack_Mem + USR_Stack_Size) + LDR R2, = (Heap_Mem + Heap_Size) + LDR R3, = Stack_Mem + BX LR + ENDIF + + + END diff --git a/rt-thread/libcpu/arm/s3c44b0/trap.c b/rt-thread/libcpu/arm/s3c44b0/trap.c new file mode 100644 index 0000000..546d9b2 --- /dev/null +++ b/rt-thread/libcpu/arm/s3c44b0/trap.c @@ -0,0 +1,181 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-09-06 XuXinming first version + * 2006-09-15 Bernard modify rt_hw_trap_irq for more effective + */ + +#include +#include + +#include "s3c44b0.h" + +extern unsigned char interrupt_bank0[256]; +extern unsigned char interrupt_bank1[256]; +extern unsigned char interrupt_bank2[256]; +extern unsigned char interrupt_bank3[256]; + +extern struct rt_thread *rt_current_thread; + +/** + * @addtogroup S3C44B0 + */ +/*@{*/ + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ +void rt_hw_show_register (struct rt_hw_register *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When ARM7TDMI comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_udef(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("undefined instruction\n"); + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_register *regs) +{ + rt_kprintf("software interrupt\n"); + rt_hw_show_register(regs); + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("prefetch abort\n"); + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("data abort\n"); + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_register *regs) +{ + rt_kprintf("not used\n"); + rt_hw_show_register(regs); + rt_hw_cpu_shutdown(); +} + +extern rt_isr_handler_t isr_table[]; +void rt_hw_trap_irq() +{ + register unsigned long ispr, intstat; + register rt_isr_handler_t isr_func; + +#ifdef BSP_INT_DEBUG + rt_kprintf("irq coming, "); +#endif + intstat = I_ISPR & 0x7ffffff; +#ifdef BSP_INT_DEBUG + rt_kprintf("I_ISPR: %d\n", intstat); +#endif + + ispr = intstat; + + /* to find interrupt */ + if ( intstat & 0xff ) /* lowest 8bits */ + { + intstat = interrupt_bank0[intstat & 0xff]; + isr_func = (rt_isr_handler_t)isr_table[ intstat ]; + } + else if ( intstat & 0xff00 ) /* low 8bits */ + { + intstat = interrupt_bank1[(intstat & 0xff00) >> 8]; + isr_func = (rt_isr_handler_t)isr_table[ intstat ]; + } + else if ( intstat & 0xff0000 ) /* high 8bits */ + { + intstat = interrupt_bank2[(intstat & 0xff0000) >> 16]; + isr_func = (rt_isr_handler_t)isr_table[ intstat ]; + } + else if ( intstat & 0xff000000 ) /* highest 8bits */ + { + intstat = interrupt_bank3[(intstat & 0xff000000) >> 24]; + isr_func = (rt_isr_handler_t)isr_table[ intstat ]; + } + else return; + +#ifdef BSP_INT_DEBUG + rt_kprintf("irq: %d happen\n", intstat); +#endif + + /* turn to interrupt service routine */ + isr_func(intstat); + + I_ISPC = ispr; /* clear interrupt */ +} + +void rt_hw_trap_fiq() +{ + rt_kprintf("fast interrupt request\n"); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/sep4020/clk.c b/rt-thread/libcpu/arm/sep4020/clk.c new file mode 100644 index 0000000..9de17b3 --- /dev/null +++ b/rt-thread/libcpu/arm/sep4020/clk.c @@ -0,0 +1,112 @@ +/* + * File : clock.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2010-03-20 zchong first version + */ + +#include +#include "sep4020.h" + +#define CLK_IN 4000000 /* Fin = 4.00MHz */ +#define SYSCLK 72000000 /* system clock we want */ + +#define CLK_ESRAM 0 +#define CLK_LCDC 1 +#define CLK_PWM 2 +#define CLK_DMAC 3 +#define CLK_EMI 4 +#define CLK_MMCSD 5 +#define CLK_SSI 7 +#define CLK_UART0 8 +#define CLK_UART1 9 +#define CLK_UART2 10 +#define CLK_UART3 11 +#define CLK_USB 12 +#define CLK_MAC 13 +#define CLK_SMC 14 +#define CLK_I2C 15 +#define CLK_GPT 16 + +static void rt_hw_set_system_clock(void) +{ + rt_uint8_t pv; + + /* pv value*/ + pv = SYSCLK/2/CLK_IN; + /* go to normal mode*/ + *(RP)PMU_PMDR = 0x01; + /* set the clock */ + *(RP)PMU_PMCR = 0x4000 | pv; + /* trige configurate*/ + *(RP)PMU_PMCR = 0xc000 | pv; +} + +static void rt_hw_set_usb_clock(void) +{ + /* set the clock */ + *(RP)PMU_PUCR = 0x000c; + /* trige configurate*/ + *(RP)PMU_PMCR = 0x800c; + +} + +/** + * @brief System Clock Configuration + */ +void rt_hw_clock_init(void) +{ + /* set system clock */ + rt_hw_set_system_clock(); + /* set usb clock */ + rt_hw_set_usb_clock(); +} + +/** + * @brief Get system clock + */ +rt_uint32_t rt_hw_get_clock(void) +{ + rt_uint32_t val; + rt_uint8_t pv, pd, npd; + + /* get PMCR value */ + val =*(RP) PMU_PMCR; + /* get NPD */ + npd = (val >> 14) & 0x01; + /* get PD */ + pd = (val >> 10) & 0x0f; + /* get PV */ + pv = val & 0x7f; + /* caculate the system clock */ + if(npd) + val = 2 * CLK_IN * pv; + else + val = CLK_IN * pv / (pd + 1); + + return(val); +} + +/** + * @brief Enable module clock + */ + void rt_hw_enable_module_clock(rt_uint8_t module) + { + + } + +/** + * @brief Disable module clock + */ + void rt_hw_disable_module_clock(rt_uint8_t module) + { + + } + diff --git a/rt-thread/libcpu/arm/sep4020/context_rvds.S b/rt-thread/libcpu/arm/sep4020/context_rvds.S new file mode 100644 index 0000000..641ec7a --- /dev/null +++ b/rt-thread/libcpu/arm/sep4020/context_rvds.S @@ -0,0 +1,107 @@ +;/* +; * File : context_rvds.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2006, 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-20 Bernard first version +; */ + +NOINT EQU 0xc0 ; disable interrupt in psr + + AREA |.text|, CODE, READONLY, ALIGN=2 + ARM + REQUIRE8 + PRESERVE8 + +;/* +; * rt_base_t rt_hw_interrupt_disable(); +; */ +rt_hw_interrupt_disable PROC + EXPORT rt_hw_interrupt_disable + MRS r0, cpsr + ORR r1, r0, #NOINT + MSR cpsr_c, r1 + BX lr + ENDP + +;/* +; * void rt_hw_interrupt_enable(rt_base_t level); +; */ +rt_hw_interrupt_enable PROC + EXPORT rt_hw_interrupt_enable + MSR cpsr_c, r0 + BX lr + ENDP + +;/* +; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); +; * r0 --> from +; * r1 --> to +; */ +rt_hw_context_switch PROC + EXPORT rt_hw_context_switch + STMFD sp!, {lr} ; push pc (lr should be pushed in place of PC) + STMFD sp!, {r0-r12, lr} ; push lr & register file + + MRS r4, cpsr + STMFD sp!, {r4} ; push cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push spsr + + STR sp, [r0] ; store sp in preempted tasks TCB + LDR sp, [r1] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_to(rt_uint32 to); +; * r0 --> to +; */ +rt_hw_context_switch_to PROC + EXPORT rt_hw_context_switch_to + LDR sp, [r0] ; get new task stack pointer + + LDMFD sp!, {r4} ; pop new task spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task cpsr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc + ENDP + +;/* +; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); +; */ + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + +rt_hw_context_switch_interrupt PROC + EXPORT rt_hw_context_switch_interrupt + LDR r2, =rt_thread_switch_interrupt_flag + LDR r3, [r2] + CMP r3, #1 + BEQ _reswitch + MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 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] + BX lr + ENDP + + END \ No newline at end of file diff --git a/rt-thread/libcpu/arm/sep4020/cpu.c b/rt-thread/libcpu/arm/sep4020/cpu.c new file mode 100644 index 0000000..093f3c1 --- /dev/null +++ b/rt-thread/libcpu/arm/sep4020/cpu.c @@ -0,0 +1,190 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + */ + +#include +#include + +extern rt_uint32_t rt_hw_interrupt_disable(void); + +//TODO +#warning I DON'T KNOW IF THE MMU OPERATION WORKS ON SEP4020 + +/** + * @addtogroup S3C24X0 + */ +/*@{*/ + +#define ICACHE_MASK (rt_uint32_t)(1 << 12) +#define DCACHE_MASK (rt_uint32_t)(1 << 2) + +#ifdef __GNUC__ +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i)); + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + __asm__ __volatile__( \ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "orr r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + __asm__ __volatile__( \ + "mrc p15,0,r0,c1,c0,0\n\t" \ + "bic r0,r0,%0\n\t" \ + "mcr p15,0,r0,c1,c0,0" \ + : \ + :"r" (bit) \ + :"memory"); +} +#endif + +#ifdef __CC_ARM +rt_inline rt_uint32_t cp15_rd(void) +{ + rt_uint32_t i; + + __asm + { + mrc p15, 0, i, c1, c0, 0 + } + + return i; +} + +rt_inline void cache_enable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm + { + mrc p15, 0, value, c1, c0, 0 + orr value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} + +rt_inline void cache_disable(rt_uint32_t bit) +{ + rt_uint32_t value; + + __asm + { + mrc p15, 0, value, c1, c0, 0 + bic value, value, bit + mcr p15, 0, value, c1, c0, 0 + } +} +#endif + +/** + * enable I-Cache + * + */ +void rt_hw_cpu_icache_enable() +{ + cache_enable(ICACHE_MASK); +} + +/** + * disable I-Cache + * + */ +void rt_hw_cpu_icache_disable() +{ + cache_disable(ICACHE_MASK); +} + +/** + * return the status of I-Cache + * + */ +rt_base_t rt_hw_cpu_icache_status() +{ + return (cp15_rd() & ICACHE_MASK); +} + +/** + * enable D-Cache + * + */ +void rt_hw_cpu_dcache_enable() +{ + cache_enable(DCACHE_MASK); +} + +/** + * disable D-Cache + * + */ +void rt_hw_cpu_dcache_disable() +{ + cache_disable(DCACHE_MASK); +} + +/** + * return the status of D-Cache + * + */ +rt_base_t rt_hw_cpu_dcache_status() +{ + return (cp15_rd() & DCACHE_MASK); +} + +/** + * reset cpu by dog's time-out + * + */ +void rt_hw_cpu_reset() +{ + + /* enable watchdog */ + *(RP)(RTC_CTR) = 0x02; + + /*Enable watchdog reset*/ + *(RP)(RTC_INT_EN) = 0x20; + + /* Initialize watchdog timer count register */ + *(RP)(RTC_WD_CNT) = 0x0001; + + while(1); /* loop forever and wait for reset to happen */ + + /* NEVER REACHED */ +} + +/** + * shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t UNUSED level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + + RT_ASSERT(RT_NULL); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/sep4020/interrupt.c b/rt-thread/libcpu/arm/sep4020/interrupt.c new file mode 100644 index 0000000..8b0b8bb --- /dev/null +++ b/rt-thread/libcpu/arm/sep4020/interrupt.c @@ -0,0 +1,135 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + * 2013-03-29 aozima Modify the interrupt interface implementations. + */ + +#include +#include +#include + +#define MAX_HANDLERS 32 + +extern rt_uint32_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +struct rt_irq_desc isr_table[MAX_HANDLERS]; +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +/** + * @addtogroup S3C24X0 + */ +/*@{*/ + +static void rt_hw_interrupt_handle(int vector, void *param) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + register rt_uint32_t idx; + + /*Make sure all intc registers in proper state*/ + + /*mask all the irq*/ + *(RP)(INTC_IMR) = 0xFFFFFFFF; + + /*enable all the irq*/ + *(RP)(INTC_IER) = 0XFFFFFFFF; + + /*Dont use any forced irq*/ + *(RP)(INTC_IFR) = 0x0; + + /*Disable all the fiq*/ + *(RP)(INTC_FIER) = 0x0; + + /*Mask all the fiq*/ + *(RP)(INTC_FIMR) = 0x0F; + + /*Dont use forced fiq*/ + *(RP)(INTC_FIFR) = 0x0; + + /*Intrrupt priority register*/ + *(RP)(INTC_IPLR) = 0x0; + + /* init exceptions table */ + rt_memset(isr_table, 0x00, sizeof(isr_table)); + for(idx=0; idx < MAX_HANDLERS; idx++) + { + isr_table[idx].handler = rt_hw_interrupt_handle; + } + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + *(RP)(INTC_IMR) |= 1 << vector; +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + if(vector == 16) + { + rt_kprintf("Interrupt vec %d is not used!\n", vector); + } + else + *(RP)(INTC_IMR) &= ~(1 << vector); +} + + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if(vector < MAX_HANDLERS) + { + old_handler = isr_table[vector].handler; + + if (handler != RT_NULL) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + } + + return old_handler; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/sep4020/sep4020.h b/rt-thread/libcpu/arm/sep4020/sep4020.h new file mode 100644 index 0000000..022fddc --- /dev/null +++ b/rt-thread/libcpu/arm/sep4020/sep4020.h @@ -0,0 +1,867 @@ +#ifndef __SEP4020_H +#define __SEP4020_H + +#include + +/*Core definations*/ +#define SVCMODE +#define Mode_USR 0x10 +#define Mode_FIQ 0x11 +#define Mode_IRQ 0x12 +#define Mode_SVC 0x13 +#define Mode_ABT 0x17 +#define Mode_UND 0x1B +#define Mode_SYS 0x1F + + + +/* + * ¸÷Ä£¿é¼Ä´æÆ÷»ùÖµ + */ + +#define ESRAM_BASE 0x04000000 +#define INTC_BASE 0x10000000 +#define PMU_BASE 0x10001000 +#define RTC_BASE 0x10002000 +#define WD_BASE 0x10002000 +#define TIMER_BASE 0x10003000 +#define PWM_BASE 0x10004000 +#define UART0_BASE 0X10005000 +#define UART1_BASE 0X10006000 +#define UART2_BASE 0X10007000 +#define UART3_BASE 0X10008000 +#define SSI_BASE 0X10009000 +#define I2S_BASE 0x1000A000 +#define MMC_BASE 0x1000B000 +#define SD_BASE 0x1000B000 +#define SMC0_BASE 0x1000C000 +#define SMC1_BASE 0x1000D000 +#define USBD_BASE 0x1000E000 +#define GPIO_BASE 0x1000F000 +#define EMI_BASE 0x11000000 +#define DMAC_BASE 0x11001000 +#define LCDC_BASE 0x11002000 +#define MAC_BASE 0x11003000 +#define AMBA_BASE 0x11005000 + + +/* + * INTCÄ£¿é + * »ùÖ·: 0x10000000 + */ + +#define INTC_IER (INTC_BASE+0X000) /* IRQÖжÏÔÊÐí¼Ä´æÆ÷ */ +#define INTC_IMR (INTC_BASE+0X008) /* IRQÖÐ¶ÏÆÁ±Î¼Ä´æÆ÷ */ +#define INTC_IFR (INTC_BASE+0X010) /* IRQÈí¼þÇ¿ÖÆÖжϼĴæÆ÷ */ +#define INTC_IRSR (INTC_BASE+0X018) /* IRQδ´¦ÀíÖжÏ״̬¼Ä´æÆ÷ */ +#define INTC_ISR (INTC_BASE+0X020) /* IRQÖжÏ״̬¼Ä´æÆ÷ */ +#define INTC_IMSR (INTC_BASE+0X028) /* IRQÆÁ±ÎÖжÏ״̬¼Ä´æÆ÷ */ +#define INTC_IFSR (INTC_BASE+0X030) /* IRQÖжÏ×îÖÕ״̬¼Ä´æÆ÷ */ +#define INTC_FIER (INTC_BASE+0X0C0) /* FIQÖжÏÔÊÐí¼Ä´æÆ÷ */ +#define INTC_FIMR (INTC_BASE+0X0C4) /* FIQÖÐ¶ÏÆÁ±Î¼Ä´æÆ÷ */ +#define INTC_FIFR (INTC_BASE+0X0C8) /* FIQÈí¼þÇ¿ÖÆÖжϼĴæÆ÷ */ +#define INTC_FIRSR (INTC_BASE+0X0CC) /* FIQδ´¦ÀíÖжÏ״̬¼Ä´æÆ÷ */ +#define INTC_FISR (INTC_BASE+0X0D0) /* FIQÖжÏ״̬¼Ä´æÆ÷ */ +#define INTC_FIFSR (INTC_BASE+0X0D4) /* FIQÖжÏ×îÖÕ״̬¼Ä´æÆ÷ */ +#define INTC_IPLR (INTC_BASE+0X0D8) /* IRQÖжÏÓÅÏȼ¶¼Ä´æÆ÷ */ +#define INTC_ICR1 (INTC_BASE+0X0DC) /* IRQÄÚ²¿ÖжÏÓÅÏȼ¶¿ØÖƼĴæÆ÷1 */ +#define INTC_ICR2 (INTC_BASE+0X0E0) /* IRQÄÚ²¿ÖжÏÓÅÏȼ¶¿ØÖƼĴæÆ÷2 */ +#define INTC_EXICR1 (INTC_BASE+0X0E4) /* IRQÍⲿÖжÏÓÅÏȼ¶¿ØÖƼĴæÆ÷1 */ +#define INTC_EXICR2 (INTC_BASE+0X0E8) /* IRQÍⲿÖжÏÓÅÏȼ¶¿ØÖƼĴæÆ÷2 */ + + +/* + * PMUÄ£¿é + * »ùÖ·: 0x10001000 + */ + +#define PMU_PLTR (PMU_BASE+0X000) /* PLLµÄÎȶ¨¹ý¶Éʱ¼ä */ +#define PMU_PMCR (PMU_BASE+0X004) /* ϵͳÖ÷ʱÖÓPLLµÄ¿ØÖƼĴæÆ÷ */ +#define PMU_PUCR (PMU_BASE+0X008) /* USBʱÖÓPLLµÄ¿ØÖƼĴæÆ÷ */ +#define PMU_PCSR (PMU_BASE+0X00C) /* ÄÚ²¿Ä£¿éʱÖÓÔ´¹©¸øµÄ¿ØÖƼĴæÆ÷ */ +#define PMU_PDSLOW (PMU_BASE+0X010) /* SLOW״̬ÏÂʱÖӵķ֯µÒò×Ó */ +#define PMU_PMDR (PMU_BASE+0X014) /* оƬ¹¤×÷ģʽ¼Ä´æÆ÷ */ +#define PMU_RCTR (PMU_BASE+0X018) /* Reset¿ØÖƼĴæÆ÷ */ +#define PMU_CLRWAKUP (PMU_BASE+0X01C) /* WakeUpÇå³ý¼Ä´æÆ÷ */ + + +/* + * RTCÄ£¿é + * »ùÖ·: 0x10002000 + */ + +#define RTC_STA_YMD (RTC_BASE+0X000) /* Äê, ÔÂ, ÈÕ¼ÆÊý¼Ä´æÆ÷ */ +#define RTC_STA_HMS (RTC_BASE+0X004) /* Сʱ, ·ÖÖÓ, Ãë¼Ä´æÆ÷ */ +#define RTC_ALARM_ALL (RTC_BASE+0X008) /* ¶¨Ê±ÔÂ, ÈÕ, ʱ, ·Ö¼Ä´æÆ÷ */ +#define RTC_CTR (RTC_BASE+0X00C) /* ¿ØÖƼĴæÆ÷ */ +#define RTC_INT_EN (RTC_BASE+0X010) /* ÖжÏʹÄܼĴæÆ÷ */ +#define RTC_INT_STS (RTC_BASE+0X014) /* ÖжÏ״̬¼Ä´æÆ÷ */ +#define RTC_SAMP (RTC_BASE+0X018) /* ²ÉÑùÖÜÆÚ¼Ä´æÆ÷ */ +#define RTC_WD_CNT (RTC_BASE+0X01C) /* Watch-Dog¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define RTC_WD_SEV (RTC_BASE+0X020) /* Watch-Dog·þÎñ¼Ä´æÆ÷ */ +#define RTC_CONFIG_CHECK (RTC_BASE+0X024) /* ÅäÖÃʱ¼äÈ·ÈϼĴæÆ÷ (ÔÚÅäÖÃʱ¼ä֮ǰÏÈд0xaaaaaaaa) */ +#define RTC_KEY0 (RTC_BASE+0X02C) /* ÃÜÔ¿¼Ä´æÆ÷ */ + +/* + * TIMERÄ£¿é + * »ùÖ·: 0x10003000 + */ + +#define TIMER_T1LCR (TIMER_BASE+0X000) /* ͨµÀ1¼ÓÔØ¼ÆÊý¼Ä´æÆ÷ */ +#define TIMER_T1CCR (TIMER_BASE+0X004) /* ͨµÀ1µ±Ç°¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define TIMER_T1CR (TIMER_BASE+0X008) /* ͨµÀ1¿ØÖƼĴæÆ÷ */ +#define TIMER_T1ISCR (TIMER_BASE+0X00C) /* ͨµÀ1ÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_T1IMSR (TIMER_BASE+0X010) /* ͨµÀ1ÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_T2LCR (TIMER_BASE+0X020) /* ͨµÀ2¼ÓÔØ¼ÆÊý¼Ä´æÆ÷ */ +#define TIMER_T2CCR (TIMER_BASE+0X024) /* ͨµÀ2µ±Ç°¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define TIMER_T2CR (TIMER_BASE+0X028) /* ͨµÀ2¿ØÖƼĴæÆ÷ */ +#define TIMER_T2ISCR (TIMER_BASE+0X02C) /* ͨµÀ2ÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_T2IMSR (TIMER_BASE+0X030) /* ͨµÀ2ÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_T3LCR (TIMER_BASE+0X040) /* ͨµÀ3¼ÓÔØ¼ÆÊý¼Ä´æÆ÷ */ +#define TIMER_T3CCR (TIMER_BASE+0X044) /* ͨµÀ3µ±Ç°¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define TIMER_T3CR (TIMER_BASE+0X048) /* ͨµÀ3¿ØÖƼĴæÆ÷ */ +#define TIMER_T3ISCR (TIMER_BASE+0X04C) /* ͨµÀ3ÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_T3IMSR (TIMER_BASE+0X050) /* ͨµÀ3ÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_T3CAPR (TIMER_BASE+0X054) /* ͨµÀ3²¶»ñ¼Ä´æÆ÷ */ +#define TIMER_T4LCR (TIMER_BASE+0X060) /* ͨµÀ4¼ÓÔØ¼ÆÊý¼Ä´æÆ÷ */ +#define TIMER_T4CCR (TIMER_BASE+0X064) /* ͨµÀ4µ±Ç°¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define TIMER_T4CR (TIMER_BASE+0X068) /* ͨµÀ4¿ØÖƼĴæÆ÷ */ +#define TIMER_T4ISCR (TIMER_BASE+0X06C) /* ͨµÀ4ÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_T4IMSR (TIMER_BASE+0X070) /* ͨµÀ4ÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_T4CAPR (TIMER_BASE+0X074) /* ͨµÀ4²¶»ñ¼Ä´æÆ÷ */ +#define TIMER_T5LCR (TIMER_BASE+0X080) /* ͨµÀ5¼ÓÔØ¼ÆÊý¼Ä´æÆ÷ */ +#define TIMER_T5CCR (TIMER_BASE+0X084) /* ͨµÀ5µ±Ç°¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define TIMER_T5CR (TIMER_BASE+0X088) /* ͨµÀ5¿ØÖƼĴæÆ÷ */ +#define TIMER_T5ISCR (TIMER_BASE+0X08C) /* ͨµÀ5ÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_T5IMSR (TIMER_BASE+0X090) /* ͨµÀ5ÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_T5CAPR (TIMER_BASE+0X094) /* ͨµÀ5²¶»ñ¼Ä´æÆ÷ */ +#define TIMER_T6LCR (TIMER_BASE+0X0A0) /* ͨµÀ6¼ÓÔØ¼ÆÊý¼Ä´æÆ÷ */ +#define TIMER_T6CCR (TIMER_BASE+0X0A4) /* ͨµÀ6µ±Ç°¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define TIMER_T6CR (TIMER_BASE+0X0A8) /* ͨµÀ6¿ØÖƼĴæÆ÷ */ +#define TIMER_T6ISCR (TIMER_BASE+0X0AC) /* ͨµÀ6ÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_T6IMSR (TIMER_BASE+0X0B0) /* ͨµÀ6ÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_T6CAPR (TIMER_BASE+0X0B4) /* ͨµÀ6²¶»ñ¼Ä´æÆ÷ */ +#define TIMER_T7LCR (TIMER_BASE+0X0C0) /* ͨµÀ7¼ÓÔØ¼ÆÊý¼Ä´æÆ÷ */ +#define TIMER_T7CCR (TIMER_BASE+0X0C4) /* ͨµÀ7µ±Ç°¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define TIMER_T7CR (TIMER_BASE+0X0C8) /* ͨµÀ7¿ØÖƼĴæÆ÷ */ +#define TIMER_T7ISCR (TIMER_BASE+0X0CC) /* ͨµÀ7ÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_T7IMSR (TIMER_BASE+0X0D0) /* ͨµÀ7ÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_T8LCR (TIMER_BASE+0X0E0) /* ͨµÀ8¼ÓÔØ¼ÆÊý¼Ä´æÆ÷ */ +#define TIMER_T8CCR (TIMER_BASE+0X0E4) /* ͨµÀ8µ±Ç°¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define TIMER_T8CR (TIMER_BASE+0X0E8) /* ͨµÀ8¿ØÖƼĴæÆ÷ */ +#define TIMER_T8ISCR (TIMER_BASE+0X0EC) /* ͨµÀ8ÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_T8IMSR (TIMER_BASE+0X0F0) /* ͨµÀ8ÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_T9LCR (TIMER_BASE+0X100) /* ͨµÀ9¼ÓÔØ¼ÆÊý¼Ä´æÆ÷ */ +#define TIMER_T9CCR (TIMER_BASE+0X104) /* ͨµÀ9µ±Ç°¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define TIMER_T9CR (TIMER_BASE+0X108) /* ͨµÀ9¿ØÖƼĴæÆ÷ */ +#define TIMER_T9ISCR (TIMER_BASE+0X10C) /* ͨµÀ9ÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_T9IMSR (TIMER_BASE+0X110) /* ͨµÀ9ÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_T10LCR (TIMER_BASE+0X120) /* ͨµÀ10¼ÓÔØ¼ÆÊý¼Ä´æÆ÷ */ +#define TIMER_T10CCR (TIMER_BASE+0X124) /* ͨµÀ10µ±Ç°¼ÆÊýÖµ¼Ä´æÆ÷ */ +#define TIMER_T10CR (TIMER_BASE+0X128) /* ͨµÀ10¿ØÖƼĴæÆ÷ */ +#define TIMER_T10ISCR (TIMER_BASE+0X12C) /* ͨµÀ10ÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_T10IMSR (TIMER_BASE+0X130) /* ͨµÀ10ÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_TIMSR (TIMER_BASE+0X140) /* TIMERÖÐ¶ÏÆÁ±Î״̬¼Ä´æÆ÷ */ +#define TIMER_TISCR (TIMER_BASE+0X144) /* TIMERÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define TIMER_TISR (TIMER_BASE+0X148) /* TIMERÖжÏ״̬¼Ä´æÆ÷ */ + + + +/* + * PWMÄ£¿é + * »ùÖ·: 0x10004000 + */ + +#define PWM0_CTRL (PWM_BASE+0X000) /* PWM0¿ØÖƼĴæÆ÷ */ +#define PWM0_DIV (PWM_BASE+0X004) /* PWM0·ÖƵ¼Ä´æÆ÷ */ +#define PWM0_PERIOD (PWM_BASE+0X008) /* PWM0ÖÜÆÚ¼Ä´æÆ÷ */ +#define PWM0_DATA (PWM_BASE+0X00C) /* PWM0Êý¾Ý¼Ä´æÆ÷ */ +#define PWM0_CNT (PWM_BASE+0X010) /* PWM0¼ÆÊý¼Ä´æÆ÷ */ +#define PWM0_STATUS (PWM_BASE+0X014) /* PWM0״̬¼Ä´æÆ÷ */ +#define PWM1_CTRL (PWM_BASE+0X020) /* PWM1¿ØÖƼĴæÆ÷ */ +#define PWM1_DIV (PWM_BASE+0X024) /* PWM1·ÖƵ¼Ä´æÆ÷ */ +#define PWM1_PERIOD (PWM_BASE+0X028) /* PWM1ÖÜÆÚ¼Ä´æÆ÷ */ +#define PWM1_DATA (PWM_BASE+0X02C) /* PWM1Êý¾Ý¼Ä´æÆ÷ */ +#define PWM1_CNT (PWM_BASE+0X030) /* PWM1¼ÆÊý¼Ä´æÆ÷ */ +#define PWM1_STATUS (PWM_BASE+0X034) /* PWM1״̬¼Ä´æÆ÷ */ +#define PWM2_CTRL (PWM_BASE+0X040) /* PWM2¿ØÖƼĴæÆ÷ */ +#define PWM2_DIV (PWM_BASE+0X044) /* PWM2·ÖƵ¼Ä´æÆ÷ */ +#define PWM2_PERIOD (PWM_BASE+0X048) /* PWM2ÖÜÆÚ¼Ä´æÆ÷ */ +#define PWM2_DATA (PWM_BASE+0X04C) /* PWM2Êý¾Ý¼Ä´æÆ÷ */ +#define PWM2_CNT (PWM_BASE+0X050) /* PWM2¼ÆÊý¼Ä´æÆ÷ */ +#define PWM2_STATUS (PWM_BASE+0X054) /* PWM2״̬¼Ä´æÆ÷ */ +#define PWM3_CTRL (PWM_BASE+0X060) /* PWM3¿ØÖƼĴæÆ÷ */ +#define PWM3_DIV (PWM_BASE+0X064) /* PWM3·ÖƵ¼Ä´æÆ÷ */ +#define PWM3_PERIOD (PWM_BASE+0X068) /* PWM3ÖÜÆÚ¼Ä´æÆ÷ */ +#define PWM3_DATA (PWM_BASE+0X06C) /* PWM3Êý¾Ý¼Ä´æÆ÷ */ +#define PWM3_CNT (PWM_BASE+0X070) /* PWM3¼ÆÊý¼Ä´æÆ÷ */ +#define PWM3_STATUS (PWM_BASE+0X074) /* PWM3״̬¼Ä´æÆ÷ */ +#define PWM_INTMASK (PWM_BASE+0X080) /* PWMÖÐ¶ÏÆÁ±Î¼Ä´æÆ÷ */ +#define PWM_INT (PWM_BASE+0X084) /* PWMÖжϼĴæÆ÷ */ +#define PWM_ENABLE (PWM_BASE+0X088) /* PWMʹÄܼĴæÆ÷ */ + + +/* + * UART0Ä£¿é + * »ùÖ·: 0x10005000 + */ + +#define UART0_DLBL (UART0_BASE+0X000) /* ²¨ÌØÂÊÉèÖõͰËλ¼Ä´æÆ÷ */ +#define UART0_RXFIFO (UART0_BASE+0X000) /* ½ÓÊÕFIFO */ +#define UART0_TXFIFO (UART0_BASE+0X000) /* ·¢ËÍFIFO */ +#define UART0_DLBH (UART0_BASE+0X004) /* ²¨ÌØÂÊÉèÖø߰Ëλ¼Ä´æÆ÷ */ +#define UART0_IER (UART0_BASE+0X004) /* ÖжÏʹÄܼĴæÆ÷ */ +#define UART0_IIR (UART0_BASE+0X008) /* ÖжÏʶ±ð¼Ä´æÆ÷ */ +#define UART0_FCR (UART0_BASE+0X008) /* FIFO¿ØÖƼĴæÆ÷ */ +#define UART0_LCR (UART0_BASE+0X00C) /* ÐпØÖƼĴæÆ÷ */ +#define UART0_MCR (UART0_BASE+0X010) /* Modem¿ØÖƼĴæÆ÷ */ +#define UART0_LSR (UART0_BASE+0X014) /* ÐÐ״̬¼Ä´æÆ÷ */ +#define UART0_MSR (UART0_BASE+0X018) /* Modem״̬¼Ä´æÆ÷ */ + + +/* + * UART1Ä£¿é + * »ùÖ·: 0x10006000 + */ + +#define UART1_DLBL (UART1_BASE+0X000) /* ²¨ÌØÂÊÉèÖõͰËλ¼Ä´æÆ÷ */ +#define UART1_RXFIFO (UART1_BASE+0X000) /* ½ÓÊÕFIFO */ +#define UART1_TXFIFO (UART1_BASE+0X000) /* ·¢ËÍFIFO */ +#define UART1_DLBH (UART1_BASE+0X004) /* ²¨ÌØÂÊÉèÖø߰Ëλ¼Ä´æÆ÷ */ +#define UART1_IER (UART1_BASE+0X004) /* ÖжÏʹÄܼĴæÆ÷ */ +#define UART1_IIR (UART1_BASE+0X008) /* ÖжÏʶ±ð¼Ä´æÆ÷ */ +#define UART1_FCR (UART1_BASE+0X008) /* FIFO¿ØÖƼĴæÆ÷ */ +#define UART1_LCR (UART1_BASE+0X00C) /* ÐпØÖƼĴæÆ÷ */ +#define UART1_MCR (UART1_BASE+0X010) /* Modem¿ØÖƼĴæÆ÷ */ +#define UART1_LSR (UART1_BASE+0X014) /* ÐÐ״̬¼Ä´æÆ÷ */ +#define UART1_MSR (UART1_BASE+0X018) /* Modem״̬¼Ä´æÆ÷ */ + + +/* + * UART2Ä£¿é + * »ùÖ·: 0x10007000 + */ + +#define UART2_DLBL (UART2_BASE+0X000) /* ²¨ÌØÂÊÉèÖõͰËλ¼Ä´æÆ÷ */ +#define UART2_RXFIFO (UART2_BASE+0X000) /* ½ÓÊÕFIFO */ +#define UART2_TXFIFO (UART2_BASE+0X000) /* ·¢ËÍFIFO */ +#define UART2_DLBH (UART2_BASE+0X004) /* ²¨ÌØÂÊÉèÖø߰Ëλ¼Ä´æÆ÷ */ +#define UART2_IER (UART2_BASE+0X004) /* ÖжÏʹÄܼĴæÆ÷ */ +#define UART2_IIR (UART2_BASE+0X008) /* ÖжÏʶ±ð¼Ä´æÆ÷ */ +#define UART2_FCR (UART2_BASE+0X008) /* FIFO¿ØÖƼĴæÆ÷ */ +#define UART2_LCR (UART2_BASE+0X00C) /* ÐпØÖƼĴæÆ÷ */ +#define UART2_MCR (UART2_BASE+0X010) /* Modem¿ØÖƼĴæÆ÷ */ +#define UART2_LSR (UART2_BASE+0X014) /* ÐÐ״̬¼Ä´æÆ÷ */ +#define UART2_MSR (UART2_BASE+0X018) /* Modem״̬¼Ä´æÆ÷ */ + + +/* + * UART3Ä£¿é + * »ùÖ·: 0x10008000 + */ + +#define UART3_DLBL (UART3_BASE+0X000) /* ²¨ÌØÂÊÉèÖõͰËλ¼Ä´æÆ÷ */ +#define UART3_RXFIFO (UART3_BASE+0X000) /* ½ÓÊÕFIFO */ +#define UART3_TXFIFO (UART3_BASE+0X000) /* ·¢ËÍFIFO */ +#define UART3_DLBH (UART3_BASE+0X004) /* ²¨ÌØÂÊÉèÖø߰Ëλ¼Ä´æÆ÷ */ +#define UART3_IER (UART3_BASE+0X004) /* ÖжÏʹÄܼĴæÆ÷ */ +#define UART3_IIR (UART3_BASE+0X008) /* ÖжÏʶ±ð¼Ä´æÆ÷ */ +#define UART3_FCR (UART3_BASE+0X008) /* FIFO¿ØÖƼĴæÆ÷ */ +#define UART3_LCR (UART3_BASE+0X00C) /* ÐпØÖƼĴæÆ÷ */ +#define UART3_MCR (UART3_BASE+0X010) /* Modem¿ØÖƼĴæÆ÷ */ +#define UART3_LSR (UART3_BASE+0X014) /* ÐÐ״̬¼Ä´æÆ÷ */ +#define UART3_MSR (UART3_BASE+0X018) /* Modem״̬¼Ä´æÆ÷ */ + + +/* + * SSIÄ£¿é + * »ùÖ·: 0x10009000 + */ + +#define SSI_CONTROL0 (SSI_BASE+0X000) /* ¿ØÖƼĴæÆ÷0 */ +#define SSI_CONTROL1 (SSI_BASE+0X004) /* ¿ØÖƼĴæÆ÷1 */ +#define SSI_SSIENR (SSI_BASE+0X008) /* SSIʹÄܼĴæÆ÷ */ +#define SSI_MWCR (SSI_BASE+0X00C) /* Microwire¿ØÖƼĴæÆ÷ */ +#define SSI_SER (SSI_BASE+0X010) /* ´ÓÉ豸ʹÄܼĴæÆ÷ */ +#define SSI_BAUDR (SSI_BASE+0X014) /* ²¨ÌØÂÊÉèÖüĴæÆ÷ */ +#define SSI_TXFTLR (SSI_BASE+0X018) /* ·¢ËÍFIFOãÐÖµ¼Ä´æÆ÷ */ +#define SSI_RXFTLR (SSI_BASE+0X01C) /* ½ÓÊÕFIFOãÐÖµ¼Ä´æÆ÷ */ +#define SSI_TXFLR (SSI_BASE+0X020) /* ·¢ËÍFIFO״̬¼Ä´æÆ÷ */ +#define SSI_RXFLR (SSI_BASE+0X024) /* ½ÓÊÕFIFO״̬¼Ä´æÆ÷ */ +#define SSI_SR (SSI_BASE+0X028) /* ״̬¼Ä´æÆ÷ */ +#define SSI_IMR (SSI_BASE+0X02C) /* ÖÐ¶ÏÆÁ±Î¼Ä´æÆ÷ */ +#define SSI_ISR (SSI_BASE+0X030) /* ÖжÏ×îÖÕ״̬¼Ä´æÆ÷ */ +#define SSI_RISR (SSI_BASE+0X034) /* ÖжÏԭʼ״̬¼Ä´æÆ÷ */ +#define SSI_TXOICR (SSI_BASE+0X038) /* ·¢ËÍFIFOÉÏÒçÖжÏÇå³ý¼Ä´æÆ÷ */ +#define SSI_RXOICR (SSI_BASE+0X03C) /* ½ÓÊÕFIFOÉÏÒçÖжÏÇå³ý¼Ä´æÆ÷ */ +#define SSI_RXUICR (SSI_BASE+0X040) /* ½ÓÊÕFIFOÏÂÒçÖжÏÇå³ý¼Ä´æÆ÷ */ +#define SSI_ICR (SSI_BASE+0X02C) /* ÖжÏÇå³ý¼Ä´æÆ÷ */ +#define SSI_DMACR (SSI_BASE+0X04C) /* DMA¿ØÖƼĴæÆ÷ */ +#define SSI_DMATDLR (SSI_BASE+0X050) /* DMA·¢ËÍ״̬¼Ä´æÆ÷ */ +#define SSI_DMARDLR (SSI_BASE+0X054) /* DMA½ÓÊÕ״̬¼Ä´æÆ÷ */ +#define SSI_DR (SSI_BASE+0X060) /* Êý¾Ý¼Ä´æÆ÷ */ + + +/* + * I2SÄ£¿é + * »ùÖ·: 0x1000A000 + */ + +#define I2S_CTRL (I2S_BASE+0X000) /* I2S¿ØÖƼĴæÆ÷ */ +#define I2S_DATA (I2S_BASE+0X004) /* I2SÊý¾Ý¼Ä´æÆ÷ */ +#define I2S_INT (I2S_BASE+0X008) /* I2SÖжϼĴæÆ÷ */ +#define I2S_STATUS (I2S_BASE+0X00C) /* I2S״̬¼Ä´æÆ÷ */ + + +/* + * SDÄ£¿é + * »ùÖ·: 0x1000B000 + */ + +#define SDC_CLOCK_CONTROL (SD_BASE+0x00) /* SDIOʱÖÓ¿ØÖƼĴæÆ÷ */ +#define SDC_SOFTWARE_RESET (SD_BASE+0X04) /* SDIOÈí¼þ¸´Î»¼Ä´æÆ÷ */ +#define SDC_ARGUMENT (SD_BASE+0X08) /* SDIOÃüÁî²ÎÊý¼Ä´æÆ÷ */ +#define SDC_COMMAND (SD_BASE+0X0C) /* SDIOÃüÁî¿ØÖÆ¼Ä´æÆ÷ */ +#define SDC_BLOCK_SIZE (SD_BASE+0X10) /* SDIOÊý¾Ý¿é³¤¶È¼Ä´æÆ÷ */ +#define SDC_BLOCK_COUNT (SD_BASE+0X14) /* SDIOÊý¾Ý¿éÊýÄ¿¼Ä´æÆ÷ */ +#define SDC_TRANSFER_MODE (SD_BASE+0X18) /* SDIO´«ÊäģʽѡÔñ¼Ä´æÆ÷ */ +#define SDC_RESPONSE0 (SD_BASE+0X1c) /* SDIOÏìÓ¦¼Ä´æÆ÷0 */ +#define SDC_RESPONSE1 (SD_BASE+0X20) /* SDIOÏìÓ¦¼Ä´æÆ÷1 */ +#define SDC_RESPONSE2 (SD_BASE+0X24) /* SDIOÏìÓ¦¼Ä´æÆ÷2 */ +#define SDC_RESPONSE3 (SD_BASE+0X28) /* SDIOÏìÓ¦¼Ä´æÆ÷3 */ +#define SDC_READ_TIMEOUT_CONTROL (SD_BASE+0X2c) /* SDIO¶Á³¬Ê±¿ØÖƼĴæÆ÷ */ +#define SDC_INTERRUPT_STATUS (SD_BASE+0X30) /* SDIOÖжÏ״̬¼Ä´æÆ÷ */ +#define SDC_INTERRUPT_STATUS_MASK (SD_BASE+0X34) /* SDIOÖжÏ״̬ÆÁ±Î¼Ä´æÆ÷ */ +#define SDC_READ_BUFER_ACCESS (SD_BASE+0X38) /* SDIO½ÓÊÕFIFO */ +#define SDC_WRITE_BUFER_ACCESS (SD_BASE+0X3c) /* SDIO·¢ËÍFIFO */ + + + +/* + * SMC0Ä£¿é + * »ùÖ·: 0x1000C000 + */ + +#define SMC0_CTRL (SMC0_BASE+0X000) /* SMC0¿ØÖƼĴæÆ÷ */ +#define SMC0_INT (SMC0_BASE+0X004) /* SMC0ÖжϼĴæÆ÷ */ +#define SMC0_FD (SMC0_BASE+0X008) /* SMC0»ù±¾µ¥ÔªÊ±¼ä¼Ä´æÆ÷ */ +#define SMC0_CT (SMC0_BASE+0X00C) /* SMC0×Ö·û´«Êäʱ¼ä¼Ä´æÆ÷ */ +#define SMC0_BT (SMC0_BASE+0X010) /* SMC0¿é´«Êäʱ¼ä¼Ä´æÆ÷ */ + + + +/* + * SMC1Ä£¿é + * »ùÖ·: 0x1000D000 + */ + +#define SMC1_CTRL (SMC1_BASE+0X000) /* SMC1¿ØÖƼĴæÆ÷ */ +#define SMC1_INT (SMC1_BASE+0X004) /* SMC1ÖжϼĴæÆ÷ */ +#define SMC1_FD (SMC1_BASE+0X008) /* SMC1»ù±¾µ¥ÔªÊ±¼ä¼Ä´æÆ÷ */ +#define SMC1_CT (SMC1_BASE+0X00C) /* SMC1×Ö·û´«Êäʱ¼ä¼Ä´æÆ÷ */ +#define SMC1_BT (SMC1_BASE+0X010) /* SMC1¿é´«Êäʱ¼ä¼Ä´æÆ÷ */ + + + +/* + * USBDÄ£¿é + * »ùÖ·: 0x1000E000 + */ + +#define USBD_PROTOCOLINTR (USBD_BASE+0X000) /* USBЭÒéÖжϼĴæÆ÷ */ +#define USBD_INTRMASK (USBD_BASE+0X004) /* USBÖÐ¶ÏÆÁ±Î¼Ä´æÆ÷ */ +#define USBD_INTRCTRL (USBD_BASE+0X008) /* USBÖжÏÀàÐÍ¿ØÖƼĴæÆ÷ */ +#define USBD_EPINFO (USBD_BASE+0X00C) /* USB»î¶¯¶Ëµã״̬¼Ä´æÆ÷ */ +#define USBD_BCONFIGURATIONVALUE (USBD_BASE+0X010) /* SET_CCONFIGURATION¼Ç¼ */ +#define USBD_BMATTRIBUTES (USBD_BASE+0X014) /* µ±Ç°ÅäÖÃÊôÐԼĴæÆ÷ */ +#define USBD_DEVSPEED (USBD_BASE+0X018) /* µ±Ç°É豸¹¤×÷ËٶȼĴæÆ÷ */ +#define USBD_FRAMENUMBER (USBD_BASE+0X01C) /* ¼Ç¼µ±Ç°SOF°üÄÚµÄÖ¡ºÅ */ +#define USBD_EPTRANSACTIONS0 (USBD_BASE+0X020) /* ¼Ç¼Ï´ÎÒªÇóµÄ´«Êä´ÎÊý */ +#define USBD_EPTRANSACTIONS1 (USBD_BASE+0X024) /* ¼Ç¼Ï´ÎÒªÇóµÄ´«Êä´ÎÊý */ +#define USBD_APPIFUPDATE (USBD_BASE+0X028) /* ½Ó¿ÚºÅ¿ìËÙ¸üмĴæÆ÷ */ +#define USBD_CFGINTERFACE0 (USBD_BASE+0X02C) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE1 (USBD_BASE+0X030) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE2 (USBD_BASE+0X034) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE3 (USBD_BASE+0X038) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE4 (USBD_BASE+0X03C) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE5 (USBD_BASE+0X040) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE6 (USBD_BASE+0X044) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE7 (USBD_BASE+0X048) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE8 (USBD_BASE+0X04C) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE9 (USBD_BASE+0X050) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE10 (USBD_BASE+0X054) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE11 (USBD_BASE+0X058) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE12 (USBD_BASE+0X05C) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE13 (USBD_BASE+0X060) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE14 (USBD_BASE+0X064) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE15 (USBD_BASE+0X068) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE16 (USBD_BASE+0X06C) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE17 (USBD_BASE+0X070) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE18 (USBD_BASE+0X074) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE19 (USBD_BASE+0X078) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE20 (USBD_BASE+0X07C) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE21 (USBD_BASE+0X080) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE22 (USBD_BASE+0X084) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE23 (USBD_BASE+0X088) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE24 (USBD_BASE+0X08C) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE25 (USBD_BASE+0X090) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE26 (USBD_BASE+0X094) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE27 (USBD_BASE+0X098) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE28 (USBD_BASE+0X09C) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE29 (USBD_BASE+0X0A0) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE30 (USBD_BASE+0X0A4) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_CFGINTERFACE31 (USBD_BASE+0X0A8) /* ¼Ç¼½Ó¿ÚµÄÖµ */ +#define USBD_PKTPASSEDCTRL (USBD_BASE+0X0AC) /* ¼Ç¼³É¹¦½ÓÊյİüÊý */ +#define USBD_PKTDROPPEDCTRL (USBD_BASE+0X0B0) /* ¼Ç¼¶ªÊ§µÄ°üÊý */ +#define USBD_CRCERRCTRL (USBD_BASE+0X0B4) /* ¼Ç¼CRC´íÎóµÄ°üÊý */ +#define USBD_BITSTUFFERRCTRL (USBD_BASE+0X0B8) /* ¼Ç¼λÌî³ä´íÎóµÄ°üÊý */ +#define USBD_PIDERRCTRL (USBD_BASE+0X0BC) /* ¼Ç¼PID´íÎóµÄ°üÊý */ +#define USBD_FRAMINGERRCTL (USBD_BASE+0X0C0) /* ¼Ç¼ÓÐSYNCºÍEOPµÄ°üÊý */ +#define USBD_TXPKTCTRL (USBD_BASE+0X0C4) /* ¼Ç¼·¢ËͰüµÄÊýÁ¿ */ +#define USBD_STATCTRLOV (USBD_BASE+0X0C8) /* ¼Ç¼ͳ¼Æ¼Ä´æÆ÷Òç³öÇé¿ö */ +#define USBD_TXLENGTH (USBD_BASE+0X0CC) /* ¼Ç¼ÿ´ÎIN´«ÊäÊÂÎñ°ü³¤¶È */ +#define USBD_RXLENGTH (USBD_BASE+0X0D0) /* ¼Ç¼OUT´«ÊäÊÂÎñ°ü³¤¶È */ +#define USBD_RESUME (USBD_BASE+0X0D4) /* USB»½ÐѼĴæÆ÷ */ +#define USBD_READFLAG (USBD_BASE+0X0D8) /* ¶ÁÒ첽״̬¼Ä´æÆ÷±êÖ¾ */ +#define USBD_RECEIVETYPE (USBD_BASE+0X0DC) /* ´«Êä״̬¼Ä´æÆ÷ */ +#define USBD_APPLOCK (USBD_BASE+0X0E0) /* ËøÐźżĴæÆ÷ */ +#define USBD_EP0OUTADDR (USBD_BASE+0X100) /* ¶Ëµã0¶ËµãºÅºÍ·½Ïò */ +#define USBD_EP0OUTBMATTR (USBD_BASE+0X104) /* ¶Ëµã0ÀàÐͼĴæÆ÷ */ +#define USBD_EP0OUTMAXPKTSIZE (USBD_BASE+0X108) /* ¶Ëµã0×î´ó°ü³ß´ç¼Ä´æÆ÷ */ +#define USBD_EP0OUTIFNUM (USBD_BASE+0X10C) /* ¶Ëµã0½Ó¿ÚºÅ¼Ä´æÆ÷ */ +#define USBD_EP0OUTSTAT (USBD_BASE+0X110) /* ¶Ëµã0״̬¼Ä´æÆ÷ */ +#define USBD_EP0OUTBMREQTYPE (USBD_BASE+0X114) /* ¶Ëµã0 SETUPÊÂÎñÇëÇóÀà */ +#define USBD_EP0OUTBREQUEST (USBD_BASE+0X118) /* ¶Ëµã0 SETUPÊÂÎñÇëÇóÄÚÈÝ */ +#define USBD_EP0OUTWVALUE (USBD_BASE+0X11C) /* ¶Ëµã0 SETUPÊÂÎñÇëÇóÖµ */ +#define USBD_EP0OUTWINDEX (USBD_BASE+0X120) /* ¶Ëµã0 SETUPÊÂÎñÇëÇóË÷Òý */ +#define USBD_EP0OUTWLENGTH (USBD_BASE+0X120) /* ¶Ëµã0 SETUPÊÂÎñÇëÇó³¤¶È */ +#define USBD_EP0OUTSYNCHFRAME (USBD_BASE+0X128) /* ¶Ëµã0ͬ²½°üÖ¡ºÅ */ +#define USBD_EP1OUTADDR (USBD_BASE+0X12C) /* ¶Ëµã1Êä³ö¶ËµãºÅºÍ·½Ïò */ +#define USBD_EP1OUTBMATTR (USBD_BASE+0X130) /* ¶Ëµã1Êä³öÀàÐͼĴæÆ÷ */ +#define USBD_EP1OUTMAXPKTSIZE (USBD_BASE+0X134) /* ¶Ëµã1Êä³ö×î´ó°ü³ß´ç¼Ä´æÆ÷ */ +#define USBD_EP1OUTIFNUM (USBD_BASE+0X138) /* ¶Ëµã1Êä³ö½Ó¿ÚºÅ¼Ä´æÆ÷ */ +#define USBD_EP1OUTSTAT (USBD_BASE+0X13C) /* ¶Ëµã1Êä³ö״̬¼Ä´æÆ÷ */ +#define USBD_EP1OUTBMREQTYPE (USBD_BASE+0X140) /* ¶Ëµã1Êä³öSETUPÊÂÎñÇëÇóÀàÐÍ */ +#define USBD_EP1OUTBREQUEST (USBD_BASE+0X144) /* ¶Ëµã1Êä³öSETUPÊÂÎñÇëÇóÄÚÈÝ */ +#define USBD_EP1OUTWVALUE (USBD_BASE+0X148) /* ¶Ëµã1Êä³öSETUPÊÂÎñÇëÇóÖµ */ +#define USBD_EP1OUTWINDX (USBD_BASE+0X14C) /* ¶Ëµã1Êä³öSETUPÊÂÎñÇëÇóË÷Òý */ +#define USBD_EP1OUTWLENGH (USBD_BASE+0X150) /* ¶Ëµã1Êä³öSETUPÊÂÎñÇëÇóÓò³¤¶È */ +#define USBD_EP1OUTSYNCHFRAME (USBD_BASE+0X154) /* ¶Ëµã1Êä³öͬ²½°üÖ¡ºÅ */ +#define USBD_EP1INADDR (USBD_BASE+0X158) /* ¶Ëµã1ÊäÈë¶ËµãºÅºÍ·½Ïò */ +#define USBD_EP1INBMATTR (USBD_BASE+0X15C) /* ¶Ëµã1ÊäÈëÀàÐͼĴæÆ÷ */ +#define USBD_EP1INMAXPKTSIZE (USBD_BASE+0X160) /* ¶Ëµã1ÊäÈë×î´ó°ü³ß´ç¼Ä´æÆ÷ */ +#define USBD_EP1INIFNUM (USBD_BASE+0X164) /* ¶Ëµã1ÊäÈë½Ó¿ÚºÅ¼Ä´æÆ÷ */ +#define USBD_EP1INSTAT (USBD_BASE+0X168) /* ¶Ëµã1ÊäÈë״̬¼Ä´æÆ÷ */ +#define USBD_EP1INBMREQTYPE (USBD_BASE+0X16C) /* ¶Ëµã1ÊäÈëSETUPÊÂÎñÇëÇóÀàÐÍ */ +#define USBD_EP1INBREQUEST (USBD_BASE+0X170) /* ¶Ëµã1ÊäÈëSETUPÊÂÎñÇëÇóÄÚÈÝ */ +#define USBD_EP1INWVALUE (USBD_BASE+0X174) /* ¶Ëµã1ÊäÈëSETUPÊÂÎñÇëÇóÖµ */ +#define USBD_EP1INWINDEX (USBD_BASE+0X178) /* ¶Ëµã1ÊäÈëSETUPÊÂÎñÇëÇóË÷Òý */ +#define USBD_EP1INWLENGTH (USBD_BASE+0X17C) /* ¶Ëµã1ÊäÈëSETUPÊÂÎñÇëÇóÓò³¤¶È */ +#define USBD_EP1INSYNCHFRAME (USBD_BASE+0X180) /* ¶Ëµã1ÊäÈëͬ²½°üÖ¡ºÅ */ +#define USBD_EP2OUTADDR (USBD_BASE+0X184) /* ¶Ëµã2Êä³ö¶ËµãºÅºÍ·½Ïò */ +#define USBD_EP2OUTBMATTR (USBD_BASE+0X188) /* ¶Ëµã2Êä³öÀàÐͼĴæÆ÷ */ +#define USBD_EP2OUTMAXPKTSIZE (USBD_BASE+0X18C) /* ¶Ëµã2Êä³ö×î´ó°ü³ß´ç¼Ä´æÆ÷ */ +#define USBD_EP2OUTIFNUM (USBD_BASE+0X190) /* ¶Ëµã2Êä³ö½Ó¿ÚºÅ¼Ä´æÆ÷ */ +#define USBD_EP2OUTSTAT (USBD_BASE+0X194) /* ¶Ëµã2Êä³ö״̬¼Ä´æÆ÷ */ +#define USBD_EP2OUTBMREQTYPE (USBD_BASE+0X198) /* ¶Ëµã2Êä³öSETUPÊÂÎñÇëÇóÀàÐÍ */ +#define USBD_EP2OUTBREQUEST (USBD_BASE+0X19C) /* ¶Ëµã2Êä³öSETUPÊÂÎñÇëÇóÄÚÈÝ */ +#define USBD_EP2OUTWVALUE (USBD_BASE+0X1A0) /* ¶Ëµã2Êä³öSETUPÊÂÎñÇëÇóÖµ */ +#define USBD_EP2OUTWINDEX (USBD_BASE+0X1A4) /* ¶Ëµã2Êä³öSETUPÊÂÎñÇëÇóË÷Òý */ +#define USBD_EP2OUTWLENGTH (USBD_BASE+0X1A8) /* ¶Ëµã2Êä³öSETUPÊÂÎñÇëÇóÓò³¤¶È */ +#define USBD_EP2OUTSYNCHFRAME (USBD_BASE+0X1AC) /* ¶Ëµã2Êä³öͬ²½°üÖ¡ºÅ */ +#define USBD_EP2INADDR (USBD_BASE+0X1B0) /* ¶Ëµã2ÊäÈë¶ËµãºÅºÍ·½Ïò */ +#define USBD_EP2INBMATTR (USBD_BASE+0X1B4) /* ¶Ëµã2ÊäÈëÀàÐͼĴæÆ÷ */ +#define USBD_EP2INMAXPKTSIZE (USBD_BASE+0X1B8) /* ¶Ëµã2ÊäÈë×î´ó°ü³ß´ç¼Ä´æÆ÷ */ +#define USBD_EP2INIFNUM (USBD_BASE+0X1BC) /* ¶Ëµã2ÊäÈë½Ó¿ÚºÅ¼Ä´æÆ÷ */ +#define USBD_EP2INSTAT (USBD_BASE+0X1C0) /* ¶Ëµã2ÊäÈë״̬¼Ä´æÆ÷ */ +#define USBD_EP2INBMREQTYPE (USBD_BASE+0X1C4) /* ¶Ëµã2ÊäÈëSETUPÊÂÎñÇëÇóÀàÐÍ */ +#define USBD_EP2INBREQUEST (USBD_BASE+0X1C8) /* ¶Ëµã2ÊäÈëSETUPÊÂÎñÇëÇóÄÚÈÝ */ +#define USBD_EP2INWVALUE (USBD_BASE+0X1CC) /* ¶Ëµã2ÊäÈëSETUPÊÂÎñÇëÇóÖµ */ +#define USBD_EP2INWINDEX (USBD_BASE+0X1D0) /* ¶Ëµã2ÊäÈëSETUPÊÂÎñÇëÇóË÷Òý */ +#define USBD_EP2INWLENGTH (USBD_BASE+0X1D4) /* ¶Ëµã2ÊäÈëSETUPÊÂÎñÇëÇóÓò³¤¶È */ +#define USBD_EP2INSYNCHFRAME (USBD_BASE+0X1D8) /* ¶Ëµã2ÊäÈëͬ²½°üÖ¡ºÅ */ +#define USBD_RXFIFO (USBD_BASE+0X200) /* ½ÓÊÜFIFO */ +#define USBD_TXFIFO (USBD_BASE+0X300) /* ·¢ËÍFIFO */ + + +/* + * GPIOÄ£¿é + * »ùÖ·: 0x1000F000 + */ + +#define GPIO_DBCLK_DIV (GPIO_BASE+0X000) /* ȥë´Ì²ÉÓÃʱÖÓ·ÖÆµ±ÈÅäÖüĴæÆ÷ */ +#define GPIO_PORTA_DIR (GPIO_BASE+0X004) /* A×é¶Ë¿ÚÊäÈëÊä³ö·½ÏòÅäÖüĴæÆ÷ */ +#define GPIO_PORTA_SEL (GPIO_BASE+0X008) /* A×é¶Ë¿ÚͨÓÃÓÃ;ѡÔñÅäÖüĴæÆ÷ */ +#define GPIO_PORTA_INCTL (GPIO_BASE+0X00C) /* A×é¶Ë¿ÚͨÓÃÓÃ;ÊäÈëʱÀàÐÍÅäÖüĴæÆ÷ */ +#define GPIO_PORTA_INTRCTL (GPIO_BASE+0X010) /* A×é¶Ë¿ÚÖжϴ¥·¢ÀàÐÍÅäÖüĴæÆ÷ */ +#define GPIO_PORTA_INTRCLR (GPIO_BASE+0X014) /* A×é¶Ë¿ÚͨÓÃÓÃ;ÖжÏÇå³ýÅäÖüĴæÆ÷ */ +#define GPIO_PORTA_DATA (GPIO_BASE+0X018) /* A×é¶Ë¿ÚͨÓÃÓÃ;Êý¾ÝÅäÖüĴæÆ÷ */ +#define GPIO_PORTB_DIR (GPIO_BASE+0X01C) /* B×é¶Ë¿ÚÊäÈëÊä³ö·½ÏòÅäÖüĴæÆ÷ */ +#define GPIO_PORTB_SEL (GPIO_BASE+0X020) /* B×é¶Ë¿ÚͨÓÃÓÃ;ѡÔñÅäÖüĴæÆ÷ */ +#define GPIO_PORTB_DATA (GPIO_BASE+0X024) /* B×é¶Ë¿ÚͨÓÃÓÃ;Êý¾ÝÅäÖüĴæÆ÷ */ +#define GPIO_PORTC_DIR (GPIO_BASE+0X028) /* C×é¶Ë¿ÚÊäÈëÊä³ö·½ÏòÅäÖüĴæÆ÷ */ +#define GPIO_PORTC_SEL (GPIO_BASE+0X02C) /* C×é¶Ë¿ÚͨÓÃÓÃ;ѡÔñÅäÖüĴæÆ÷ */ +#define GPIO_PORTC_DATA (GPIO_BASE+0X030) /* C×é¶Ë¿ÚͨÓÃÓÃ;Êý¾ÝÅäÖüĴæÆ÷ */ +#define GPIO_PORTD_DIR (GPIO_BASE+0X034) /* D×é¶Ë¿ÚÊäÈëÊä³ö·½ÏòÅäÖüĴæÆ÷ */ +#define GPIO_PORTD_SEL (GPIO_BASE+0X038) /* D×é¶Ë¿ÚͨÓÃÓÃ;ѡÔñÅäÖüĴæÆ÷ */ +#define GPIO_PORTD_SPECII (GPIO_BASE+0X03C) /* D×é¶Ë¿ÚרÓÃÓÃ;2Ñ¡ÔñÅäÖüĴæÆ÷ */ +#define GPIO_PORTD_DATA (GPIO_BASE+0X040) /* D×é¶Ë¿ÚͨÓÃÓÃ;Êý¾ÝÅäÖüĴæÆ÷ */ +#define GPIO_PORTE_DIR (GPIO_BASE+0X044) /* E×é¶Ë¿ÚÊäÈëÊä³ö·½ÏòÅäÖüĴæÆ÷ */ +#define GPIO_PORTE_SEL (GPIO_BASE+0X048) /* E×é¶Ë¿ÚͨÓÃÓÃ;ѡÔñÅäÖüĴæÆ÷ */ +#define GPIO_PORTE_DATA (GPIO_BASE+0X04C) /* E×é¶Ë¿ÚͨÓÃÓÃ;Êý¾ÝÅäÖüĴæÆ÷ */ +#define GPIO_PORTF_DIR (GPIO_BASE+0X050) /* F×é¶Ë¿ÚÊäÈëÊä³ö·½ÏòÅäÖüĴæÆ÷ */ +#define GPIO_PORTF_SEL (GPIO_BASE+0X054) /* F×é¶Ë¿ÚͨÓÃÓÃ;ѡÔñÅäÖüĴæÆ÷ */ +#define GPIO_PORTF_INCTL (GPIO_BASE+0X058) /* F×é¶Ë¿ÚͨÓÃÓÃ;ÊäÈëʱÀàÐÍÅäÖüĴæÆ÷ */ +#define GPIO_PORTF_INTRCTL (GPIO_BASE+0X05C) /* F×é¶Ë¿ÚÖжϴ¥·¢ÀàÐÍÅäÖüĴæÆ÷ */ +#define GPIO_PORTF_INTRCLR (GPIO_BASE+0X060) /* F×é¶Ë¿ÚͨÓÃÓÃ;ÖжÏÇå³ýÅäÖüĴæÆ÷ */ +#define GPIO_PORTF_DATA (GPIO_BASE+0X064) /* F×é¶Ë¿ÚͨÓÃÓÃ;Êý¾ÝÅäÖüĴæÆ÷ */ +#define GPIO_PORTG_DIR (GPIO_BASE+0X068) /* G×é¶Ë¿ÚÊäÈëÊä³ö·½ÏòÅäÖüĴæÆ÷ */ +#define GPIO_PORTG_SEL (GPIO_BASE+0X06C) /* G×é¶Ë¿ÚͨÓÃÓÃ;ѡÔñÅäÖüĴæÆ÷ */ +#define GPIO_PORTG_DATA (GPIO_BASE+0X070) /* G×é¶Ë¿ÚͨÓÃÓÃ;Êý¾ÝÅäÖüĴæÆ÷ */ +#define GPIO_PORTH_DIR (GPIO_BASE+0X07C) /* H×é¶Ë¿ÚÊäÈëÊä³ö·½ÏòÅäÖüĴæÆ÷ */ +#define GPIO_PORTH_SEL (GPIO_BASE+0X078) /* H×é¶Ë¿ÚͨÓÃÓÃ;ѡÔñÅäÖüĴæÆ÷ */ +#define GPIO_PORTH_DATA (GPIO_BASE+0X07C) /* H×é¶Ë¿ÚͨÓÃÓÃ;Êý¾ÝÅäÖüĴæÆ÷ */ +#define GPIO_PORTI_DIR (GPIO_BASE+0X080) /* I×é¶Ë¿ÚÊäÈëÊä³ö·½ÏòÅäÖüĴæÆ÷ */ +#define GPIO_PORTI_SEL (GPIO_BASE+0X084) /* I×é¶Ë¿ÚͨÓÃÓÃ;ѡÔñÅäÖüĴæÆ÷ */ +#define GPIO_PORTI_DATA (GPIO_BASE+0X088) /* I×é¶Ë¿ÚͨÓÃÓÃ;Êý¾ÝÅäÖüĴæÆ÷ */ + + + +/* + * EMIÄ£¿é + * »ùÖ·: 0x11000000 + */ + +#define EMI_CSACONF (EMI_BASE+0X000) /* CSA²ÎÊýÅäÖüĴæÆ÷ */ +#define EMI_CSBCONF (EMI_BASE+0X004) /* CSB²ÎÊýÅäÖüĴæÆ÷ */ +#define EMI_CSCCONF (EMI_BASE+0X008) /* CSC²ÎÊýÅäÖüĴæÆ÷ */ +#define EMI_CSDCONF (EMI_BASE+0X00C) /* CSD²ÎÊýÅäÖüĴæÆ÷ */ +#define EMI_CSECONF (EMI_BASE+0X010) /* CSE²ÎÊýÅäÖüĴæÆ÷ */ +#define EMI_CSFCONF (EMI_BASE+0X014) /* CSF²ÎÊýÅäÖüĴæÆ÷ */ +#define EMI_SDCONF1 (EMI_BASE+0X018) /* SDRAMʱÐòÅäÖüĴæÆ÷1 */ +#define EMI_SDCONF2 (EMI_BASE+0X01C) /* SDRAMʱÐòÅäÖüĴæÆ÷2, SDRAM³õʼ»¯Óõ½µÄÅäÖÃÐÅÏ¢ */ +#define EMI_REMAPCONF (EMI_BASE+0X020) /* Ƭѡ¿Õ¼ä¼°µØÖ·Ó³ÉäREMAPÅäÖüĴæÆ÷ */ +#define EMI_NAND_ADDR1 (EMI_BASE+0X100) /* NAND FLASHµÄµØÖ·¼Ä´æÆ÷1 */ +#define EMI_NAND_COM (EMI_BASE+0X104) /* NAND FLASHµÄ¿ØÖÆ×ּĴæÆ÷ */ +#define EMI_NAND_STA (EMI_BASE+0X10C) /* NAND FLASHµÄ״̬¼Ä´æÆ÷ */ +#define EMI_ERR_ADDR1 (EMI_BASE+0X110) /* ¶Á²Ù×÷³ö´íµÄµØÖ·¼Ä´æÆ÷1 */ +#define EMI_ERR_ADDR2 (EMI_BASE+0X114) /* ¶Á²Ù×÷³ö´íµÄµØÖ·¼Ä´æÆ÷2 */ +#define EMI_NAND_CONF1 (EMI_BASE+0X118) /* NAND FLASHµÄÅäÖÃÆ÷´æÆ÷1 */ +#define EMI_NAND_INTR (EMI_BASE+0X11C) /* NAND FLASHÖжϼĴæÆ÷ */ +#define EMI_NAND_ECC (EMI_BASE+0X120) /* ECCУÑéÍê³É¼Ä´æÆ÷ */ +#define EMI_NAND_IDLE (EMI_BASE+0X124) /* NAND FLASH¿ÕÏмĴæÆ÷ */ +#define EMI_NAND_CONF2 (EMI_BASE+0X128) /* NAND FLASHµÄÅäÖÃÆ÷´æÆ÷2 */ +#define EMI_NAND_ADDR2 (EMI_BASE+0X12C) /* NAND FLASHµÄµØÖ·¼Ä´æÆ÷2 */ +#define EMI_NAND_DATA (EMI_BASE+0X200) /* NAND FLASHµÄÊý¾Ý¼Ä´æÆ÷ */ + + +/* + * DMACÄ£¿é + * »ùÖ·: 0x11001000 + */ + +#define DMAC_INTSTATUS (DMAC_BASE+0X020) /* DAMCÖжÏ״̬¼Ä´æÆ÷¡£ */ +#define DMAC_INTTCSTATUS (DMAC_BASE+0X050) /* DMAC´«ÊäÍê³ÉÖжÏ״̬¼Ä´æÆ÷ */ +#define DMAC_INTTCCLEAR (DMAC_BASE+0X060) /* DMAC´«ÊäÍê³ÉÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define DMAC_INTERRORSTATUS (DMAC_BASE+0X080) /* DMAC´«Êä´íÎóÖжÏ״̬¼Ä´æÆ÷ */ +#define DMAC_INTINTERRCLR (DMAC_BASE+0X090) /* DMAC´«Êä´íÎóÖжÏ״̬Çå³ý¼Ä´æÆ÷ */ +#define DMAC_ENBLDCHNS (DMAC_BASE+0X0B0) /* DMACͨµÀʹÄÜ״̬¼Ä´æÆ÷ */ +#define DMAC_C0SRCADDR (DMAC_BASE+0X000) /* DMACµÀ0Ô´µØÖ·¼Ä´æÆ÷ */ +#define DMAC_C0DESTADD (DMAC_BASE+0X004) /* DMACµÀ0Ä¿µÄµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C0CONTROL (DMAC_BASE+0X00C) /* DMACµÀ0¿ØÖƼĴæÆ÷ */ +#define DMAC_C0CONFIGURATION (DMAC_BASE+0X010) /* DMACµÀ0ÅäÖüĴæÆ÷ */ +#define DMAC_C0DESCRIPTOR (DMAC_BASE+0X01C) /* DMACµÀ0Á´±íµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C1SRCADDR (DMAC_BASE+0X100) /* DMACµÀ1Ô´µØÖ·¼Ä´æÆ÷ */ +#define DMAC_C1DESTADDR (DMAC_BASE+0X104) /* DMACµÀ1Ä¿µÄµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C1CONTROL (DMAC_BASE+0X10C) /* DMACµÀ1¿ØÖƼĴæÆ÷ */ +#define DMAC_C1CONFIGURATION (DMAC_BASE+0X110) /* DMACµÀ1ÅäÖüĴæÆ÷ */ +#define DMAC_C1DESCRIPTOR (DMAC_BASE+0X114) /* DMACµÀ1Á´±íµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C2SRCADDR (DMAC_BASE+0X200) /* DMACµÀ2Ô´µØÖ·¼Ä´æÆ÷ */ +#define DMAC_C2DESTADDR (DMAC_BASE+0X204) /* DMACµÀ2Ä¿µÄµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C2CONTROL (DMAC_BASE+0X20C) /* DMACµÀ2¿ØÖƼĴæÆ÷ */ +#define DMAC_C2CONFIGURATION (DMAC_BASE+0X210) /* DMACµÀ2ÅäÖüĴæÆ÷ */ +#define DMAC_C2DESCRIPTOR (DMAC_BASE+0X214) /* DMACµÀ2Á´±íµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C3SRCADDR (DMAC_BASE+0X300) /* DMACµÀ3Ô´µØÖ·¼Ä´æÆ÷ */ +#define DMAC_C3DESTADDR (DMAC_BASE+0X304) /* DMACµÀ3Ä¿µÄµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C3CONTROL (DMAC_BASE+0X30C) /* DMACµÀ3¿ØÖƼĴæÆ÷ */ +#define DMAC_C3CONFIGURATION (DMAC_BASE+0X310) /* DMACµÀ3ÅäÖüĴæÆ÷ */ +#define DMAC_C3DESCRIPTOR (DMAC_BASE+0X314) /* DMACµÀ3Á´±íµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C4SRCADDR (DMAC_BASE+0X400) /* DMACµÀ4Ô´µØÖ·¼Ä´æÆ÷ */ +#define DMAC_C4DESTADDR (DMAC_BASE+0X404) /* DMACµÀ4Ä¿µÄµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C4CONTROL (DMAC_BASE+0X40C) /* DMACµÀ4¿ØÖƼĴæÆ÷ */ +#define DMAC_C4CONFIGURATION (DMAC_BASE+0X410) /* DMACµÀ4ÅäÖüĴæÆ÷ */ +#define DMAC_C4DESCRIPTOR (DMAC_BASE+0X414) /* DMACµÀ4Á´±íµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C5SRCADDR (DMAC_BASE+0X500) /* DMACµÀ5Ô´µØÖ·¼Ä´æÆ÷ */ +#define DMAC_C5DESTADDR (DMAC_BASE+0X504) /* DMACµÀ5Ä¿µÄµØÖ·¼Ä´æÆ÷ */ +#define DMAC_C5CONTROL (DMAC_BASE+0X50C) /* DMACµÀ5¿ØÖƼĴæÆ÷ */ +#define DMAC_C5CONFIGURATION (DMAC_BASE+0X510) /* DMACµÀ5ÅäÖüĴæÆ÷ */ +#define DMAC_C5DESCRIPTOR (DMAC_BASE+0X514) /* DMACµÀ5Á´±íµØÖ·¼Ä´æÆ÷ */ + + +/* + * LCDCÄ£¿é + * »ùÖ·: 0x11002000 + */ + +#define LCDC_SSA (LCDC_BASE+0X000) /* ÆÁÄ»ÆðʼµØÖ·¼Ä´æÆ÷ */ +#define LCDC_SIZE (LCDC_BASE+0X004) /* ÆÁÄ»³ß´ç¼Ä´æÆ÷ */ +#define LCDC_PCR (LCDC_BASE+0X008) /* Ãæ°åÅäÖüĴæÆ÷ */ +#define LCDC_HCR (LCDC_BASE+0X00C) /* ˮƽÅäÖüĴæÆ÷ */ +#define LCDC_VCR (LCDC_BASE+0X010) /* ´¹Ö±ÅäÖüĴæÆ÷ */ +#define LCDC_PWMR (LCDC_BASE+0X014) /* PWM¶Ô±È¶È¿ØÖƼĴæÆ÷ */ +#define LCDC_LECR (LCDC_BASE+0X018) /* ʹÄÜ¿ØÖƼĴæÆ÷ */ +#define LCDC_DMACR (LCDC_BASE+0X01C) /* DMA¿ØÖƼĴæÆ÷ */ +#define LCDC_LCDISREN (LCDC_BASE+0X020) /* ÖжÏʹÄܼĴæÆ÷ */ +#define LCDC_LCDISR (LCDC_BASE+0X024) /* ÖжÏ״̬¼Ä´æÆ÷ */ +#define LCDC_LGPMR (LCDC_BASE+0X040) /* »Ò¶Èµ÷ɫӳÉä¼Ä´æÆ÷×é (16¸ö32bit¼Ä´æÆ÷) */ + + +/* + * MACÄ£¿é + * »ùÖ·: 0x11003000 + */ + +#define MAC_CTRL (MAC_BASE+0X000) /* MAC¿ØÖƼĴæÆ÷ */ +#define MAC_INTSRC (MAC_BASE+0X004) /* MACÖжÏÔ´¼Ä´æÆ÷ */ +#define MAC_INTMASK (MAC_BASE+0X008) /* MACÖÐ¶ÏÆÁ±Î¼Ä´æÆ÷ */ +#define MAC_IPGT (MAC_BASE+0X00C) /* Á¬ÐøÖ¡¼ä¸ô¼Ä´æÆ÷ */ +#define MAC_IPGR1 (MAC_BASE+0X010) /* µÈ´ý´°¿Ú¼Ä´æÆ÷ */ +#define MAC_IPGR2 (MAC_BASE+0X014) /* µÈ´ý´°¿Ú¼Ä´æÆ÷ */ +#define MAC_PACKETLEN (MAC_BASE+0X018) /* Ö¡³¤¶È¼Ä´æÆ÷ */ +#define MAC_COLLCONF (MAC_BASE+0X01C) /* Åöײ֨·¢¼Ä´æÆ÷ */ +#define MAC_TXBD_NUM (MAC_BASE+0X020) /* ·¢ËÍÃèÊö·û¼Ä´æÆ÷ */ +#define MAC_FLOWCTRL (MAC_BASE+0X024) /* Á÷¿Ø¼Ä´æÆ÷ */ +#define MAC_MII_CTRL (MAC_BASE+0X028) /* PHY¿ØÖƼĴæÆ÷ */ +#define MAC_MII_CMD (MAC_BASE+0X02C) /* PHYÃüÁî¼Ä´æÆ÷ */ +#define MAC_MII_ADDRESS (MAC_BASE+0X030) /* PHYµØÖ·¼Ä´æÆ÷ */ +#define MAC_MII_TXDATA (MAC_BASE+0X034) /* PHYдÊý¾Ý¼Ä´æÆ÷ */ +#define MAC_MII_RXDATA (MAC_BASE+0X038) /* PHY¶ÁÊý¾Ý¼Ä´æÆ÷ */ +#define MAC_MII_STATUS (MAC_BASE+0X03C) /* PHY״̬¼Ä´æÆ÷ */ +#define MAC_ADDR0 (MAC_BASE+0X040) /* MACµØÖ·¼Ä´æÆ÷ */ +#define MAC_ADDR1 (MAC_BASE+0X044) /* MACµØÖ·¼Ä´æÆ÷ */ +#define MAC_HASH0 (MAC_BASE+0X048) /* MAC HASH¼Ä´æÆ÷ */ +#define MAC_HASH1 (MAC_BASE+0X04C) /* MAC HASH¼Ä´æÆ÷ */ +#define MAC_TXPAUSE (MAC_BASE+0X050) /* MAC¿ØÖÆÖ¡¼Ä´æÆ÷ */ +#define MAC_TX_BD (MAC_BASE+0X400) +#define MAC_RX_BD (MAC_BASE+0X600) + + +/* + ************************************** + * Error Codes: + * IF SUCCESS RETURN 0, ELSE RETURN OTHER ERROR CODE, + * parameter error return (-33)/E_PAR, + * hardware error reture (-99)/E_HA + ************************************** + */ + +#define E_OK 0 /* Normal completion */ +#define E_SYS (-5) /* System error */ +#define E_NOMEM (-10) /* Insufficient memory */ +#define E_NOSPT (-17) /* Feature not supported */ +#define E_INOSPT (-18) /* Feature not supported by ITRON/FILE specification */ +#define E_RSFN (-20) /* Reserved function code number */ +#define E_RSATR (-24) /* Reserved attribute */ +#define E_PAR (-33) /* Parameter error */ +#define E_ID (-35) /* Invalid ID number */ +#define E_NOEXS (-52) /* Object does not exist */ +#define E_OBJ (-63) /* Invalid object state */ +#define E_MACV (-65) /* Memory access disabled or memory access violation */ +#define E_OACV (-66) /* Object access violation */ +#define E_CTX (-69) /* Context error */ +#define E_QOVR (-73) /* Queuing or nesting overflow */ +#define E_DLT (-81) /* Object being waited for was deleted */ +#define E_TMOUT (-85) /* Polling failure or timeout exceeded */ +#define E_RLWAI (-86) /* WAIT state was forcibly released */ + +#define E_HA (-99) /* HARD WARE ERROR */ + + +/* + ************************************** + * PMU Ä£¿éʱÖÓ + ************************************** + */ + +#define CLK_SGPT (1 << 16) +#define CLK_SI2S (1 << 15) +#define CLK_SSMC (1 << 14) +#define CLK_SMAC (1 << 13) +#define CLK_SUSB (1 << 12) +#define CLK_SUART3 (1 << 11) +#define CLK_SUART2 (1 << 10) +#define CLK_SUART1 (1 << 9) +#define CLK_SUART0 (1 << 8) +#define CLK_SSSI (1 << 7) +#define CLK_SAC97 (1 << 6) +#define CLK_SMMCSD (1 << 5) +#define CLK_SEMI (1 << 4) +#define CLK_SDMAC (1 << 3) +#define CLK_SPWM (1 << 2) +#define CLK_SLCDC (1 << 1) +#define CLK_SESRAM (1) + + +/*Interrupt Sources*/ + + +#define INTSRC_RTC 31 +#define INTSRC_DMAC 30 +#define INTSRC_EMI 29 +#define INTSRC_MAC 28 +#define INTSRC_TIMER1 27 +#define INTSRC_TIMER2 26 +#define INTSRC_TIMER3 25 +#define INTSRC_UART0 24 +#define INTSRC_UART1 23 +#define INTSRC_UART2 22 +#define INTSRC_UART3 21 +#define INTSRC_PWM 20 +#define INTSRC_LCDC 19 +#define INTSRC_I2S 18 +#define INTSRC_SSI 17 + +#define INTSRC_USB 15 +#define INTSRC_SMC0 14 +#define INTSRC_SMC1 13 +#define INTSRC_SDIO 12 +#define INTSRC_EXINT10 11 +#define INTSRC_EXINT9 10 +#define INTSRC_EXINT8 9 +#define INTSRC_EXINT7 8 +#define INTSRC_EXINT6 7 +#define INTSRC_EXINT5 6 +#define INTSRC_EXINT4 5 +#define INTSRC_EXINT3 4 +#define INTSRC_EXINT2 3 +#define INTSRC_EXINT1 2 +#define INTSRC_EXINT0 1 +#define INTSRC_NULL 0 + + +/*Sereral useful macros*/ +#define set_plevel(plevel) *(RP)INTC_IPLR = plevel //ÉèÖÃÆÕͨÖжϵÄÓÅÏȼ¶ÃÅÏÞ£¬Ö»ÓÐÓÅÏȼ¶´óÓÚ´ËÖµµÄÖжϲÅÄÜͨ¹ý +#define set_int_force(intnum) *(RP)INTC_IFR = (1 << intnum) //ÖÃ1ºó£¬Èí¼þÇ¿ÖÆ¸Ãλ¶ÔÓ¦µÄÖжÏÔ´·¢³öÖжÏÐźŠ+#define enable_irq(intnum) *(RP)INTC_IER |= (1 << intnum) //ÖÃ1ºó£¬ÔÊÐíÖжÏÔ´µÄIRQ ÖжÏÐźŠ+#define disable_irq( intnum) *(RP)INTC_IER &= ~(1<< intnum) //ÖÃ0ºó£¬²»ÔÊÐíÖжÏÔ´µÄIRQ ÖжÏÐźŠ+#define mask_irq(intnum) *(RP)INTC_IMR |= (1 << intnum) //ÖÃ1ºó£¬ÆÁ±Î¶ÔÓ¦µÄIRQ ÖжÏÐźŠ+#define unmask_irq(intnum) *(RP)INTC_IMR &= ~(1 << intnum) //ÖÃ0ºó£¬Í¨¹ý¶ÔÓ¦µÄIRQ ÖжÏÐźŠ+#define mask_all_irq() *(RP)INTC_IMR = 0xFFFFFFFF //ÆÁ±Î¶ÔÓ¦µÄIRQ ÖжÏÐźŠ+#define unmask_all_irq() *(RP)INTC_IMR = 0x00000000 //ͨ¹ý¶ÔÓ¦µÄIRQ ÖжÏÐźŠ+#define enable_all_irq() *(RP)INTC_IER = 0XFFFFFFFF //ÔÊÐíÖжÏÔ´µÄIRQ ÖжÏÐźŠ+#define disable_all_irq() *(RP)INTC_IER = 0X00000000 //²»ÔÊÐíÖжÏÔ´µÄIRQ ÖжÏÐźŠ+#define InitInt() do{mask_all_irq(); enable_all_irq();}while(0) + +/* + ************************************** + * ËùÓгÌÐòÖÐÓõ½µÄTypedef + ************************************** + */ + +typedef char S8; /* signed 8-bit integer */ +typedef short S16; /* signed 16-bit integer */ +typedef long S32; /* signed 32-bit integer */ +typedef unsigned char U8; /* unsigned 8-bit integer */ +typedef unsigned short U16; /* unsigned 16-bit integer */ +typedef unsigned long U32; /* unsigned 32-bit integer */ + +typedef volatile U32 * RP; +typedef volatile U16 * RP16; +typedef volatile U8 * RP8; + +typedef void *VP; /* pointer to an unpredictable data type */ +typedef void (*FP)(); /* program start address */ + +#ifndef _BOOL_TYPE_ +#define _BOOL_TYPE_ +typedef int BOOL; /* Boolean value. TRUE (1) or FALSE (0). */ +#endif + +typedef int ER; /* Error code. A signed integer. */ + +/** + * IO definitions + * + * define access restrictions to peripheral registers + */ + +#define __I volatile const /*!< defines 'read only' permissions */ +#define __O volatile /*!< defines 'write only' permissions */ +#define __IO volatile /*!< defines 'read / write' permissions */ +#define __iomem volatile + + +/*Macros for debug*/ + +#define EOUT(fmt,...) \ + do \ + { \ + rt_kprintf("EOUT:(%s:%i) ",__FILE__,__LINE__); \ + rt_kprintf(fmt,##__VA_ARGS__); \ + }while(0) + +#define RT_DEBUG +#ifdef RT_DEBUG + #define DBOUT(fmt,...) \ + do \ + { \ + rt_kprintf("DBOUT:(%s:%i) ",__FILE__,__LINE__); \ + rt_kprintf(fmt,##__VA_ARGS__); \ + }while(0) +#else + #define DBOUT(fmt,...) \ + do{}while(0) +#endif + +#ifdef RT_DEBUG + #define ASSERT(arg) \ + if((arg) == 0) \ + { \ + while(1) \ + { \ + rt_kprintf("have a assert failure\n"); \ + } \ + } +#else + #define ASSERT(arg) \ + do \ + { \ + }while(0) +#endif + + +#define write_reg(reg,value) \ + do \ + { \ + *(RP)(reg) = value; \ + }while(0) + +#define read_reg(reg) (*(RP)reg) + + +struct rt_hw_register +{ + rt_uint32_t r0; + rt_uint32_t r1; + rt_uint32_t r2; + rt_uint32_t r3; + rt_uint32_t r4; + rt_uint32_t r5; + rt_uint32_t r6; + rt_uint32_t r7; + rt_uint32_t r8; + rt_uint32_t r9; + rt_uint32_t r10; + rt_uint32_t fp; + rt_uint32_t ip; + rt_uint32_t sp; + rt_uint32_t lr; + rt_uint32_t pc; + rt_uint32_t cpsr; + rt_uint32_t ORIG_r0; +}; + + +/*@}*/ + +#endif diff --git a/rt-thread/libcpu/arm/sep4020/serial.c b/rt-thread/libcpu/arm/sep4020/serial.c new file mode 100644 index 0000000..3f484ee --- /dev/null +++ b/rt-thread/libcpu/arm/sep4020/serial.c @@ -0,0 +1,282 @@ +/* + * File : serial.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + * 2009-04-20 yi.qiu modified according bernard's stm32 version + * 2010-10-6 wangmeng added sep4020 surpport + */ +#include +#include +#include "serial.h" + +/** + * @addtogroup SEP4020 + */ +/*@{*/ + +/* RT-Thread Device Interface */ +/** + * This function initializes serial + */ +static rt_err_t rt_serial_init (rt_device_t dev) +{ + struct serial_device* uart = (struct serial_device*) dev->user_data; + + if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) + { + + if (dev->flag & RT_DEVICE_FLAG_INT_RX) + { + rt_memset(uart->int_rx->rx_buffer, 0, + sizeof(uart->int_rx->rx_buffer)); + uart->int_rx->read_index = uart->int_rx->save_index = 0; + } + + if (dev->flag & RT_DEVICE_FLAG_INT_TX) + { + rt_memset(uart->int_tx->tx_buffer, 0, + sizeof(uart->int_tx->tx_buffer)); + uart->int_tx->write_index = uart->int_tx->save_index = 0; + } + + dev->flag |= RT_DEVICE_FLAG_ACTIVATED; + } + + return RT_EOK; +} + +/* save a char to serial buffer */ +static void rt_serial_savechar(struct serial_device* uart, char ch) +{ + rt_base_t level; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + uart->int_rx->rx_buffer[uart->int_rx->save_index] = ch; + uart->int_rx->save_index ++; + if (uart->int_rx->save_index >= UART_RX_BUFFER_SIZE) + uart->int_rx->save_index = 0; + + /* if the next position is read index, discard this 'read char' */ + if (uart->int_rx->save_index == uart->int_rx->read_index) + { + uart->int_rx->read_index ++; + if (uart->int_rx->read_index >= UART_RX_BUFFER_SIZE) + uart->int_rx->read_index = 0; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); +} + +static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag) +{ + RT_ASSERT(dev != RT_NULL); + return RT_EOK; +} + +static rt_err_t rt_serial_close(rt_device_t dev) +{ + RT_ASSERT(dev != RT_NULL); + return RT_EOK; +} + +static rt_size_t rt_serial_read (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size) +{ + rt_uint8_t* ptr; + rt_err_t err_code; + struct serial_device* uart; + + ptr = buffer; + err_code = RT_EOK; + uart = (struct serial_device*)dev->user_data; + + if (dev->flag & RT_DEVICE_FLAG_INT_RX) + { + rt_base_t level; + + /* interrupt mode Rx */ + while (size) + { + if (uart->int_rx->read_index != uart->int_rx->save_index) + { + *ptr++ = uart->int_rx->rx_buffer[uart->int_rx->read_index]; + size --; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + uart->int_rx->read_index ++; + if (uart->int_rx->read_index >= UART_RX_BUFFER_SIZE) + uart->int_rx->read_index = 0; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + } + else + { + /* set error code */ + err_code = -RT_EEMPTY; + break; + } + } + } + else + { + /* polling mode */ + while ((rt_uint32_t)ptr - (rt_uint32_t)buffer < size) + { + while (uart->uart_device->lsr & USTAT_RCV_READY) + { + *ptr = uart->uart_device->dlbl_fifo.txfifo & 0xff; + ptr ++; + } + } + } + + /* set error code */ + rt_set_errno(err_code); + return (rt_uint32_t)ptr - (rt_uint32_t)buffer; +} + +static rt_size_t rt_serial_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) +{ + rt_uint8_t* ptr; + rt_err_t err_code; + struct serial_device* uart; + + err_code = RT_EOK; + ptr = (rt_uint8_t*)buffer; + uart = (struct serial_device*)dev->user_data; + + if (dev->flag & RT_DEVICE_FLAG_INT_TX) + { + /* interrupt mode Tx */ + while (uart->int_tx->save_index != uart->int_tx->write_index) + { + /* save on tx buffer */ + uart->int_tx->tx_buffer[uart->int_tx->save_index] = *ptr++; + + -- size; + + /* move to next position */ + uart->int_tx->save_index ++; + + /* wrap save index */ + if (uart->int_tx->save_index >= UART_TX_BUFFER_SIZE) + uart->int_tx->save_index = 0; + } + + /* set error code */ + if (size > 0) + err_code = -RT_EFULL; + } + else + { + /* polling mode */ + while (size) + { + /* + * to be polite with serial console add a line feed + * to the carriage return character + */ + if (*ptr == '\n' && (dev->flag & RT_DEVICE_FLAG_STREAM)) + { + while (!(uart->uart_device->lsr & USTAT_TXB_EMPTY)); + uart->uart_device->dlbl_fifo.txfifo = '\r'; + } + + while (!(uart->uart_device->lsr & USTAT_TXB_EMPTY)); + uart->uart_device->dlbl_fifo.txfifo = (*ptr & 0x1FF); + + ++ptr; --size; + } + } + + /* set error code */ + rt_set_errno(err_code); + + return (rt_uint32_t)ptr - (rt_uint32_t)buffer; +} + +static rt_err_t rt_serial_control (rt_device_t dev, int cmd, void *args) +{ + RT_ASSERT(dev != RT_NULL); + + switch (cmd) + { + case RT_DEVICE_CTRL_SUSPEND: + /* suspend device */ + dev->flag |= RT_DEVICE_FLAG_SUSPENDED; + break; + + case RT_DEVICE_CTRL_RESUME: + /* resume device */ + dev->flag &= ~RT_DEVICE_FLAG_SUSPENDED; + break; + } + + return RT_EOK; +} + +/* + * serial register + */ +rt_err_t rt_hw_serial_register(rt_device_t device, const char* name, rt_uint32_t flag, struct serial_device *serial) +{ + RT_ASSERT(device != RT_NULL); + + device->type = RT_Device_Class_Char; + device->rx_indicate = RT_NULL; + device->tx_complete = RT_NULL; + device->init = rt_serial_init; + device->open = rt_serial_open; + device->close = rt_serial_close; + device->read = rt_serial_read; + device->write = rt_serial_write; + device->control = rt_serial_control; + device->user_data = serial; + + /* register a character device */ + return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | flag); +} + +/* ISR for serial interrupt */ +void rt_hw_serial_isr(rt_device_t device) +{ + struct serial_device* uart = (struct serial_device*) device->user_data; + + /* interrupt mode receive */ + RT_ASSERT(device->flag & RT_DEVICE_FLAG_INT_RX); + + /* save on rx buffer */ + while (uart->uart_device->lsr & USTAT_RCV_READY) + { + rt_serial_savechar(uart, uart->uart_device->dlbl_fifo.rxfifo & 0xff); + } + + /* invoke callback */ + if (device->rx_indicate != RT_NULL) + { + rt_size_t rx_length; + + /* get rx length */ + rx_length = uart->int_rx->read_index > uart->int_rx->save_index ? + UART_RX_BUFFER_SIZE - uart->int_rx->read_index + uart->int_rx->save_index : + uart->int_rx->save_index - uart->int_rx->read_index; + + device->rx_indicate(device, rx_length); + } +} + +/*@}*/ + diff --git a/rt-thread/libcpu/arm/sep4020/serial.h b/rt-thread/libcpu/arm/sep4020/serial.h new file mode 100644 index 0000000..f0357aa --- /dev/null +++ b/rt-thread/libcpu/arm/sep4020/serial.h @@ -0,0 +1,90 @@ +/* + * File : serial.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + * 2009-04-20 yi.qiu modified according bernard's stm32 version + * 2010-10-6 wangmeng added sep4020 surpport + */ + +#ifndef __SERIAL_H__ +#define __SERIAL_H__ + +#include + +#define USTAT_RCV_READY 0x01 /* receive data ready */ +#define USTAT_TXB_EMPTY 0x40 /* tx buffer empty */ +#define BPS 115200 /* serial baudrate */ + +#define UART_RX_BUFFER_SIZE 64 +#define UART_TX_BUFFER_SIZE 64 + +/*For sep4020's uart have several secondary function*/ +/*we use union to decribe it*/ + +union dlbl_fifo +{ + rt_uint32_t dlbl; + rt_uint32_t rxfifo; + rt_uint32_t txfifo; +}; + +union dlbh_ier +{ + rt_uint32_t dlbh; + rt_uint32_t ier; +}; + +union iir_fcr +{ + rt_uint32_t iir; + rt_uint32_t fcr; +}; + +struct serial_int_rx +{ + rt_uint8_t rx_buffer[UART_RX_BUFFER_SIZE]; + rt_uint32_t read_index, save_index; +}; + +struct serial_int_tx +{ + rt_uint8_t tx_buffer[UART_TX_BUFFER_SIZE]; + rt_uint32_t write_index, save_index; +}; + +typedef struct uartport +{ + union dlbl_fifo dlbl_fifo; + union dlbh_ier dlbh_ier; + union iir_fcr iir_fcr; + rt_uint32_t lcr; + rt_uint32_t mcr; + rt_uint32_t lsr; + rt_uint32_t msr; +}uartport; + +struct serial_device +{ + uartport* uart_device; + + /* rx structure */ + struct serial_int_rx* int_rx; + + /* tx structure */ + struct serial_int_tx* int_tx; +}; + +rt_err_t rt_hw_serial_register(rt_device_t device, const char* name, rt_uint32_t flag, struct serial_device *serial); + +void rt_hw_serial_isr(rt_device_t device); + + +#endif diff --git a/rt-thread/libcpu/arm/sep4020/stack.c b/rt-thread/libcpu/arm/sep4020/stack.c new file mode 100644 index 0000000..318b435 --- /dev/null +++ b/rt-thread/libcpu/arm/sep4020/stack.c @@ -0,0 +1,61 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard the first version + */ +#include +#include +/** + * @addtogroup S3C24X0 + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + *(--stk) = Mode_SVC; /* cpsr */ + *(--stk) = Mode_SVC; /* spsr */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/sep4020/start_rvds.S b/rt-thread/libcpu/arm/sep4020/start_rvds.S new file mode 100644 index 0000000..bf5431e --- /dev/null +++ b/rt-thread/libcpu/arm/sep4020/start_rvds.S @@ -0,0 +1,385 @@ +;============================================================================================== +; star_rvds.s for Keil MDK 4.10 +; +; SEP4020 start up code +; +; Change Logs: +; Date Author Notes +; 2010-03-17 zchong +;============================================================================================= + +PMU_PLTR EQU 0x10001000 ; PLLµÄÎȶ¨¹ý¶Éʱ¼ä +PMU_PMCR EQU 0x10001004 ; ϵͳÖ÷ʱÖÓPLLµÄ¿ØÖƼĴæÆ÷ +PMU_PUCR EQU 0x10001008 ; USBʱÖÓPLLµÄ¿ØÖƼĴæÆ÷ +PMU_PCSR EQU 0x1000100C ; ÄÚ²¿Ä£¿éʱÖÓÔ´¹©¸øµÄ¿ØÖƼĴæÆ÷ +PMU_PDSLOW EQU 0x10001010 ; SLOW״̬ÏÂʱÖӵķ֯µÒò×Ó +PMU_PMDR EQU 0x10001014 ; оƬ¹¤×÷ģʽ¼Ä´æÆ÷ +PMU_RCTR EQU 0x10001018 ; Reset¿ØÖƼĴæÆ÷ +PMU_CLRWAKUP EQU 0x1000101C ; WakeUpÇå³ý¼Ä´æÆ÷ + +RTC_CTR EQU 0x1000200C ; RTC¿ØÖƼĴæÆ÷ + +INTC_IER EQU 0x10000000 ; IRQÖжÏÔÊÐí¼Ä´æÆ÷ +INTC_IMR EQU 0x10000008 ; IRQÖÐ¶ÏÆÁ±Î¼Ä´æÆ÷ +INTC_IFSR EQU 0x10000030 ; IRQÖжÏ×îÖÕ״̬¼Ä´æÆ÷ +INTC_FIER EQU 0x100000C0 ; FIQÖжÏÔÊÐí¼Ä´æÆ÷ +INTC_FIMR EQU 0x100000C4 ; FIQÖÐ¶ÏÆÁ±Î¼Ä´æÆ÷ + +EMI_CSACONF EQU 0x11000000 ; CSA²ÎÊýÅäÖüĴæÆ÷ +EMI_CSECONF EQU 0x11000010 ; CSE²ÎÊýÅäÖüĴæÆ÷ +EMI_CSFCONF EQU 0x11000014 ; CSF²ÎÊýÅäÖüĴæÆ÷ +EMI_SDCONF1 EQU 0x11000018 ; SDRAMʱÐòÅäÖüĴæÆ÷1 +EMI_SDCONF2 EQU 0x1100001C ; SDRAMʱÐòÅäÖüĴæÆ÷2, SDRAM³õʼ»¯Óõ½µÄÅäÖÃÐÅÏ¢ +EMI_REMAPCONF EQU 0x11000020 ; Ƭѡ¿Õ¼ä¼°µØÖ·Ó³ÉäREMAPÅäÖüĴæÆ÷ + +Mode_USR EQU 0x10 +Mode_FIQ EQU 0x11 +Mode_IRQ EQU 0x12 +Mode_SVC EQU 0x13 +Mode_ABT EQU 0x17 +Mode_UND EQU 0x1B +Mode_SYS EQU 0x1F + +I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled +F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled +NOINT EQU 0xc0 +MASK_MODE EQU 0x0000003F +MODE_SVC32 EQU 0x00000013 + +; Internal Memory Base Addresses +FLASH_BASE EQU 0x20000000 +RAM_BASE EQU 0x04000000 +SDRAM_BASE EQU 0x30000000 + +; Stack +Unused_Stack_Size EQU 0x00000100 +Svc_Stack_Size EQU 0x00001000 +Abt_Stack_Size EQU 0x00000000 +Fiq_Stack_Size EQU 0x00000000 +Irq_Stack_Size EQU 0x00001000 +Usr_Stack_Size EQU 0x00000000 + +;SVC STACK + AREA STACK, NOINIT, READWRITE, ALIGN=3 +Svc_Stack SPACE Svc_Stack_Size +__initial_sp +Svc_Stack_Top + +;IRQ STACK + AREA STACK, NOINIT, READWRITE, ALIGN=3 +Irq_Stack SPACE Irq_Stack_Size +Irq_Stack_Top + +;UNUSED STACK + AREA STACK, NOINIT, READWRITE, ALIGN=3 +Unused_Stack SPACE Unused_Stack_Size +Unused_Stack_Top + + +; Heap +Heap_Size EQU 0x0000100 + + AREA HEAP, NOINIT, READWRITE, ALIGN=3 + EXPORT Heap_Mem +__heap_base +Heap_Mem SPACE Heap_Size +__heap_limit + + PRESERVE8 + +; Area Definition and Entry Point +; Startup Code must be linked first at Address at which it expects to run. + + AREA RESET, CODE, READONLY + ARM + +; Exception Vectors +; Mapped to Address 0. +; Absolute addressing mode must be used. +; Dummy Handlers are implemented as infinite loops which can be modified. + EXPORT Entry_Point +Entry_Point +Vectors LDR PC,Reset_Addr + LDR PC,Undef_Addr + LDR PC,SWI_Addr + LDR PC,PAbt_Addr + LDR PC,DAbt_Addr + NOP ; Reserved Vector + LDR PC,IRQ_Addr + LDR PC,FIQ_Addr + +Reset_Addr DCD Reset_Handler +Undef_Addr DCD Undef_Handler +SWI_Addr DCD SWI_Handler +PAbt_Addr DCD PAbt_Handler +DAbt_Addr DCD DAbt_Handler + DCD 0 ; Reserved Address +IRQ_Addr DCD IRQ_Handler +FIQ_Addr DCD FIQ_Handler + +Undef_Handler B Undef_Handler +SWI_Handler B SWI_Handler +PAbt_Handler B Abort_Handler +DAbt_Handler B Abort_Handler +FIQ_Handler B FIQ_Handler + +Abort_Handler PROC + ARM + EXPORT Abort_Handler +DeadLoop BHI DeadLoop ; Abort happened in irq mode, halt system. + ENDP + + +; Reset Handler + ;IMPORT __user_initial_stackheap + EXPORT Reset_Handler +Reset_Handler + +;**************************************************************** +;* Shutdown watchdog +;**************************************************************** + LDR R0,=RTC_CTR + LDR R1,=0x0 + STR R1,[R0] + +;**************************************************************** +;* shutdown interrupts +;**************************************************************** + MRS R0, CPSR + BIC R0, R0, #MASK_MODE + ORR R0, R0, #MODE_SVC32 + ORR R0, R0, #I_Bit + ORR R0, R0, #F_Bit + MSR CPSR_c, r0 + + LDR R0,=INTC_IER + LDR R1,=0x0 + STR R1,[R0] + LDR R0,=INTC_IMR + LDR R1,=0xFFFFFFFF + STR R1,[R0] + + LDR R0,=INTC_FIER + LDR R1,=0x0 + STR R1,[R0] + LDR R0,=INTC_FIMR + LDR R1,=0x0F + STR R1,[R0] + +;**************************************************************** +;* Initialize Stack Pointer +;**************************************************************** + + LDR SP, =Svc_Stack_Top ;init SP_svc + + MOV R4, #0xD2 ;chmod to irq and init SP_irq + MSR cpsr_c, R4 + LDR SP, =Irq_Stack_Top + + MOV R4, #0XD1 ;chomod to fiq and init SP_fiq + MSR cpsr_c, R4 + LDR SP, =Unused_Stack_Top + + MOV R4, #0XD7 ;chomod to abt and init SP_ABT + MSR cpsr_c, R4 + LDR SP, =Unused_Stack_Top + + MOV R4, #0XDB ;chomod to undf and init SP_UNDF + MSR cpsr_c, R4 + LDR SP, =Unused_Stack_Top + + ;chomod to abt and init SP_sys + MOV R4, #0xDF ;all interrupts disabled + MSR cpsr_c, R4 ;SYSTEM mode, @32-bit code mode + LDR SP, =Unused_Stack_Top + + MOV R4, #0XD3 ;chmod to svc modle, CPSR IRQ bit is disable + MSR cpsr_c, R4 + + + +;**************************************************************** +;* Initialize PMU & System Clock +;**************************************************************** + + LDR R4, =PMU_PCSR ; ´òËùÓÐÄ£¿éʱÖÓ + LDR R5, =0x0001ffff + STR R5, [ R4 ] + + LDR R4, =PMU_PLTR ; ÅäÖÃPLLÎȶ¨¹ý¶Èʱ¼äΪ±£ÊØÖµ50us*100M. + LDR R5, =0x00fa00fa + STR R5, [ R4 ] + + LDR R4, =PMU_PMDR ; ÓÉSLOWģʽ½øÈëNORMALģʽ + LDR R5, =0x00000001 + STR R5, [ R4 ] + + LDR R4, =PMU_PMCR ; ÅäÖÃϵͳʱÖÓΪ80MHz + LDR R5, =0x00004009 ; 400b -- 88M + STR R5, [ R4 ] + + ;PMU_PMCR¼Ä´æÆ÷µÚ15λÐèÒªÓдӵ͵½¸ßµÄ·­×ª£¬²ÅÄÜ´¥·¢PLLµÄʱÖÓÅäÖà + LDR R4, =PMU_PMCR + LDR R5, =0x0000c009 + STR R5, [ R4 ] + +;**************************************************************** +;* ³õʼ»¯EMI +;**************************************************************** + + IF :DEF:INIT_EMI + + LDR R4, =EMI_CSACONF ; CSAƬѡʱÐò²ÎÊýÅäÖà + LDR R5, =0x08a6a6a1 + STR R5, [ R4 ] + + LDR R4, =EMI_CSECONF ; CSEƬѡʱÐò²ÎÊýÅäÖÃ,×î±£ÊØÅäÖà + LDR R5, =0x8cfffff1 + STR R5, [ R4 ] + + LDR R4, =EMI_SDCONF1 ; SDRAM²ÎÊýÅäÖÃ1 + LDR R5, =0x1E104177 + STR R5, [ R4 ] + + LDR R4, =EMI_SDCONF2 ; SDRAM²ÎÊýÅäÖÃ2 + LDR R5, =0x80001860 + STR R5, [ R4 ] + + ENDIF + +; Copy Exception Vectors to Internal RAM + + IF :DEF:RAM_INTVEC + + ADR R8, Vectors ; Source + LDR R9, =RAM_BASE ; Destination + LDMIA R8!, {R0-R7} ; Load Vectors + STMIA R9!, {R0-R7} ; Store Vectors + LDMIA R8!, {R0-R7} ; Load Handler Addresses + STMIA R9!, {R0-R7} ; Store Handler Addresses + + ENDIF + +; Remap on-chip RAM to address 0 + + IF :DEF:REMAP + + LDR R0, =EMI_REMAPCONF + IF :DEF:RAM_INTVEC + MOV R1, #0x80000000 + ELSE + MOV R1, #0x0000000b + ENDIF + STR R1, [R0, #0] ; Remap + + ENDIF + +;*************************************************************** +;* Open irq interrupt +;*************************************************************** + + MRS R4, cpsr + BIC R4, R4, #0x80 ; set bit7 to zero + MSR cpsr_c, R4 + +; Enter the C code + IMPORT __main + LDR R0,=__main + BX R0 + + + IMPORT rt_interrupt_enter + IMPORT rt_interrupt_leave + IMPORT rt_thread_switch_interrupt_flag + IMPORT rt_interrupt_from_thread + IMPORT rt_interrupt_to_thread + IMPORT rt_hw_trap_irq + +IRQ_Handler PROC + EXPORT IRQ_Handler + STMFD sp!, {r0-r12,lr} + BL rt_interrupt_enter + BL rt_hw_trap_irq + BL rt_interrupt_leave + + ; if rt_thread_switch_interrupt_flag set, jump to + ; rt_hw_context_switch_interrupt_do and don't return + LDR r0, =rt_thread_switch_interrupt_flag + LDR r1, [r0] + CMP r1, #1 + BEQ rt_hw_context_switch_interrupt_do + + LDMFD sp!, {r0-r12,lr} + SUBS pc, lr, #4 + ENDP + +; /* +; * void rt_hw_context_switch_interrupt_do(rt_base_t flag) +; */ +rt_hw_context_switch_interrupt_do PROC + EXPORT rt_hw_context_switch_interrupt_do + MOV r1, #0 ; clear flag + STR r1, [r0] + + LDMFD sp!, {r0-r12,lr}; reload saved registers + STMFD sp!, {r0-r3} ; save r0-r3 + MOV r1, sp + ADD sp, sp, #16 ; restore sp + SUB r2, lr, #4 ; save old task's pc to r2 + + MRS r3, spsr ; get cpsr of interrupt thread + + ; switch to SVC mode and no interrupt + MSR cpsr_c, #I_Bit :OR F_Bit :OR Mode_SVC + + STMFD sp!, {r2} ; push old task's pc + STMFD sp!, {r4-r12,lr}; push old task's lr,r12-r4 + MOV r4, r1 ; Special optimised code below + MOV r5, r3 + LDMFD r4!, {r0-r3} + STMFD sp!, {r0-r3} ; push old task's r3-r0 + STMFD sp!, {r5} ; push old task's cpsr + MRS r4, spsr + STMFD sp!, {r4} ; push old task's spsr + + LDR r4, =rt_interrupt_from_thread + LDR r5, [r4] + STR sp, [r5] ; store sp in preempted tasks's TCB + + LDR r6, =rt_interrupt_to_thread + LDR r6, [r6] + LDR sp, [r6] ; get new task's stack pointer + + LDMFD sp!, {r4} ; pop new task's spsr + MSR spsr_cxsf, r4 + LDMFD sp!, {r4} ; pop new task's psr + MSR cpsr_cxsf, r4 + + LDMFD sp!, {r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc + ENDP + + + + ALIGN + IF :DEF:__MICROLIB + + EXPORT __heap_base + EXPORT __heap_limit + EXPORT __initial_sp + + ELSE ;__MICROLIB +; User Initial Stack & Heap + AREA |.text|, CODE, READONLY + + IMPORT __use_two_region_memory + EXPORT __user_initial_stackheap +__user_initial_stackheap + + LDR R0, = Heap_Mem + LDR R1, = (Svc_Stack + Svc_Stack_Size) + LDR R2, = (Heap_Mem + Heap_Size) + LDR R3, = Svc_Stack + BX LR + ALIGN + ENDIF + END diff --git a/rt-thread/libcpu/arm/sep4020/trap.c b/rt-thread/libcpu/arm/sep4020/trap.c new file mode 100644 index 0000000..9c18ced --- /dev/null +++ b/rt-thread/libcpu/arm/sep4020/trap.c @@ -0,0 +1,171 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, 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://openlab.rt-thread.com/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2006-03-13 Bernard first version + * 2006-05-27 Bernard add skyeye support + * 2007-11-19 Yi.Qiu fix rt_hw_trap_irq function + * 2013-03-29 aozima Modify the interrupt interface implementations. + */ + +#include +#include + +#include + +/** + * @addtogroup S3C24X0 + */ +/*@{*/ + +extern struct rt_thread *rt_current_thread; + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ + +void rt_hw_show_register (struct rt_hw_register *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When ARM7TDMI comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_udef(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("undefined instruction\n"); + rt_kprintf("thread - %s stack:\n", rt_current_thread->name); + rt_hw_backtrace((rt_uint32_t *)regs->fp, (rt_uint32_t)rt_current_thread->entry); + + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("software interrupt\n"); + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("prefetch abort\n"); + rt_kprintf("thread - %s stack:\n", rt_current_thread->name); + rt_hw_backtrace((rt_uint32_t *)regs->fp, (rt_uint32_t)rt_current_thread->entry); + + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_register *regs) +{ + rt_hw_show_register(regs); + + rt_kprintf("data abort\n"); + rt_kprintf("thread - %s stack:\n", rt_current_thread->name); + rt_hw_backtrace((rt_uint32_t *)regs->fp, (rt_uint32_t)rt_current_thread->entry); + + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_register *regs) +{ + rt_kprintf("not used\n"); + rt_hw_show_register(regs); + rt_hw_cpu_shutdown(); +} + +extern struct rt_irq_desc isr_table[]; + +void rt_hw_trap_irq(void) +{ + unsigned long intstat; + rt_uint32_t irq = 0; + rt_isr_handler_t isr_func; + void *param; + + /*Get the final intrrupt source*/ + intstat = *(RP)(INTC_IFSR);; + + /*Shift to get the intrrupt number*/ + while(intstat != 1) + { + intstat = intstat >> 1; + irq++; + } + + /* get interrupt service routine */ + isr_func = isr_table[irq].handler; + param = isr_table[irq].param; + + /* turn to interrupt service routine */ + isr_func(irq, param); + +#ifdef RT_USING_INTERRUPT_INFO + isr_table[irq].counter++; +#endif /* RT_USING_INTERRUPT_INFO */ +} + +void rt_hw_trap_fiq(void) +{ + rt_kprintf("fast interrupt request\n"); +} + +/*@}*/ diff --git a/rt-thread/libcpu/arm/zynq7000/SConscript b/rt-thread/libcpu/arm/zynq7000/SConscript new file mode 100644 index 0000000..2ad51b5 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/SConscript @@ -0,0 +1,17 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +if rtconfig.PLATFORM == 'iar': + src += Glob('*_iar.S') +elif rtconfig.PLATFORM == 'gcc': + src += Glob('*_gcc.S') +elif rtconfig.PLATFORM == 'armcc': + src += Glob('*_rvds.S') + +group = DefineGroup('AM1808', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/rt-thread/libcpu/arm/zynq7000/armv7.h b/rt-thread/libcpu/arm/zynq7000/armv7.h new file mode 100644 index 0000000..65f6c27 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/armv7.h @@ -0,0 +1,65 @@ +#ifndef __ARMV7_H__ +#define __ARMV7_H__ +/* + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* the exception stack without VFP registers */ +struct rt_hw_exp_stack +{ + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long sp; + unsigned long lr; + unsigned long pc; + unsigned long cpsr; +}; + +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define MONITORMODE 0x16 +#define ABORTMODE 0x17 +#define HYPMODE 0x1b +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +#define T_Bit (1<<5) +#define F_Bit (1<<6) +#define I_Bit (1<<7) +#define A_Bit (1<<8) +#define E_Bit (1<<9) +#define J_Bit (1<<24) + +void rt_hw_mmu_init(void); + +#endif diff --git a/rt-thread/libcpu/arm/zynq7000/context_gcc.S b/rt-thread/libcpu/arm/zynq7000/context_gcc.S new file mode 100644 index 0000000..3dbf3c8 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/context_gcc.S @@ -0,0 +1,102 @@ +/* + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define NOINT 0xc0 + +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + orr r1, r0, #NOINT + msr cpsr_c, r1 + bx lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + bx lr + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + tst lr, #0x01 + beq _ARM_MODE + orr r4, r4, #0x20 @ it's thumb code + +_ARM_MODE: + stmfd sp!, {r4} @ push cpsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task cpsr to spsr + msr spsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + + bic r4, r4, #0x20 @ must be ARM mode + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 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] + bx lr diff --git a/rt-thread/libcpu/arm/zynq7000/cp15.h b/rt-thread/libcpu/arm/zynq7000/cp15.h new file mode 100644 index 0000000..bd6a23f --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/cp15.h @@ -0,0 +1,31 @@ +#ifndef __CP15_H__ +#define __CP15_H__ +/* + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +unsigned long rt_cpu_get_smp_id(void); + +void rt_cpu_mmu_disable(void); +void rt_cpu_mmu_enable(void); +void rt_cpu_tlb_set(volatile unsigned long*); + +void rt_cpu_vector_set_base(unsigned int addr); + +#endif diff --git a/rt-thread/libcpu/arm/zynq7000/cp15_gcc.S b/rt-thread/libcpu/arm/zynq7000/cp15_gcc.S new file mode 100644 index 0000000..f1ed649 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/cp15_gcc.S @@ -0,0 +1,140 @@ +/* + * File : cp15_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * http://www.rt-thread.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.globl rt_cpu_get_smp_id +rt_cpu_get_smp_id: + mrc p15, #0, r0, c0, c0, #5 + bx lr + +.globl rt_cpu_vector_set_base +rt_cpu_vector_set_base: + mcr p15, #0, r0, c12, c0, #0 + dsb + bx lr + +.globl rt_hw_cpu_dcache_enable +rt_hw_cpu_dcache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_hw_cpu_icache_enable +rt_hw_cpu_icache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +_FLD_MAX_WAY: + .word 0x3ff +_FLD_MAX_IDX: + .word 0x7ff + +.globl rt_cpu_dcache_clean_flush +rt_cpu_dcache_clean_flush: + push {r4-r11} + dmb + mrc p15, #1, r0, c0, c0, #1 @ read clid register + ands r3, r0, #0x7000000 @ get level of coherency + mov r3, r3, lsr #23 + beq finished + mov r10, #0 +loop1: + add r2, r10, r10, lsr #1 + mov r1, r0, lsr r2 + and r1, r1, #7 + cmp r1, #2 + blt skip + mcr p15, #2, r10, c0, c0, #0 + isb + mrc p15, #1, r1, c0, c0, #0 + and r2, r1, #7 + add r2, r2, #4 + ldr r4, _FLD_MAX_WAY + ands r4, r4, r1, lsr #3 + clz r5, r4 + ldr r7, _FLD_MAX_IDX + ands r7, r7, r1, lsr #13 +loop2: + mov r9, r4 +loop3: + orr r11, r10, r9, lsl r5 + orr r11, r11, r7, lsl r2 + mcr p15, #0, r11, c7, c14, #2 + subs r9, r9, #1 + bge loop3 + subs r7, r7, #1 + bge loop2 +skip: + add r10, r10, #2 + cmp r3, r10 + bgt loop1 + +finished: + dsb + isb + pop {r4-r11} + bx lr + +.globl rt_hw_cpu_dcache_disable +rt_hw_cpu_dcache_disable: + push {r4-r11, lr} + bl rt_cpu_dcache_clean_flush + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + pop {r4-r11, lr} + bx lr + +.globl rt_hw_cpu_icache_disable +rt_hw_cpu_icache_disable: + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_cpu_mmu_disable +rt_cpu_mmu_disable: + mcr p15, #0, r0, c8, c7, #0 @ invalidate tlb + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #1 + mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit + dsb + bx lr + +.globl rt_cpu_mmu_enable +rt_cpu_mmu_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x001 + mcr p15, #0, r0, c1, c0, #0 @ set mmu enable bit + dsb + bx lr + +.globl rt_cpu_tlb_set +rt_cpu_tlb_set: + mcr p15, #0, r0, c2, c0, #0 + dmb + bx lr diff --git a/rt-thread/libcpu/arm/zynq7000/cpu.c b/rt-thread/libcpu/arm/zynq7000/cpu.c new file mode 100644 index 0000000..9853eff --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/cpu.c @@ -0,0 +1,45 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Develop 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 + * 2013-07-20 Bernard first version + */ + +#include +#include +#include "zynq7000.h" + +/** + * reset cpu by dog's time-out + * + */ +void rt_hw_cpu_reset() +{ + while (1); /* loop forever and wait for reset to happen */ + + /* NEVER REACHED */ +} + +/** + * shutdown CPU + * + */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + while (level) + { + RT_ASSERT(0); + } +} + diff --git a/rt-thread/libcpu/arm/zynq7000/gic.c b/rt-thread/libcpu/arm/zynq7000/gic.c new file mode 100644 index 0000000..498446d --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/gic.c @@ -0,0 +1,239 @@ +/* + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include "gic.h" +#include "cp15.h" + +struct arm_gic +{ + rt_uint32_t offset; + + rt_uint32_t dist_hw_base; + rt_uint32_t cpu_hw_base; +}; +static struct arm_gic _gic_table[ARM_GIC_MAX_NR]; + +#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00) +#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04) +#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08) +#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0c) +#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10) +#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14) +#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18) + +#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000) +#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004) +#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080 + (n/32) * 4) +#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100 + (n/32) * 4) +#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180 + (n/32) * 4) +#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200) +#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280) +#define GIC_DIST_ACTIVE_BIT(hw_base) __REG32((hw_base) + 0x300) +#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400 + (n/4) * 4) +#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800 + (n/4) * 4) +#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00 + (n/16) * 4) +#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00) +#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10 + (n/4) * 4) +#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8) + +static unsigned int _gic_max_irq; + +int arm_gic_get_active_irq(rt_uint32_t index) +{ + int irq; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = GIC_CPU_INTACK(_gic_table[index].cpu_hw_base); + irq += _gic_table[index].offset; + return irq; +} + +void arm_gic_ack(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; + GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq; + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_mask(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask) +{ + rt_uint32_t old_tgt; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq); + + old_tgt &= ~(0x0FFUL << ((irq % 4)*8)); + old_tgt |= cpumask << ((irq % 4)*8); + + GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt; +} + +void arm_gic_umask(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_dump_type(rt_uint32_t index) +{ + unsigned int gic_type; + + gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base); + rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n", + (GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4) & 0xf, + _gic_table[index].dist_hw_base, + _gic_max_irq, + gic_type & (1 << 10) ? "has" : "no", + gic_type); +} + +int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start) +{ + unsigned int gic_type, i; + rt_uint32_t cpumask = 1 << 0; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + _gic_table[index].dist_hw_base = dist_base; + _gic_table[index].offset = irq_start; + + /* Find out how many interrupts are supported. */ + gic_type = GIC_DIST_TYPE(dist_base); + _gic_max_irq = ((gic_type & 0x1f) + 1) * 32; + + /* + * The GIC only supports up to 1020 interrupt sources. + * Limit this to either the architected maximum, or the + * platform maximum. + */ + if (_gic_max_irq > 1020) + _gic_max_irq = 1020; + if (_gic_max_irq > ARM_GIC_NR_IRQS) + _gic_max_irq = ARM_GIC_NR_IRQS; + + cpumask |= cpumask << 8; + cpumask |= cpumask << 16; + + GIC_DIST_CTRL(dist_base) = 0x0; + + /* Set all global interrupts to be level triggered, active low. */ + for (i = 32; i < _gic_max_irq; i += 16) + GIC_DIST_CONFIG(dist_base, i) = 0x0; + + /* Set all global interrupts to this CPU only. */ + for (i = 32; i < _gic_max_irq; i += 4) + GIC_DIST_TARGET(dist_base, i) = cpumask; + + /* Set priority on all interrupts. */ + for (i = 0; i < _gic_max_irq; i += 4) + GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0; + + /* Disable all interrupts. */ + for (i = 0; i < _gic_max_irq; i += 32) + GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffff; + + /* Set the FIQEn bit, signal FIQ for IGROUP0. */ + GIC_DIST_CTRL(dist_base) = 0x01; + + return 0; +} + +int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + _gic_table[index].cpu_hw_base = cpu_base; + + GIC_CPU_PRIMASK(cpu_base) = 0xf0; + /* Enable CPU interrupt */ + GIC_CPU_CTRL(cpu_base) = 0x01; + + return 0; +} + +void arm_gic_set_group(rt_uint32_t index, int vector, int group) +{ + /* As for GICv2, there are only group0 and group1. */ + RT_ASSERT(group <= 1); + RT_ASSERT(vector < _gic_max_irq); + + if (group == 0) + { + GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, + vector) &= ~(1 << (vector % 32)); + } + else if (group == 1) + { + GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, + vector) |= (1 << (vector % 32)); + } +} + +void arm_gic_trigger(rt_uint32_t index, int target_cpu, int irq) +{ + unsigned int reg; + + RT_ASSERT(irq <= 15); + RT_ASSERT(target_cpu <= 255); + + reg = (target_cpu << 16) | irq; + GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = reg; +} + +void arm_gic_clear_sgi(rt_uint32_t index, int target_cpu, int irq) +{ + RT_ASSERT(irq <= 15); + RT_ASSERT(target_cpu <= 255); + + GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = target_cpu << (irq % 4); +} diff --git a/rt-thread/libcpu/arm/zynq7000/gic.h b/rt-thread/libcpu/arm/zynq7000/gic.h new file mode 100644 index 0000000..4b89538 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/gic.h @@ -0,0 +1,41 @@ +/* + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __GIC_H__ +#define __GIC_H__ + +int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start); +int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base); + +void arm_gic_mask(rt_uint32_t index, int irq); +void arm_gic_umask(rt_uint32_t index, int irq); +void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask); +void arm_gic_set_group(rt_uint32_t index, int vector, int group); + +int arm_gic_get_active_irq(rt_uint32_t index); +void arm_gic_ack(rt_uint32_t index, int irq); + +void arm_gic_trigger(rt_uint32_t index, int target_cpu, int irq); +void arm_gic_clear_sgi(rt_uint32_t index, int target_cpu, int irq); + +void arm_gic_dump_type(rt_uint32_t index); + +#endif + diff --git a/rt-thread/libcpu/arm/zynq7000/interrupt.c b/rt-thread/libcpu/arm/zynq7000/interrupt.c new file mode 100644 index 0000000..ce3fbc8 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/interrupt.c @@ -0,0 +1,143 @@ +/* + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include "zynq7000.h" +#include "cp15.h" +#include "gic.h" + +#define MAX_HANDLERS IRQ_Zynq7000_MAXNR + +extern volatile rt_uint8_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +struct rt_irq_desc isr_table[MAX_HANDLERS]; +rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +static void rt_hw_interrupt_handle(int vector, void *param) +{ + rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); +} + +const unsigned int VECTOR_BASE = 0x00; +extern int system_vectors; + +static void rt_hw_vector_init(void) +{ + int sctrl; + unsigned int *src = (unsigned int *)&system_vectors; + + /* C12-C0 is only active when SCTLR.V = 0 */ + asm volatile ("mrc p15, #0, %0, c1, c0, #0" + :"=r" (sctrl)); + sctrl &= ~(1 << 13); + asm volatile ("mcr p15, #0, %0, c1, c0, #0" + : + :"r" (sctrl)); + + asm volatile ("mcr p15, #0, %0, c12, c0, #0" + : + :"r" (src)); +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + register rt_uint32_t idx; + + /* set vector table */ + rt_hw_vector_init(); + + /* init exceptions table */ + rt_memset(isr_table, 0x00, sizeof(isr_table)); + for (idx = 0; idx < MAX_HANDLERS; idx++) + { + isr_table[idx].handler = rt_hw_interrupt_handle; + } + + /* initialize ARM GIC */ + arm_gic_dist_init(0, Zynq7000_GIC_DIST_BASE, 0); + arm_gic_cpu_init(0, Zynq7000_GIC_CPU_BASE); + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + arm_gic_mask(0, vector); +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + arm_gic_umask(0, vector); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if (vector < MAX_HANDLERS) + { + old_handler = isr_table[vector].handler; + + if (handler != RT_NULL) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + /* set the interrupt to this cpu */ + arm_gic_set_cpu(0, vector, 1 << rt_cpu_get_smp_id()); + } + + return old_handler; +} + +void rt_hw_interrupt_clear(int vector) +{ + /* SGI will be cleared automatically. */ + if (vector < 16) + return; +} diff --git a/rt-thread/libcpu/arm/zynq7000/interrupt.h b/rt-thread/libcpu/arm/zynq7000/interrupt.h new file mode 100644 index 0000000..07eafc8 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/interrupt.h @@ -0,0 +1,26 @@ +#ifndef __INTERRUPT_H__ +#define __INTERRUPT_H__ +/* + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +void rt_hw_interrupt_clear(int vector); + +#endif /* end of include guard: __INTERRUPT_H__ */ + diff --git a/rt-thread/libcpu/arm/zynq7000/mmu.c b/rt-thread/libcpu/arm/zynq7000/mmu.c new file mode 100644 index 0000000..2a58fab --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/mmu.c @@ -0,0 +1,182 @@ +/* + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include "cp15.h" + +#define DESC_SEC (0x2) +#define CB (3<<2) //cache_on, write_back +#define CNB (2<<2) //cache_on, write_through +#define NCB (1<<2) //cache_off,WR_BUF on +#define NCNB (0<<2) //cache_off,WR_BUF off +#define AP_RW (3<<10) //supervisor=RW, user=RW +#define AP_RO (2<<10) //supervisor=RW, user=RO +#define XN (1<<4) //eXecute Never + +#define DOMAIN_FAULT (0x0) +#define DOMAIN_CHK (0x1) +#define DOMAIN_NOTCHK (0x3) +#define DOMAIN0 (0x0<<5) +#define DOMAIN1 (0x1<<5) + +#define DOMAIN0_ATTR (DOMAIN_CHK<<0) +#define DOMAIN1_ATTR (DOMAIN_FAULT<<2) + +/* Read/Write, cache, write back */ +#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) +/* Read/Write, cache, write through */ +#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) +/* Read/Write, device type */ +#define RW_NCB (AP_RW|DOMAIN0|NCB|DESC_SEC) +/* Read/Write strongly ordered type */ +#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) +/* Read/Write without cache and write buffer, no execute */ +#define RW_NCNBXN (AP_RW|DOMAIN0|NCNB|DESC_SEC|XN) +/* Read/Write without cache and write buffer */ +#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) + +void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + rt_kprintf("page table@%p\n", ptb); + for (i = 0; i < 1024*4; i++) + { + rt_uint32_t pte1 = ptb[i]; + if ((pte1 & 0x3) == 0) + { + rt_kprintf("%03x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf("%03x: %08x: ", i, pte1); + if ((pte1 & 0x3) == 0x3) + { + rt_kprintf("LPAE\n"); + } + else if ((pte1 & 0x3) == 0x1) + { + rt_kprintf("pte,ns:%d,domain:%d\n", + (pte1 >> 3) & 0x1, (pte1 >> 5) & 0xf); + /* + *rt_hw_cpu_dump_page_table_2nd((void*)((pte1 & 0xfffffc000) + * - 0x80000000 + 0xC0000000)); + */ + } + else if (pte1 & (1 << 18)) + { + rt_kprintf("super section,ns:%d,ap:%x,xn:%d,texcb:%02x\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + ((pte1 >> 10) | (pte1 >> 2)) & 0x1f); + } + else + { + rt_kprintf("section,ns:%d,ap:%x," + "xn:%d,texcb:%02x,domain:%d\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + (((pte1 & (0x7 << 12)) >> 10) | + ((pte1 & 0x0c) >> 2)) & 0x1f, + (pte1 >> 5) & 0xf); + } + } +} + +/* level1 page table, each entry for 1MB memory. */ +/* MMUTable is the name used by codes of Xilinx */ +volatile unsigned long MMUTable[4*1024] SECTION("mmu_tbl") __attribute__((aligned(16*1024))); +void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart, + rt_uint32_t vaddrEnd, + rt_uint32_t paddrStart, + rt_uint32_t attr) +{ + volatile rt_uint32_t *pTT; + volatile int i, nSec; + pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20); + nSec = (vaddrEnd >> 20) - (vaddrStart >> 20); + for(i = 0; i <= nSec; i++) + { + *pTT = attr | (((paddrStart >> 20) + i) << 20); + pTT++; + } +} + +unsigned long rt_hw_set_domain_register(unsigned long domain_val) +{ + unsigned long old_domain; + + asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain)); + asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory"); + + return old_domain; +} + +void rt_hw_mmu_init(void) +{ + extern rt_uint32_t __text_start; + rt_hw_cpu_dcache_disable(); + rt_hw_cpu_icache_disable(); + rt_cpu_mmu_disable(); + + /* set page table */ + /* no access to the memory below .text */ + /* 128M cached DDR memory */ + rt_hw_mmu_setmtt((rt_uint32_t)&__text_start, 0x20000000-1, + 0x1ff00000, RW_CB); + /* PL region */ + rt_hw_mmu_setmtt(0x40000000, 0xBFFFFFFF, 0x40000000, RW_NCNBXN); + /* IOP registers */ + rt_hw_mmu_setmtt(0xE0000000, 0xE02FFFFF, 0xE0000000, RW_NCNBXN); + /* no access to the SMC memory(enable it if you want) */ + /* SLCR, PS and CPU private registers, note we map more memory space as the + * entry is 1MB in size. */ + rt_hw_mmu_setmtt(0xF8000000, 0xF8FFFFFF, 0xF8000000, RW_NCNBXN); + + /*rt_hw_cpu_dump_page_table(MMUTable);*/ + + /* become clients for all domains */ + rt_hw_set_domain_register(0x55555555); + + rt_cpu_tlb_set(MMUTable); + + rt_cpu_mmu_enable(); + + rt_hw_cpu_icache_enable(); + rt_hw_cpu_dcache_enable(); +} + diff --git a/rt-thread/libcpu/arm/zynq7000/stack.c b/rt-thread/libcpu/arm/zynq7000/stack.c new file mode 100644 index 0000000..08dd4b4 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/stack.c @@ -0,0 +1,62 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, 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 + * 2011-09-23 Bernard the first version + * 2011-10-05 Bernard add thumb mode + * 2013-07-15 Bernard add Cortex-A8 support. + */ +#include +#include "zynq7000.h" + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stack_addr += sizeof(rt_uint32_t); + stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8); + stk = (rt_uint32_t *)stack_addr; + *(--stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0xdeadbeef; /* r12 */ + *(--stk) = 0xdeadbeef; /* r11 */ + *(--stk) = 0xdeadbeef; /* r10 */ + *(--stk) = 0xdeadbeef; /* r9 */ + *(--stk) = 0xdeadbeef; /* r8 */ + *(--stk) = 0xdeadbeef; /* r7 */ + *(--stk) = 0xdeadbeef; /* r6 */ + *(--stk) = 0xdeadbeef; /* r5 */ + *(--stk) = 0xdeadbeef; /* r4 */ + *(--stk) = 0xdeadbeef; /* r3 */ + *(--stk) = 0xdeadbeef; /* r2 */ + *(--stk) = 0xdeadbeef; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + diff --git a/rt-thread/libcpu/arm/zynq7000/start_gcc.S b/rt-thread/libcpu/arm/zynq7000/start_gcc.S new file mode 100644 index 0000000..41a7906 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/start_gcc.S @@ -0,0 +1,254 @@ +/* + * File : start_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.equ Mode_USR, 0x10 +.equ Mode_FIQ, 0x11 +.equ Mode_IRQ, 0x12 +.equ Mode_SVC, 0x13 +.equ Mode_ABT, 0x17 +.equ Mode_UND, 0x1B +.equ Mode_SYS, 0x1F + +.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled +.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled + +.equ UND_Stack_Size, 0x00000000 +.equ SVC_Stack_Size, 0x00000000 +.equ ABT_Stack_Size, 0x00000000 +.equ FIQ_Stack_Size, 0x00000100 +.equ IRQ_Stack_Size, 0x00000100 +.equ USR_Stack_Size, 0x00000000 + +#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + FIQ_Stack_Size + IRQ_Stack_Size) + +/* stack */ +.globl stack_start +.globl stack_top + +.bss +stack_start: +.rept ISR_Stack_Size +.long 0 +.endr +stack_top: + +.text +/* reset entry */ +.globl _reset +_reset: + /* invalidate SCU */ + ldr r7, =0xF8F0000C + ldr r6, =0xFFFF + str r6, [r7] + + /* disable MMU */ + mrc p15, 0, r0, c1, c0, 0 /* read CP15 register 1 */ + bic r0, r0, #0x1 /* clear bit 0 */ + mcr p15, 0, r0, c1, c0, 0 /* write value back */ + + /* set the cpu to SVC32 mode and disable interrupt */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0x13 + msr cpsr_c, r0 + + /* setup stack */ + bl stack_setup + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop +ctor_end: + + /* start RT-Thread Kernel */ + ldr pc, _rtthread_startup + +_rtthread_startup: + .word rtthread_startup + +stack_setup: + ldr r0, =stack_top + + @ Set the startup stack for svc + mov sp, r0 + + @ Enter Undefined Instruction Mode and set its Stack Pointer + msr cpsr_c, #Mode_UND|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #UND_Stack_Size + + @ Enter Abort Mode and set its Stack Pointer + msr cpsr_c, #Mode_ABT|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #ABT_Stack_Size + + @ Enter FIQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #FIQ_Stack_Size + + @ Enter IRQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #IRQ_Stack_Size + + @ Switch back to SVC + msr cpsr_c, #Mode_SVC|I_Bit|F_Bit + + bx lr + +.section .text.isr, "ax" +/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */ + .align 5 +.globl vector_fiq +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc,lr,#4 + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread + + .align 5 +.globl vector_irq +vector_irq: + stmfd sp!, {r0-r12,lr} + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + + @ if rt_thread_switch_interrupt_flag set, jump to + @ rt_hw_context_switch_interrupt_do and don't return + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq rt_hw_context_switch_interrupt_do + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +rt_hw_context_switch_interrupt_do: + mov r1, #0 @ clear flag + str r1, [r0] + + mov r1, sp @ r1 point to {r0-r3} in stack + add sp, sp, #4*4 + ldmfd sp!, {r4-r12,lr}@ reload saved registers + mrs r0, spsr @ get cpsr of interrupt thread + sub r2, lr, #4 @ save old task's pc to r2 + + @ Switch to SVC mode with no interrupt. + msr cpsr_c, #I_Bit|F_Bit|Mode_SVC + + stmfd sp!, {r2} @ push old task's pc + stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4 + ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt thread + stmfd sp!, {r1-r4} @ push old task's r0-r3 + stmfd sp!, {r0} @ push old task's cpsr + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] @ store sp in preempted tasks's TCB + + ldr r6, =rt_interrupt_to_thread + ldr r7, [r6] + ldr sp, [r7] @ get new task's stack pointer + + ldmfd sp!, {r4} @ pop new task's cpsr to spsr + msr spsr_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr + + +.macro push_svc_reg + sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */ + stmia sp, {r0 - r12} @/* Calling r0-r12 */ + mov r0, sp + mrs r6, spsr @/* Save CPSR */ + str lr, [r0, #15*4] @/* Push PC */ + str r6, [r0, #16*4] @/* Push CPSR */ + cps #Mode_SVC + str sp, [r0, #13*4] @/* Save calling SP */ + str lr, [r0, #14*4] @/* Save calling PC */ +.endm + + .align 5 + .globl vector_swi +vector_swi: + push_svc_reg + bl rt_hw_trap_swi + b . + + .align 5 + .globl vector_undef +vector_undef: + push_svc_reg + bl rt_hw_trap_undef + b . + + .align 5 + .globl vector_pabt +vector_pabt: + push_svc_reg + bl rt_hw_trap_pabt + b . + + .align 5 + .globl vector_dabt +vector_dabt: + push_svc_reg + bl rt_hw_trap_dabt + b . + + .align 5 + .globl vector_resv +vector_resv: + push_svc_reg + bl rt_hw_trap_resv + b . diff --git a/rt-thread/libcpu/arm/zynq7000/trap.c b/rt-thread/libcpu/arm/zynq7000/trap.c new file mode 100644 index 0000000..9bf58f9 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/trap.c @@ -0,0 +1,185 @@ +/* + * COPYRIGHT (C) 2013-2014, Shanghai Real-Thread Technology Co., Ltd + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include + +#include "zynq7000.h" +#include "gic.h" + +extern struct rt_thread *rt_current_thread; +#ifdef RT_USING_FINSH +extern long list_thread(void); +#endif + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ +void rt_hw_show_register (struct rt_hw_exp_stack *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_undef(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("undefined instruction:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("software interrupt:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("prefetch abort:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("data abort:"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("reserved trap:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +#define GIC_ACK_INTID_MASK 0x000003ff + +void rt_hw_trap_irq() +{ + void *param; + unsigned long ir; + unsigned long fullir; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + fullir = arm_gic_get_active_irq(0); + ir = fullir & GIC_ACK_INTID_MASK; + + /* get interrupt service routine */ + isr_func = isr_table[ir].handler; + if (isr_func) + { + param = isr_table[ir].param; + /* turn to interrupt service routine */ + isr_func(ir, param); + } + + /* end of interrupt */ + arm_gic_ack(0, fullir); +} + +void rt_hw_trap_fiq() +{ + void *param; + unsigned long ir; + unsigned long fullir; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + fullir = arm_gic_get_active_irq(0); + ir = fullir & GIC_ACK_INTID_MASK; + + /* get interrupt service routine */ + isr_func = isr_table[ir].handler; + param = isr_table[ir].param; + + /* turn to interrupt service routine */ + isr_func(ir, param); + + /* end of interrupt */ + arm_gic_ack(0, fullir); +} + diff --git a/rt-thread/libcpu/arm/zynq7000/vector_gcc.S b/rt-thread/libcpu/arm/zynq7000/vector_gcc.S new file mode 100644 index 0000000..4a44a73 --- /dev/null +++ b/rt-thread/libcpu/arm/zynq7000/vector_gcc.S @@ -0,0 +1,65 @@ +/* + * File : vector_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.section .vectors, "ax" +.code 32 + +.globl system_vectors +system_vectors: + ldr pc, _vector_reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + ldr pc, _vector_resv + ldr pc, _vector_irq + ldr pc, _vector_fiq + +.globl _reset +.globl vector_undef +.globl vector_swi +.globl vector_pabt +.globl vector_dabt +.globl vector_resv +.globl vector_irq +.globl vector_fiq + +_vector_reset: + .word _reset +_vector_undef: + .word vector_undef +_vector_swi: + .word vector_swi +_vector_pabt: + .word vector_pabt +_vector_dabt: + .word vector_dabt +_vector_resv: + .word vector_resv +_vector_irq: + .word vector_irq +_vector_fiq: + .word vector_fiq + +.balignl 16,0xdeadbeef diff --git a/rt-thread/libcpu/risc-v/e310/SConscript b/rt-thread/libcpu/risc-v/e310/SConscript new file mode 100644 index 0000000..4e4bc0c --- /dev/null +++ b/rt-thread/libcpu/risc-v/e310/SConscript @@ -0,0 +1,13 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +if rtconfig.PLATFORM == 'gcc': + src += Glob('*_gcc.S') + +group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/rt-thread/libcpu/risc-v/e310/context_gcc.S b/rt-thread/libcpu/risc-v/e310/context_gcc.S new file mode 100644 index 0000000..7aaa8db --- /dev/null +++ b/rt-thread/libcpu/risc-v/e310/context_gcc.S @@ -0,0 +1,227 @@ +;/* +; * File : context_gcc.S +; * This file is part of RT-Thread RTOS +; * COPYRIGHT (C) 2018, RT-Thread Development Team +; * +; * This program is free software; you can redistribute it and/or modify +; * it under the terms of the GNU General Public License as published by +; * the Free Software Foundation; either version 2 of the License, or +; * (at your option) any later version. +; * +; * This program is distributed in the hope that it will be useful, +; * but WITHOUT ANY WARRANTY; without even the implied warranty of +; * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; * GNU General Public License for more details. +; * +; * You should have received a copy of the GNU General Public License along +; * with this program; if not, write to the Free Software Foundation, Inc., +; * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +; * +; * Change Logs: +; * Date Author Notes +; * 2017-07-16 zhangjun for hifive1 +; * 2018-05-29 tanek optimize rt_hw_interrupt_* +; * 2018-05-29 tanek add mie register to context +; */ + +/* + * rt_base_t rt_hw_interrupt_disable(void); + */ + .globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + csrrci a0, mstatus, 8 + ret + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ + .globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + csrw mstatus, a0 + ret + +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * a0 --> from + * a1 --> to + */ + .globl rt_hw_context_switch +rt_hw_context_switch: + + /* saved from thread context + * x1/ra -> sp(0) + * x1/ra -> sp(1) + * mstatus.mie -> sp(2) + * x(i) -> sp(i-4) + */ + addi sp, sp, -32 * 4 + sw sp, (a0) + + sw x1, 0 * 4(sp) + sw x1, 1 * 4(sp) + + csrr a0, mstatus + andi a0, a0, 8 + beqz a0, save_mpie + li a0, 0x80 +save_mpie: + sw a0, 2 * 4(sp) + + sw x4, 4 * 4(sp) + sw x5, 5 * 4(sp) + sw x6, 6 * 4(sp) + sw x7, 7 * 4(sp) + sw x8, 8 * 4(sp) + sw x9, 9 * 4(sp) + sw x10, 10 * 4(sp) + sw x11, 11 * 4(sp) + sw x12, 12 * 4(sp) + sw x13, 13 * 4(sp) + sw x14, 14 * 4(sp) + sw x15, 15 * 4(sp) + sw x16, 16 * 4(sp) + sw x17, 17 * 4(sp) + sw x18, 18 * 4(sp) + sw x19, 19 * 4(sp) + sw x20, 20 * 4(sp) + sw x21, 21 * 4(sp) + sw x22, 22 * 4(sp) + sw x23, 23 * 4(sp) + sw x24, 24 * 4(sp) + sw x25, 25 * 4(sp) + sw x26, 26 * 4(sp) + sw x27, 27 * 4(sp) + sw x28, 28 * 4(sp) + sw x29, 29 * 4(sp) + sw x30, 30 * 4(sp) + sw x31, 31 * 4(sp) + + /* restore to thread context + * sp(0) -> epc; + * sp(1) -> ra; + * sp(i) -> x(i+2) + */ + lw sp, (a1) + + /* resw ra to mepc */ + lw a1, 0 * 4(sp) + csrw mepc, a1 + lw x1, 1 * 4(sp) + + /* force to machin mode(MPP=11) */ + li a1, 0x00001800; + csrs mstatus, a1 + lw a1, 2 * 4(sp) + csrs mstatus, a1 + + lw x4, 4 * 4(sp) + lw x5, 5 * 4(sp) + lw x6, 6 * 4(sp) + lw x7, 7 * 4(sp) + lw x8, 8 * 4(sp) + lw x9, 9 * 4(sp) + lw x10, 10 * 4(sp) + lw x11, 11 * 4(sp) + lw x12, 12 * 4(sp) + lw x13, 13 * 4(sp) + lw x14, 14 * 4(sp) + lw x15, 15 * 4(sp) + lw x16, 16 * 4(sp) + lw x17, 17 * 4(sp) + lw x18, 18 * 4(sp) + lw x19, 19 * 4(sp) + lw x20, 20 * 4(sp) + lw x21, 21 * 4(sp) + lw x22, 22 * 4(sp) + lw x23, 23 * 4(sp) + lw x24, 24 * 4(sp) + lw x25, 25 * 4(sp) + lw x26, 26 * 4(sp) + lw x27, 27 * 4(sp) + lw x28, 28 * 4(sp) + lw x29, 29 * 4(sp) + lw x30, 30 * 4(sp) + lw x31, 31 * 4(sp) + + addi sp, sp, 32 * 4 + mret + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * a0 --> to + */ + .globl rt_hw_context_switch_to +rt_hw_context_switch_to: + lw sp, (a0) + + /* load epc from stack */ + lw a0, 0 * 4(sp) + csrw mepc, a0 + lw x1, 1 * 4(sp) + /* load mstatus from stack */ + lw a0, 2 * 4(sp) + csrw mstatus, a0 + lw x4, 4 * 4(sp) + lw x5, 5 * 4(sp) + lw x6, 6 * 4(sp) + lw x7, 7 * 4(sp) + lw x8, 8 * 4(sp) + lw x9, 9 * 4(sp) + lw x10, 10 * 4(sp) + lw x11, 11 * 4(sp) + lw x12, 12 * 4(sp) + lw x13, 13 * 4(sp) + lw x14, 14 * 4(sp) + lw x15, 15 * 4(sp) + lw x16, 16 * 4(sp) + lw x17, 17 * 4(sp) + lw x18, 18 * 4(sp) + lw x19, 19 * 4(sp) + lw x20, 20 * 4(sp) + lw x21, 21 * 4(sp) + lw x22, 22 * 4(sp) + lw x23, 23 * 4(sp) + lw x24, 24 * 4(sp) + lw x25, 25 * 4(sp) + lw x26, 26 * 4(sp) + lw x27, 27 * 4(sp) + lw x28, 28 * 4(sp) + lw x29, 29 * 4(sp) + lw x30, 30 * 4(sp) + lw x31, 31 * 4(sp) + + addi sp, sp, 32 * 4 + mret + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ + .globl rt_thread_switch_interrupt_flag + .globl rt_interrupt_from_thread + .globl rt_interrupt_to_thread + .globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + addi sp, sp, -16 + sw s0, 12(sp) + sw a0, 8(sp) + sw a5, 4(sp) + + la a0, rt_thread_switch_interrupt_flag + lw a5, (a0) + bnez a5, _reswitch + li a5, 1 + sw a5, (a0) + + la a5, rt_interrupt_from_thread + lw a0, 8(sp) + sw a0, (a5) + +_reswitch: + la a5, rt_interrupt_to_thread + sw a1, (a5) + + lw a5, 4(sp) + lw a0, 8(sp) + lw s0, 12(sp) + addi sp, sp, 16 + ret diff --git a/rt-thread/libcpu/risc-v/e310/entry_gcc.S b/rt-thread/libcpu/risc-v/e310/entry_gcc.S new file mode 100644 index 0000000..83631e6 --- /dev/null +++ b/rt-thread/libcpu/risc-v/e310/entry_gcc.S @@ -0,0 +1,145 @@ +/* + * File : context_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2018, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2018-05-29 tanek first implementation + */ + + .section .text.entry + .align 2 + .global trap_entry +trap_entry: + + // save all from thread context + addi sp, sp, -32 * 4 + + sw x1, 1 * 4(sp) + li t0, 0x80 + sw t0, 2 * 4(sp) + + sw x4, 4 * 4(sp) + sw x5, 5 * 4(sp) + sw x6, 6 * 4(sp) + sw x7, 7 * 4(sp) + sw x8, 8 * 4(sp) + sw x9, 9 * 4(sp) + sw x10, 10 * 4(sp) + sw x11, 11 * 4(sp) + sw x12, 12 * 4(sp) + sw x13, 13 * 4(sp) + sw x14, 14 * 4(sp) + sw x15, 15 * 4(sp) + sw x16, 16 * 4(sp) + sw x17, 17 * 4(sp) + sw x18, 18 * 4(sp) + sw x19, 19 * 4(sp) + sw x20, 20 * 4(sp) + sw x21, 21 * 4(sp) + sw x22, 22 * 4(sp) + sw x23, 23 * 4(sp) + sw x24, 24 * 4(sp) + sw x25, 25 * 4(sp) + sw x26, 26 * 4(sp) + sw x27, 27 * 4(sp) + sw x28, 28 * 4(sp) + sw x29, 29 * 4(sp) + sw x30, 30 * 4(sp) + sw x31, 31 * 4(sp) + + // switch to interrupt stack + move s0, sp + la sp, _sp + + // interrupt handle + call rt_interrupt_enter + csrr a0, mcause + csrr a1, mepc + mv a2, sp + call handle_trap + call rt_interrupt_leave + + // switch to from thread stack + move sp, s0 + + // need to switch new thread + la s0, rt_thread_switch_interrupt_flag + lw s2, 0(s0) + beqz s2, spurious_interrupt + sw zero, 0(s0) + + csrr a0, mepc + sw a0, 0 * 4(sp) + + la s0, rt_interrupt_from_thread + lw s1, 0(s0) + sw sp, 0(s1) + + la s0, rt_interrupt_to_thread + lw s1, 0(s0) + lw sp, 0(s1) + + lw a0, 0 * 4(sp) + csrw mepc, a0 + +spurious_interrupt: + lw x1, 1 * 4(sp) + + // Remain in M-mode after mret + li t0, 0x00001800 + csrs mstatus, t0 + lw t0, 2 * 4(sp) + csrs mstatus, t0 + + lw x4, 4 * 4(sp) + lw x5, 5 * 4(sp) + lw x6, 6 * 4(sp) + lw x7, 7 * 4(sp) + lw x8, 8 * 4(sp) + lw x9, 9 * 4(sp) + lw x10, 10 * 4(sp) + lw x11, 11 * 4(sp) + lw x12, 12 * 4(sp) + lw x13, 13 * 4(sp) + lw x14, 14 * 4(sp) + lw x15, 15 * 4(sp) + lw x16, 16 * 4(sp) + lw x17, 17 * 4(sp) + lw x18, 18 * 4(sp) + lw x19, 19 * 4(sp) + lw x20, 20 * 4(sp) + lw x21, 21 * 4(sp) + lw x22, 22 * 4(sp) + lw x23, 23 * 4(sp) + lw x24, 24 * 4(sp) + lw x25, 25 * 4(sp) + lw x26, 26 * 4(sp) + lw x27, 27 * 4(sp) + lw x28, 28 * 4(sp) + lw x29, 29 * 4(sp) + lw x30, 30 * 4(sp) + lw x31, 31 * 4(sp) + + addi sp, sp, 32 * 4 + mret + +.weak handle_trap +handle_trap: +1: + j 1b diff --git a/rt-thread/libcpu/risc-v/e310/stack.c b/rt-thread/libcpu/risc-v/e310/stack.c new file mode 100644 index 0000000..a68c646 --- /dev/null +++ b/rt-thread/libcpu/risc-v/e310/stack.c @@ -0,0 +1,104 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-07-31 tanek first implementation + */ + +#include + +/* flag in interrupt handling */ +rt_uint32_t rt_interrupt_from_thread; +rt_uint32_t rt_interrupt_to_thread; +rt_uint32_t rt_thread_switch_interrupt_flag; + +struct stack_frame +{ + rt_ubase_t epc; /* epc - epc - program counter */ + rt_ubase_t ra; /* x1 - ra - return address for jumps */ + rt_ubase_t mstatus; /* - machine status register */ + rt_ubase_t gp; /* x3 - gp - global pointer */ + rt_ubase_t tp; /* x4 - tp - thread pointer */ + rt_ubase_t t0; /* x5 - t0 - temporary register 0 */ + rt_ubase_t t1; /* x6 - t1 - temporary register 1 */ + rt_ubase_t t2; /* x7 - t2 - temporary register 2 */ + rt_ubase_t s0_fp; /* x8 - s0/fp - saved register 0 or frame pointer */ + rt_ubase_t s1; /* x9 - s1 - saved register 1 */ + rt_ubase_t a0; /* x10 - a0 - return value or function argument 0 */ + rt_ubase_t a1; /* x11 - a1 - return value or function argument 1 */ + rt_ubase_t a2; /* x12 - a2 - function argument 2 */ + rt_ubase_t a3; /* x13 - a3 - function argument 3 */ + rt_ubase_t a4; /* x14 - a4 - function argument 4 */ + rt_ubase_t a5; /* x15 - a5 - function argument 5 */ + rt_ubase_t a6; /* x16 - a6 - function argument 6 */ + rt_ubase_t a7; /* x17 - s7 - function argument 7 */ + rt_ubase_t s2; /* x18 - s2 - saved register 2 */ + rt_ubase_t s3; /* x19 - s3 - saved register 3 */ + rt_ubase_t s4; /* x20 - s4 - saved register 4 */ + rt_ubase_t s5; /* x21 - s5 - saved register 5 */ + rt_ubase_t s6; /* x22 - s6 - saved register 6 */ + rt_ubase_t s7; /* x23 - s7 - saved register 7 */ + rt_ubase_t s8; /* x24 - s8 - saved register 8 */ + rt_ubase_t s9; /* x25 - s9 - saved register 9 */ + rt_ubase_t s10; /* x26 - s10 - saved register 10 */ + rt_ubase_t s11; /* x27 - s11 - saved register 11 */ + rt_ubase_t t3; /* x28 - t3 - temporary register 3 */ + rt_ubase_t t4; /* x29 - t4 - temporary register 4 */ + rt_ubase_t t5; /* x30 - t5 - temporary register 5 */ + rt_ubase_t t6; /* x31 - t6 - temporary register 6 */ +}; + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + struct stack_frame *stack_frame; + rt_uint8_t *stk; + int i; + + stk = stack_addr + sizeof(rt_uint32_t); + stk = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stk, 8); + stk -= sizeof(struct stack_frame); + + stack_frame = (struct stack_frame *)stk; + + for (i = 0; i < sizeof(struct stack_frame) / sizeof(rt_ubase_t); i++) + { + ((rt_ubase_t *)stack_frame)[i] = 0xdeadbeef; + } + + stack_frame->ra = (rt_ubase_t)texit; + stack_frame->a0 = (rt_ubase_t)parameter; + stack_frame->epc = (rt_ubase_t)tentry; + + // force to machine mode(MPP=11) and set MPIE to 1 + stack_frame->mstatus = 0x00001880; + + return stk; +} diff --git a/rt-thread/src/Kconfig b/rt-thread/src/Kconfig new file mode 100644 index 0000000..d3889f4 --- /dev/null +++ b/rt-thread/src/Kconfig @@ -0,0 +1,298 @@ +menu "RT-Thread Kernel" + +config RT_NAME_MAX + int "The maximal size of kernel object name" + range 2 32 + default 8 + help + Each kernel object, such as thread, timer, semaphore etc, has a name, + the RT_NAME_MAX is the maximal size of this object name. + +config RT_ALIGN_SIZE + int "Alignment size for CPU architecture data access" + default 4 + help + Alignment size for CPU architecture data access + + choice + prompt "The maximal level value of priority of thread" + default RT_THREAD_PRIORITY_32 + + config RT_THREAD_PRIORITY_8 + bool "8" + + config RT_THREAD_PRIORITY_32 + bool "32" + + config RT_THREAD_PRIORITY_256 + bool "256" + endchoice + +config RT_THREAD_PRIORITY_MAX + int + default 8 if RT_THREAD_PRIORITY_8 + default 32 if RT_THREAD_PRIORITY_32 + default 256 if RT_THREAD_PRIORITY_256 + +config RT_TICK_PER_SECOND + int "Tick frequency, Hz" + range 10 1000 + default 100 + help + System's tick frequency, Hz. + +config RT_USING_OVERFLOW_CHECK + bool "Using stack overflow checking" + default y + help + Enable thread stack overflow checking. The stack overflow is checking when + each thread switch. + +config RT_USING_HOOK + bool "Enable system hook" + default y + help + Enable the hook function when system running, such as idle thread hook, + thread context switch etc. + + if RT_USING_HOOK + config RT_IDEL_HOOK_LIST_SIZE + int "The max size of idel hook list" + default 4 + range 1 16 + help + The system has a hook list. This is the hook list size. + endif + +config IDLE_THREAD_STACK_SIZE + int "The stack size of idle thread" + default 256 + +config RT_USING_TIMER_SOFT + bool "Enable software timer with a timer thread" + default n + help + the timeout function context of soft-timer is under a high priority timer + thread. + +if RT_USING_TIMER_SOFT +config RT_TIMER_THREAD_PRIO + int "The priority level value of timer thread" + default 4 + +config RT_TIMER_THREAD_STACK_SIZE + int "The stack size of timer thread" + default 512 + +endif + +menuconfig RT_DEBUG + bool "Enable debugging features" + default y + +if RT_DEBUG + +config RT_DEBUG_INIT_CONFIG + bool "Enable debugging of components initialization" + default n + +config RT_DEBUG_INIT + int + default 1 if RT_DEBUG_INIT_CONFIG + +config RT_DEBUG_THREAD_CONFIG + bool "Enable debugging of Thread State Changes" + default n + +config RT_DEBUG_THREAD + int + default 1 if RT_DEBUG_THREAD_CONFIG + +config RT_DEBUG_SCHEDULER_CONFIG + bool "Enable debugging of Scheduler" + default n + +config RT_DEBUG_SCHEDULER + int + default 1 if RT_DEBUG_SCHEDULER_CONFIG + +config RT_DEBUG_IPC_CONFIG + bool "Enable debugging of IPC" + default n + +config RT_DEBUG_IPC + int + default 1 if RT_DEBUG_IPC_CONFIG + +config RT_DEBUG_TIMER_CONFIG + bool "Enable debugging of Timer" + default n + +config RT_DEBUG_TIMER + int + default 1 if RT_DEBUG_TIMER_CONFIG + +config RT_DEBUG_IRQ_CONFIG + bool "Enable debugging of IRQ(Interrupt Request)" + default n + +config RT_DEBUG_IRQ + int + default 1 if RT_DEBUG_IRQ_CONFIG + +config RT_DEBUG_MEM_CONFIG + bool "Enable debugging of Small Memory Algorithm" + default n + +config RT_DEBUG_MEM + int + default 1 if RT_DEBUG_MEM_CONFIG + +config RT_DEBUG_SLAB_CONFIG + bool "Enable debugging of SLAB Memory Algorithm" + default n + +config RT_DEBUG_SLAB + int + default 1 if RT_DEBUG_SLAB_CONFIG + +config RT_DEBUG_MEMHEAP_CONFIG + bool "Enable debugging of Memory Heap Algorithm" + default n + +config RT_DEBUG_MEMHEAP + int + default 1 if RT_DEBUG_MEMHEAP_CONFIG + +config RT_DEBUG_MODULE_CONFIG + bool "Enable debugging of Application Module" + default n + +config RT_DEBUG_MODULE + int + default 1 if RT_DEBUG_MODULE_CONFIG + +endif + +menu "Inter-Thread communication" + +config RT_USING_SEMAPHORE + bool "Enable semaphore" + default y + +config RT_USING_MUTEX + bool "Enable mutex" + default y + +config RT_USING_EVENT + bool "Enable event flag" + default y + +config RT_USING_MAILBOX + bool "Enable mailbox" + default y + +config RT_USING_MESSAGEQUEUE + bool "Enable message queue" + default y + +config RT_USING_SIGNALS + bool "Enable signals" + select RT_USING_MEMPOOL + default n + help + A signal is an asynchronous notification sent to a specific thread + in order to notify it of an event that occurred. +endmenu + +menu "Memory Management" + + config RT_USING_MEMPOOL + bool "Using memory pool" + default y + help + Using static memory fixed partition + + config RT_USING_MEMHEAP + bool "Using memory heap object" + default n + help + Using memory heap object to manage dynamic memory heap. + + choice + prompt "Dynamic Memory Management" + default RT_USING_SMALL_MEM + + config RT_USING_NOHEAP + bool "Disable Heap" + + config RT_USING_SMALL_MEM + bool "Small Memory Algorithm" + + config RT_USING_SLAB + bool "SLAB Algorithm for large memory" + + if RT_USING_MEMHEAP + config RT_USING_MEMHEAP_AS_HEAP + bool "Use all of memheap objects as heap" + endif + endchoice + + if RT_USING_SMALL_MEM + config RT_USING_MEMTRACE + bool "Enable memory trace" + default n + help + When enable RT_USING_MEMTRACE with shell, developer can call cmd: + 1. memtrace + to dump memory block information. + 2. memcheck + to check memory block to avoid memory overwritten. + + And developer also can call memcheck() in each of scheduling + to check memory block to find which thread has wrongly modified + memory. + endif + + config RT_USING_HEAP + bool + default n if RT_USING_NOHEAP + default y if RT_USING_SMALL_MEM + default y if RT_USING_SLAB + default y if RT_USING_MEMHEAP_AS_HEAP + +endmenu + +menu "Kernel Device Object" + + config RT_USING_DEVICE + bool "Using device object" + default y + + config RT_USING_DEVICE_OPS + bool "Using ops for each device object" + default n + + config RT_USING_INTERRUPT_INFO + bool "Enable additional interrupt trace information" + default n + help + Add name and counter information for interrupt trace. + + config RT_USING_CONSOLE + bool "Using console for rt_kprintf" + default y + + if RT_USING_CONSOLE + config RT_CONSOLEBUF_SIZE + int "the buffer size for console log printf" + default 128 + + config RT_CONSOLE_DEVICE_NAME + string "the device name for console" + default "uart" + endif + +endmenu + +endmenu diff --git a/rt-thread/src/SConscript b/rt-thread/src/SConscript new file mode 100644 index 0000000..bb38baa --- /dev/null +++ b/rt-thread/src/SConscript @@ -0,0 +1,43 @@ +Import('RTT_ROOT') +Import('rtconfig') +from building import * + +src = Glob('*.c') + +CPPPATH = [RTT_ROOT + '/include'] +if rtconfig.CROSS_TOOL == 'keil': + # add more link flags for module and components_init. + LINKFLAGS = '' + if GetDepend('RT_USING_MODULE'): + LINKFLAGS += ' --keep *.o(RTMSymTab) ' + if GetDepend('RT_USING_COMPONENTS_INIT'): + LINKFLAGS += ' --keep *.o(.rti_fn.*) ' +else: + LINKFLAGS = '' + +if GetDepend('RT_USING_COMPONENTS_INIT') == False: + SrcRemove(src, ['components.c']) + +if GetDepend('RT_USING_MODULE') == False: + SrcRemove(src, ['module.c']) + +if GetDepend('RT_USING_HEAP') == False or GetDepend('RT_USING_SMALL_MEM') == False: + SrcRemove(src, ['mem.c']) + +if GetDepend('RT_USING_HEAP') == False or GetDepend('RT_USING_SLAB') == False: + SrcRemove(src, ['slab.c']) + +if GetDepend('RT_USING_MEMPOOL') == False: + SrcRemove(src, ['mempool.c']) + +if GetDepend('RT_USING_MEMHEAP') == False: + SrcRemove(src, ['memheap.c']) + if GetDepend('RT_USING_MEMHEAP_AS_HEAP'): + SrcRemove(src, ['mem.c']) + +if GetDepend('RT_USING_DEVICE') == False: + SrcRemove(src, ['device.c']) + +group = DefineGroup('Kernel', src, depend = [''], CPPPATH = CPPPATH, LINKFLAGS = LINKFLAGS) + +Return('group') diff --git a/rt-thread/src/clock.c b/rt-thread/src/clock.c new file mode 100644 index 0000000..651465e --- /dev/null +++ b/rt-thread/src/clock.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-03-12 Bernard first version + * 2006-05-27 Bernard add support for same priority thread schedule + * 2006-08-10 Bernard remove the last rt_schedule in rt_tick_increase + * 2010-03-08 Bernard remove rt_passed_second + * 2010-05-20 Bernard fix the tick exceeds the maximum limits + * 2010-07-13 Bernard fix rt_tick_from_millisecond issue found by kuronca + * 2011-06-26 Bernard add rt_tick_set function. + */ + +#include +#include + +static rt_tick_t rt_tick = 0; + +extern void rt_timer_check(void); + +/** + * This function will init system tick and set it to zero. + * @ingroup SystemInit + * + * @deprecated since 1.1.0, this function does not need to be invoked + * in the system initialization. + */ +void rt_system_tick_init(void) +{ +} + +/** + * @addtogroup Clock + */ + +/**@{*/ + +/** + * This function will return current tick from operating system startup + * + * @return current tick + */ +rt_tick_t rt_tick_get(void) +{ + /* return the global tick */ + return rt_tick; +} +RTM_EXPORT(rt_tick_get); + +/** + * This function will set current tick + */ +void rt_tick_set(rt_tick_t tick) +{ + rt_base_t level; + + level = rt_hw_interrupt_disable(); + rt_tick = tick; + rt_hw_interrupt_enable(level); +} + +/** + * This function will notify kernel there is one tick passed. Normally, + * this function is invoked by clock ISR. + */ +void rt_tick_increase(void) +{ + struct rt_thread *thread; + + /* increase the global tick */ + ++ rt_tick; + + /* check time slice */ + thread = rt_thread_self(); + + -- thread->remaining_tick; + if (thread->remaining_tick == 0) + { + /* change to initialized tick */ + thread->remaining_tick = thread->init_tick; + + /* yield */ + rt_thread_yield(); + } + + /* check timer */ + rt_timer_check(); +} + +/** + * This function will calculate the tick from millisecond. + * + * @param ms the specified millisecond + * - Negative Number wait forever + * - Zero not wait + * - Max 0x7fffffff + * + * @return the calculated tick + */ +int rt_tick_from_millisecond(rt_int32_t ms) +{ + int tick; + + if (ms < 0) + tick = RT_WAITING_FOREVER; + else + tick = (RT_TICK_PER_SECOND * ms + 999) / 1000; + + /* return the calculated tick */ + return tick; +} +RTM_EXPORT(rt_tick_from_millisecond); + +/**@}*/ + diff --git a/rt-thread/src/components.c b/rt-thread/src/components.c new file mode 100644 index 0000000..679a88e --- /dev/null +++ b/rt-thread/src/components.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2012-09-20 Bernard Change the name to components.c + * And all components related header files. + * 2012-12-23 Bernard fix the pthread initialization issue. + * 2013-06-23 Bernard Add the init_call for components initialization. + * 2013-07-05 Bernard Remove initialization feature for MS VC++ compiler + * 2015-02-06 Bernard Remove the MS VC++ support and move to the kernel + * 2015-05-04 Bernard Rename it to components.c because compiling issue + * in some IDEs. + * 2015-07-29 Arda.Fu Add support to use RT_USING_USER_MAIN with IAR + */ + +#include +#include + +#ifdef RT_USING_USER_MAIN +#ifndef RT_MAIN_THREAD_STACK_SIZE +#define RT_MAIN_THREAD_STACK_SIZE 2048 +#endif +#ifndef RT_MAIN_THREAD_PRIORITY +#define RT_MAIN_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 3) +#endif +#endif + +#ifdef RT_USING_COMPONENTS_INIT +/* + * Components Initialization will initialize some driver and components as following + * order: + * rti_start --> 0 + * BOARD_EXPORT --> 1 + * rti_board_end --> 1.end + * + * DEVICE_EXPORT --> 2 + * COMPONENT_EXPORT --> 3 + * FS_EXPORT --> 4 + * ENV_EXPORT --> 5 + * APP_EXPORT --> 6 + * + * rti_end --> 6.end + * + * These automatically initializaiton, the driver or component initial function must + * be defined with: + * INIT_BOARD_EXPORT(fn); + * INIT_DEVICE_EXPORT(fn); + * ... + * INIT_APP_EXPORT(fn); + * etc. + */ +static int rti_start(void) +{ + return 0; +} +INIT_EXPORT(rti_start, "0"); + +static int rti_board_start(void) +{ + return 0; +} +INIT_EXPORT(rti_board_start, "0.end"); + +static int rti_board_end(void) +{ + return 0; +} +INIT_EXPORT(rti_board_end, "1.end"); + +static int rti_end(void) +{ + return 0; +} +INIT_EXPORT(rti_end, "6.end"); + +/** + * RT-Thread Components Initialization for board + */ +void rt_components_board_init(void) +{ +#if RT_DEBUG_INIT + int result; + const struct rt_init_desc *desc; + for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++) + { + rt_kprintf("initialize %s", desc->fn_name); + result = desc->fn(); + rt_kprintf(":%d done\n", result); + } +#else + const init_fn_t *fn_ptr; + + for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++) + { + (*fn_ptr)(); + } +#endif +} + +/** + * RT-Thread Components Initialization + */ +void rt_components_init(void) +{ +#if RT_DEBUG_INIT + int result; + const struct rt_init_desc *desc; + + rt_kprintf("do components intialization.\n"); + for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++) + { + rt_kprintf("initialize %s", desc->fn_name); + result = desc->fn(); + rt_kprintf(":%d done\n", result); + } +#else + const init_fn_t *fn_ptr; + + for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++) + { + (*fn_ptr)(); + } +#endif +} + +#ifdef RT_USING_USER_MAIN + +void rt_application_init(void); +void rt_hw_board_init(void); +int rtthread_startup(void); + +#if defined(__CC_ARM) || defined(__CLANG_ARM) +extern int $Super$$main(void); +/* re-define main function */ +int $Sub$$main(void) +{ + rt_hw_interrupt_disable(); + rtthread_startup(); + return 0; +} +#elif defined(__ICCARM__) +extern int main(void); +/* __low_level_init will auto called by IAR cstartup */ +extern void __iar_data_init3(void); +int __low_level_init(void) +{ + // call IAR table copy function. + __iar_data_init3(); + rt_hw_interrupt_disable(); + rtthread_startup(); + return 0; +} +#elif defined(__GNUC__) +extern int main(void); +/* Add -eentry to arm-none-eabi-gcc argument */ +int entry(void) +{ + rt_hw_interrupt_disable(); + rtthread_startup(); + return 0; +} +#endif + +#ifndef RT_USING_HEAP +/* if there is not enable heap, we should use static thread and stack. */ +ALIGN(8) +static rt_uint8_t main_stack[RT_MAIN_THREAD_STACK_SIZE]; +struct rt_thread main_thread; +#endif + +/* the system main thread */ +void main_thread_entry(void *parameter) +{ + extern int main(void); + extern int $Super$$main(void); + + /* RT-Thread components initialization */ + rt_components_init(); + + /* invoke system main function */ +#if defined(__CC_ARM) || defined(__CLANG_ARM) + $Super$$main(); /* for ARMCC. */ +#elif defined(__ICCARM__) || defined(__GNUC__) + main(); +#endif +} + +void rt_application_init(void) +{ + rt_thread_t tid; + +#ifdef RT_USING_HEAP + tid = rt_thread_create("main", main_thread_entry, RT_NULL, + RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20); + RT_ASSERT(tid != RT_NULL); +#else + rt_err_t result; + + tid = &main_thread; + result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL, + main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20); + RT_ASSERT(result == RT_EOK); + + /* if not define RT_USING_HEAP, using to eliminate the warning */ + (void)result; +#endif + + rt_thread_startup(tid); +} + +int rtthread_startup(void) +{ + rt_hw_interrupt_disable(); + + /* board level initalization + * NOTE: please initialize heap inside board initialization. + */ + rt_hw_board_init(); + + /* show RT-Thread version */ + rt_show_version(); + + /* timer system initialization */ + rt_system_timer_init(); + + /* scheduler system initialization */ + rt_system_scheduler_init(); + +#ifdef RT_USING_SIGNALS + /* signal system initialization */ + rt_system_signal_init(); +#endif + + /* create init_thread */ + rt_application_init(); + + /* timer thread initialization */ + rt_system_timer_thread_init(); + + /* idle thread initialization */ + rt_thread_idle_init(); + + /* start scheduler */ + rt_system_scheduler_start(); + + /* never reach here */ + return 0; +} +#endif +#endif diff --git a/rt-thread/src/device.c b/rt-thread/src/device.c new file mode 100644 index 0000000..51fc617 --- /dev/null +++ b/rt-thread/src/device.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2007-01-21 Bernard the first version + * 2010-05-04 Bernard add rt_device_init implementation + * 2012-10-20 Bernard add device check in register function, + * provided by Rob + * 2012-12-25 Bernard return RT_EOK if the device interface not exist. + * 2013-07-09 Grissiom add ref_count support + * 2016-04-02 Bernard fix the open_flag initialization issue. + */ + +#include +#if defined(RT_USING_POSIX) +#include /* for wqueue_init */ +#endif + +#ifdef RT_USING_DEVICE + +#ifdef RT_USING_DEVICE_OPS +#define device_init (dev->ops->init) +#define device_open (dev->ops->open) +#define device_close (dev->ops->close) +#define device_read (dev->ops->read) +#define device_write (dev->ops->write) +#define device_control (dev->ops->control) +#else +#define device_init (dev->init) +#define device_open (dev->open) +#define device_close (dev->close) +#define device_read (dev->read) +#define device_write (dev->write) +#define device_control (dev->control) +#endif + +/** + * This function registers a device driver with specified name. + * + * @param dev the pointer of device driver structure + * @param name the device driver's name + * @param flags the capabilities flag of device + * + * @return the error code, RT_EOK on initialization successfully. + */ +rt_err_t rt_device_register(rt_device_t dev, + const char *name, + rt_uint16_t flags) +{ + if (dev == RT_NULL) + return -RT_ERROR; + + if (rt_device_find(name) != RT_NULL) + return -RT_ERROR; + + rt_object_init(&(dev->parent), RT_Object_Class_Device, name); + dev->flag = flags; + dev->ref_count = 0; + dev->open_flag = 0; + +#if defined(RT_USING_POSIX) + dev->fops = RT_NULL; + rt_wqueue_init(&(dev->wait_queue)); +#endif + + return RT_EOK; +} +RTM_EXPORT(rt_device_register); + +/** + * This function removes a previously registered device driver + * + * @param dev the pointer of device driver structure + * + * @return the error code, RT_EOK on successfully. + */ +rt_err_t rt_device_unregister(rt_device_t dev) +{ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + RT_ASSERT(rt_object_is_systemobject(&dev->parent)); + + rt_object_detach(&(dev->parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_device_unregister); + +/** + * This function initializes all registered device driver + * + * @return the error code, RT_EOK on successfully. + * + * @deprecated since 1.2.x, this function is not needed because the initialization + * of a device is performed when applicaiton opens it. + */ +rt_err_t rt_device_init_all(void) +{ + return RT_EOK; +} + +/** + * This function finds a device driver by specified name. + * + * @param name the device driver's name + * + * @return the registered device driver on successful, or RT_NULL on failure. + */ +rt_device_t rt_device_find(const char *name) +{ + struct rt_object *object; + struct rt_list_node *node; + struct rt_object_information *information; + + /* enter critical */ + if (rt_thread_self() != RT_NULL) + rt_enter_critical(); + + /* try to find device object */ + information = rt_object_get_information(RT_Object_Class_Device); + RT_ASSERT(information != RT_NULL); + for (node = information->object_list.next; + node != &(information->object_list); + node = node->next) + { + object = rt_list_entry(node, struct rt_object, list); + if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0) + { + /* leave critical */ + if (rt_thread_self() != RT_NULL) + rt_exit_critical(); + + return (rt_device_t)object; + } + } + + /* leave critical */ + if (rt_thread_self() != RT_NULL) + rt_exit_critical(); + + /* not found */ + return RT_NULL; +} +RTM_EXPORT(rt_device_find); + +#ifdef RT_USING_HEAP +/** + * This function creates a device object with user data size. + * + * @param type, the kind type of this device object. + * @param attach_size, the size of user data. + * + * @return the allocated device object, or RT_NULL when failed. + */ +rt_device_t rt_device_create(int type, int attach_size) +{ + int size; + rt_device_t device; + + size = RT_ALIGN(sizeof(struct rt_device), RT_ALIGN_SIZE); + attach_size = RT_ALIGN(attach_size, RT_ALIGN_SIZE); + /* use the totoal size */ + size += attach_size; + + device = (rt_device_t)rt_malloc(size); + if (device) + { + rt_memset(device, 0x0, sizeof(struct rt_device)); + device->type = (enum rt_device_class_type)type; + } + + return device; +} +RTM_EXPORT(rt_device_create); + +/** + * This function destroy the specific device object. + * + * @param dev, the specific device object. + */ +void rt_device_destroy(rt_device_t dev) +{ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + RT_ASSERT(rt_object_is_systemobject(&dev->parent) == RT_FALSE); + + rt_object_detach(&(dev->parent)); + + /* release this device object */ + rt_free(dev); +} +RTM_EXPORT(rt_device_destroy); +#endif + +/** + * This function will initialize the specified device + * + * @param dev the pointer of device driver structure + * + * @return the result + */ +rt_err_t rt_device_init(rt_device_t dev) +{ + rt_err_t result = RT_EOK; + + RT_ASSERT(dev != RT_NULL); + + /* get device init handler */ + if (device_init != RT_NULL) + { + if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) + { + result = device_init(dev); + if (result != RT_EOK) + { + rt_kprintf("To initialize device:%s failed. The error code is %d\n", + dev->parent.name, result); + } + else + { + dev->flag |= RT_DEVICE_FLAG_ACTIVATED; + } + } + } + + return result; +} + +/** + * This function will open a device + * + * @param dev the pointer of device driver structure + * @param oflag the flags for device open + * + * @return the result + */ +rt_err_t rt_device_open(rt_device_t dev, rt_uint16_t oflag) +{ + rt_err_t result = RT_EOK; + + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + /* if device is not initialized, initialize it. */ + if (!(dev->flag & RT_DEVICE_FLAG_ACTIVATED)) + { + if (device_init != RT_NULL) + { + result = device_init(dev); + if (result != RT_EOK) + { + rt_kprintf("To initialize device:%s failed. The error code is %d\n", + dev->parent.name, result); + + return result; + } + } + + dev->flag |= RT_DEVICE_FLAG_ACTIVATED; + } + + /* device is a stand alone device and opened */ + if ((dev->flag & RT_DEVICE_FLAG_STANDALONE) && + (dev->open_flag & RT_DEVICE_OFLAG_OPEN)) + { + return -RT_EBUSY; + } + + /* call device open interface */ + if (device_open != RT_NULL) + { + result = device_open(dev, oflag); + } + else + { + /* set open flag */ + dev->open_flag = (oflag & RT_DEVICE_OFLAG_MASK); + } + + /* set open flag */ + if (result == RT_EOK || result == -RT_ENOSYS) + { + dev->open_flag |= RT_DEVICE_OFLAG_OPEN; + + dev->ref_count++; + /* don't let bad things happen silently. If you are bitten by this assert, + * please set the ref_count to a bigger type. */ + RT_ASSERT(dev->ref_count != 0); + } + + return result; +} +RTM_EXPORT(rt_device_open); + +/** + * This function will close a device + * + * @param dev the pointer of device driver structure + * + * @return the result + */ +rt_err_t rt_device_close(rt_device_t dev) +{ + rt_err_t result = RT_EOK; + + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + if (dev->ref_count == 0) + return -RT_ERROR; + + dev->ref_count--; + + if (dev->ref_count != 0) + return RT_EOK; + + /* call device close interface */ + if (device_close != RT_NULL) + { + result = device_close(dev); + } + + /* set open flag */ + if (result == RT_EOK || result == -RT_ENOSYS) + dev->open_flag = RT_DEVICE_OFLAG_CLOSE; + + return result; +} +RTM_EXPORT(rt_device_close); + +/** + * This function will read some data from a device. + * + * @param dev the pointer of device driver structure + * @param pos the position of reading + * @param buffer the data buffer to save read data + * @param size the size of buffer + * + * @return the actually read size on successful, otherwise negative returned. + * + * @note since 0.4.0, the unit of size/pos is a block for block device. + */ +rt_size_t rt_device_read(rt_device_t dev, + rt_off_t pos, + void *buffer, + rt_size_t size) +{ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + if (dev->ref_count == 0) + { + rt_set_errno(-RT_ERROR); + return 0; + } + + /* call device read interface */ + if (device_read != RT_NULL) + { + return device_read(dev, pos, buffer, size); + } + + /* set error code */ + rt_set_errno(-RT_ENOSYS); + + return 0; +} +RTM_EXPORT(rt_device_read); + +/** + * This function will write some data to a device. + * + * @param dev the pointer of device driver structure + * @param pos the position of written + * @param buffer the data buffer to be written to device + * @param size the size of buffer + * + * @return the actually written size on successful, otherwise negative returned. + * + * @note since 0.4.0, the unit of size/pos is a block for block device. + */ +rt_size_t rt_device_write(rt_device_t dev, + rt_off_t pos, + const void *buffer, + rt_size_t size) +{ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + if (dev->ref_count == 0) + { + rt_set_errno(-RT_ERROR); + return 0; + } + + /* call device write interface */ + if (device_write != RT_NULL) + { + return device_write(dev, pos, buffer, size); + } + + /* set error code */ + rt_set_errno(-RT_ENOSYS); + + return 0; +} +RTM_EXPORT(rt_device_write); + +/** + * This function will perform a variety of control functions on devices. + * + * @param dev the pointer of device driver structure + * @param cmd the command sent to device + * @param arg the argument of command + * + * @return the result + */ +rt_err_t rt_device_control(rt_device_t dev, int cmd, void *arg) +{ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + /* call device write interface */ + if (device_control != RT_NULL) + { + return device_control(dev, cmd, arg); + } + + return -RT_ENOSYS; +} +RTM_EXPORT(rt_device_control); + +/** + * This function will set the reception indication callback function. This callback function + * is invoked when this device receives data. + * + * @param dev the pointer of device driver structure + * @param rx_ind the indication callback function + * + * @return RT_EOK + */ +rt_err_t +rt_device_set_rx_indicate(rt_device_t dev, + rt_err_t (*rx_ind)(rt_device_t dev, rt_size_t size)) +{ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + dev->rx_indicate = rx_ind; + + return RT_EOK; +} +RTM_EXPORT(rt_device_set_rx_indicate); + +/** + * This function will set the indication callback function when device has + * written data to physical hardware. + * + * @param dev the pointer of device driver structure + * @param tx_done the indication callback function + * + * @return RT_EOK + */ +rt_err_t +rt_device_set_tx_complete(rt_device_t dev, + rt_err_t (*tx_done)(rt_device_t dev, void *buffer)) +{ + RT_ASSERT(dev != RT_NULL); + RT_ASSERT(rt_object_get_type(&dev->parent) == RT_Object_Class_Device); + + dev->tx_complete = tx_done; + + return RT_EOK; +} +RTM_EXPORT(rt_device_set_tx_complete); + +#endif diff --git a/rt-thread/src/idle.c b/rt-thread/src/idle.c new file mode 100644 index 0000000..ec7d6be --- /dev/null +++ b/rt-thread/src/idle.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-03-23 Bernard the first version + * 2010-11-10 Bernard add cleanup callback function in thread exit. + * 2012-12-29 Bernard fix compiling warning. + * 2013-12-21 Grissiom let rt_thread_idle_excute loop until there is no + * dead thread. + * 2016-08-09 ArdaFu add method to get the handler of the idle thread. + * 2018-02-07 Bernard lock scheduler to protect tid->cleanup. + * 2018-07-14 armink add idle hook list + */ + +#include +#include + +#ifdef RT_USING_MODULE +#include +#endif + +#if defined (RT_USING_HOOK) +#ifndef RT_USING_IDLE_HOOK +#define RT_USING_IDLE_HOOK +#endif +#endif + +#ifndef IDLE_THREAD_STACK_SIZE +#if defined (RT_USING_IDLE_HOOK) || defined(RT_USING_HEAP) +#define IDLE_THREAD_STACK_SIZE 256 +#else +#define IDLE_THREAD_STACK_SIZE 128 +#endif +#endif + +static struct rt_thread idle; +ALIGN(RT_ALIGN_SIZE) +static rt_uint8_t rt_thread_stack[IDLE_THREAD_STACK_SIZE]; + +extern rt_list_t rt_thread_defunct; + +#ifdef RT_USING_IDLE_HOOK + +#ifndef RT_IDEL_HOOK_LIST_SIZE +#define RT_IDEL_HOOK_LIST_SIZE 4 +#endif + +static void (*idle_hook_list[RT_IDEL_HOOK_LIST_SIZE])(); + +/** + * @ingroup Hook + * This function sets a hook function to idle thread loop. When the system performs + * idle loop, this hook function should be invoked. + * + * @param hook the specified hook function + * + * @return RT_EOK: set OK + * -RT_EFULL: hook list is full + * + * @note the hook function must be simple and never be blocked or suspend. + */ +rt_err_t rt_thread_idle_sethook(void (*hook)(void)) +{ + rt_size_t i; + rt_base_t level; + rt_err_t ret = -RT_EFULL; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++) + { + if (idle_hook_list[i] == RT_NULL) + { + idle_hook_list[i] = hook; + ret = RT_EOK; + break; + } + } + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return ret; +} + +/** + * delete the idle hook on hook list + * + * @param hook the specified hook function + * + * @return RT_EOK: delete OK + * -RT_ENOSYS: hook was not found + */ +rt_err_t rt_thread_idle_delhook(void (*hook)(void)) +{ + rt_size_t i; + rt_base_t level; + rt_err_t ret = -RT_ENOSYS; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++) + { + if (idle_hook_list[i] == hook) + { + idle_hook_list[i] = RT_NULL; + ret = RT_EOK; + break; + } + } + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return ret; +} + +#endif + +/* Return whether there is defunctional thread to be deleted. */ +rt_inline int _has_defunct_thread(void) +{ + /* The rt_list_isempty has prototype of "int rt_list_isempty(const rt_list_t *l)". + * So the compiler has a good reason that the rt_thread_defunct list does + * not change within rt_thread_idle_excute thus optimize the "while" loop + * into a "if". + * + * So add the volatile qualifier here. */ + const volatile rt_list_t *l = (const volatile rt_list_t *)&rt_thread_defunct; + + return l->next != l; +} + +/** + * @ingroup Thread + * + * This function will perform system background job when system idle. + */ +void rt_thread_idle_excute(void) +{ + /* Loop until there is no dead thread. So one call to rt_thread_idle_excute + * will do all the cleanups. */ + while (_has_defunct_thread()) + { + rt_base_t lock; + rt_thread_t thread; +#ifdef RT_USING_MODULE + struct rt_dlmodule *module = RT_NULL; +#endif + RT_DEBUG_NOT_IN_INTERRUPT; + + /* disable interrupt */ + lock = rt_hw_interrupt_disable(); + + /* re-check whether list is empty */ + if (_has_defunct_thread()) + { + /* get defunct thread */ + thread = rt_list_entry(rt_thread_defunct.next, + struct rt_thread, + tlist); +#ifdef RT_USING_MODULE + module = (struct rt_dlmodule*)thread->module_id; + if (module) + { + dlmodule_destroy(module); + } +#endif + /* remove defunct thread */ + rt_list_remove(&(thread->tlist)); + + /* lock scheduler to prevent scheduling in cleanup function. */ + rt_enter_critical(); + + /* invoke thread cleanup */ + if (thread->cleanup != RT_NULL) + thread->cleanup(thread); + +#ifdef RT_USING_SIGNALS + rt_thread_free_sig(thread); +#endif + + /* if it's a system object, not delete it */ + if (rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) + { + /* unlock scheduler */ + rt_exit_critical(); + + /* enable interrupt */ + rt_hw_interrupt_enable(lock); + + return; + } + + /* unlock scheduler */ + rt_exit_critical(); + } + else + { + /* enable interrupt */ + rt_hw_interrupt_enable(lock); + + /* may the defunct thread list is removed by others, just return */ + return; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(lock); + +#ifdef RT_USING_HEAP + /* release thread's stack */ + RT_KERNEL_FREE(thread->stack_addr); + /* delete thread object */ + rt_object_delete((rt_object_t)thread); +#endif + } +} + +static void rt_thread_idle_entry(void *parameter) +{ +#ifdef RT_USING_IDLE_HOOK + rt_size_t i; +#endif + + while (1) + { + +#ifdef RT_USING_IDLE_HOOK + for (i = 0; i < RT_IDEL_HOOK_LIST_SIZE; i++) + { + if (idle_hook_list[i] != RT_NULL) + { + idle_hook_list[i](); + } + } +#endif + + rt_thread_idle_excute(); + } +} + +/** + * @ingroup SystemInit + * + * This function will initialize idle thread, then start it. + * + * @note this function must be invoked when system init. + */ +void rt_thread_idle_init(void) +{ + /* initialize thread */ + rt_thread_init(&idle, + "tidle", + rt_thread_idle_entry, + RT_NULL, + &rt_thread_stack[0], + sizeof(rt_thread_stack), + RT_THREAD_PRIORITY_MAX - 1, + 32); + + /* startup */ + rt_thread_startup(&idle); +} + +/** + * @ingroup Thread + * + * This function will get the handler of the idle thread. + * + */ +rt_thread_t rt_thread_idle_gethandler(void) +{ + return (rt_thread_t)(&idle); +} diff --git a/rt-thread/src/ipc.c b/rt-thread/src/ipc.c new file mode 100644 index 0000000..5604591 --- /dev/null +++ b/rt-thread/src/ipc.c @@ -0,0 +1,2326 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-03-14 Bernard the first version + * 2006-04-25 Bernard implement semaphore + * 2006-05-03 Bernard add RT_IPC_DEBUG + * modify the type of IPC waiting time to rt_int32_t + * 2006-05-10 Bernard fix the semaphore take bug and add IPC object + * 2006-05-12 Bernard implement mailbox and message queue + * 2006-05-20 Bernard implement mutex + * 2006-05-23 Bernard implement fast event + * 2006-05-24 Bernard implement event + * 2006-06-03 Bernard fix the thread timer init bug + * 2006-06-05 Bernard fix the mutex release bug + * 2006-06-07 Bernard fix the message queue send bug + * 2006-08-04 Bernard add hook support + * 2009-05-21 Yi.qiu fix the sem release bug + * 2009-07-18 Bernard fix the event clear bug + * 2009-09-09 Bernard remove fast event and fix ipc release bug + * 2009-10-10 Bernard change semaphore and mutex value to unsigned value + * 2009-10-25 Bernard change the mb/mq receive timeout to 0 if the + * re-calculated delta tick is a negative number. + * 2009-12-16 Bernard fix the rt_ipc_object_suspend issue when IPC flag + * is RT_IPC_FLAG_PRIO + * 2010-01-20 mbbill remove rt_ipc_object_decrease function. + * 2010-04-20 Bernard move memcpy outside interrupt disable in mq + * 2010-10-26 yi.qiu add module support in rt_mp_delete and rt_mq_delete + * 2010-11-10 Bernard add IPC reset command implementation. + * 2011-12-18 Bernard add more parameter checking in message queue + * 2013-09-14 Grissiom add an option check in rt_event_recv + */ + +#include +#include + +#ifdef RT_USING_HOOK +extern void (*rt_object_trytake_hook)(struct rt_object *object); +extern void (*rt_object_take_hook)(struct rt_object *object); +extern void (*rt_object_put_hook)(struct rt_object *object); +#endif + +/** + * @addtogroup IPC + */ + +/**@{*/ + +/** + * This function will initialize an IPC object + * + * @param ipc the IPC object + * + * @return the operation status, RT_EOK on successful + */ +rt_inline rt_err_t rt_ipc_object_init(struct rt_ipc_object *ipc) +{ + /* init ipc object */ + rt_list_init(&(ipc->suspend_thread)); + + return RT_EOK; +} + +/** + * This function will suspend a thread to a specified list. IPC object or some + * double-queue object (mailbox etc.) contains this kind of list. + * + * @param list the IPC suspended thread list + * @param thread the thread object to be suspended + * @param flag the IPC object flag, + * which shall be RT_IPC_FLAG_FIFO/RT_IPC_FLAG_PRIO. + * + * @return the operation status, RT_EOK on successful + */ +rt_inline rt_err_t rt_ipc_list_suspend(rt_list_t *list, + struct rt_thread *thread, + rt_uint8_t flag) +{ + /* suspend thread */ + rt_thread_suspend(thread); + + switch (flag) + { + case RT_IPC_FLAG_FIFO: + rt_list_insert_before(list, &(thread->tlist)); + break; + + case RT_IPC_FLAG_PRIO: + { + struct rt_list_node *n; + struct rt_thread *sthread; + + /* find a suitable position */ + for (n = list->next; n != list; n = n->next) + { + sthread = rt_list_entry(n, struct rt_thread, tlist); + + /* find out */ + if (thread->current_priority < sthread->current_priority) + { + /* insert this thread before the sthread */ + rt_list_insert_before(&(sthread->tlist), &(thread->tlist)); + break; + } + } + + /* + * not found a suitable position, + * append to the end of suspend_thread list + */ + if (n == list) + rt_list_insert_before(list, &(thread->tlist)); + } + break; + } + + return RT_EOK; +} + +/** + * This function will resume the first thread in the list of a IPC object: + * - remove the thread from suspend queue of IPC object + * - put the thread into system ready queue + * + * @param list the thread list + * + * @return the operation status, RT_EOK on successful + */ +rt_inline rt_err_t rt_ipc_list_resume(rt_list_t *list) +{ + struct rt_thread *thread; + + /* get thread entry */ + thread = rt_list_entry(list->next, struct rt_thread, tlist); + + RT_DEBUG_LOG(RT_DEBUG_IPC, ("resume thread:%s\n", thread->name)); + + /* resume it */ + rt_thread_resume(thread); + + return RT_EOK; +} + +/** + * This function will resume all suspended threads in a list, including + * suspend list of IPC object and private list of mailbox etc. + * + * @param list of the threads to resume + * + * @return the operation status, RT_EOK on successful + */ +rt_inline rt_err_t rt_ipc_list_resume_all(rt_list_t *list) +{ + struct rt_thread *thread; + register rt_ubase_t temp; + + /* wakeup all suspend threads */ + while (!rt_list_isempty(list)) + { + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* get next suspend thread */ + thread = rt_list_entry(list->next, struct rt_thread, tlist); + /* set error code to RT_ERROR */ + thread->error = -RT_ERROR; + + /* + * resume thread + * In rt_thread_resume function, it will remove current thread from + * suspend list + */ + rt_thread_resume(thread); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + } + + return RT_EOK; +} + +#ifdef RT_USING_SEMAPHORE +/** + * This function will initialize a semaphore and put it under control of + * resource management. + * + * @param sem the semaphore object + * @param name the name of semaphore + * @param value the init value of semaphore + * @param flag the flag of semaphore + * + * @return the operation status, RT_EOK on successful + */ +rt_err_t rt_sem_init(rt_sem_t sem, + const char *name, + rt_uint32_t value, + rt_uint8_t flag) +{ + RT_ASSERT(sem != RT_NULL); + + /* init object */ + rt_object_init(&(sem->parent.parent), RT_Object_Class_Semaphore, name); + + /* init ipc object */ + rt_ipc_object_init(&(sem->parent)); + + /* set init value */ + sem->value = value; + + /* set parent */ + sem->parent.parent.flag = flag; + + return RT_EOK; +} +RTM_EXPORT(rt_sem_init); + +/** + * This function will detach a semaphore from resource management + * + * @param sem the semaphore object + * + * @return the operation status, RT_EOK on successful + * + * @see rt_sem_delete + */ +rt_err_t rt_sem_detach(rt_sem_t sem) +{ + /* parameter check */ + RT_ASSERT(sem != RT_NULL); + RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore); + RT_ASSERT(rt_object_is_systemobject(&sem->parent.parent)); + + /* wakeup all suspend threads */ + rt_ipc_list_resume_all(&(sem->parent.suspend_thread)); + + /* detach semaphore object */ + rt_object_detach(&(sem->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_sem_detach); + +#ifdef RT_USING_HEAP +/** + * This function will create a semaphore from system resource + * + * @param name the name of semaphore + * @param value the init value of semaphore + * @param flag the flag of semaphore + * + * @return the created semaphore, RT_NULL on error happen + * + * @see rt_sem_init + */ +rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag) +{ + rt_sem_t sem; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* allocate object */ + sem = (rt_sem_t)rt_object_allocate(RT_Object_Class_Semaphore, name); + if (sem == RT_NULL) + return sem; + + /* init ipc object */ + rt_ipc_object_init(&(sem->parent)); + + /* set init value */ + sem->value = value; + + /* set parent */ + sem->parent.parent.flag = flag; + + return sem; +} +RTM_EXPORT(rt_sem_create); + +/** + * This function will delete a semaphore object and release the memory + * + * @param sem the semaphore object + * + * @return the error code + * + * @see rt_sem_detach + */ +rt_err_t rt_sem_delete(rt_sem_t sem) +{ + RT_DEBUG_NOT_IN_INTERRUPT; + + /* parameter check */ + RT_ASSERT(sem != RT_NULL); + RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore); + RT_ASSERT(rt_object_is_systemobject(&sem->parent.parent) == RT_FALSE); + + /* wakeup all suspend threads */ + rt_ipc_list_resume_all(&(sem->parent.suspend_thread)); + + /* delete semaphore object */ + rt_object_delete(&(sem->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_sem_delete); +#endif + +/** + * This function will take a semaphore, if the semaphore is unavailable, the + * thread shall wait for a specified time. + * + * @param sem the semaphore object + * @param time the waiting time + * + * @return the error code + */ +rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time) +{ + register rt_base_t temp; + struct rt_thread *thread; + + /* parameter check */ + RT_ASSERT(sem != RT_NULL); + RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore); + + RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(sem->parent.parent))); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s take sem:%s, which value is: %d\n", + rt_thread_self()->name, + ((struct rt_object *)sem)->name, + sem->value)); + + if (sem->value > 0) + { + /* semaphore is available */ + sem->value --; + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + } + else + { + /* no waiting, return with timeout */ + if (time == 0) + { + rt_hw_interrupt_enable(temp); + + return -RT_ETIMEOUT; + } + else + { + /* current context checking */ + RT_DEBUG_IN_THREAD_CONTEXT; + + /* semaphore is unavailable, push to suspend list */ + /* get current thread */ + thread = rt_thread_self(); + + /* reset thread error number */ + thread->error = RT_EOK; + + RT_DEBUG_LOG(RT_DEBUG_IPC, ("sem take: suspend thread - %s\n", + thread->name)); + + /* suspend thread */ + rt_ipc_list_suspend(&(sem->parent.suspend_thread), + thread, + sem->parent.parent.flag); + + /* has waiting time, start thread timer */ + if (time > 0) + { + RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n", + thread->name)); + + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &time); + rt_timer_start(&(thread->thread_timer)); + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* do schedule */ + rt_schedule(); + + if (thread->error != RT_EOK) + { + return thread->error; + } + } + } + + RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(sem->parent.parent))); + + return RT_EOK; +} +RTM_EXPORT(rt_sem_take); + +/** + * This function will try to take a semaphore and immediately return + * + * @param sem the semaphore object + * + * @return the error code + */ +rt_err_t rt_sem_trytake(rt_sem_t sem) +{ + return rt_sem_take(sem, 0); +} +RTM_EXPORT(rt_sem_trytake); + +/** + * This function will release a semaphore, if there are threads suspended on + * semaphore, it will be waked up. + * + * @param sem the semaphore object + * + * @return the error code + */ +rt_err_t rt_sem_release(rt_sem_t sem) +{ + register rt_base_t temp; + register rt_bool_t need_schedule; + + /* parameter check */ + RT_ASSERT(sem != RT_NULL); + RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore); + + RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(sem->parent.parent))); + + need_schedule = RT_FALSE; + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + RT_DEBUG_LOG(RT_DEBUG_IPC, ("thread %s releases sem:%s, which value is: %d\n", + rt_thread_self()->name, + ((struct rt_object *)sem)->name, + sem->value)); + + if (!rt_list_isempty(&sem->parent.suspend_thread)) + { + /* resume the suspended thread */ + rt_ipc_list_resume(&(sem->parent.suspend_thread)); + need_schedule = RT_TRUE; + } + else + sem->value ++; /* increase value */ + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* resume a thread, re-schedule */ + if (need_schedule == RT_TRUE) + rt_schedule(); + + return RT_EOK; +} +RTM_EXPORT(rt_sem_release); + +/** + * This function can get or set some extra attributions of a semaphore object. + * + * @param sem the semaphore object + * @param cmd the execution command + * @param arg the execution argument + * + * @return the error code + */ +rt_err_t rt_sem_control(rt_sem_t sem, int cmd, void *arg) +{ + rt_ubase_t level; + + /* parameter check */ + RT_ASSERT(sem != RT_NULL); + RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore); + + if (cmd == RT_IPC_CMD_RESET) + { + rt_uint32_t value; + + /* get value */ + value = (rt_uint32_t)arg; + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* resume all waiting thread */ + rt_ipc_list_resume_all(&sem->parent.suspend_thread); + + /* set new value */ + sem->value = (rt_uint16_t)value; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_schedule(); + + return RT_EOK; + } + + return -RT_ERROR; +} +RTM_EXPORT(rt_sem_control); +#endif /* end of RT_USING_SEMAPHORE */ + +#ifdef RT_USING_MUTEX +/** + * This function will initialize a mutex and put it under control of resource + * management. + * + * @param mutex the mutex object + * @param name the name of mutex + * @param flag the flag of mutex + * + * @return the operation status, RT_EOK on successful + */ +rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag) +{ + /* parameter check */ + RT_ASSERT(mutex != RT_NULL); + + /* init object */ + rt_object_init(&(mutex->parent.parent), RT_Object_Class_Mutex, name); + + /* init ipc object */ + rt_ipc_object_init(&(mutex->parent)); + + mutex->value = 1; + mutex->owner = RT_NULL; + mutex->original_priority = 0xFF; + mutex->hold = 0; + + /* set flag */ + mutex->parent.parent.flag = flag; + + return RT_EOK; +} +RTM_EXPORT(rt_mutex_init); + +/** + * This function will detach a mutex from resource management + * + * @param mutex the mutex object + * + * @return the operation status, RT_EOK on successful + * + * @see rt_mutex_delete + */ +rt_err_t rt_mutex_detach(rt_mutex_t mutex) +{ + /* parameter check */ + RT_ASSERT(mutex != RT_NULL); + RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex); + RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent)); + + /* wakeup all suspend threads */ + rt_ipc_list_resume_all(&(mutex->parent.suspend_thread)); + + /* detach semaphore object */ + rt_object_detach(&(mutex->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_mutex_detach); + +#ifdef RT_USING_HEAP +/** + * This function will create a mutex from system resource + * + * @param name the name of mutex + * @param flag the flag of mutex + * + * @return the created mutex, RT_NULL on error happen + * + * @see rt_mutex_init + */ +rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag) +{ + struct rt_mutex *mutex; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* allocate object */ + mutex = (rt_mutex_t)rt_object_allocate(RT_Object_Class_Mutex, name); + if (mutex == RT_NULL) + return mutex; + + /* init ipc object */ + rt_ipc_object_init(&(mutex->parent)); + + mutex->value = 1; + mutex->owner = RT_NULL; + mutex->original_priority = 0xFF; + mutex->hold = 0; + + /* set flag */ + mutex->parent.parent.flag = flag; + + return mutex; +} +RTM_EXPORT(rt_mutex_create); + +/** + * This function will delete a mutex object and release the memory + * + * @param mutex the mutex object + * + * @return the error code + * + * @see rt_mutex_detach + */ +rt_err_t rt_mutex_delete(rt_mutex_t mutex) +{ + RT_DEBUG_NOT_IN_INTERRUPT; + + /* parameter check */ + RT_ASSERT(mutex != RT_NULL); + RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex); + RT_ASSERT(rt_object_is_systemobject(&mutex->parent.parent) == RT_FALSE); + + /* wakeup all suspend threads */ + rt_ipc_list_resume_all(&(mutex->parent.suspend_thread)); + + /* delete semaphore object */ + rt_object_delete(&(mutex->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_mutex_delete); +#endif + +/** + * This function will take a mutex, if the mutex is unavailable, the + * thread shall wait for a specified time. + * + * @param mutex the mutex object + * @param time the waiting time + * + * @return the error code + */ +rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time) +{ + register rt_base_t temp; + struct rt_thread *thread; + + /* this function must not be used in interrupt even if time = 0 */ + RT_DEBUG_IN_THREAD_CONTEXT; + + /* parameter check */ + RT_ASSERT(mutex != RT_NULL); + RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex); + + /* get current thread */ + thread = rt_thread_self(); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mutex->parent.parent))); + + RT_DEBUG_LOG(RT_DEBUG_IPC, + ("mutex_take: current thread %s, mutex value: %d, hold: %d\n", + thread->name, mutex->value, mutex->hold)); + + /* reset thread error */ + thread->error = RT_EOK; + + if (mutex->owner == thread) + { + /* it's the same thread */ + mutex->hold ++; + } + else + { +__again: + /* The value of mutex is 1 in initial status. Therefore, if the + * value is great than 0, it indicates the mutex is avaible. + */ + if (mutex->value > 0) + { + /* mutex is available */ + mutex->value --; + + /* set mutex owner and original priority */ + mutex->owner = thread; + mutex->original_priority = thread->current_priority; + mutex->hold ++; + } + else + { + /* no waiting, return with timeout */ + if (time == 0) + { + /* set error as timeout */ + thread->error = -RT_ETIMEOUT; + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + return -RT_ETIMEOUT; + } + else + { + /* mutex is unavailable, push to suspend list */ + RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_take: suspend thread: %s\n", + thread->name)); + + /* change the owner thread priority of mutex */ + if (thread->current_priority < mutex->owner->current_priority) + { + /* change the owner thread priority */ + rt_thread_control(mutex->owner, + RT_THREAD_CTRL_CHANGE_PRIORITY, + &thread->current_priority); + } + + /* suspend current thread */ + rt_ipc_list_suspend(&(mutex->parent.suspend_thread), + thread, + mutex->parent.parent.flag); + + /* has waiting time, start thread timer */ + if (time > 0) + { + RT_DEBUG_LOG(RT_DEBUG_IPC, + ("mutex_take: start the timer of thread:%s\n", + thread->name)); + + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &time); + rt_timer_start(&(thread->thread_timer)); + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* do schedule */ + rt_schedule(); + + if (thread->error != RT_EOK) + { + /* interrupt by signal, try it again */ + if (thread->error == -RT_EINTR) goto __again; + + /* return error */ + return thread->error; + } + else + { + /* the mutex is taken successfully. */ + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + } + } + } + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mutex->parent.parent))); + + return RT_EOK; +} +RTM_EXPORT(rt_mutex_take); + +/** + * This function will release a mutex, if there are threads suspended on mutex, + * it will be waked up. + * + * @param mutex the mutex object + * + * @return the error code + */ +rt_err_t rt_mutex_release(rt_mutex_t mutex) +{ + register rt_base_t temp; + struct rt_thread *thread; + rt_bool_t need_schedule; + + /* parameter check */ + RT_ASSERT(mutex != RT_NULL); + RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex); + + need_schedule = RT_FALSE; + + /* only thread could release mutex because we need test the ownership */ + RT_DEBUG_IN_THREAD_CONTEXT; + + /* get current thread */ + thread = rt_thread_self(); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + RT_DEBUG_LOG(RT_DEBUG_IPC, + ("mutex_release:current thread %s, mutex value: %d, hold: %d\n", + thread->name, mutex->value, mutex->hold)); + + RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mutex->parent.parent))); + + /* mutex only can be released by owner */ + if (thread != mutex->owner) + { + thread->error = -RT_ERROR; + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + return -RT_ERROR; + } + + /* decrease hold */ + mutex->hold --; + /* if no hold */ + if (mutex->hold == 0) + { + /* change the owner thread to original priority */ + if (mutex->original_priority != mutex->owner->current_priority) + { + rt_thread_control(mutex->owner, + RT_THREAD_CTRL_CHANGE_PRIORITY, + &(mutex->original_priority)); + } + + /* wakeup suspended thread */ + if (!rt_list_isempty(&mutex->parent.suspend_thread)) + { + /* get suspended thread */ + thread = rt_list_entry(mutex->parent.suspend_thread.next, + struct rt_thread, + tlist); + + RT_DEBUG_LOG(RT_DEBUG_IPC, ("mutex_release: resume thread: %s\n", + thread->name)); + + /* set new owner and priority */ + mutex->owner = thread; + mutex->original_priority = thread->current_priority; + mutex->hold ++; + + /* resume thread */ + rt_ipc_list_resume(&(mutex->parent.suspend_thread)); + + need_schedule = RT_TRUE; + } + else + { + /* increase value */ + mutex->value ++; + + /* clear owner */ + mutex->owner = RT_NULL; + mutex->original_priority = 0xff; + } + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* perform a schedule */ + if (need_schedule == RT_TRUE) + rt_schedule(); + + return RT_EOK; +} +RTM_EXPORT(rt_mutex_release); + +/** + * This function can get or set some extra attributions of a mutex object. + * + * @param mutex the mutex object + * @param cmd the execution command + * @param arg the execution argument + * + * @return the error code + */ +rt_err_t rt_mutex_control(rt_mutex_t mutex, int cmd, void *arg) +{ + /* parameter check */ + RT_ASSERT(mutex != RT_NULL); + RT_ASSERT(rt_object_get_type(&mutex->parent.parent) == RT_Object_Class_Mutex); + + return -RT_ERROR; +} +RTM_EXPORT(rt_mutex_control); +#endif /* end of RT_USING_MUTEX */ + +#ifdef RT_USING_EVENT +/** + * This function will initialize an event and put it under control of resource + * management. + * + * @param event the event object + * @param name the name of event + * @param flag the flag of event + * + * @return the operation status, RT_EOK on successful + */ +rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag) +{ + /* parameter check */ + RT_ASSERT(event != RT_NULL); + + /* init object */ + rt_object_init(&(event->parent.parent), RT_Object_Class_Event, name); + + /* set parent flag */ + event->parent.parent.flag = flag; + + /* init ipc object */ + rt_ipc_object_init(&(event->parent)); + + /* init event */ + event->set = 0; + + return RT_EOK; +} +RTM_EXPORT(rt_event_init); + +/** + * This function will detach an event object from resource management + * + * @param event the event object + * + * @return the operation status, RT_EOK on successful + */ +rt_err_t rt_event_detach(rt_event_t event) +{ + /* parameter check */ + RT_ASSERT(event != RT_NULL); + RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event); + RT_ASSERT(rt_object_is_systemobject(&event->parent.parent)); + + /* resume all suspended thread */ + rt_ipc_list_resume_all(&(event->parent.suspend_thread)); + + /* detach event object */ + rt_object_detach(&(event->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_event_detach); + +#ifdef RT_USING_HEAP +/** + * This function will create an event object from system resource + * + * @param name the name of event + * @param flag the flag of event + * + * @return the created event, RT_NULL on error happen + */ +rt_event_t rt_event_create(const char *name, rt_uint8_t flag) +{ + rt_event_t event; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* allocate object */ + event = (rt_event_t)rt_object_allocate(RT_Object_Class_Event, name); + if (event == RT_NULL) + return event; + + /* set parent */ + event->parent.parent.flag = flag; + + /* init ipc object */ + rt_ipc_object_init(&(event->parent)); + + /* init event */ + event->set = 0; + + return event; +} +RTM_EXPORT(rt_event_create); + +/** + * This function will delete an event object and release the memory + * + * @param event the event object + * + * @return the error code + */ +rt_err_t rt_event_delete(rt_event_t event) +{ + /* parameter check */ + RT_ASSERT(event != RT_NULL); + RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event); + RT_ASSERT(rt_object_is_systemobject(&event->parent.parent) == RT_FALSE); + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* resume all suspended thread */ + rt_ipc_list_resume_all(&(event->parent.suspend_thread)); + + /* delete event object */ + rt_object_delete(&(event->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_event_delete); +#endif + +/** + * This function will send an event to the event object, if there are threads + * suspended on event object, it will be waked up. + * + * @param event the event object + * @param set the event set + * + * @return the error code + */ +rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set) +{ + struct rt_list_node *n; + struct rt_thread *thread; + register rt_ubase_t level; + register rt_base_t status; + rt_bool_t need_schedule; + + /* parameter check */ + RT_ASSERT(event != RT_NULL); + RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event); + + if (set == 0) + return -RT_ERROR; + + need_schedule = RT_FALSE; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* set event */ + event->set |= set; + + RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(event->parent.parent))); + + if (!rt_list_isempty(&event->parent.suspend_thread)) + { + /* search thread list to resume thread */ + n = event->parent.suspend_thread.next; + while (n != &(event->parent.suspend_thread)) + { + /* get thread */ + thread = rt_list_entry(n, struct rt_thread, tlist); + + status = -RT_ERROR; + if (thread->event_info & RT_EVENT_FLAG_AND) + { + if ((thread->event_set & event->set) == thread->event_set) + { + /* received an AND event */ + status = RT_EOK; + } + } + else if (thread->event_info & RT_EVENT_FLAG_OR) + { + if (thread->event_set & event->set) + { + /* save recieved event set */ + thread->event_set = thread->event_set & event->set; + + /* received an OR event */ + status = RT_EOK; + } + } + + /* move node to the next */ + n = n->next; + + /* condition is satisfied, resume thread */ + if (status == RT_EOK) + { + /* clear event */ + if (thread->event_info & RT_EVENT_FLAG_CLEAR) + event->set &= ~thread->event_set; + + /* resume thread, and thread list breaks out */ + rt_thread_resume(thread); + + /* need do a scheduling */ + need_schedule = RT_TRUE; + } + } + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* do a schedule */ + if (need_schedule == RT_TRUE) + rt_schedule(); + + return RT_EOK; +} +RTM_EXPORT(rt_event_send); + +/** + * This function will receive an event from event object, if the event is + * unavailable, the thread shall wait for a specified time. + * + * @param event the fast event object + * @param set the interested event set + * @param option the receive option, either RT_EVENT_FLAG_AND or + * RT_EVENT_FLAG_OR should be set. + * @param timeout the waiting time + * @param recved the received event, if you don't care, RT_NULL can be set. + * + * @return the error code + */ +rt_err_t rt_event_recv(rt_event_t event, + rt_uint32_t set, + rt_uint8_t option, + rt_int32_t timeout, + rt_uint32_t *recved) +{ + struct rt_thread *thread; + register rt_ubase_t level; + register rt_base_t status; + + RT_DEBUG_IN_THREAD_CONTEXT; + + /* parameter check */ + RT_ASSERT(event != RT_NULL); + RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event); + + if (set == 0) + return -RT_ERROR; + + /* init status */ + status = -RT_ERROR; + /* get current thread */ + thread = rt_thread_self(); + /* reset thread error */ + thread->error = RT_EOK; + + RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(event->parent.parent))); + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* check event set */ + if (option & RT_EVENT_FLAG_AND) + { + if ((event->set & set) == set) + status = RT_EOK; + } + else if (option & RT_EVENT_FLAG_OR) + { + if (event->set & set) + status = RT_EOK; + } + else + { + /* either RT_EVENT_FLAG_AND or RT_EVENT_FLAG_OR should be set */ + RT_ASSERT(0); + } + + if (status == RT_EOK) + { + /* set received event */ + if (recved) + *recved = (event->set & set); + + /* received event */ + if (option & RT_EVENT_FLAG_CLEAR) + event->set &= ~set; + } + else if (timeout == 0) + { + /* no waiting */ + thread->error = -RT_ETIMEOUT; + } + else + { + /* fill thread event info */ + thread->event_set = set; + thread->event_info = option; + + /* put thread to suspended thread list */ + rt_ipc_list_suspend(&(event->parent.suspend_thread), + thread, + event->parent.parent.flag); + + /* if there is a waiting timeout, active thread timer */ + if (timeout > 0) + { + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* do a schedule */ + rt_schedule(); + + if (thread->error != RT_EOK) + { + /* return error */ + return thread->error; + } + + /* received an event, disable interrupt to protect */ + level = rt_hw_interrupt_disable(); + + /* set received event */ + if (recved) + *recved = thread->event_set; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(event->parent.parent))); + + return thread->error; +} +RTM_EXPORT(rt_event_recv); + +/** + * This function can get or set some extra attributions of an event object. + * + * @param event the event object + * @param cmd the execution command + * @param arg the execution argument + * + * @return the error code + */ +rt_err_t rt_event_control(rt_event_t event, int cmd, void *arg) +{ + rt_ubase_t level; + + /* parameter check */ + RT_ASSERT(event != RT_NULL); + RT_ASSERT(rt_object_get_type(&event->parent.parent) == RT_Object_Class_Event); + + if (cmd == RT_IPC_CMD_RESET) + { + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* resume all waiting thread */ + rt_ipc_list_resume_all(&event->parent.suspend_thread); + + /* init event set */ + event->set = 0; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_schedule(); + + return RT_EOK; + } + + return -RT_ERROR; +} +RTM_EXPORT(rt_event_control); +#endif /* end of RT_USING_EVENT */ + +#ifdef RT_USING_MAILBOX +/** + * This function will initialize a mailbox and put it under control of resource + * management. + * + * @param mb the mailbox object + * @param name the name of mailbox + * @param msgpool the begin address of buffer to save received mail + * @param size the size of mailbox + * @param flag the flag of mailbox + * + * @return the operation status, RT_EOK on successful + */ +rt_err_t rt_mb_init(rt_mailbox_t mb, + const char *name, + void *msgpool, + rt_size_t size, + rt_uint8_t flag) +{ + RT_ASSERT(mb != RT_NULL); + + /* init object */ + rt_object_init(&(mb->parent.parent), RT_Object_Class_MailBox, name); + + /* set parent flag */ + mb->parent.parent.flag = flag; + + /* init ipc object */ + rt_ipc_object_init(&(mb->parent)); + + /* init mailbox */ + mb->msg_pool = msgpool; + mb->size = size; + mb->entry = 0; + mb->in_offset = 0; + mb->out_offset = 0; + + /* init an additional list of sender suspend thread */ + rt_list_init(&(mb->suspend_sender_thread)); + + return RT_EOK; +} +RTM_EXPORT(rt_mb_init); + +/** + * This function will detach a mailbox from resource management + * + * @param mb the mailbox object + * + * @return the operation status, RT_EOK on successful + */ +rt_err_t rt_mb_detach(rt_mailbox_t mb) +{ + /* parameter check */ + RT_ASSERT(mb != RT_NULL); + RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox); + RT_ASSERT(rt_object_is_systemobject(&mb->parent.parent)); + + /* resume all suspended thread */ + rt_ipc_list_resume_all(&(mb->parent.suspend_thread)); + /* also resume all mailbox private suspended thread */ + rt_ipc_list_resume_all(&(mb->suspend_sender_thread)); + + /* detach mailbox object */ + rt_object_detach(&(mb->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_mb_detach); + +#ifdef RT_USING_HEAP +/** + * This function will create a mailbox object from system resource + * + * @param name the name of mailbox + * @param size the size of mailbox + * @param flag the flag of mailbox + * + * @return the created mailbox, RT_NULL on error happen + */ +rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag) +{ + rt_mailbox_t mb; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* allocate object */ + mb = (rt_mailbox_t)rt_object_allocate(RT_Object_Class_MailBox, name); + if (mb == RT_NULL) + return mb; + + /* set parent */ + mb->parent.parent.flag = flag; + + /* init ipc object */ + rt_ipc_object_init(&(mb->parent)); + + /* init mailbox */ + mb->size = size; + mb->msg_pool = RT_KERNEL_MALLOC(mb->size * sizeof(rt_uint32_t)); + if (mb->msg_pool == RT_NULL) + { + /* delete mailbox object */ + rt_object_delete(&(mb->parent.parent)); + + return RT_NULL; + } + mb->entry = 0; + mb->in_offset = 0; + mb->out_offset = 0; + + /* init an additional list of sender suspend thread */ + rt_list_init(&(mb->suspend_sender_thread)); + + return mb; +} +RTM_EXPORT(rt_mb_create); + +/** + * This function will delete a mailbox object and release the memory + * + * @param mb the mailbox object + * + * @return the error code + */ +rt_err_t rt_mb_delete(rt_mailbox_t mb) +{ + RT_DEBUG_NOT_IN_INTERRUPT; + + /* parameter check */ + RT_ASSERT(mb != RT_NULL); + RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox); + RT_ASSERT(rt_object_is_systemobject(&mb->parent.parent) == RT_FALSE); + + /* resume all suspended thread */ + rt_ipc_list_resume_all(&(mb->parent.suspend_thread)); + + /* also resume all mailbox private suspended thread */ + rt_ipc_list_resume_all(&(mb->suspend_sender_thread)); + + /* free mailbox pool */ + RT_KERNEL_FREE(mb->msg_pool); + + /* delete mailbox object */ + rt_object_delete(&(mb->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_mb_delete); +#endif + +/** + * This function will send a mail to mailbox object. If the mailbox is full, + * current thread will be suspended until timeout. + * + * @param mb the mailbox object + * @param value the mail + * @param timeout the waiting time + * + * @return the error code + */ +rt_err_t rt_mb_send_wait(rt_mailbox_t mb, + rt_uint32_t value, + rt_int32_t timeout) +{ + struct rt_thread *thread; + register rt_ubase_t temp; + rt_uint32_t tick_delta; + + /* parameter check */ + RT_ASSERT(mb != RT_NULL); + RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox); + + /* initialize delta tick */ + tick_delta = 0; + /* get current thread */ + thread = rt_thread_self(); + + RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mb->parent.parent))); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* for non-blocking call */ + if (mb->entry == mb->size && timeout == 0) + { + rt_hw_interrupt_enable(temp); + + return -RT_EFULL; + } + + /* mailbox is full */ + while (mb->entry == mb->size) + { + /* reset error number in thread */ + thread->error = RT_EOK; + + /* no waiting, return timeout */ + if (timeout == 0) + { + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + return -RT_EFULL; + } + + RT_DEBUG_IN_THREAD_CONTEXT; + /* suspend current thread */ + rt_ipc_list_suspend(&(mb->suspend_sender_thread), + thread, + mb->parent.parent.flag); + + /* has waiting time, start thread timer */ + if (timeout > 0) + { + /* get the start tick of timer */ + tick_delta = rt_tick_get(); + + RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_send_wait: start timer of thread:%s\n", + thread->name)); + + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* re-schedule */ + rt_schedule(); + + /* resume from suspend state */ + if (thread->error != RT_EOK) + { + /* return error */ + return thread->error; + } + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* if it's not waiting forever and then re-calculate timeout tick */ + if (timeout > 0) + { + tick_delta = rt_tick_get() - tick_delta; + timeout -= tick_delta; + if (timeout < 0) + timeout = 0; + } + } + + /* set ptr */ + mb->msg_pool[mb->in_offset] = value; + /* increase input offset */ + ++ mb->in_offset; + if (mb->in_offset >= mb->size) + mb->in_offset = 0; + /* increase message entry */ + mb->entry ++; + + /* resume suspended thread */ + if (!rt_list_isempty(&mb->parent.suspend_thread)) + { + rt_ipc_list_resume(&(mb->parent.suspend_thread)); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + rt_schedule(); + + return RT_EOK; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + return RT_EOK; +} +RTM_EXPORT(rt_mb_send_wait); + +/** + * This function will send a mail to mailbox object, if there are threads + * suspended on mailbox object, it will be waked up. This function will return + * immediately, if you want blocking send, use rt_mb_send_wait instead. + * + * @param mb the mailbox object + * @param value the mail + * + * @return the error code + */ +rt_err_t rt_mb_send(rt_mailbox_t mb, rt_uint32_t value) +{ + return rt_mb_send_wait(mb, value, 0); +} +RTM_EXPORT(rt_mb_send); + +/** + * This function will receive a mail from mailbox object, if there is no mail + * in mailbox object, the thread shall wait for a specified time. + * + * @param mb the mailbox object + * @param value the received mail will be saved in + * @param timeout the waiting time + * + * @return the error code + */ +rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_uint32_t *value, rt_int32_t timeout) +{ + struct rt_thread *thread; + register rt_ubase_t temp; + rt_uint32_t tick_delta; + + /* parameter check */ + RT_ASSERT(mb != RT_NULL); + RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox); + + /* initialize delta tick */ + tick_delta = 0; + /* get current thread */ + thread = rt_thread_self(); + + RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mb->parent.parent))); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* for non-blocking call */ + if (mb->entry == 0 && timeout == 0) + { + rt_hw_interrupt_enable(temp); + + return -RT_ETIMEOUT; + } + + /* mailbox is empty */ + while (mb->entry == 0) + { + /* reset error number in thread */ + thread->error = RT_EOK; + + /* no waiting, return timeout */ + if (timeout == 0) + { + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + thread->error = -RT_ETIMEOUT; + + return -RT_ETIMEOUT; + } + + RT_DEBUG_IN_THREAD_CONTEXT; + /* suspend current thread */ + rt_ipc_list_suspend(&(mb->parent.suspend_thread), + thread, + mb->parent.parent.flag); + + /* has waiting time, start thread timer */ + if (timeout > 0) + { + /* get the start tick of timer */ + tick_delta = rt_tick_get(); + + RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_recv: start timer of thread:%s\n", + thread->name)); + + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* re-schedule */ + rt_schedule(); + + /* resume from suspend state */ + if (thread->error != RT_EOK) + { + /* return error */ + return thread->error; + } + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* if it's not waiting forever and then re-calculate timeout tick */ + if (timeout > 0) + { + tick_delta = rt_tick_get() - tick_delta; + timeout -= tick_delta; + if (timeout < 0) + timeout = 0; + } + } + + /* fill ptr */ + *value = mb->msg_pool[mb->out_offset]; + + /* increase output offset */ + ++ mb->out_offset; + if (mb->out_offset >= mb->size) + mb->out_offset = 0; + /* decrease message entry */ + mb->entry --; + + /* resume suspended thread */ + if (!rt_list_isempty(&(mb->suspend_sender_thread))) + { + rt_ipc_list_resume(&(mb->suspend_sender_thread)); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mb->parent.parent))); + + rt_schedule(); + + return RT_EOK; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mb->parent.parent))); + + return RT_EOK; +} +RTM_EXPORT(rt_mb_recv); + +/** + * This function can get or set some extra attributions of a mailbox object. + * + * @param mb the mailbox object + * @param cmd the execution command + * @param arg the execution argument + * + * @return the error code + */ +rt_err_t rt_mb_control(rt_mailbox_t mb, int cmd, void *arg) +{ + rt_ubase_t level; + + /* parameter check */ + RT_ASSERT(mb != RT_NULL); + RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox); + + if (cmd == RT_IPC_CMD_RESET) + { + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* resume all waiting thread */ + rt_ipc_list_resume_all(&(mb->parent.suspend_thread)); + /* also resume all mailbox private suspended thread */ + rt_ipc_list_resume_all(&(mb->suspend_sender_thread)); + + /* re-init mailbox */ + mb->entry = 0; + mb->in_offset = 0; + mb->out_offset = 0; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_schedule(); + + return RT_EOK; + } + + return -RT_ERROR; +} +RTM_EXPORT(rt_mb_control); +#endif /* end of RT_USING_MAILBOX */ + +#ifdef RT_USING_MESSAGEQUEUE +struct rt_mq_message +{ + struct rt_mq_message *next; +}; + +/** + * This function will initialize a message queue and put it under control of + * resource management. + * + * @param mq the message object + * @param name the name of message queue + * @param msgpool the beginning address of buffer to save messages + * @param msg_size the maximum size of message + * @param pool_size the size of buffer to save messages + * @param flag the flag of message queue + * + * @return the operation status, RT_EOK on successful + */ +rt_err_t rt_mq_init(rt_mq_t mq, + const char *name, + void *msgpool, + rt_size_t msg_size, + rt_size_t pool_size, + rt_uint8_t flag) +{ + struct rt_mq_message *head; + register rt_base_t temp; + + /* parameter check */ + RT_ASSERT(mq != RT_NULL); + + /* init object */ + rt_object_init(&(mq->parent.parent), RT_Object_Class_MessageQueue, name); + + /* set parent flag */ + mq->parent.parent.flag = flag; + + /* init ipc object */ + rt_ipc_object_init(&(mq->parent)); + + /* set messasge pool */ + mq->msg_pool = msgpool; + + /* get correct message size */ + mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE); + mq->max_msgs = pool_size / (mq->msg_size + sizeof(struct rt_mq_message)); + + /* init message list */ + mq->msg_queue_head = RT_NULL; + mq->msg_queue_tail = RT_NULL; + + /* init message empty list */ + mq->msg_queue_free = RT_NULL; + for (temp = 0; temp < mq->max_msgs; temp ++) + { + head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool + + temp * (mq->msg_size + sizeof(struct rt_mq_message))); + head->next = mq->msg_queue_free; + mq->msg_queue_free = head; + } + + /* the initial entry is zero */ + mq->entry = 0; + + return RT_EOK; +} +RTM_EXPORT(rt_mq_init); + +/** + * This function will detach a message queue object from resource management + * + * @param mq the message queue object + * + * @return the operation status, RT_EOK on successful + */ +rt_err_t rt_mq_detach(rt_mq_t mq) +{ + /* parameter check */ + RT_ASSERT(mq != RT_NULL); + RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue); + RT_ASSERT(rt_object_is_systemobject(&mq->parent.parent)); + + /* resume all suspended thread */ + rt_ipc_list_resume_all(&mq->parent.suspend_thread); + + /* detach message queue object */ + rt_object_detach(&(mq->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_mq_detach); + +#ifdef RT_USING_HEAP +/** + * This function will create a message queue object from system resource + * + * @param name the name of message queue + * @param msg_size the size of message + * @param max_msgs the maximum number of message in queue + * @param flag the flag of message queue + * + * @return the created message queue, RT_NULL on error happen + */ +rt_mq_t rt_mq_create(const char *name, + rt_size_t msg_size, + rt_size_t max_msgs, + rt_uint8_t flag) +{ + struct rt_messagequeue *mq; + struct rt_mq_message *head; + register rt_base_t temp; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* allocate object */ + mq = (rt_mq_t)rt_object_allocate(RT_Object_Class_MessageQueue, name); + if (mq == RT_NULL) + return mq; + + /* set parent */ + mq->parent.parent.flag = flag; + + /* init ipc object */ + rt_ipc_object_init(&(mq->parent)); + + /* init message queue */ + + /* get correct message size */ + mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE); + mq->max_msgs = max_msgs; + + /* allocate message pool */ + mq->msg_pool = RT_KERNEL_MALLOC((mq->msg_size + sizeof(struct rt_mq_message)) * mq->max_msgs); + if (mq->msg_pool == RT_NULL) + { + rt_mq_delete(mq); + + return RT_NULL; + } + + /* init message list */ + mq->msg_queue_head = RT_NULL; + mq->msg_queue_tail = RT_NULL; + + /* init message empty list */ + mq->msg_queue_free = RT_NULL; + for (temp = 0; temp < mq->max_msgs; temp ++) + { + head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool + + temp * (mq->msg_size + sizeof(struct rt_mq_message))); + head->next = mq->msg_queue_free; + mq->msg_queue_free = head; + } + + /* the initial entry is zero */ + mq->entry = 0; + + return mq; +} +RTM_EXPORT(rt_mq_create); + +/** + * This function will delete a message queue object and release the memory + * + * @param mq the message queue object + * + * @return the error code + */ +rt_err_t rt_mq_delete(rt_mq_t mq) +{ + RT_DEBUG_NOT_IN_INTERRUPT; + + /* parameter check */ + RT_ASSERT(mq != RT_NULL); + RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue); + RT_ASSERT(rt_object_is_systemobject(&mq->parent.parent) == RT_FALSE); + + /* resume all suspended thread */ + rt_ipc_list_resume_all(&(mq->parent.suspend_thread)); + + /* free message queue pool */ + RT_KERNEL_FREE(mq->msg_pool); + + /* delete message queue object */ + rt_object_delete(&(mq->parent.parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_mq_delete); +#endif + +/** + * This function will send a message to message queue object, if there are + * threads suspended on message queue object, it will be waked up. + * + * @param mq the message queue object + * @param buffer the message + * @param size the size of buffer + * + * @return the error code + */ +rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size) +{ + register rt_ubase_t temp; + struct rt_mq_message *msg; + + /* parameter check */ + RT_ASSERT(mq != RT_NULL); + RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue); + RT_ASSERT(buffer != RT_NULL); + RT_ASSERT(size != 0); + + /* greater than one message size */ + if (size > mq->msg_size) + return -RT_ERROR; + + RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mq->parent.parent))); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* get a free list, there must be an empty item */ + msg = (struct rt_mq_message *)mq->msg_queue_free; + /* message queue is full */ + if (msg == RT_NULL) + { + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + return -RT_EFULL; + } + /* move free list pointer */ + mq->msg_queue_free = msg->next; + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* the msg is the new tailer of list, the next shall be NULL */ + msg->next = RT_NULL; + /* copy buffer */ + rt_memcpy(msg + 1, buffer, size); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + /* link msg to message queue */ + if (mq->msg_queue_tail != RT_NULL) + { + /* if the tail exists, */ + ((struct rt_mq_message *)mq->msg_queue_tail)->next = msg; + } + + /* set new tail */ + mq->msg_queue_tail = msg; + /* if the head is empty, set head */ + if (mq->msg_queue_head == RT_NULL) + mq->msg_queue_head = msg; + + /* increase message entry */ + mq->entry ++; + + /* resume suspended thread */ + if (!rt_list_isempty(&mq->parent.suspend_thread)) + { + rt_ipc_list_resume(&(mq->parent.suspend_thread)); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + rt_schedule(); + + return RT_EOK; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + return RT_EOK; +} +RTM_EXPORT(rt_mq_send); + +/** + * This function will send an urgent message to message queue object, which + * means the message will be inserted to the head of message queue. If there + * are threads suspended on message queue object, it will be waked up. + * + * @param mq the message queue object + * @param buffer the message + * @param size the size of buffer + * + * @return the error code + */ +rt_err_t rt_mq_urgent(rt_mq_t mq, void *buffer, rt_size_t size) +{ + register rt_ubase_t temp; + struct rt_mq_message *msg; + + /* parameter check */ + RT_ASSERT(mq != RT_NULL); + RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue); + RT_ASSERT(buffer != RT_NULL); + RT_ASSERT(size != 0); + + /* greater than one message size */ + if (size > mq->msg_size) + return -RT_ERROR; + + RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mq->parent.parent))); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* get a free list, there must be an empty item */ + msg = (struct rt_mq_message *)mq->msg_queue_free; + /* message queue is full */ + if (msg == RT_NULL) + { + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + return -RT_EFULL; + } + /* move free list pointer */ + mq->msg_queue_free = msg->next; + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* copy buffer */ + rt_memcpy(msg + 1, buffer, size); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* link msg to the beginning of message queue */ + msg->next = mq->msg_queue_head; + mq->msg_queue_head = msg; + + /* if there is no tail */ + if (mq->msg_queue_tail == RT_NULL) + mq->msg_queue_tail = msg; + + /* increase message entry */ + mq->entry ++; + + /* resume suspended thread */ + if (!rt_list_isempty(&mq->parent.suspend_thread)) + { + rt_ipc_list_resume(&(mq->parent.suspend_thread)); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + rt_schedule(); + + return RT_EOK; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + return RT_EOK; +} +RTM_EXPORT(rt_mq_urgent); + +/** + * This function will receive a message from message queue object, if there is + * no message in message queue object, the thread shall wait for a specified + * time. + * + * @param mq the message queue object + * @param buffer the received message will be saved in + * @param size the size of buffer + * @param timeout the waiting time + * + * @return the error code + */ +rt_err_t rt_mq_recv(rt_mq_t mq, + void *buffer, + rt_size_t size, + rt_int32_t timeout) +{ + struct rt_thread *thread; + register rt_ubase_t temp; + struct rt_mq_message *msg; + rt_uint32_t tick_delta; + + /* parameter check */ + RT_ASSERT(mq != RT_NULL); + RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue); + RT_ASSERT(buffer != RT_NULL); + RT_ASSERT(size != 0); + + /* initialize delta tick */ + tick_delta = 0; + /* get current thread */ + thread = rt_thread_self(); + RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mq->parent.parent))); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* for non-blocking call */ + if (mq->entry == 0 && timeout == 0) + { + rt_hw_interrupt_enable(temp); + + return -RT_ETIMEOUT; + } + + /* message queue is empty */ + while (mq->entry == 0) + { + RT_DEBUG_IN_THREAD_CONTEXT; + + /* reset error number in thread */ + thread->error = RT_EOK; + + /* no waiting, return timeout */ + if (timeout == 0) + { + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + thread->error = -RT_ETIMEOUT; + + return -RT_ETIMEOUT; + } + + /* suspend current thread */ + rt_ipc_list_suspend(&(mq->parent.suspend_thread), + thread, + mq->parent.parent.flag); + + /* has waiting time, start thread timer */ + if (timeout > 0) + { + /* get the start tick of timer */ + tick_delta = rt_tick_get(); + + RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n", + thread->name)); + + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(thread->thread_timer)); + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* re-schedule */ + rt_schedule(); + + /* recv message */ + if (thread->error != RT_EOK) + { + /* return error */ + return thread->error; + } + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* if it's not waiting forever and then re-calculate timeout tick */ + if (timeout > 0) + { + tick_delta = rt_tick_get() - tick_delta; + timeout -= tick_delta; + if (timeout < 0) + timeout = 0; + } + } + + /* get message from queue */ + msg = (struct rt_mq_message *)mq->msg_queue_head; + + /* move message queue head */ + mq->msg_queue_head = msg->next; + /* reach queue tail, set to NULL */ + if (mq->msg_queue_tail == msg) + mq->msg_queue_tail = RT_NULL; + + /* decrease message entry */ + mq->entry --; + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* copy message */ + rt_memcpy(buffer, msg + 1, size > mq->msg_size ? mq->msg_size : size); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + /* put message to free list */ + msg->next = (struct rt_mq_message *)mq->msg_queue_free; + mq->msg_queue_free = msg; + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mq->parent.parent))); + + return RT_EOK; +} +RTM_EXPORT(rt_mq_recv); + +/** + * This function can get or set some extra attributions of a message queue + * object. + * + * @param mq the message queue object + * @param cmd the execution command + * @param arg the execution argument + * + * @return the error code + */ +rt_err_t rt_mq_control(rt_mq_t mq, int cmd, void *arg) +{ + rt_ubase_t level; + struct rt_mq_message *msg; + + /* parameter check */ + RT_ASSERT(mq != RT_NULL); + RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue); + + if (cmd == RT_IPC_CMD_RESET) + { + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* resume all waiting thread */ + rt_ipc_list_resume_all(&mq->parent.suspend_thread); + + /* release all message in the queue */ + while (mq->msg_queue_head != RT_NULL) + { + /* get message from queue */ + msg = (struct rt_mq_message *)mq->msg_queue_head; + + /* move message queue head */ + mq->msg_queue_head = msg->next; + /* reach queue tail, set to NULL */ + if (mq->msg_queue_tail == msg) + mq->msg_queue_tail = RT_NULL; + + /* put message to free list */ + msg->next = (struct rt_mq_message *)mq->msg_queue_free; + mq->msg_queue_free = msg; + } + + /* clean entry */ + mq->entry = 0; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_schedule(); + + return RT_EOK; + } + + return -RT_ERROR; +} +RTM_EXPORT(rt_mq_control); +#endif /* end of RT_USING_MESSAGEQUEUE */ + +/**@}*/ diff --git a/rt-thread/src/irq.c b/rt-thread/src/irq.c new file mode 100644 index 0000000..72d220b --- /dev/null +++ b/rt-thread/src/irq.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-02-24 Bernard first version + * 2006-05-03 Bernard add IRQ_DEBUG + * 2016-08-09 ArdaFu add interrupt enter and leave hook. + */ + +#include +#include + +#ifdef RT_USING_HOOK + +static void (*rt_interrupt_enter_hook)(void); +static void (*rt_interrupt_leave_hook)(void); + +/** + * @ingroup Hook + * This function set a hook function when the system enter a interrupt + * + * @note the hook function must be simple and never be blocked or suspend. + */ +void rt_interrupt_enter_sethook(void (*hook)(void)) +{ + rt_interrupt_enter_hook = hook; +} +/** + * @ingroup Hook + * This function set a hook function when the system exit a interrupt. + * + * @note the hook function must be simple and never be blocked or suspend. + */ +void rt_interrupt_leave_sethook(void (*hook)(void)) +{ + rt_interrupt_leave_hook = hook; +} +#endif + +/* #define IRQ_DEBUG */ + +/** + * @addtogroup Kernel + */ + +/**@{*/ + +volatile rt_uint8_t rt_interrupt_nest; + +/** + * This function will be invoked by BSP, when enter interrupt service routine + * + * @note please don't invoke this routine in application + * + * @see rt_interrupt_leave + */ +void rt_interrupt_enter(void) +{ + rt_base_t level; + + RT_DEBUG_LOG(RT_DEBUG_IRQ, ("irq coming..., irq nest:%d\n", + rt_interrupt_nest)); + + level = rt_hw_interrupt_disable(); + rt_interrupt_nest ++; + RT_OBJECT_HOOK_CALL(rt_interrupt_enter_hook,()); + rt_hw_interrupt_enable(level); +} +RTM_EXPORT(rt_interrupt_enter); + +/** + * This function will be invoked by BSP, when leave interrupt service routine + * + * @note please don't invoke this routine in application + * + * @see rt_interrupt_enter + */ +void rt_interrupt_leave(void) +{ + rt_base_t level; + + RT_DEBUG_LOG(RT_DEBUG_IRQ, ("irq leave, irq nest:%d\n", + rt_interrupt_nest)); + + level = rt_hw_interrupt_disable(); + rt_interrupt_nest --; + RT_OBJECT_HOOK_CALL(rt_interrupt_leave_hook,()); + rt_hw_interrupt_enable(level); +} +RTM_EXPORT(rt_interrupt_leave); + +/** + * This function will return the nest of interrupt. + * + * User application can invoke this function to get whether current + * context is interrupt context. + * + * @return the number of nested interrupts. + */ +rt_uint8_t rt_interrupt_get_nest(void) +{ + return rt_interrupt_nest; +} +RTM_EXPORT(rt_interrupt_get_nest); + +RTM_EXPORT(rt_hw_interrupt_disable); +RTM_EXPORT(rt_hw_interrupt_enable); + +/**@}*/ + diff --git a/rt-thread/src/kservice.c b/rt-thread/src/kservice.c new file mode 100644 index 0000000..dbc4a2f --- /dev/null +++ b/rt-thread/src/kservice.c @@ -0,0 +1,1358 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-03-16 Bernard the first version + * 2006-05-25 Bernard rewrite vsprintf + * 2006-08-10 Bernard add rt_show_version + * 2010-03-17 Bernard remove rt_strlcpy function + * fix gcc compiling issue. + * 2010-04-15 Bernard remove weak definition on ICCM16C compiler + * 2012-07-18 Arda add the alignment display for signed integer + * 2012-11-23 Bernard fix IAR compiler error. + * 2012-12-22 Bernard fix rt_kprintf issue, which found by Grissiom. + * 2013-06-24 Bernard remove rt_kprintf if RT_USING_CONSOLE is not defined. + * 2013-09-24 aozima make sure the device is in STREAM mode when used by rt_kprintf. + * 2015-07-06 Bernard Add rt_assert_handler routine. + */ + +#include +#include + +#ifdef RT_USING_MODULE +#include +#endif + +/* use precision */ +#define RT_PRINTF_PRECISION + +/** + * @addtogroup KernelService + */ + +/**@{*/ + +/* global errno in RT-Thread */ +static volatile int __rt_errno; + +#if defined(RT_USING_DEVICE) && defined(RT_USING_CONSOLE) +static rt_device_t _console_device = RT_NULL; +#endif + +/* + * This function will get errno + * + * @return errno + */ +rt_err_t rt_get_errno(void) +{ + rt_thread_t tid; + + if (rt_interrupt_get_nest() != 0) + { + /* it's in interrupt context */ + return __rt_errno; + } + + tid = rt_thread_self(); + if (tid == RT_NULL) + return __rt_errno; + + return tid->error; +} +RTM_EXPORT(rt_get_errno); + +/* + * This function will set errno + * + * @param error the errno shall be set + */ +void rt_set_errno(rt_err_t error) +{ + rt_thread_t tid; + + if (rt_interrupt_get_nest() != 0) + { + /* it's in interrupt context */ + __rt_errno = error; + + return; + } + + tid = rt_thread_self(); + if (tid == RT_NULL) + { + __rt_errno = error; + + return; + } + + tid->error = error; +} +RTM_EXPORT(rt_set_errno); + +/** + * This function returns errno. + * + * @return the errno in the system + */ +int *_rt_errno(void) +{ + rt_thread_t tid; + + if (rt_interrupt_get_nest() != 0) + return (int *)&__rt_errno; + + tid = rt_thread_self(); + if (tid != RT_NULL) + return (int *) & (tid->error); + + return (int *)&__rt_errno; +} +RTM_EXPORT(_rt_errno); + +/** + * This function will set the content of memory to specified value + * + * @param s the address of source memory + * @param c the value shall be set in content + * @param count the copied length + * + * @return the address of source memory + */ +void *rt_memset(void *s, int c, rt_ubase_t count) +{ +#ifdef RT_USING_TINY_SIZE + char *xs = (char *)s; + + while (count--) + *xs++ = c; + + return s; +#else +#define LBLOCKSIZE (sizeof(rt_int32_t)) +#define UNALIGNED(X) ((rt_int32_t)X & (LBLOCKSIZE - 1)) +#define TOO_SMALL(LEN) ((LEN) < LBLOCKSIZE) + + int i; + char *m = (char *)s; + rt_uint32_t buffer; + rt_uint32_t *aligned_addr; + rt_uint32_t d = c & 0xff; + + if (!TOO_SMALL(count) && !UNALIGNED(s)) + { + /* If we get this far, we know that n is large and m is word-aligned. */ + aligned_addr = (rt_uint32_t *)s; + + /* Store D into each char sized location in BUFFER so that + * we can set large blocks quickly. + */ + if (LBLOCKSIZE == 4) + { + buffer = (d << 8) | d; + buffer |= (buffer << 16); + } + else + { + buffer = 0; + for (i = 0; i < LBLOCKSIZE; i ++) + buffer = (buffer << 8) | d; + } + + while (count >= LBLOCKSIZE * 4) + { + *aligned_addr++ = buffer; + *aligned_addr++ = buffer; + *aligned_addr++ = buffer; + *aligned_addr++ = buffer; + count -= 4 * LBLOCKSIZE; + } + + while (count >= LBLOCKSIZE) + { + *aligned_addr++ = buffer; + count -= LBLOCKSIZE; + } + + /* Pick up the remainder with a bytewise loop. */ + m = (char *)aligned_addr; + } + + while (count--) + { + *m++ = (char)d; + } + + return s; + +#undef LBLOCKSIZE +#undef UNALIGNED +#undef TOO_SMALL +#endif +} +RTM_EXPORT(rt_memset); + +/** + * This function will copy memory content from source address to destination + * address. + * + * @param dst the address of destination memory + * @param src the address of source memory + * @param count the copied length + * + * @return the address of destination memory + */ +void *rt_memcpy(void *dst, const void *src, rt_ubase_t count) +{ +#ifdef RT_USING_TINY_SIZE + char *tmp = (char *)dst, *s = (char *)src; + rt_ubase_t len; + + if (tmp <= s || tmp > (s + count)) + { + while (count--) + *tmp ++ = *s ++; + } + else + { + for (len = count; len > 0; len --) + tmp[len - 1] = s[len - 1]; + } + + return dst; +#else + +#define UNALIGNED(X, Y) \ + (((rt_int32_t)X & (sizeof(rt_int32_t) - 1)) | \ + ((rt_int32_t)Y & (sizeof(rt_int32_t) - 1))) +#define BIGBLOCKSIZE (sizeof(rt_int32_t) << 2) +#define LITTLEBLOCKSIZE (sizeof(rt_int32_t)) +#define TOO_SMALL(LEN) ((LEN) < BIGBLOCKSIZE) + + char *dst_ptr = (char *)dst; + char *src_ptr = (char *)src; + rt_int32_t *aligned_dst; + rt_int32_t *aligned_src; + int len = count; + + /* If the size is small, or either SRC or DST is unaligned, + then punt into the byte copy loop. This should be rare. */ + if (!TOO_SMALL(len) && !UNALIGNED(src_ptr, dst_ptr)) + { + aligned_dst = (rt_int32_t *)dst_ptr; + aligned_src = (rt_int32_t *)src_ptr; + + /* Copy 4X long words at a time if possible. */ + while (len >= BIGBLOCKSIZE) + { + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + *aligned_dst++ = *aligned_src++; + len -= BIGBLOCKSIZE; + } + + /* Copy one long word at a time if possible. */ + while (len >= LITTLEBLOCKSIZE) + { + *aligned_dst++ = *aligned_src++; + len -= LITTLEBLOCKSIZE; + } + + /* Pick up any residual with a byte copier. */ + dst_ptr = (char *)aligned_dst; + src_ptr = (char *)aligned_src; + } + + while (len--) + *dst_ptr++ = *src_ptr++; + + return dst; +#undef UNALIGNED +#undef BIGBLOCKSIZE +#undef LITTLEBLOCKSIZE +#undef TOO_SMALL +#endif +} +RTM_EXPORT(rt_memcpy); + +/** + * This function will move memory content from source address to destination + * address. + * + * @param dest the address of destination memory + * @param src the address of source memory + * @param n the copied length + * + * @return the address of destination memory + */ +void *rt_memmove(void *dest, const void *src, rt_ubase_t n) +{ + char *tmp = (char *)dest, *s = (char *)src; + + if (s < tmp && tmp < s + n) + { + tmp += n; + s += n; + + while (n--) + *(--tmp) = *(--s); + } + else + { + while (n--) + *tmp++ = *s++; + } + + return dest; +} +RTM_EXPORT(rt_memmove); + +/** + * This function will compare two areas of memory + * + * @param cs one area of memory + * @param ct znother area of memory + * @param count the size of the area + * + * @return the result + */ +rt_int32_t rt_memcmp(const void *cs, const void *ct, rt_ubase_t count) +{ + const unsigned char *su1, *su2; + int res = 0; + + for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if ((res = *su1 - *su2) != 0) + break; + + return res; +} +RTM_EXPORT(rt_memcmp); + +/** + * This function will return the first occurrence of a string. + * + * @param s1 the source string + * @param s2 the find string + * + * @return the first occurrence of a s2 in s1, or RT_NULL if no found. + */ +char *rt_strstr(const char *s1, const char *s2) +{ + int l1, l2; + + l2 = rt_strlen(s2); + if (!l2) + return (char *)s1; + l1 = rt_strlen(s1); + while (l1 >= l2) + { + l1 --; + if (!rt_memcmp(s1, s2, l2)) + return (char *)s1; + s1 ++; + } + + return RT_NULL; +} +RTM_EXPORT(rt_strstr); + +/** + * This function will compare two strings while ignoring differences in case + * + * @param a the string to be compared + * @param b the string to be compared + * + * @return the result + */ +rt_uint32_t rt_strcasecmp(const char *a, const char *b) +{ + int ca, cb; + + do + { + ca = *a++ & 0xff; + cb = *b++ & 0xff; + if (ca >= 'A' && ca <= 'Z') + ca += 'a' - 'A'; + if (cb >= 'A' && cb <= 'Z') + cb += 'a' - 'A'; + } + while (ca == cb && ca != '\0'); + + return ca - cb; +} +RTM_EXPORT(rt_strcasecmp); + +/** + * This function will copy string no more than n bytes. + * + * @param dst the string to copy + * @param src the string to be copied + * @param n the maximum copied length + * + * @return the result + */ +char *rt_strncpy(char *dst, const char *src, rt_ubase_t n) +{ + if (n != 0) + { + char *d = dst; + const char *s = src; + + do + { + if ((*d++ = *s++) == 0) + { + /* NUL pad the remaining n-1 bytes */ + while (--n != 0) + *d++ = 0; + break; + } + } while (--n != 0); + } + + return (dst); +} +RTM_EXPORT(rt_strncpy); + +/** + * This function will compare two strings with specified maximum length + * + * @param cs the string to be compared + * @param ct the string to be compared + * @param count the maximum compare length + * + * @return the result + */ +rt_int32_t rt_strncmp(const char *cs, const char *ct, rt_ubase_t count) +{ + register signed char __res = 0; + + while (count) + { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + count --; + } + + return __res; +} +RTM_EXPORT(rt_strncmp); + +/** + * This function will compare two strings without specified length + * + * @param cs the string to be compared + * @param ct the string to be compared + * + * @return the result + */ +rt_int32_t rt_strcmp(const char *cs, const char *ct) +{ + while (*cs && *cs == *ct) + cs++, ct++; + + return (*cs - *ct); +} +RTM_EXPORT(rt_strcmp); +/** + * The strnlen() function returns the number of characters in the + * string pointed to by s, excluding the terminating null byte ('\0'), + * but at most maxlen. In doing this, strnlen() looks only at the + * first maxlen characters in the string pointed to by s and never + * beyond s+maxlen. + * + * @param s the string + * @param maxlen the max size + * @return the length of string + */ +rt_size_t rt_strnlen(const char *s, rt_ubase_t maxlen) +{ + const char *sc; + + for (sc = s; *sc != '\0' && sc - s < maxlen; ++sc) /* nothing */ + ; + + return sc - s; +} +/** + * This function will return the length of a string, which terminate will + * null character. + * + * @param s the string + * + * @return the length of string + */ +rt_size_t rt_strlen(const char *s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) /* nothing */ + ; + + return sc - s; +} +RTM_EXPORT(rt_strlen); + +#ifdef RT_USING_HEAP +/** + * This function will duplicate a string. + * + * @param s the string to be duplicated + * + * @return the duplicated string pointer + */ +char *rt_strdup(const char *s) +{ + rt_size_t len = rt_strlen(s) + 1; + char *tmp = (char *)rt_malloc(len); + + if (!tmp) + return RT_NULL; + + rt_memcpy(tmp, s, len); + + return tmp; +} +RTM_EXPORT(rt_strdup); +#if defined(__CC_ARM) || defined(__CLANG_ARM) +char *strdup(const char *s) __attribute__((alias("rt_strdup"))); +#endif +#endif + +/** + * This function will show the version of rt-thread rtos + */ +void rt_show_version(void) +{ + rt_kprintf("\n \\ | /\n"); + rt_kprintf("- RT - Thread Operating System\n"); + rt_kprintf(" / | \\ %d.%d.%d build %s\n", + RT_VERSION, RT_SUBVERSION, RT_REVISION, __DATE__); + rt_kprintf(" 2006 - 2018 Copyright by rt-thread team\n"); +} +RTM_EXPORT(rt_show_version); + +/* private function */ +#define isdigit(c) ((unsigned)((c) - '0') < 10) + +rt_inline rt_int32_t divide(rt_int32_t *n, rt_int32_t base) +{ + rt_int32_t res; + + /* optimized for processor which does not support divide instructions. */ + if (base == 10) + { + res = ((rt_uint32_t) * n) % 10U; + *n = ((rt_uint32_t) * n) / 10U; + } + else + { + res = ((rt_uint32_t) * n) % 16U; + *n = ((rt_uint32_t) * n) / 16U; + } + + return res; +} + +rt_inline int skip_atoi(const char **s) +{ + register int i = 0; + while (isdigit(**s)) + i = i * 10 + *((*s)++) - '0'; + + return i; +} + +#define ZEROPAD (1 << 0) /* pad with zero */ +#define SIGN (1 << 1) /* unsigned/signed long */ +#define PLUS (1 << 2) /* show plus */ +#define SPACE (1 << 3) /* space if plus */ +#define LEFT (1 << 4) /* left justified */ +#define SPECIAL (1 << 5) /* 0x */ +#define LARGE (1 << 6) /* use 'ABCDEF' instead of 'abcdef' */ + +#ifdef RT_PRINTF_PRECISION +static char *print_number(char *buf, + char *end, + long num, + int base, + int s, + int precision, + int type) +#else +static char *print_number(char *buf, + char *end, + long num, + int base, + int s, + int type) +#endif +{ + char c, sign; +#ifdef RT_PRINTF_LONGLONG + char tmp[32]; +#else + char tmp[16]; +#endif + const char *digits; + static const char small_digits[] = "0123456789abcdef"; + static const char large_digits[] = "0123456789ABCDEF"; + register int i; + register int size; + + size = s; + + digits = (type & LARGE) ? large_digits : small_digits; + if (type & LEFT) + type &= ~ZEROPAD; + + c = (type & ZEROPAD) ? '0' : ' '; + + /* get sign */ + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + } + else if (type & PLUS) + sign = '+'; + else if (type & SPACE) + sign = ' '; + } + +#ifdef RT_PRINTF_SPECIAL + if (type & SPECIAL) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } +#endif + + i = 0; + if (num == 0) + tmp[i++] = '0'; + else + { + while (num != 0) + tmp[i++] = digits[divide(&num, base)]; + } + +#ifdef RT_PRINTF_PRECISION + if (i > precision) + precision = i; + size -= precision; +#else + size -= i; +#endif + + if (!(type & (ZEROPAD | LEFT))) + { + if ((sign) && (size > 0)) + size--; + + while (size-- > 0) + { + if (buf <= end) + *buf = ' '; + ++ buf; + } + } + + if (sign) + { + if (buf <= end) + { + *buf = sign; + -- size; + } + ++ buf; + } + +#ifdef RT_PRINTF_SPECIAL + if (type & SPECIAL) + { + if (base == 8) + { + if (buf <= end) + *buf = '0'; + ++ buf; + } + else if (base == 16) + { + if (buf <= end) + *buf = '0'; + ++ buf; + if (buf <= end) + { + *buf = type & LARGE ? 'X' : 'x'; + } + ++ buf; + } + } +#endif + + /* no align to the left */ + if (!(type & LEFT)) + { + while (size-- > 0) + { + if (buf <= end) + *buf = c; + ++ buf; + } + } + +#ifdef RT_PRINTF_PRECISION + while (i < precision--) + { + if (buf <= end) + *buf = '0'; + ++ buf; + } +#endif + + /* put number in the temporary buffer */ + while (i-- > 0) + { + if (buf <= end) + *buf = tmp[i]; + ++ buf; + } + + while (size-- > 0) + { + if (buf <= end) + *buf = ' '; + ++ buf; + } + + return buf; +} + +rt_int32_t rt_vsnprintf(char *buf, + rt_size_t size, + const char *fmt, + va_list args) +{ +#ifdef RT_PRINTF_LONGLONG + unsigned long long num; +#else + rt_uint32_t num; +#endif + int i, len; + char *str, *end, c; + const char *s; + + rt_uint8_t base; /* the base of number */ + rt_uint8_t flags; /* flags to print number */ + rt_uint8_t qualifier; /* 'h', 'l', or 'L' for integer fields */ + rt_int32_t field_width; /* width of output field */ + +#ifdef RT_PRINTF_PRECISION + int precision; /* min. # of digits for integers and max for a string */ +#endif + + str = buf; + end = buf + size - 1; + + /* Make sure end is always >= buf */ + if (end < buf) + { + end = ((char *) - 1); + size = end - buf; + } + + for (; *fmt ; ++fmt) + { + if (*fmt != '%') + { + if (str <= end) + *str = *fmt; + ++ str; + continue; + } + + /* process flags */ + flags = 0; + + while (1) + { + /* skips the first '%' also */ + ++ fmt; + if (*fmt == '-') flags |= LEFT; + else if (*fmt == '+') flags |= PLUS; + else if (*fmt == ' ') flags |= SPACE; + else if (*fmt == '#') flags |= SPECIAL; + else if (*fmt == '0') flags |= ZEROPAD; + else break; + } + + /* get field width */ + field_width = -1; + if (isdigit(*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; + } + } + +#ifdef RT_PRINTF_PRECISION + /* get the precision */ + precision = -1; + if (*fmt == '.') + { + ++ fmt; + if (isdigit(*fmt)) precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++ fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) precision = 0; + } +#endif + /* get the conversion qualifier */ + qualifier = 0; +#ifdef RT_PRINTF_LONGLONG + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') +#else + if (*fmt == 'h' || *fmt == 'l') +#endif + { + qualifier = *fmt; + ++ fmt; +#ifdef RT_PRINTF_LONGLONG + if (qualifier == 'l' && *fmt == 'l') + { + qualifier = 'L'; + ++ fmt; + } +#endif + } + + /* the default base */ + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) + { + while (--field_width > 0) + { + if (str <= end) *str = ' '; + ++ str; + } + } + + /* get character */ + c = (rt_uint8_t)va_arg(args, int); + if (str <= end) *str = c; + ++ str; + + /* put width */ + while (--field_width > 0) + { + if (str <= end) *str = ' '; + ++ str; + } + continue; + + case 's': + s = va_arg(args, char *); + if (!s) s = "(NULL)"; + + len = rt_strlen(s); +#ifdef RT_PRINTF_PRECISION + if (precision > 0 && len > precision) len = precision; +#endif + + if (!(flags & LEFT)) + { + while (len < field_width--) + { + if (str <= end) *str = ' '; + ++ str; + } + } + + for (i = 0; i < len; ++i) + { + if (str <= end) *str = *s; + ++ str; + ++ s; + } + + while (len < field_width--) + { + if (str <= end) *str = ' '; + ++ str; + } + continue; + + case 'p': + if (field_width == -1) + { + field_width = sizeof(void *) << 1; + flags |= ZEROPAD; + } +#ifdef RT_PRINTF_PRECISION + str = print_number(str, end, + (long)va_arg(args, void *), + 16, field_width, precision, flags); +#else + str = print_number(str, end, + (long)va_arg(args, void *), + 16, field_width, flags); +#endif + continue; + + case '%': + if (str <= end) *str = '%'; + ++ str; + 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 (str <= end) *str = '%'; + ++ str; + + if (*fmt) + { + if (str <= end) *str = *fmt; + ++ str; + } + else + { + -- fmt; + } + continue; + } + +#ifdef RT_PRINTF_LONGLONG + if (qualifier == 'L') num = va_arg(args, long long); + else if (qualifier == 'l') +#else + if (qualifier == 'l') +#endif + { + num = va_arg(args, rt_uint32_t); + if (flags & SIGN) num = (rt_int32_t)num; + } + else if (qualifier == 'h') + { + num = (rt_uint16_t)va_arg(args, rt_int32_t); + if (flags & SIGN) num = (rt_int16_t)num; + } + else + { + num = va_arg(args, rt_uint32_t); + if (flags & SIGN) num = (rt_int32_t)num; + } +#ifdef RT_PRINTF_PRECISION + str = print_number(str, end, num, base, field_width, precision, flags); +#else + str = print_number(str, end, num, base, field_width, flags); +#endif + } + + if (str <= end) *str = '\0'; + else *end = '\0'; + + /* the trailing null byte doesn't count towards the total + * ++str; + */ + return str - buf; +} +RTM_EXPORT(rt_vsnprintf); + +/** + * This function will fill a formatted string to buffer + * + * @param buf the buffer to save formatted string + * @param size the size of buffer + * @param fmt the format + */ +rt_int32_t rt_snprintf(char *buf, rt_size_t size, const char *fmt, ...) +{ + rt_int32_t n; + va_list args; + + va_start(args, fmt); + n = rt_vsnprintf(buf, size, fmt, args); + va_end(args); + + return n; +} +RTM_EXPORT(rt_snprintf); + +/** + * This function will fill a formatted string to buffer + * + * @param buf the buffer to save formatted string + * @param arg_ptr the arg_ptr + * @param format the format + */ +rt_int32_t rt_vsprintf(char *buf, const char *format, va_list arg_ptr) +{ + return rt_vsnprintf(buf, (rt_size_t) - 1, format, arg_ptr); +} +RTM_EXPORT(rt_vsprintf); + +/** + * This function will fill a formatted string to buffer + * + * @param buf the buffer to save formatted string + * @param format the format + */ +rt_int32_t rt_sprintf(char *buf, const char *format, ...) +{ + rt_int32_t n; + va_list arg_ptr; + + va_start(arg_ptr, format); + n = rt_vsprintf(buf, format, arg_ptr); + va_end(arg_ptr); + + return n; +} +RTM_EXPORT(rt_sprintf); + +#ifdef RT_USING_CONSOLE + +#ifdef RT_USING_DEVICE +/** + * This function returns the device using in console. + * + * @return the device using in console or RT_NULL + */ +rt_device_t rt_console_get_device(void) +{ + return _console_device; +} +RTM_EXPORT(rt_console_get_device); + +/** + * This function will set a device as console device. + * After set a device to console, all output of rt_kprintf will be + * redirected to this new device. + * + * @param name the name of new console device + * + * @return the old console device handler + */ +rt_device_t rt_console_set_device(const char *name) +{ + rt_device_t new, old; + + /* save old device */ + old = _console_device; + + /* find new console device */ + new = rt_device_find(name); + if (new != RT_NULL) + { + if (_console_device != RT_NULL) + { + /* close old console device */ + rt_device_close(_console_device); + } + + /* set new console device */ + rt_device_open(new, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM); + _console_device = new; + } + + return old; +} +RTM_EXPORT(rt_console_set_device); +#endif + +RT_WEAK void rt_hw_console_output(const char *str) +{ + /* empty console output */ +} +RTM_EXPORT(rt_hw_console_output); + +/** + * This function will put string to the console. + * + * @param str the string output to the console. + */ +void rt_kputs(const char *str) +{ + if (!str) return; + +#ifdef RT_USING_DEVICE + if (_console_device == RT_NULL) + { + rt_hw_console_output(str); + } + else + { + rt_uint16_t old_flag = _console_device->open_flag; + + _console_device->open_flag |= RT_DEVICE_FLAG_STREAM; + rt_device_write(_console_device, 0, str, rt_strlen(str)); + _console_device->open_flag = old_flag; + } +#else + rt_hw_console_output(str); +#endif +} + +/** + * This function will print a formatted string on system console + * + * @param fmt the format + */ +void rt_kprintf(const char *fmt, ...) +{ + va_list args; + rt_size_t length; + static char rt_log_buf[RT_CONSOLEBUF_SIZE]; + + va_start(args, fmt); + /* the return value of vsnprintf is the number of bytes that would be + * written to buffer had if the size of the buffer been sufficiently + * large excluding the terminating null byte. If the output string + * would be larger than the rt_log_buf, we have to adjust the output + * length. */ + length = rt_vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args); + if (length > RT_CONSOLEBUF_SIZE - 1) + length = RT_CONSOLEBUF_SIZE - 1; +#ifdef RT_USING_DEVICE + if (_console_device == RT_NULL) + { + rt_hw_console_output(rt_log_buf); + } + else + { + rt_uint16_t old_flag = _console_device->open_flag; + + _console_device->open_flag |= RT_DEVICE_FLAG_STREAM; + rt_device_write(_console_device, 0, rt_log_buf, length); + _console_device->open_flag = old_flag; + } +#else + rt_hw_console_output(rt_log_buf); +#endif + va_end(args); +} +RTM_EXPORT(rt_kprintf); +#endif + +#ifdef RT_USING_HEAP +/** + * This function allocates a memory block, which address is aligned to the + * specified alignment size. + * + * @param size the allocated memory block size + * @param align the alignment size + * + * @return the allocated memory block on successful, otherwise returns RT_NULL + */ +void *rt_malloc_align(rt_size_t size, rt_size_t align) +{ + void *align_ptr; + void *ptr; + rt_size_t align_size; + + /* align the alignment size to 4 byte */ + align = ((align + 0x03) & ~0x03); + + /* get total aligned size */ + align_size = ((size + 0x03) & ~0x03) + align; + /* allocate memory block from heap */ + ptr = rt_malloc(align_size); + if (ptr != RT_NULL) + { + /* the allocated memory block is aligned */ + if (((rt_uint32_t)ptr & (align - 1)) == 0) + { + align_ptr = (void *)((rt_uint32_t)ptr + align); + } + else + { + align_ptr = (void *)(((rt_uint32_t)ptr + (align - 1)) & ~(align - 1)); + } + + /* set the pointer before alignment pointer to the real pointer */ + *((rt_uint32_t *)((rt_uint32_t)align_ptr - sizeof(void *))) = (rt_uint32_t)ptr; + + ptr = align_ptr; + } + + return ptr; +} +RTM_EXPORT(rt_malloc_align); + +/** + * This function release the memory block, which is allocated by + * rt_malloc_align function and address is aligned. + * + * @param ptr the memory block pointer + */ +void rt_free_align(void *ptr) +{ + void *real_ptr; + + real_ptr = (void *) * (rt_uint32_t *)((rt_uint32_t)ptr - sizeof(void *)); + rt_free(real_ptr); +} +RTM_EXPORT(rt_free_align); +#endif + +#ifndef RT_USING_CPU_FFS +const rt_uint8_t __lowest_bit_bitmap[] = +{ + /* 00 */ 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* 10 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* 20 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* 30 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* 40 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* 50 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* 60 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* 70 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* 80 */ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* 90 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* A0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* B0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* C0 */ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* D0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* E0 */ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + /* F0 */ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +/** + * This function finds the first bit set (beginning with the least significant bit) + * in value and return the index of that bit. + * + * Bits are numbered starting at 1 (the least significant bit). A return value of + * zero from any of these functions means that the argument was zero. + * + * @return return the index of the first bit set. If value is 0, then this function + * shall return 0. + */ +int __rt_ffs(int value) +{ + if (value == 0) return 0; + + if (value & 0xff) + return __lowest_bit_bitmap[value & 0xff] + 1; + + if (value & 0xff00) + return __lowest_bit_bitmap[(value & 0xff00) >> 8] + 9; + + if (value & 0xff0000) + return __lowest_bit_bitmap[(value & 0xff0000) >> 16] + 17; + + return __lowest_bit_bitmap[(value & 0xff000000) >> 24] + 25; +} +#endif + +#ifdef RT_DEBUG +/* RT_ASSERT(EX)'s hook */ +void (*rt_assert_hook)(const char *ex, const char *func, rt_size_t line); +/** + * This function will set a hook function to RT_ASSERT(EX). It will run when the expression is false. + * + * @param hook the hook function + */ +void rt_assert_set_hook(void (*hook)(const char *ex, const char *func, rt_size_t line)) +{ + rt_assert_hook = hook; +} + +/** + * The RT_ASSERT function. + * + * @param ex the assertion condition string + * @param func the function name when assertion. + * @param line the file line number when assertion. + */ +void rt_assert_handler(const char *ex_string, const char *func, rt_size_t line) +{ + volatile char dummy = 0; + + if (rt_assert_hook == RT_NULL) + { +#ifdef RT_USING_MODULE + if (dlmodule_self()) + { + /* close assertion module */ + dlmodule_exit(-1); + } + else +#endif + { + rt_kprintf("(%s) assertion failed at function:%s, line number:%d \n", ex_string, func, line); + while (dummy == 0); + } + } + else + { + rt_assert_hook(ex_string, func, line); + } +} +RTM_EXPORT(rt_assert_handler); +#endif /* RT_DEBUG */ + +#if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) && defined (__GNUC__) +#include +void *memcpy(void *dest, const void *src, size_t n) __attribute__((weak, alias("rt_memcpy"))); +void *memset(void *s, int c, size_t n) __attribute__((weak, alias("rt_memset"))); +void *memmove(void *dest, const void *src, size_t n) __attribute__((weak, alias("rt_memmove"))); +int memcmp(const void *s1, const void *s2, size_t n) __attribute__((weak, alias("rt_memcmp"))); + +size_t strlen(const char *s) __attribute__((weak, alias("rt_strlen"))); +char *strstr(const char *s1, const char *s2) __attribute__((weak, alias("rt_strstr"))); +int strcasecmp(const char *a, const char *b) __attribute__((weak, alias("rt_strcasecmp"))); +char *strncpy(char *dest, const char *src, size_t n) __attribute__((weak, alias("rt_strncpy"))); +int strncmp(const char *cs, const char *ct, size_t count) __attribute__((weak, alias("rt_strncmp"))); +#ifdef RT_USING_HEAP +char *strdup(const char *s) __attribute__((weak, alias("rt_strdup"))); +#endif + +int sprintf(char *buf, const char *format, ...) __attribute__((weak, alias("rt_sprintf"))); +int snprintf(char *buf, rt_size_t size, const char *fmt, ...) __attribute__((weak, alias("rt_snprintf"))); +int vsprintf(char *buf, const char *format, va_list arg_ptr) __attribute__((weak, alias("rt_vsprintf"))); + +#endif + +/**@}*/ diff --git a/rt-thread/src/mem.c b/rt-thread/src/mem.c new file mode 100644 index 0000000..cb96ab9 --- /dev/null +++ b/rt-thread/src/mem.c @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2008-7-12 Bernard the first version + * 2010-06-09 Bernard fix the end stub of heap + * fix memory check in rt_realloc function + * 2010-07-13 Bernard fix RT_ALIGN issue found by kuronca + * 2010-10-14 Bernard fix rt_realloc issue when realloc a NULL pointer. + * 2017-07-14 armink fix rt_realloc issue when new size is 0 + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * Simon Goldschmidt + * + */ + +#include +#include + +#ifndef RT_USING_MEMHEAP_AS_HEAP + +/* #define RT_MEM_DEBUG */ +#define RT_MEM_STATS + +#if defined (RT_USING_HEAP) && defined (RT_USING_SMALL_MEM) +#ifdef RT_USING_HOOK +static void (*rt_malloc_hook)(void *ptr, rt_size_t size); +static void (*rt_free_hook)(void *ptr); + +/** + * @addtogroup Hook + */ + +/**@{*/ + +/** + * This function will set a hook function, which will be invoked when a memory + * block is allocated from heap memory. + * + * @param hook the hook function + */ +void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size)) +{ + rt_malloc_hook = hook; +} + +/** + * This function will set a hook function, which will be invoked when a memory + * block is released to heap memory. + * + * @param hook the hook function + */ +void rt_free_sethook(void (*hook)(void *ptr)) +{ + rt_free_hook = hook; +} + +/**@}*/ + +#endif + +#define HEAP_MAGIC 0x1ea0 +struct heap_mem +{ + /* magic and used flag */ + rt_uint16_t magic; + rt_uint16_t used; + + rt_size_t next, prev; + +#ifdef RT_USING_MEMTRACE + rt_uint8_t thread[4]; /* thread name */ +#endif +}; + +/** pointer to the heap: for alignment, heap_ptr is now a pointer instead of an array */ +static rt_uint8_t *heap_ptr; + +/** the last entry, always unused! */ +static struct heap_mem *heap_end; + +#define MIN_SIZE 12 +#define MIN_SIZE_ALIGNED RT_ALIGN(MIN_SIZE, RT_ALIGN_SIZE) +#define SIZEOF_STRUCT_MEM RT_ALIGN(sizeof(struct heap_mem), RT_ALIGN_SIZE) + +static struct heap_mem *lfree; /* pointer to the lowest free block */ + +static struct rt_semaphore heap_sem; +static rt_size_t mem_size_aligned; + +#ifdef RT_MEM_STATS +static rt_size_t used_mem, max_mem; +#endif +#ifdef RT_USING_MEMTRACE +rt_inline void rt_mem_setname(struct heap_mem *mem, const char *name) +{ + int index; + for (index = 0; index < sizeof(mem->thread); index ++) + { + if (name[index] == '\0') break; + mem->thread[index] = name[index]; + } + + for (; index < sizeof(mem->thread); index ++) + { + mem->thread[index] = ' '; + } +} +#endif + +static void plug_holes(struct heap_mem *mem) +{ + struct heap_mem *nmem; + struct heap_mem *pmem; + + RT_ASSERT((rt_uint8_t *)mem >= heap_ptr); + RT_ASSERT((rt_uint8_t *)mem < (rt_uint8_t *)heap_end); + RT_ASSERT(mem->used == 0); + + /* plug hole forward */ + nmem = (struct heap_mem *)&heap_ptr[mem->next]; + if (mem != nmem && + nmem->used == 0 && + (rt_uint8_t *)nmem != (rt_uint8_t *)heap_end) + { + /* if mem->next is unused and not end of heap_ptr, + * combine mem and mem->next + */ + if (lfree == nmem) + { + lfree = mem; + } + mem->next = nmem->next; + ((struct heap_mem *)&heap_ptr[nmem->next])->prev = (rt_uint8_t *)mem - heap_ptr; + } + + /* plug hole backward */ + pmem = (struct heap_mem *)&heap_ptr[mem->prev]; + if (pmem != mem && pmem->used == 0) + { + /* if mem->prev is unused, combine mem and mem->prev */ + if (lfree == mem) + { + lfree = pmem; + } + pmem->next = mem->next; + ((struct heap_mem *)&heap_ptr[mem->next])->prev = (rt_uint8_t *)pmem - heap_ptr; + } +} + +/** + * @ingroup SystemInit + * + * This function will initialize system heap memory. + * + * @param begin_addr the beginning address of system heap memory. + * @param end_addr the end address of system heap memory. + */ +void rt_system_heap_init(void *begin_addr, void *end_addr) +{ + struct heap_mem *mem; + rt_uint32_t begin_align = RT_ALIGN((rt_uint32_t)begin_addr, RT_ALIGN_SIZE); + rt_uint32_t end_align = RT_ALIGN_DOWN((rt_uint32_t)end_addr, RT_ALIGN_SIZE); + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* alignment addr */ + if ((end_align > (2 * SIZEOF_STRUCT_MEM)) && + ((end_align - 2 * SIZEOF_STRUCT_MEM) >= begin_align)) + { + /* calculate the aligned memory size */ + mem_size_aligned = end_align - begin_align - 2 * SIZEOF_STRUCT_MEM; + } + else + { + rt_kprintf("mem init, error begin address 0x%x, and end address 0x%x\n", + (rt_uint32_t)begin_addr, (rt_uint32_t)end_addr); + + return; + } + + /* point to begin address of heap */ + heap_ptr = (rt_uint8_t *)begin_align; + + RT_DEBUG_LOG(RT_DEBUG_MEM, ("mem init, heap begin address 0x%x, size %d\n", + (rt_uint32_t)heap_ptr, mem_size_aligned)); + + /* initialize the start of the heap */ + mem = (struct heap_mem *)heap_ptr; + mem->magic = HEAP_MAGIC; + mem->next = mem_size_aligned + SIZEOF_STRUCT_MEM; + mem->prev = 0; + mem->used = 0; +#ifdef RT_USING_MEMTRACE + rt_mem_setname(mem, "INIT"); +#endif + + /* initialize the end of the heap */ + heap_end = (struct heap_mem *)&heap_ptr[mem->next]; + heap_end->magic = HEAP_MAGIC; + heap_end->used = 1; + heap_end->next = mem_size_aligned + SIZEOF_STRUCT_MEM; + heap_end->prev = mem_size_aligned + SIZEOF_STRUCT_MEM; +#ifdef RT_USING_MEMTRACE + rt_mem_setname(heap_end, "INIT"); +#endif + + rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_FIFO); + + /* initialize the lowest-free pointer to the start of the heap */ + lfree = (struct heap_mem *)heap_ptr; +} + +/** + * @addtogroup MM + */ + +/**@{*/ + +/** + * Allocate a block of memory with a minimum of 'size' bytes. + * + * @param size is the minimum size of the requested block in bytes. + * + * @return pointer to allocated memory or NULL if no free memory was found. + */ +void *rt_malloc(rt_size_t size) +{ + rt_size_t ptr, ptr2; + struct heap_mem *mem, *mem2; + + RT_DEBUG_NOT_IN_INTERRUPT; + + if (size == 0) + return RT_NULL; + + if (size != RT_ALIGN(size, RT_ALIGN_SIZE)) + RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d, but align to %d\n", + size, RT_ALIGN(size, RT_ALIGN_SIZE))); + else + RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d\n", size)); + + /* alignment size */ + size = RT_ALIGN(size, RT_ALIGN_SIZE); + + if (size > mem_size_aligned) + { + RT_DEBUG_LOG(RT_DEBUG_MEM, ("no memory\n")); + + return RT_NULL; + } + + /* every data block must be at least MIN_SIZE_ALIGNED long */ + if (size < MIN_SIZE_ALIGNED) + size = MIN_SIZE_ALIGNED; + + /* take memory semaphore */ + rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + + for (ptr = (rt_uint8_t *)lfree - heap_ptr; + ptr < mem_size_aligned - size; + ptr = ((struct heap_mem *)&heap_ptr[ptr])->next) + { + mem = (struct heap_mem *)&heap_ptr[ptr]; + + if ((!mem->used) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) + { + /* mem is not used and at least perfect fit is possible: + * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ + + if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= + (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) + { + /* (in addition to the above, we test if another struct heap_mem (SIZEOF_STRUCT_MEM) containing + * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') + * -> split large block, create empty remainder, + * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if + * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, + * struct heap_mem would fit in but no data between mem2 and mem2->next + * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty + * region that couldn't hold data, but when mem->next gets freed, + * the 2 regions would be combined, resulting in more free memory + */ + ptr2 = ptr + SIZEOF_STRUCT_MEM + size; + + /* create mem2 struct */ + mem2 = (struct heap_mem *)&heap_ptr[ptr2]; + mem2->magic = HEAP_MAGIC; + mem2->used = 0; + mem2->next = mem->next; + mem2->prev = ptr; +#ifdef RT_USING_MEMTRACE + rt_mem_setname(mem2, " "); +#endif + + /* and insert it between mem and mem->next */ + mem->next = ptr2; + mem->used = 1; + + if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM) + { + ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2; + } +#ifdef RT_MEM_STATS + used_mem += (size + SIZEOF_STRUCT_MEM); + if (max_mem < used_mem) + max_mem = used_mem; +#endif + } + else + { + /* (a mem2 struct does no fit into the user data space of mem and mem->next will always + * be used at this point: if not we have 2 unused structs in a row, plug_holes should have + * take care of this). + * -> near fit or excact fit: do not split, no mem2 creation + * also can't move mem->next directly behind mem, since mem->next + * will always be used at this point! + */ + mem->used = 1; +#ifdef RT_MEM_STATS + used_mem += mem->next - ((rt_uint8_t *)mem - heap_ptr); + if (max_mem < used_mem) + max_mem = used_mem; +#endif + } + /* set memory block magic */ + mem->magic = HEAP_MAGIC; +#ifdef RT_USING_MEMTRACE + if (rt_thread_self()) + rt_mem_setname(mem, rt_thread_self()->name); + else + rt_mem_setname(mem, "NONE"); +#endif + + if (mem == lfree) + { + /* Find next free block after mem and update lowest free pointer */ + while (lfree->used && lfree != heap_end) + lfree = (struct heap_mem *)&heap_ptr[lfree->next]; + + RT_ASSERT(((lfree == heap_end) || (!lfree->used))); + } + + rt_sem_release(&heap_sem); + RT_ASSERT((rt_uint32_t)mem + SIZEOF_STRUCT_MEM + size <= (rt_uint32_t)heap_end); + RT_ASSERT((rt_uint32_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM) % RT_ALIGN_SIZE == 0); + RT_ASSERT((((rt_uint32_t)mem) & (RT_ALIGN_SIZE - 1)) == 0); + + RT_DEBUG_LOG(RT_DEBUG_MEM, + ("allocate memory at 0x%x, size: %d\n", + (rt_uint32_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM), + (rt_uint32_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr)))); + + RT_OBJECT_HOOK_CALL(rt_malloc_hook, + (((void *)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM)), size)); + + /* return the memory data except mem struct */ + return (rt_uint8_t *)mem + SIZEOF_STRUCT_MEM; + } + } + + rt_sem_release(&heap_sem); + + return RT_NULL; +} +RTM_EXPORT(rt_malloc); + +/** + * This function will change the previously allocated memory block. + * + * @param rmem pointer to memory allocated by rt_malloc + * @param newsize the required new size + * + * @return the changed memory block address + */ +void *rt_realloc(void *rmem, rt_size_t newsize) +{ + rt_size_t size; + rt_size_t ptr, ptr2; + struct heap_mem *mem, *mem2; + void *nmem; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* alignment size */ + newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE); + if (newsize > mem_size_aligned) + { + RT_DEBUG_LOG(RT_DEBUG_MEM, ("realloc: out of memory\n")); + + return RT_NULL; + } + else if (newsize == 0) + { + rt_free(rmem); + return RT_NULL; + } + + /* allocate a new memory block */ + if (rmem == RT_NULL) + return rt_malloc(newsize); + + rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + + if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr || + (rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end) + { + /* illegal memory */ + rt_sem_release(&heap_sem); + + return rmem; + } + + mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM); + + ptr = (rt_uint8_t *)mem - heap_ptr; + size = mem->next - ptr - SIZEOF_STRUCT_MEM; + if (size == newsize) + { + /* the size is the same as */ + rt_sem_release(&heap_sem); + + return rmem; + } + + if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) + { + /* split memory block */ +#ifdef RT_MEM_STATS + used_mem -= (size - newsize); +#endif + + ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; + mem2 = (struct heap_mem *)&heap_ptr[ptr2]; + mem2->magic = HEAP_MAGIC; + mem2->used = 0; + mem2->next = mem->next; + mem2->prev = ptr; +#ifdef RT_USING_MEMTRACE + rt_mem_setname(mem2, " "); +#endif + mem->next = ptr2; + if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM) + { + ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2; + } + + plug_holes(mem2); + + rt_sem_release(&heap_sem); + + return rmem; + } + rt_sem_release(&heap_sem); + + /* expand memory */ + nmem = rt_malloc(newsize); + if (nmem != RT_NULL) /* check memory */ + { + rt_memcpy(nmem, rmem, size < newsize ? size : newsize); + rt_free(rmem); + } + + return nmem; +} +RTM_EXPORT(rt_realloc); + +/** + * This function will contiguously allocate enough space for count objects + * that are size bytes of memory each and returns a pointer to the allocated + * memory. + * + * The allocated memory is filled with bytes of value zero. + * + * @param count number of objects to allocate + * @param size size of the objects to allocate + * + * @return pointer to allocated memory / NULL pointer if there is an error + */ +void *rt_calloc(rt_size_t count, rt_size_t size) +{ + void *p; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* allocate 'count' objects of size 'size' */ + p = rt_malloc(count * size); + + /* zero the memory */ + if (p) + rt_memset(p, 0, count * size); + + return p; +} +RTM_EXPORT(rt_calloc); + +/** + * This function will release the previously allocated memory block by + * rt_malloc. The released memory block is taken back to system heap. + * + * @param rmem the address of memory which will be released + */ +void rt_free(void *rmem) +{ + struct heap_mem *mem; + + RT_DEBUG_NOT_IN_INTERRUPT; + + if (rmem == RT_NULL) + return; + RT_ASSERT((((rt_uint32_t)rmem) & (RT_ALIGN_SIZE - 1)) == 0); + RT_ASSERT((rt_uint8_t *)rmem >= (rt_uint8_t *)heap_ptr && + (rt_uint8_t *)rmem < (rt_uint8_t *)heap_end); + + RT_OBJECT_HOOK_CALL(rt_free_hook, (rmem)); + + if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr || + (rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end) + { + RT_DEBUG_LOG(RT_DEBUG_MEM, ("illegal memory\n")); + + return; + } + + /* Get the corresponding struct heap_mem ... */ + mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM); + + RT_DEBUG_LOG(RT_DEBUG_MEM, + ("release memory 0x%x, size: %d\n", + (rt_uint32_t)rmem, + (rt_uint32_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr)))); + + + /* protect the heap from concurrent access */ + rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + + /* ... which has to be in a used state ... */ + if (!mem->used || mem->magic != HEAP_MAGIC) + { + rt_kprintf("to free a bad data block:\n"); + rt_kprintf("mem: 0x%08x, used flag: %d, magic code: 0x%04x\n", mem, mem->used, mem->magic); + } + RT_ASSERT(mem->used); + RT_ASSERT(mem->magic == HEAP_MAGIC); + /* ... and is now unused. */ + mem->used = 0; + mem->magic = HEAP_MAGIC; +#ifdef RT_USING_MEMTRACE + rt_mem_setname(mem, " "); +#endif + + if (mem < lfree) + { + /* the newly freed struct is now the lowest */ + lfree = mem; + } + +#ifdef RT_MEM_STATS + used_mem -= (mem->next - ((rt_uint8_t *)mem - heap_ptr)); +#endif + + /* finally, see if prev or next are free also */ + plug_holes(mem); + rt_sem_release(&heap_sem); +} +RTM_EXPORT(rt_free); + +#ifdef RT_MEM_STATS +void rt_memory_info(rt_uint32_t *total, + rt_uint32_t *used, + rt_uint32_t *max_used) +{ + if (total != RT_NULL) + *total = mem_size_aligned; + if (used != RT_NULL) + *used = used_mem; + if (max_used != RT_NULL) + *max_used = max_mem; +} + +#ifdef RT_USING_FINSH +#include + +void list_mem(void) +{ + rt_kprintf("total memory: %d\n", mem_size_aligned); + rt_kprintf("used memory : %d\n", used_mem); + rt_kprintf("maximum allocated memory: %d\n", max_mem); +} +FINSH_FUNCTION_EXPORT(list_mem, list memory usage information) + +#ifdef RT_USING_MEMTRACE +int memcheck(void) +{ + int position; + rt_uint32_t level; + struct heap_mem *mem; + level = rt_hw_interrupt_disable(); + for (mem = (struct heap_mem *)heap_ptr; mem != heap_end; mem = (struct heap_mem *)&heap_ptr[mem->next]) + { + position = (rt_uint32_t)mem - (rt_uint32_t)heap_ptr; + if (position < 0) goto __exit; + if (position > mem_size_aligned) goto __exit; + if (mem->magic != HEAP_MAGIC) goto __exit; + if (mem->used != 0 && mem->used != 1) goto __exit; + } + rt_hw_interrupt_enable(level); + + return 0; +__exit: + rt_kprintf("Memory block wrong:\n"); + rt_kprintf("address: 0x%08x\n", mem); + rt_kprintf(" magic: 0x%04x\n", mem->magic); + rt_kprintf(" used: %d\n", mem->used); + rt_kprintf(" size: %d\n", mem->next - position - SIZEOF_STRUCT_MEM); + rt_hw_interrupt_enable(level); + + return 0; +} +MSH_CMD_EXPORT(memcheck, check memory data); + +int memtrace(int argc, char **argv) +{ + struct heap_mem *mem; + + list_mem(); + + rt_kprintf("\nmemory heap address:\n"); + rt_kprintf("heap_ptr: 0x%08x\n", heap_ptr); + rt_kprintf("lfree : 0x%08x\n", lfree); + rt_kprintf("heap_end: 0x%08x\n", heap_end); + + rt_kprintf("\n--memory item information --\n"); + for (mem = (struct heap_mem *)heap_ptr; mem != heap_end; mem = (struct heap_mem *)&heap_ptr[mem->next]) + { + int position = (rt_uint32_t)mem - (rt_uint32_t)heap_ptr; + int size; + + rt_kprintf("[0x%08x - ", mem); + + size = mem->next - position - SIZEOF_STRUCT_MEM; + if (size < 1024) + rt_kprintf("%5d", size); + else if (size < 1024 * 1024) + rt_kprintf("%4dK", size / 1024); + else + rt_kprintf("%4dM", size / (1024 * 1024)); + + rt_kprintf("] %c%c%c%c", mem->thread[0], mem->thread[1], mem->thread[2], mem->thread[3]); + if (mem->magic != HEAP_MAGIC) + rt_kprintf(": ***\n"); + else + rt_kprintf("\n"); + } + + return 0; +} +MSH_CMD_EXPORT(memtrace, dump memory trace information); +#endif /* end of RT_USING_MEMTRACE */ +#endif /* end of RT_USING_FINSH */ + +#endif + +/**@}*/ + +#endif /* end of RT_USING_HEAP */ +#endif /* end of RT_USING_MEMHEAP_AS_HEAP */ diff --git a/rt-thread/src/memheap.c b/rt-thread/src/memheap.c new file mode 100644 index 0000000..946f163 --- /dev/null +++ b/rt-thread/src/memheap.c @@ -0,0 +1,717 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : memheap.c + * + * Change Logs: + * Date Author Notes + * 2012-04-10 Bernard first implementation + * 2012-10-16 Bernard add the mutex lock for heap object. + * 2012-12-29 Bernard memheap can be used as system heap. + * change mutex lock to semaphore lock. + * 2013-04-10 Bernard add rt_memheap_realloc function. + * 2013-05-24 Bernard fix the rt_memheap_realloc issue. + * 2013-07-11 Grissiom fix the memory block splitting issue. + * 2013-07-15 Grissiom optimize rt_memheap_realloc + */ + +#include +#include + +#ifdef RT_USING_MEMHEAP + +/* dynamic pool magic and mask */ +#define RT_MEMHEAP_MAGIC 0x1ea01ea0 +#define RT_MEMHEAP_MASK 0xfffffffe +#define RT_MEMHEAP_USED 0x01 +#define RT_MEMHEAP_FREED 0x00 + +#define RT_MEMHEAP_IS_USED(i) ((i)->magic & RT_MEMHEAP_USED) +#define RT_MEMHEAP_MINIALLOC 12 + +#define RT_MEMHEAP_SIZE RT_ALIGN(sizeof(struct rt_memheap_item), RT_ALIGN_SIZE) +#define MEMITEM_SIZE(item) ((rt_uint32_t)item->next - (rt_uint32_t)item - RT_MEMHEAP_SIZE) + +/* + * The initialized memory pool will be: + * +-----------------------------------+--------------------------+ + * | whole freed memory block | Used Memory Block Tailer | + * +-----------------------------------+--------------------------+ + * + * block_list --> whole freed memory block + * + * The length of Used Memory Block Tailer is 0, + * which is prevents block merging across list + */ +rt_err_t rt_memheap_init(struct rt_memheap *memheap, + const char *name, + void *start_addr, + rt_uint32_t size) +{ + struct rt_memheap_item *item; + + RT_ASSERT(memheap != RT_NULL); + + /* initialize pool object */ + rt_object_init(&(memheap->parent), RT_Object_Class_MemHeap, name); + + memheap->start_addr = start_addr; + memheap->pool_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE); + memheap->available_size = memheap->pool_size - (2 * RT_MEMHEAP_SIZE); + memheap->max_used_size = memheap->pool_size - memheap->available_size; + + /* initialize the free list header */ + item = &(memheap->free_header); + item->magic = RT_MEMHEAP_MAGIC; + item->pool_ptr = memheap; + item->next = RT_NULL; + item->prev = RT_NULL; + item->next_free = item; + item->prev_free = item; + + /* set the free list to free list header */ + memheap->free_list = item; + + /* initialize the first big memory block */ + item = (struct rt_memheap_item *)start_addr; + item->magic = RT_MEMHEAP_MAGIC; + item->pool_ptr = memheap; + item->next = RT_NULL; + item->prev = RT_NULL; + item->next_free = item; + item->prev_free = item; + + item->next = (struct rt_memheap_item *) + ((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE); + item->prev = item->next; + + /* block list header */ + memheap->block_list = item; + + /* place the big memory block to free list */ + item->next_free = memheap->free_list->next_free; + item->prev_free = memheap->free_list; + memheap->free_list->next_free->prev_free = item; + memheap->free_list->next_free = item; + + /* move to the end of memory pool to build a small tailer block, + * which prevents block merging + */ + item = item->next; + /* it's a used memory block */ + item->magic = RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED; + item->pool_ptr = memheap; + item->next = (struct rt_memheap_item *)start_addr; + item->prev = (struct rt_memheap_item *)start_addr; + /* not in free list */ + item->next_free = item->prev_free = RT_NULL; + + /* initialize semaphore lock */ + rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_FIFO); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("memory heap: start addr 0x%08x, size %d, free list header 0x%08x\n", + start_addr, size, &(memheap->free_header))); + + return RT_EOK; +} +RTM_EXPORT(rt_memheap_init); + +rt_err_t rt_memheap_detach(struct rt_memheap *heap) +{ + RT_ASSERT(heap); + RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap); + RT_ASSERT(rt_object_is_systemobject(&heap->parent)); + + rt_object_detach(&(heap->lock.parent.parent)); + rt_object_detach(&(heap->parent)); + + /* Return a successful completion. */ + return RT_EOK; +} +RTM_EXPORT(rt_memheap_detach); + +void *rt_memheap_alloc(struct rt_memheap *heap, rt_uint32_t size) +{ + rt_err_t result; + rt_uint32_t free_size; + struct rt_memheap_item *header_ptr; + + RT_ASSERT(heap != RT_NULL); + RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap); + + /* align allocated size */ + size = RT_ALIGN(size, RT_ALIGN_SIZE); + if (size < RT_MEMHEAP_MINIALLOC) + size = RT_MEMHEAP_MINIALLOC; + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate %d on heap:%8.*s", + size, RT_NAME_MAX, heap->parent.name)); + + if (size < heap->available_size) + { + /* search on free list */ + free_size = 0; + + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); + + return RT_NULL; + } + + /* get the first free memory block */ + header_ptr = heap->free_list->next_free; + while (header_ptr != heap->free_list && free_size < size) + { + /* get current freed memory block size */ + free_size = MEMITEM_SIZE(header_ptr); + if (free_size < size) + { + /* move to next free memory block */ + header_ptr = header_ptr->next_free; + } + } + + /* determine if the memory is available. */ + if (free_size >= size) + { + /* a block that satisfies the request has been found. */ + + /* determine if the block needs to be split. */ + if (free_size >= (size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC)) + { + struct rt_memheap_item *new_ptr; + + /* split the block. */ + new_ptr = (struct rt_memheap_item *) + (((rt_uint8_t *)header_ptr) + size + RT_MEMHEAP_SIZE); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n", + header_ptr, + header_ptr->next, + header_ptr->prev, + new_ptr)); + + /* mark the new block as a memory block and freed. */ + new_ptr->magic = RT_MEMHEAP_MAGIC; + + /* put the pool pointer into the new block. */ + new_ptr->pool_ptr = heap; + + /* break down the block list */ + new_ptr->prev = header_ptr; + new_ptr->next = header_ptr->next; + header_ptr->next->prev = new_ptr; + header_ptr->next = new_ptr; + + /* remove header ptr from free list */ + header_ptr->next_free->prev_free = header_ptr->prev_free; + header_ptr->prev_free->next_free = header_ptr->next_free; + header_ptr->next_free = RT_NULL; + header_ptr->prev_free = RT_NULL; + + /* insert new_ptr to free list */ + new_ptr->next_free = heap->free_list->next_free; + new_ptr->prev_free = heap->free_list; + heap->free_list->next_free->prev_free = new_ptr; + heap->free_list->next_free = new_ptr; + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x\n", + new_ptr->next_free, + new_ptr->prev_free)); + + /* decrement the available byte count. */ + heap->available_size = heap->available_size - + size - + RT_MEMHEAP_SIZE; + if (heap->pool_size - heap->available_size > heap->max_used_size) + heap->max_used_size = heap->pool_size - heap->available_size; + } + else + { + /* decrement the entire free size from the available bytes count. */ + heap->available_size = heap->available_size - free_size; + if (heap->pool_size - heap->available_size > heap->max_used_size) + heap->max_used_size = heap->pool_size - heap->available_size; + + /* remove header_ptr from free list */ + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x\n", + header_ptr, + header_ptr->next_free, + header_ptr->prev_free)); + + header_ptr->next_free->prev_free = header_ptr->prev_free; + header_ptr->prev_free->next_free = header_ptr->next_free; + header_ptr->next_free = RT_NULL; + header_ptr->prev_free = RT_NULL; + } + + /* Mark the allocated block as not available. */ + header_ptr->magic |= RT_MEMHEAP_USED; + + /* release lock */ + rt_sem_release(&(heap->lock)); + + /* Return a memory address to the caller. */ + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("alloc mem: memory[0x%08x], heap[0x%08x], size: %d\n", + (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE), + header_ptr, + size)); + + return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE); + } + + /* release lock */ + rt_sem_release(&(heap->lock)); + } + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate memory: failed\n")); + + /* Return the completion status. */ + return RT_NULL; +} +RTM_EXPORT(rt_memheap_alloc); + +void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize) +{ + rt_err_t result; + rt_size_t oldsize; + struct rt_memheap_item *header_ptr; + struct rt_memheap_item *new_ptr; + + RT_ASSERT(heap); + RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap); + + if (newsize == 0) + { + rt_memheap_free(ptr); + + return RT_NULL; + } + /* align allocated size */ + newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE); + if (newsize < RT_MEMHEAP_MINIALLOC) + newsize = RT_MEMHEAP_MINIALLOC; + + if (ptr == RT_NULL) + { + return rt_memheap_alloc(heap, newsize); + } + + /* get memory block header and get the size of memory block */ + header_ptr = (struct rt_memheap_item *) + ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE); + oldsize = MEMITEM_SIZE(header_ptr); + /* re-allocate memory */ + if (newsize > oldsize) + { + void *new_ptr; + struct rt_memheap_item *next_ptr; + + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); + return RT_NULL; + } + + next_ptr = header_ptr->next; + + /* header_ptr should not be the tail */ + RT_ASSERT(next_ptr > header_ptr); + + /* check whether the following free space is enough to expand */ + if (!RT_MEMHEAP_IS_USED(next_ptr)) + { + rt_int32_t nextsize; + + nextsize = MEMITEM_SIZE(next_ptr); + RT_ASSERT(next_ptr > 0); + + /* Here is the ASCII art of the situation that we can make use of + * the next free node without alloc/memcpy, |*| is the control + * block: + * + * oldsize free node + * |*|-----------|*|----------------------|*| + * newsize >= minialloc + * |*|----------------|*|-----------------|*| + */ + if (nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC) + { + /* decrement the entire free size from the available bytes count. */ + heap->available_size = heap->available_size - (newsize - oldsize); + if (heap->pool_size - heap->available_size > heap->max_used_size) + heap->max_used_size = heap->pool_size - heap->available_size; + + /* remove next_ptr from free list */ + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x", + next_ptr, + next_ptr->next_free, + next_ptr->prev_free)); + + next_ptr->next_free->prev_free = next_ptr->prev_free; + next_ptr->prev_free->next_free = next_ptr->next_free; + next_ptr->next->prev = next_ptr->prev; + next_ptr->prev->next = next_ptr->next; + + /* build a new one on the right place */ + next_ptr = (struct rt_memheap_item *)((char *)ptr + newsize); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]", + next_ptr, + next_ptr->next, + next_ptr->prev)); + + /* mark the new block as a memory block and freed. */ + next_ptr->magic = RT_MEMHEAP_MAGIC; + + /* put the pool pointer into the new block. */ + next_ptr->pool_ptr = heap; + + next_ptr->prev = header_ptr; + next_ptr->next = header_ptr->next; + header_ptr->next->prev = next_ptr; + header_ptr->next = next_ptr; + + /* insert next_ptr to free list */ + next_ptr->next_free = heap->free_list->next_free; + next_ptr->prev_free = heap->free_list; + heap->free_list->next_free->prev_free = next_ptr; + heap->free_list->next_free = next_ptr; + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x", + next_ptr->next_free, + next_ptr->prev_free)); + + /* release lock */ + rt_sem_release(&(heap->lock)); + + return ptr; + } + } + + /* release lock */ + rt_sem_release(&(heap->lock)); + + /* re-allocate a memory block */ + new_ptr = (void *)rt_memheap_alloc(heap, newsize); + if (new_ptr != RT_NULL) + { + rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize); + rt_memheap_free(ptr); + } + + return new_ptr; + } + + /* don't split when there is less than one node space left */ + if (newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize) + return ptr; + + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); + + return RT_NULL; + } + + /* split the block. */ + new_ptr = (struct rt_memheap_item *) + (((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n", + header_ptr, + header_ptr->next, + header_ptr->prev, + new_ptr)); + + /* mark the new block as a memory block and freed. */ + new_ptr->magic = RT_MEMHEAP_MAGIC; + /* put the pool pointer into the new block. */ + new_ptr->pool_ptr = heap; + + /* break down the block list */ + new_ptr->prev = header_ptr; + new_ptr->next = header_ptr->next; + header_ptr->next->prev = new_ptr; + header_ptr->next = new_ptr; + + /* determine if the block can be merged with the next neighbor. */ + if (!RT_MEMHEAP_IS_USED(new_ptr->next)) + { + struct rt_memheap_item *free_ptr; + + /* merge block with next neighbor. */ + free_ptr = new_ptr->next; + heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n", + header_ptr, header_ptr->next_free, header_ptr->prev_free)); + + free_ptr->next->prev = new_ptr; + new_ptr->next = free_ptr->next; + + /* remove free ptr from free list */ + free_ptr->next_free->prev_free = free_ptr->prev_free; + free_ptr->prev_free->next_free = free_ptr->next_free; + } + + /* insert the split block to free list */ + new_ptr->next_free = heap->free_list->next_free; + new_ptr->prev_free = heap->free_list; + heap->free_list->next_free->prev_free = new_ptr; + heap->free_list->next_free = new_ptr; + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free ptr: next_free 0x%08x, prev_free 0x%08x\n", + new_ptr->next_free, + new_ptr->prev_free)); + + /* increment the available byte count. */ + heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr); + + /* release lock */ + rt_sem_release(&(heap->lock)); + + /* return the old memory block */ + return ptr; +} +RTM_EXPORT(rt_memheap_realloc); + +void rt_memheap_free(void *ptr) +{ + rt_err_t result; + struct rt_memheap *heap; + struct rt_memheap_item *header_ptr, *new_ptr; + rt_uint32_t insert_header; + + /* NULL check */ + if (ptr == RT_NULL) return; + + /* set initial status as OK */ + insert_header = 1; + new_ptr = RT_NULL; + header_ptr = (struct rt_memheap_item *) + ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE); + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("free memory: memory[0x%08x], block[0x%08x]\n", + ptr, header_ptr)); + + /* check magic */ + RT_ASSERT((header_ptr->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC); + RT_ASSERT(header_ptr->magic & RT_MEMHEAP_USED); + /* check whether this block of memory has been over-written. */ + RT_ASSERT((header_ptr->next->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC); + + /* get pool ptr */ + heap = header_ptr->pool_ptr; + + RT_ASSERT(heap); + RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap); + + /* lock memheap */ + result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); + if (result != RT_EOK) + { + rt_set_errno(result); + + return ; + } + + /* Mark the memory as available. */ + header_ptr->magic &= ~RT_MEMHEAP_USED; + /* Adjust the available number of bytes. */ + heap->available_size = heap->available_size + MEMITEM_SIZE(header_ptr); + + /* Determine if the block can be merged with the previous neighbor. */ + if (!RT_MEMHEAP_IS_USED(header_ptr->prev)) + { + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("merge: left node 0x%08x\n", + header_ptr->prev)); + + /* adjust the available number of bytes. */ + heap->available_size = heap->available_size + RT_MEMHEAP_SIZE; + + /* yes, merge block with previous neighbor. */ + (header_ptr->prev)->next = header_ptr->next; + (header_ptr->next)->prev = header_ptr->prev; + + /* move header pointer to previous. */ + header_ptr = header_ptr->prev; + /* don't insert header to free list */ + insert_header = 0; + } + + /* determine if the block can be merged with the next neighbor. */ + if (!RT_MEMHEAP_IS_USED(header_ptr->next)) + { + /* adjust the available number of bytes. */ + heap->available_size = heap->available_size + RT_MEMHEAP_SIZE; + + /* merge block with next neighbor. */ + new_ptr = header_ptr->next; + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n", + new_ptr, new_ptr->next_free, new_ptr->prev_free)); + + new_ptr->next->prev = header_ptr; + header_ptr->next = new_ptr->next; + + /* remove new ptr from free list */ + new_ptr->next_free->prev_free = new_ptr->prev_free; + new_ptr->prev_free->next_free = new_ptr->next_free; + } + + if (insert_header) + { + /* no left merge, insert to free list */ + header_ptr->next_free = heap->free_list->next_free; + header_ptr->prev_free = heap->free_list; + heap->free_list->next_free->prev_free = header_ptr; + heap->free_list->next_free = header_ptr; + + RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, + ("insert to free list: next_free 0x%08x, prev_free 0x%08x\n", + header_ptr->next_free, header_ptr->prev_free)); + } + + /* release lock */ + rt_sem_release(&(heap->lock)); +} +RTM_EXPORT(rt_memheap_free); + +#ifdef RT_USING_MEMHEAP_AS_HEAP +static struct rt_memheap _heap; + +void rt_system_heap_init(void *begin_addr, void *end_addr) +{ + /* initialize a default heap in the system */ + rt_memheap_init(&_heap, + "heap", + begin_addr, + (rt_uint32_t)end_addr - (rt_uint32_t)begin_addr); +} + +void *rt_malloc(rt_size_t size) +{ + void *ptr; + + /* try to allocate in system heap */ + ptr = rt_memheap_alloc(&_heap, size); + if (ptr == RT_NULL) + { + struct rt_object *object; + struct rt_list_node *node; + struct rt_memheap *heap; + struct rt_object_information *information; + + /* try to allocate on other memory heap */ + information = rt_object_get_information(RT_Object_Class_MemHeap); + RT_ASSERT(information != RT_NULL); + for (node = information->object_list.next; + node != &(information->object_list); + node = node->next) + { + object = rt_list_entry(node, struct rt_object, list); + heap = (struct rt_memheap *)object; + + RT_ASSERT(heap); + RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap); + + /* not allocate in the default system heap */ + if (heap == &_heap) + continue; + + ptr = rt_memheap_alloc(heap, size); + if (ptr != RT_NULL) + break; + } + } + + return ptr; +} +RTM_EXPORT(rt_malloc); + +void rt_free(void *rmem) +{ + rt_memheap_free(rmem); +} +RTM_EXPORT(rt_free); + +void *rt_realloc(void *rmem, rt_size_t newsize) +{ + void *new_ptr; + struct rt_memheap_item *header_ptr; + + if (rmem == RT_NULL) + return rt_malloc(newsize); + + if (newsize == 0) + { + rt_free(rmem); + return RT_NULL; + } + + /* get old memory item */ + header_ptr = (struct rt_memheap_item *) + ((rt_uint8_t *)rmem - RT_MEMHEAP_SIZE); + + new_ptr = rt_memheap_realloc(header_ptr->pool_ptr, rmem, newsize); + if (new_ptr == RT_NULL && newsize != 0) + { + /* allocate memory block from other memheap */ + new_ptr = rt_malloc(newsize); + if (new_ptr != RT_NULL && rmem != RT_NULL) + { + rt_size_t oldsize; + + /* get the size of old memory block */ + oldsize = MEMITEM_SIZE(header_ptr); + if (newsize > oldsize) + rt_memcpy(new_ptr, rmem, oldsize); + else + rt_memcpy(new_ptr, rmem, newsize); + + rt_free(rmem); + } + } + + return new_ptr; +} +RTM_EXPORT(rt_realloc); + +void *rt_calloc(rt_size_t count, rt_size_t size) +{ + void *ptr; + rt_size_t total_size; + + total_size = count * size; + ptr = rt_malloc(total_size); + if (ptr != RT_NULL) + { + /* clean memory */ + rt_memset(ptr, 0, total_size); + } + + return ptr; +} +RTM_EXPORT(rt_calloc); + +#endif + +#endif diff --git a/rt-thread/src/mempool.c b/rt-thread/src/mempool.c new file mode 100644 index 0000000..2184586 --- /dev/null +++ b/rt-thread/src/mempool.c @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-05-27 Bernard implement memory pool + * 2006-06-03 Bernard fix the thread timer init bug + * 2006-06-30 Bernard fix the allocate/free block bug + * 2006-08-04 Bernard add hook support + * 2006-08-10 Bernard fix interrupt bug in rt_mp_alloc + * 2010-07-13 Bernard fix RT_ALIGN issue found by kuronca + * 2010-10-26 yi.qiu add module support in rt_mp_delete + * 2011-01-24 Bernard add object allocation check. + * 2012-03-22 Bernard fix align issue in rt_mp_init and rt_mp_create. + */ + +#include +#include + +#ifdef RT_USING_MEMPOOL + +#ifdef RT_USING_HOOK +static void (*rt_mp_alloc_hook)(struct rt_mempool *mp, void *block); +static void (*rt_mp_free_hook)(struct rt_mempool *mp, void *block); + +/** + * @addtogroup Hook + */ + +/**@{*/ + +/** + * This function will set a hook function, which will be invoked when a memory + * block is allocated from memory pool. + * + * @param hook the hook function + */ +void rt_mp_alloc_sethook(void (*hook)(struct rt_mempool *mp, void *block)) +{ + rt_mp_alloc_hook = hook; +} + +/** + * This function will set a hook function, which will be invoked when a memory + * block is released to memory pool. + * + * @param hook the hook function + */ +void rt_mp_free_sethook(void (*hook)(struct rt_mempool *mp, void *block)) +{ + rt_mp_free_hook = hook; +} + +/**@}*/ +#endif + +/** + * @addtogroup MM + */ + +/**@{*/ + +/** + * This function will initialize a memory pool object, normally which is used + * for static object. + * + * @param mp the memory pool object + * @param name the name of memory pool + * @param start the star address of memory pool + * @param size the total size of memory pool + * @param block_size the size for each block + * + * @return RT_EOK + */ +rt_err_t rt_mp_init(struct rt_mempool *mp, + const char *name, + void *start, + rt_size_t size, + rt_size_t block_size) +{ + rt_uint8_t *block_ptr; + register rt_size_t offset; + + /* parameter check */ + RT_ASSERT(mp != RT_NULL); + + /* initialize object */ + rt_object_init(&(mp->parent), RT_Object_Class_MemPool, name); + + /* initialize memory pool */ + mp->start_address = start; + mp->size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE); + + /* align the block size */ + block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE); + mp->block_size = block_size; + + /* align to align size byte */ + mp->block_total_count = mp->size / (mp->block_size + sizeof(rt_uint8_t *)); + mp->block_free_count = mp->block_total_count; + + /* initialize suspended thread list */ + rt_list_init(&(mp->suspend_thread)); + mp->suspend_thread_count = 0; + + /* initialize free block list */ + block_ptr = (rt_uint8_t *)mp->start_address; + for (offset = 0; offset < mp->block_total_count; offset ++) + { + *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) = + (rt_uint8_t *)(block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *))); + } + + *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) = + RT_NULL; + + mp->block_list = block_ptr; + + return RT_EOK; +} +RTM_EXPORT(rt_mp_init); + +/** + * This function will detach a memory pool from system object management. + * + * @param mp the memory pool object + * + * @return RT_EOK + */ +rt_err_t rt_mp_detach(struct rt_mempool *mp) +{ + struct rt_thread *thread; + register rt_ubase_t temp; + + /* parameter check */ + RT_ASSERT(mp != RT_NULL); + RT_ASSERT(rt_object_get_type(&mp->parent) == RT_Object_Class_MemPool); + RT_ASSERT(rt_object_is_systemobject(&mp->parent)); + + /* wake up all suspended threads */ + while (!rt_list_isempty(&(mp->suspend_thread))) + { + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* get next suspend thread */ + thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist); + /* set error code to RT_ERROR */ + thread->error = -RT_ERROR; + + /* + * resume thread + * In rt_thread_resume function, it will remove current thread from + * suspend list + */ + rt_thread_resume(thread); + + /* decrease suspended thread count */ + mp->suspend_thread_count --; + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + } + + /* detach object */ + rt_object_detach(&(mp->parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_mp_detach); + +#ifdef RT_USING_HEAP +/** + * This function will create a mempool object and allocate the memory pool from + * heap. + * + * @param name the name of memory pool + * @param block_count the count of blocks in memory pool + * @param block_size the size for each block + * + * @return the created mempool object + */ +rt_mp_t rt_mp_create(const char *name, + rt_size_t block_count, + rt_size_t block_size) +{ + rt_uint8_t *block_ptr; + struct rt_mempool *mp; + register rt_size_t offset; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* allocate object */ + mp = (struct rt_mempool *)rt_object_allocate(RT_Object_Class_MemPool, name); + /* allocate object failed */ + if (mp == RT_NULL) + return RT_NULL; + + /* initialize memory pool */ + block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE); + mp->block_size = block_size; + mp->size = (block_size + sizeof(rt_uint8_t *)) * block_count; + + /* allocate memory */ + mp->start_address = rt_malloc((block_size + sizeof(rt_uint8_t *)) * + block_count); + if (mp->start_address == RT_NULL) + { + /* no memory, delete memory pool object */ + rt_object_delete(&(mp->parent)); + + return RT_NULL; + } + + mp->block_total_count = block_count; + mp->block_free_count = mp->block_total_count; + + /* initialize suspended thread list */ + rt_list_init(&(mp->suspend_thread)); + mp->suspend_thread_count = 0; + + /* initialize free block list */ + block_ptr = (rt_uint8_t *)mp->start_address; + for (offset = 0; offset < mp->block_total_count; offset ++) + { + *(rt_uint8_t **)(block_ptr + offset * (block_size + sizeof(rt_uint8_t *))) + = block_ptr + (offset + 1) * (block_size + sizeof(rt_uint8_t *)); + } + + *(rt_uint8_t **)(block_ptr + (offset - 1) * (block_size + sizeof(rt_uint8_t *))) + = RT_NULL; + + mp->block_list = block_ptr; + + return mp; +} +RTM_EXPORT(rt_mp_create); + +/** + * This function will delete a memory pool and release the object memory. + * + * @param mp the memory pool object + * + * @return RT_EOK + */ +rt_err_t rt_mp_delete(rt_mp_t mp) +{ + struct rt_thread *thread; + register rt_ubase_t temp; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* parameter check */ + RT_ASSERT(mp != RT_NULL); + RT_ASSERT(rt_object_get_type(&mp->parent) == RT_Object_Class_MemPool); + RT_ASSERT(rt_object_is_systemobject(&mp->parent) == RT_FALSE); + + /* wake up all suspended threads */ + while (!rt_list_isempty(&(mp->suspend_thread))) + { + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* get next suspend thread */ + thread = rt_list_entry(mp->suspend_thread.next, struct rt_thread, tlist); + /* set error code to RT_ERROR */ + thread->error = -RT_ERROR; + + /* + * resume thread + * In rt_thread_resume function, it will remove current thread from + * suspend list + */ + rt_thread_resume(thread); + + /* decrease suspended thread count */ + mp->suspend_thread_count --; + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + } + + /* release allocated room */ + rt_free(mp->start_address); + + /* detach object */ + rt_object_delete(&(mp->parent)); + + return RT_EOK; +} +RTM_EXPORT(rt_mp_delete); +#endif + +/** + * This function will allocate a block from memory pool + * + * @param mp the memory pool object + * @param time the waiting time + * + * @return the allocated memory block or RT_NULL on allocated failed + */ +void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time) +{ + rt_uint8_t *block_ptr; + register rt_base_t level; + struct rt_thread *thread; + rt_uint32_t before_sleep = 0; + + /* get current thread */ + thread = rt_thread_self(); + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + while (mp->block_free_count == 0) + { + /* memory block is unavailable. */ + if (time == 0) + { + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_set_errno(-RT_ETIMEOUT); + + return RT_NULL; + } + + RT_DEBUG_NOT_IN_INTERRUPT; + + thread->error = RT_EOK; + + /* need suspend thread */ + rt_thread_suspend(thread); + rt_list_insert_after(&(mp->suspend_thread), &(thread->tlist)); + mp->suspend_thread_count++; + + if (time > 0) + { + /* get the start tick of timer */ + before_sleep = rt_tick_get(); + + /* init thread timer and start it */ + rt_timer_control(&(thread->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &time); + rt_timer_start(&(thread->thread_timer)); + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* do a schedule */ + rt_schedule(); + + if (thread->error != RT_EOK) + return RT_NULL; + + if (time > 0) + { + time -= rt_tick_get() - before_sleep; + if (time < 0) + time = 0; + } + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + } + + /* memory block is available. decrease the free block counter */ + mp->block_free_count--; + + /* get block from block list */ + block_ptr = mp->block_list; + RT_ASSERT(block_ptr != RT_NULL); + + /* Setup the next free node. */ + mp->block_list = *(rt_uint8_t **)block_ptr; + + /* point to memory pool */ + *(rt_uint8_t **)block_ptr = (rt_uint8_t *)mp; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + RT_OBJECT_HOOK_CALL(rt_mp_alloc_hook, + (mp, (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *)))); + + return (rt_uint8_t *)(block_ptr + sizeof(rt_uint8_t *)); +} +RTM_EXPORT(rt_mp_alloc); + +/** + * This function will release a memory block + * + * @param block the address of memory block to be released + */ +void rt_mp_free(void *block) +{ + rt_uint8_t **block_ptr; + struct rt_mempool *mp; + struct rt_thread *thread; + register rt_base_t level; + + /* get the control block of pool which the block belongs to */ + block_ptr = (rt_uint8_t **)((rt_uint8_t *)block - sizeof(rt_uint8_t *)); + mp = (struct rt_mempool *)*block_ptr; + + RT_OBJECT_HOOK_CALL(rt_mp_free_hook, (mp, block)); + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* increase the free block count */ + mp->block_free_count ++; + + /* link the block into the block list */ + *block_ptr = mp->block_list; + mp->block_list = (rt_uint8_t *)block_ptr; + + if (mp->suspend_thread_count > 0) + { + /* get the suspended thread */ + thread = rt_list_entry(mp->suspend_thread.next, + struct rt_thread, + tlist); + + /* set error */ + thread->error = RT_EOK; + + /* resume thread */ + rt_thread_resume(thread); + + /* decrease suspended thread count */ + mp->suspend_thread_count --; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* do a schedule */ + rt_schedule(); + + return; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); +} +RTM_EXPORT(rt_mp_free); + +/**@}*/ + +#endif + diff --git a/rt-thread/src/object.c b/rt-thread/src/object.c new file mode 100644 index 0000000..70b9a5c --- /dev/null +++ b/rt-thread/src/object.c @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-03-14 Bernard the first version + * 2006-04-21 Bernard change the scheduler lock to interrupt lock + * 2006-05-18 Bernard fix the object init bug + * 2006-08-03 Bernard add hook support + * 2007-01-28 Bernard rename RT_OBJECT_Class_Static to RT_Object_Class_Static + * 2010-10-26 yi.qiu add module support in rt_object_allocate and rt_object_free + * 2017-12-10 Bernard Add object_info enum. + * 2018-01-25 Bernard Fix the object find issue when enable MODULE. + */ + +#include +#include + +#ifdef RT_USING_MODULE +#include +#endif + +/* + * define object_info for the number of rt_object_container items. + */ +enum rt_object_info_type +{ + RT_Object_Info_Thread = 0, /**< The object is a thread. */ +#ifdef RT_USING_SEMAPHORE + RT_Object_Info_Semaphore, /**< The object is a semaphore. */ +#endif +#ifdef RT_USING_MUTEX + RT_Object_Info_Mutex, /**< The object is a mutex. */ +#endif +#ifdef RT_USING_EVENT + RT_Object_Info_Event, /**< The object is a event. */ +#endif +#ifdef RT_USING_MAILBOX + RT_Object_Info_MailBox, /**< The object is a mail box. */ +#endif +#ifdef RT_USING_MESSAGEQUEUE + RT_Object_Info_MessageQueue, /**< The object is a message queue. */ +#endif +#ifdef RT_USING_MEMHEAP + RT_Object_Info_MemHeap, /**< The object is a memory heap */ +#endif +#ifdef RT_USING_MEMPOOL + RT_Object_Info_MemPool, /**< The object is a memory pool. */ +#endif +#ifdef RT_USING_DEVICE + RT_Object_Info_Device, /**< The object is a device */ +#endif + RT_Object_Info_Timer, /**< The object is a timer. */ +#ifdef RT_USING_MODULE + RT_Object_Info_Module, /**< The object is a module. */ +#endif + RT_Object_Info_Unknown, /**< The object is unknown. */ +}; + +#define _OBJ_CONTAINER_LIST_INIT(c) \ + {&(rt_object_container[c].object_list), &(rt_object_container[c].object_list)} +static struct rt_object_information rt_object_container[RT_Object_Info_Unknown] = +{ + /* initialize object container - thread */ + {RT_Object_Class_Thread, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread), sizeof(struct rt_thread)}, +#ifdef RT_USING_SEMAPHORE + /* initialize object container - semaphore */ + {RT_Object_Class_Semaphore, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore), sizeof(struct rt_semaphore)}, +#endif +#ifdef RT_USING_MUTEX + /* initialize object container - mutex */ + {RT_Object_Class_Mutex, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex), sizeof(struct rt_mutex)}, +#endif +#ifdef RT_USING_EVENT + /* initialize object container - event */ + {RT_Object_Class_Event, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Event), sizeof(struct rt_event)}, +#endif +#ifdef RT_USING_MAILBOX + /* initialize object container - mailbox */ + {RT_Object_Class_MailBox, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MailBox), sizeof(struct rt_mailbox)}, +#endif +#ifdef RT_USING_MESSAGEQUEUE + /* initialize object container - message queue */ + {RT_Object_Class_MessageQueue, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MessageQueue), sizeof(struct rt_messagequeue)}, +#endif +#ifdef RT_USING_MEMHEAP + /* initialize object container - memory heap */ + {RT_Object_Class_MemHeap, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemHeap), sizeof(struct rt_memheap)}, +#endif +#ifdef RT_USING_MEMPOOL + /* initialize object container - memory pool */ + {RT_Object_Class_MemPool, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemPool), sizeof(struct rt_mempool)}, +#endif +#ifdef RT_USING_DEVICE + /* initialize object container - device */ + {RT_Object_Class_Device, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Device), sizeof(struct rt_device)}, +#endif + /* initialize object container - timer */ + {RT_Object_Class_Timer, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Timer), sizeof(struct rt_timer)}, +#ifdef RT_USING_MODULE + /* initialize object container - module */ + {RT_Object_Class_Module, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Module), sizeof(struct rt_dlmodule)}, +#endif +}; + +#ifdef RT_USING_HOOK +static void (*rt_object_attach_hook)(struct rt_object *object); +static void (*rt_object_detach_hook)(struct rt_object *object); +void (*rt_object_trytake_hook)(struct rt_object *object); +void (*rt_object_take_hook)(struct rt_object *object); +void (*rt_object_put_hook)(struct rt_object *object); + +/** + * @addtogroup Hook + */ + +/**@{*/ + +/** + * This function will set a hook function, which will be invoked when object + * attaches to kernel object system. + * + * @param hook the hook function + */ +void rt_object_attach_sethook(void (*hook)(struct rt_object *object)) +{ + rt_object_attach_hook = hook; +} + +/** + * This function will set a hook function, which will be invoked when object + * detaches from kernel object system. + * + * @param hook the hook function + */ +void rt_object_detach_sethook(void (*hook)(struct rt_object *object)) +{ + rt_object_detach_hook = hook; +} + +/** + * This function will set a hook function, which will be invoked when object + * is taken from kernel object system. + * + * The object is taken means: + * semaphore - semaphore is taken by thread + * mutex - mutex is taken by thread + * event - event is received by thread + * mailbox - mail is received by thread + * message queue - message is received by thread + * + * @param hook the hook function + */ +void rt_object_trytake_sethook(void (*hook)(struct rt_object *object)) +{ + rt_object_trytake_hook = hook; +} + +/** + * This function will set a hook function, which will be invoked when object + * have been taken from kernel object system. + * + * The object have been taken means: + * semaphore - semaphore have been taken by thread + * mutex - mutex have been taken by thread + * event - event have been received by thread + * mailbox - mail have been received by thread + * message queue - message have been received by thread + * timer - timer is started + * + * @param hook the hook function + */ +void rt_object_take_sethook(void (*hook)(struct rt_object *object)) +{ + rt_object_take_hook = hook; +} + +/** + * This function will set a hook function, which will be invoked when object + * is put to kernel object system. + * + * @param hook the hook function + */ +void rt_object_put_sethook(void (*hook)(struct rt_object *object)) +{ + rt_object_put_hook = hook; +} + +/**@}*/ +#endif + +/** + * @ingroup SystemInit + * + * This function will initialize system object management. + * + * @deprecated since 0.3.0, this function does not need to be invoked + * in the system initialization. + */ +void rt_system_object_init(void) +{ +} + +/** + * @addtogroup KernelObject + */ + +/**@{*/ + +/** + * This function will return the specified type of object information. + * + * @param type the type of object + * @return the object type information or RT_NULL + */ +struct rt_object_information * +rt_object_get_information(enum rt_object_class_type type) +{ + int index; + + for (index = 0; index < RT_Object_Info_Unknown; index ++) + if (rt_object_container[index].type == type) return &rt_object_container[index]; + + return RT_NULL; +} +RTM_EXPORT(rt_object_get_information); + +/** + * This function will initialize an object and add it to object system + * management. + * + * @param object the specified object to be initialized. + * @param type the object type. + * @param name the object name. In system, the object's name must be unique. + */ +void rt_object_init(struct rt_object *object, + enum rt_object_class_type type, + const char *name) +{ + register rt_base_t temp; + struct rt_object_information *information; +#ifdef RT_USING_MODULE + struct rt_dlmodule *module = dlmodule_self(); +#endif + + /* get object information */ + information = rt_object_get_information(type); + RT_ASSERT(information != RT_NULL); + + /* initialize object's parameters */ + + /* set object type to static */ + object->type = type | RT_Object_Class_Static; + + /* copy name */ + rt_strncpy(object->name, name, RT_NAME_MAX); + + RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object)); + + /* lock interrupt */ + temp = rt_hw_interrupt_disable(); + +#ifdef RT_USING_MODULE + if (module) + { + rt_list_insert_after(&(module->object_list), &(object->list)); + object->module_id = (void *)module; + } + else +#endif + { + /* insert object into information object list */ + rt_list_insert_after(&(information->object_list), &(object->list)); + } + + /* unlock interrupt */ + rt_hw_interrupt_enable(temp); +} + +/** + * This function will detach a static object from object system, + * and the memory of static object is not freed. + * + * @param object the specified object to be detached. + */ +void rt_object_detach(rt_object_t object) +{ + register rt_base_t temp; + + /* object check */ + RT_ASSERT(object != RT_NULL); + + RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object)); + + /* reset object type */ + object->type = 0; + + /* lock interrupt */ + temp = rt_hw_interrupt_disable(); + + /* remove from old list */ + rt_list_remove(&(object->list)); + + /* unlock interrupt */ + rt_hw_interrupt_enable(temp); +} + +#ifdef RT_USING_HEAP +/** + * This function will allocate an object from object system + * + * @param type the type of object + * @param name the object name. In system, the object's name must be unique. + * + * @return object + */ +rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name) +{ + struct rt_object *object; + register rt_base_t temp; + struct rt_object_information *information; +#ifdef RT_USING_MODULE + struct rt_dlmodule *module = dlmodule_self(); +#endif + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* get object information */ + information = rt_object_get_information(type); + RT_ASSERT(information != RT_NULL); + + object = (struct rt_object *)RT_KERNEL_MALLOC(information->object_size); + if (object == RT_NULL) + { + /* no memory can be allocated */ + return RT_NULL; + } + + /* clean memory data of object */ + rt_memset(object, 0x0, information->object_size); + + /* initialize object's parameters */ + + /* set object type */ + object->type = type; + + /* set object flag */ + object->flag = 0; + + /* copy name */ + rt_strncpy(object->name, name, RT_NAME_MAX); + + RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object)); + + /* lock interrupt */ + temp = rt_hw_interrupt_disable(); + +#ifdef RT_USING_MODULE + if (module) + { + rt_list_insert_after(&(module->object_list), &(object->list)); + object->module_id = (void *)module; + } + else +#endif + { + /* insert object into information object list */ + rt_list_insert_after(&(information->object_list), &(object->list)); + } + + /* unlock interrupt */ + rt_hw_interrupt_enable(temp); + + /* return object */ + return object; +} + +/** + * This function will delete an object and release object memory. + * + * @param object the specified object to be deleted. + */ +void rt_object_delete(rt_object_t object) +{ + register rt_base_t temp; + + /* object check */ + RT_ASSERT(object != RT_NULL); + RT_ASSERT(!(object->type & RT_Object_Class_Static)); + + RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object)); + + /* reset object type */ + object->type = 0; + + /* lock interrupt */ + temp = rt_hw_interrupt_disable(); + + /* remove from old list */ + rt_list_remove(&(object->list)); + + /* unlock interrupt */ + rt_hw_interrupt_enable(temp); + + /* free the memory of object */ + RT_KERNEL_FREE(object); +} +#endif + +/** + * This function will judge the object is system object or not. + * Normally, the system object is a static object and the type + * of object set to RT_Object_Class_Static. + * + * @param object the specified object to be judged. + * + * @return RT_TRUE if a system object, RT_FALSE for others. + */ +rt_bool_t rt_object_is_systemobject(rt_object_t object) +{ + /* object check */ + RT_ASSERT(object != RT_NULL); + + if (object->type & RT_Object_Class_Static) + return RT_TRUE; + + return RT_FALSE; +} + +/** + * This function will return the type of object without + * RT_Object_Class_Static flag. + * + * @param object the specified object to be get type. + * + * @return the type of object. + */ +rt_uint8_t rt_object_get_type(rt_object_t object) +{ + /* object check */ + RT_ASSERT(object != RT_NULL); + + return object->type & ~RT_Object_Class_Static; +} + +/** + * This function will find specified name object from object + * container. + * + * @param name the specified name of object. + * @param type the type of object + * + * @return the found object or RT_NULL if there is no this object + * in object container. + * + * @note this function shall not be invoked in interrupt status. + */ +rt_object_t rt_object_find(const char *name, rt_uint8_t type) +{ + struct rt_object *object = RT_NULL; + struct rt_list_node *node = RT_NULL; + struct rt_object_information *information = RT_NULL; + + /* parameter check */ + if ((name == RT_NULL) || (type > RT_Object_Class_Unknown)) + return RT_NULL; + + /* which is invoke in interrupt status */ + RT_DEBUG_NOT_IN_INTERRUPT; + + /* enter critical */ + rt_enter_critical(); + + /* try to find object */ + if (information == RT_NULL) + { + information = rt_object_get_information((enum rt_object_class_type)type); + RT_ASSERT(information != RT_NULL); + } + for (node = information->object_list.next; + node != &(information->object_list); + node = node->next) + { + object = rt_list_entry(node, struct rt_object, list); + if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0) + { + /* leave critical */ + rt_exit_critical(); + + return object; + } + } + + /* leave critical */ + rt_exit_critical(); + + return RT_NULL; +} + +/**@}*/ diff --git a/rt-thread/src/scheduler.c b/rt-thread/src/scheduler.c new file mode 100644 index 0000000..95b5d48 --- /dev/null +++ b/rt-thread/src/scheduler.c @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-03-17 Bernard the first version + * 2006-04-28 Bernard fix the scheduler algorthm + * 2006-04-30 Bernard add SCHEDULER_DEBUG + * 2006-05-27 Bernard fix the scheduler algorthm for same priority + * thread schedule + * 2006-06-04 Bernard rewrite the scheduler algorithm + * 2006-08-03 Bernard add hook support + * 2006-09-05 Bernard add 32 priority level support + * 2006-09-24 Bernard add rt_system_scheduler_start function + * 2009-09-16 Bernard fix _rt_scheduler_stack_check + * 2010-04-11 yi.qiu add module feature + * 2010-07-13 Bernard fix the maximal number of rt_scheduler_lock_nest + * issue found by kuronca + * 2010-12-13 Bernard add defunct list initialization even if not use heap. + * 2011-05-10 Bernard clean scheduler debug log. + * 2013-12-21 Grissiom add rt_critical_level + */ + +#include +#include + +static rt_int16_t rt_scheduler_lock_nest; +extern volatile rt_uint8_t rt_interrupt_nest; + +rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; +struct rt_thread *rt_current_thread; + +rt_uint8_t rt_current_priority; + +#if RT_THREAD_PRIORITY_MAX > 32 +/* Maximum priority level, 256 */ +rt_uint32_t rt_thread_ready_priority_group; +rt_uint8_t rt_thread_ready_table[32]; +#else +/* Maximum priority level, 32 */ +rt_uint32_t rt_thread_ready_priority_group; +#endif + +rt_list_t rt_thread_defunct; + +#ifdef RT_USING_HOOK +static void (*rt_scheduler_hook)(struct rt_thread *from, struct rt_thread *to); + +/** + * @addtogroup Hook + */ + +/**@{*/ + +/** + * This function will set a hook function, which will be invoked when thread + * switch happens. + * + * @param hook the hook function + */ +void +rt_scheduler_sethook(void (*hook)(struct rt_thread *from, struct rt_thread *to)) +{ + rt_scheduler_hook = hook; +} + +/**@}*/ +#endif + +#ifdef RT_USING_OVERFLOW_CHECK +static void _rt_scheduler_stack_check(struct rt_thread *thread) +{ + RT_ASSERT(thread != RT_NULL); + + if (*((rt_uint8_t *)thread->stack_addr) != '#' || + (rt_uint32_t)thread->sp <= (rt_uint32_t)thread->stack_addr || + (rt_uint32_t)thread->sp > + (rt_uint32_t)thread->stack_addr + (rt_uint32_t)thread->stack_size) + { + rt_uint32_t level; + + rt_kprintf("thread:%s stack overflow\n", thread->name); +#ifdef RT_USING_FINSH + { + extern long list_thread(void); + list_thread(); + } +#endif + level = rt_hw_interrupt_disable(); + while (level); + } + else if ((rt_uint32_t)thread->sp <= ((rt_uint32_t)thread->stack_addr + 32)) + { + rt_kprintf("warning: %s stack is close to end of stack address.\n", + thread->name); + } +} +#endif + +/** + * @ingroup SystemInit + * This function will initialize the system scheduler + */ +void rt_system_scheduler_init(void) +{ + register rt_base_t offset; + + rt_scheduler_lock_nest = 0; + + RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("start scheduler: max priority 0x%02x\n", + RT_THREAD_PRIORITY_MAX)); + + for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++) + { + rt_list_init(&rt_thread_priority_table[offset]); + } + + rt_current_priority = RT_THREAD_PRIORITY_MAX - 1; + rt_current_thread = RT_NULL; + + /* initialize ready priority group */ + rt_thread_ready_priority_group = 0; + +#if RT_THREAD_PRIORITY_MAX > 32 + /* initialize ready table */ + rt_memset(rt_thread_ready_table, 0, sizeof(rt_thread_ready_table)); +#endif + + /* initialize thread defunct */ + rt_list_init(&rt_thread_defunct); +} + +/** + * @ingroup SystemInit + * This function will startup scheduler. It will select one thread + * with the highest priority level, then switch to it. + */ +void rt_system_scheduler_start(void) +{ + register struct rt_thread *to_thread; + register rt_ubase_t highest_ready_priority; + +#if RT_THREAD_PRIORITY_MAX > 32 + register rt_ubase_t number; + + number = __rt_ffs(rt_thread_ready_priority_group) - 1; + highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1; +#else + highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1; +#endif + + /* get switch to thread */ + to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next, + struct rt_thread, + tlist); + + rt_current_thread = to_thread; + + /* switch to new thread */ + rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp); + + /* never come back */ +} + +/** + * @addtogroup Thread + */ + +/**@{*/ + +/** + * This function will perform one schedule. It will select one thread + * with the highest priority level, then switch to it. + */ +void rt_schedule(void) +{ + rt_base_t level; + struct rt_thread *to_thread; + struct rt_thread *from_thread; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* check the scheduler is enabled or not */ + if (rt_scheduler_lock_nest == 0) + { + register rt_ubase_t highest_ready_priority; + +#if RT_THREAD_PRIORITY_MAX <= 32 + highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1; +#else + register rt_ubase_t number; + + number = __rt_ffs(rt_thread_ready_priority_group) - 1; + highest_ready_priority = (number << 3) + __rt_ffs(rt_thread_ready_table[number]) - 1; +#endif + + /* get switch to thread */ + to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next, + struct rt_thread, + tlist); + + /* if the destination thread is not the same as current thread */ + if (to_thread != rt_current_thread) + { + rt_current_priority = (rt_uint8_t)highest_ready_priority; + from_thread = rt_current_thread; + rt_current_thread = to_thread; + + RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (from_thread, to_thread)); + + /* switch to new thread */ + RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, + ("[%d]switch to priority#%d " + "thread:%.*s(sp:0x%p), " + "from thread:%.*s(sp: 0x%p)\n", + rt_interrupt_nest, highest_ready_priority, + RT_NAME_MAX, to_thread->name, to_thread->sp, + RT_NAME_MAX, from_thread->name, from_thread->sp)); + +#ifdef RT_USING_OVERFLOW_CHECK + _rt_scheduler_stack_check(to_thread); +#endif + + if (rt_interrupt_nest == 0) + { + extern void rt_thread_handle_sig(rt_bool_t clean_state); + + rt_hw_context_switch((rt_uint32_t)&from_thread->sp, + (rt_uint32_t)&to_thread->sp); + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + +#ifdef RT_USING_SIGNALS + /* check signal status */ + rt_thread_handle_sig(RT_TRUE); +#endif + } + else + { + RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("switch in interrupt\n")); + + rt_hw_context_switch_interrupt((rt_uint32_t)&from_thread->sp, + (rt_uint32_t)&to_thread->sp); + /* enable interrupt */ + rt_hw_interrupt_enable(level); + } + } + else + { + /* enable interrupt */ + rt_hw_interrupt_enable(level); + } + } + else + { + /* enable interrupt */ + rt_hw_interrupt_enable(level); + } +} + +/* + * This function will insert a thread to system ready queue. The state of + * thread will be set as READY and remove from suspend queue. + * + * @param thread the thread to be inserted + * @note Please do not invoke this function in user application. + */ +void rt_schedule_insert_thread(struct rt_thread *thread) +{ + register rt_base_t temp; + + RT_ASSERT(thread != RT_NULL); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* change stat */ + thread->stat = RT_THREAD_READY | (thread->stat & ~RT_THREAD_STAT_MASK); + + /* insert thread to ready list */ + rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]), + &(thread->tlist)); + + /* set priority mask */ +#if RT_THREAD_PRIORITY_MAX <= 32 + RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("insert thread[%.*s], the priority: %d\n", + RT_NAME_MAX, thread->name, thread->current_priority)); +#else + RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, + ("insert thread[%.*s], the priority: %d 0x%x %d\n", + RT_NAME_MAX, + thread->name, + thread->number, + thread->number_mask, + thread->high_mask)); +#endif + +#if RT_THREAD_PRIORITY_MAX > 32 + rt_thread_ready_table[thread->number] |= thread->high_mask; +#endif + rt_thread_ready_priority_group |= thread->number_mask; + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); +} + +/* + * This function will remove a thread from system ready queue. + * + * @param thread the thread to be removed + * + * @note Please do not invoke this function in user application. + */ +void rt_schedule_remove_thread(struct rt_thread *thread) +{ + register rt_base_t temp; + + RT_ASSERT(thread != RT_NULL); + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + +#if RT_THREAD_PRIORITY_MAX <= 32 + RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, ("remove thread[%.*s], the priority: %d\n", + RT_NAME_MAX, thread->name, + thread->current_priority)); +#else + RT_DEBUG_LOG(RT_DEBUG_SCHEDULER, + ("remove thread[%.*s], the priority: %d 0x%x %d\n", + RT_NAME_MAX, + thread->name, + thread->number, + thread->number_mask, + thread->high_mask)); +#endif + + /* remove thread from ready list */ + rt_list_remove(&(thread->tlist)); + if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority]))) + { +#if RT_THREAD_PRIORITY_MAX > 32 + rt_thread_ready_table[thread->number] &= ~thread->high_mask; + if (rt_thread_ready_table[thread->number] == 0) + { + rt_thread_ready_priority_group &= ~thread->number_mask; + } +#else + rt_thread_ready_priority_group &= ~thread->number_mask; +#endif + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); +} + +/** + * This function will lock the thread scheduler. + */ +void rt_enter_critical(void) +{ + register rt_base_t level; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* + * the maximal number of nest is RT_UINT16_MAX, which is big + * enough and does not check here + */ + rt_scheduler_lock_nest ++; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); +} +RTM_EXPORT(rt_enter_critical); + +/** + * This function will unlock the thread scheduler. + */ +void rt_exit_critical(void) +{ + register rt_base_t level; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + rt_scheduler_lock_nest --; + + if (rt_scheduler_lock_nest <= 0) + { + rt_scheduler_lock_nest = 0; + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_schedule(); + } + else + { + /* enable interrupt */ + rt_hw_interrupt_enable(level); + } +} +RTM_EXPORT(rt_exit_critical); + +/** + * Get the scheduler lock level + * + * @return the level of the scheduler lock. 0 means unlocked. + */ +rt_uint16_t rt_critical_level(void) +{ + return rt_scheduler_lock_nest; +} +RTM_EXPORT(rt_critical_level); +/**@}*/ + diff --git a/rt-thread/src/signal.c b/rt-thread/src/signal.c new file mode 100644 index 0000000..c783420 --- /dev/null +++ b/rt-thread/src/signal.c @@ -0,0 +1,486 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2017/10/5 Bernard the first version + */ + +#include +#include + +#include +#include + +#ifdef RT_USING_SIGNALS + +#ifndef RT_SIG_INFO_MAX +#define RT_SIG_INFO_MAX 32 +#endif + +// #define DBG_ENABLE +#define DBG_SECTION_NAME "SIGN" +#define DBG_COLOR +#define DBG_LEVEL DBG_LOG +#include + +#define sig_mask(sig_no) (1u << sig_no) +#define sig_valid(sig_no) (sig_no >= 0 && sig_no < RT_SIG_MAX) + +struct siginfo_node +{ + siginfo_t si; + struct rt_slist_node list; +}; + +static struct rt_mempool *_rt_siginfo_pool; +static void _signal_deliver(rt_thread_t tid); +void rt_thread_handle_sig(rt_bool_t clean_state); + +static void _signal_default_handler(int signo) +{ + dbg_log(DBG_INFO, "handled signo[%d] with default action.\n", signo); + return ; +} + +static void _signal_entry(void *parameter) +{ + rt_thread_t tid = rt_thread_self(); + + dbg_enter; + + /* handle signal */ + rt_thread_handle_sig(RT_FALSE); + + /* never come back... */ + rt_hw_interrupt_disable(); + /* return to thread */ + tid->sp = tid->sig_ret; + tid->sig_ret = RT_NULL; + + dbg_log(DBG_LOG, "switch back to: 0x%08x\n", tid->sp); + tid->stat &= ~RT_THREAD_STAT_SIGNAL; + + rt_hw_context_switch_to((rt_uint32_t) & (tid->sp)); +} + +/* + * To deliver a signal to thread, there are cases: + * 1. When thread is suspended, function resumes thread and + * set signal stat; + * 2. When thread is ready: + * - If function delivers a signal to self thread, just handle + * it. + * - If function delivers a signal to another ready thread, OS + * should build a slice context to handle it. + */ +static void _signal_deliver(rt_thread_t tid) +{ + rt_ubase_t level; + + /* thread is not interested in pended signals */ + if (!(tid->sig_pending & tid->sig_mask)) return; + + level = rt_hw_interrupt_disable(); + if ((tid->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND) + { + /* resume thread to handle signal */ + rt_thread_resume(tid); + /* add signal state */ + tid->stat |= RT_THREAD_STAT_SIGNAL; + + rt_hw_interrupt_enable(level); + + /* re-schedule */ + rt_schedule(); + } + else + { + if (tid == rt_thread_self()) + { + /* add signal state */ + tid->stat |= RT_THREAD_STAT_SIGNAL; + + rt_hw_interrupt_enable(level); + + /* do signal action in self thread context */ + rt_thread_handle_sig(RT_TRUE); + } + else if (!((tid->stat & RT_THREAD_STAT_MASK) & RT_THREAD_STAT_SIGNAL)) + { + /* add signal state */ + tid->stat |= RT_THREAD_STAT_SIGNAL; + + /* point to the signal handle entry */ + tid->sig_ret = tid->sp; + tid->sp = rt_hw_stack_init((void *)_signal_entry, RT_NULL, + (void *)((char *)tid->sig_ret - 32), RT_NULL); + + rt_hw_interrupt_enable(level); + dbg_log(DBG_LOG, "signal stack pointer @ 0x%08x\n", tid->sp); + + /* re-schedule */ + rt_schedule(); + } + else + { + rt_hw_interrupt_enable(level); + } + } +} + +rt_sighandler_t rt_signal_install(int signo, rt_sighandler_t handler) +{ + rt_sighandler_t old = RT_NULL; + rt_thread_t tid = rt_thread_self(); + + if (!sig_valid(signo)) return SIG_ERR; + + rt_enter_critical(); + if (tid->sig_vectors == RT_NULL) + { + rt_thread_alloc_sig(tid); + } + + if (tid->sig_vectors) + { + old = tid->sig_vectors[signo]; + + if (handler == SIG_IGN) tid->sig_vectors[signo] = RT_NULL; + else if (handler == SIG_DFL) tid->sig_vectors[signo] = _signal_default_handler; + else tid->sig_vectors[signo] = handler; + } + rt_exit_critical(); + + return old; +} + +void rt_signal_mask(int signo) +{ + rt_base_t level; + rt_thread_t tid = rt_thread_self(); + + level = rt_hw_interrupt_disable(); + + tid->sig_mask &= ~sig_mask(signo); + + rt_hw_interrupt_enable(level); +} + +void rt_signal_unmask(int signo) +{ + rt_base_t level; + rt_thread_t tid = rt_thread_self(); + + level = rt_hw_interrupt_disable(); + + tid->sig_mask |= sig_mask(signo); + + /* let thread handle pended signals */ + if (tid->sig_mask & tid->sig_pending) + { + rt_hw_interrupt_enable(level); + _signal_deliver(tid); + } + else + { + rt_hw_interrupt_enable(level); + } +} + +int rt_signal_wait(const rt_sigset_t *set, rt_siginfo_t *si, rt_int32_t timeout) +{ + int ret = RT_EOK; + rt_base_t level; + rt_thread_t tid = rt_thread_self(); + struct siginfo_node *si_node = RT_NULL, *si_prev = RT_NULL; + + /* current context checking */ + RT_DEBUG_IN_THREAD_CONTEXT; + + /* parameters check */ + if (set == NULL || *set == 0 || si == NULL ) + { + ret = -RT_EINVAL; + goto __done_return; + } + + /* clear siginfo to avoid unknown value */ + memset(si, 0x0, sizeof(rt_siginfo_t)); + + level = rt_hw_interrupt_disable(); + + /* already pending */ + if (tid->sig_pending & *set) goto __done; + + if (timeout == 0) + { + ret = -RT_ETIMEOUT; + goto __done_int; + } + + /* suspend self thread */ + rt_thread_suspend(tid); + /* set thread stat as waiting for signal */ + tid->stat |= RT_THREAD_STAT_SIGNAL_WAIT; + + /* start timeout timer */ + if (timeout != RT_WAITING_FOREVER) + { + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(tid->thread_timer), + RT_TIMER_CTRL_SET_TIME, + &timeout); + rt_timer_start(&(tid->thread_timer)); + } + rt_hw_interrupt_enable(level); + + /* do thread scheduling */ + rt_schedule(); + + level = rt_hw_interrupt_disable(); + + /* remove signal waiting flag */ + tid->stat &= ~RT_THREAD_STAT_SIGNAL_WAIT; + + /* check errno of thread */ + if (tid->error == -RT_ETIMEOUT) + { + tid->error = RT_EOK; + rt_hw_interrupt_enable(level); + + /* timer timeout */ + ret = -RT_ETIMEOUT; + goto __done_return; + } + +__done: + /* to get the first matched pending signals */ + si_node = (struct siginfo_node *)tid->si_list; + while (si_node) + { + int signo; + + signo = si_node->si.si_signo; + if (sig_mask(signo) & *set) + { + *si = si_node->si; + + dbg_log(DBG_LOG, "sigwait: %d sig raised!\n", signo); + if (si_prev) si_prev->list.next = si_node->list.next; + else tid->si_list = si_node->list.next; + + /* clear pending */ + tid->sig_pending &= ~sig_mask(signo); + rt_mp_free(si_node); + break; + } + + si_prev = si_node; + si_node = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list); + } + +__done_int: + rt_hw_interrupt_enable(level); + +__done_return: + return ret; +} + +void rt_thread_handle_sig(rt_bool_t clean_state) +{ + rt_base_t level; + + rt_thread_t tid = rt_thread_self(); + struct siginfo_node *si_node; + + level = rt_hw_interrupt_disable(); + if (tid->sig_pending & tid->sig_mask) + { + /* if thread is not waiting for signal */ + if (!(tid->stat & RT_THREAD_STAT_SIGNAL_WAIT)) + { + while (tid->sig_pending & tid->sig_mask) + { + int signo, error; + rt_sighandler_t handler; + + si_node = (struct siginfo_node *)tid->si_list; + if (!si_node) break; + + /* remove this sig info node from list */ + if (si_node->list.next == RT_NULL) + tid->si_list = RT_NULL; + else + tid->si_list = (void *)rt_slist_entry(si_node->list.next, struct siginfo_node, list); + + signo = si_node->si.si_signo; + handler = tid->sig_vectors[signo]; + rt_hw_interrupt_enable(level); + + dbg_log(DBG_LOG, "handle signal: %d, handler 0x%08x\n", signo, handler); + if (handler) handler(signo); + + level = rt_hw_interrupt_disable(); + tid->sig_pending &= ~sig_mask(signo); + error = -RT_EINTR; + + rt_mp_free(si_node); /* release this siginfo node */ + /* set errno in thread tcb */ + tid->error = error; + } + + /* whether clean signal status */ + if (clean_state == RT_TRUE) tid->stat &= ~RT_THREAD_STAT_SIGNAL; + } + } + + rt_hw_interrupt_enable(level); +} + +void rt_thread_alloc_sig(rt_thread_t tid) +{ + int index; + rt_base_t level; + rt_sighandler_t *vectors; + + vectors = (rt_sighandler_t *)RT_KERNEL_MALLOC(sizeof(rt_sighandler_t) * RT_SIG_MAX); + RT_ASSERT(vectors != RT_NULL); + + for (index = 0; index < RT_SIG_MAX; index ++) + { + vectors[index] = _signal_default_handler; + } + + level = rt_hw_interrupt_disable(); + tid->sig_vectors = vectors; + rt_hw_interrupt_enable(level); +} + +void rt_thread_free_sig(rt_thread_t tid) +{ + rt_base_t level; + struct siginfo_node *si_list; + rt_sighandler_t *sig_vectors; + + level = rt_hw_interrupt_disable(); + si_list = (struct siginfo_node *)tid->si_list; + tid->si_list = RT_NULL; + + sig_vectors = tid->sig_vectors; + tid->sig_vectors = RT_NULL; + rt_hw_interrupt_enable(level); + + if (si_list) + { + struct rt_slist_node *node; + struct siginfo_node *si_node; + + dbg_log(DBG_LOG, "free signal info list\n"); + node = &(si_list->list); + do + { + si_node = rt_slist_entry(node, struct siginfo_node, list); + rt_mp_free(si_node); + + node = node->next; + } while (node); + } + + if (sig_vectors) + { + RT_KERNEL_FREE(sig_vectors); + } +} + +int rt_thread_kill(rt_thread_t tid, int sig) +{ + siginfo_t si; + rt_base_t level; + struct siginfo_node *si_node; + + RT_ASSERT(tid != RT_NULL); + if (!sig_valid(sig)) return -RT_EINVAL; + + dbg_log(DBG_INFO, "send signal: %d\n", sig); + si.si_signo = sig; + si.si_code = SI_USER; + si.si_value.sival_ptr = RT_NULL; + + level = rt_hw_interrupt_disable(); + if (tid->sig_pending & sig_mask(sig)) + { + /* whether already emits this signal? */ + struct rt_slist_node *node; + struct siginfo_node *entry; + + node = (struct rt_slist_node *)tid->si_list; + rt_hw_interrupt_enable(level); + + /* update sig info */ + rt_enter_critical(); + for (; (node) != RT_NULL; node = node->next) + { + entry = rt_slist_entry(node, struct siginfo_node, list); + if (entry->si.si_signo == sig) + { + memcpy(&(entry->si), &si, sizeof(siginfo_t)); + rt_exit_critical(); + return 0; + } + } + rt_exit_critical(); + + /* disable interrupt to protect tcb */ + level = rt_hw_interrupt_disable(); + } + else + { + /* a new signal */ + tid->sig_pending |= sig_mask(sig); + } + rt_hw_interrupt_enable(level); + + si_node = (struct siginfo_node *) rt_mp_alloc(_rt_siginfo_pool, 0); + if (si_node) + { + rt_slist_init(&(si_node->list)); + memcpy(&(si_node->si), &si, sizeof(siginfo_t)); + + level = rt_hw_interrupt_disable(); + if (!tid->si_list) tid->si_list = si_node; + else + { + struct siginfo_node *si_list; + + si_list = (struct siginfo_node *)tid->si_list; + rt_slist_append(&(si_list->list), &(si_node->list)); + } + rt_hw_interrupt_enable(level); + } + else + { + dbg_log(DBG_ERROR, "The allocation of signal info node failed.\n"); + } + + /* deliver signal to this thread */ + _signal_deliver(tid); + + return RT_EOK; +} + +int rt_system_signal_init(void) +{ + _rt_siginfo_pool = rt_mp_create("signal", RT_SIG_INFO_MAX, sizeof(struct siginfo_node)); + if (_rt_siginfo_pool == RT_NULL) + { + dbg_log(DBG_ERROR, "create memory pool for signal info failed.\n"); + RT_ASSERT(0); + } + + return 0; +} + +#endif diff --git a/rt-thread/src/slab.c b/rt-thread/src/slab.c new file mode 100644 index 0000000..bf26c84 --- /dev/null +++ b/rt-thread/src/slab.c @@ -0,0 +1,937 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * File : slab.c + * + * Change Logs: + * Date Author Notes + * 2008-07-12 Bernard the first version + * 2010-07-13 Bernard fix RT_ALIGN issue found by kuronca + * 2010-10-23 yi.qiu add module memory allocator + * 2010-12-18 yi.qiu fix zone release bug + */ + +/* + * KERN_SLABALLOC.C - Kernel SLAB memory allocator + * + * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. + * + * This code is derived from software contributed to The DragonFly Project + * by Matthew Dillon + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name of The DragonFly Project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific, prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +#include + +#define RT_MEM_STATS + +#if defined (RT_USING_HEAP) && defined (RT_USING_SLAB) +/* some statistical variable */ +#ifdef RT_MEM_STATS +static rt_size_t used_mem, max_mem; +#endif + +#ifdef RT_USING_HOOK +static void (*rt_malloc_hook)(void *ptr, rt_size_t size); +static void (*rt_free_hook)(void *ptr); + +/** + * @addtogroup Hook + */ + +/**@{*/ + +/** + * This function will set a hook function, which will be invoked when a memory + * block is allocated from heap memory. + * + * @param hook the hook function + */ +void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size)) +{ + rt_malloc_hook = hook; +} +RTM_EXPORT(rt_malloc_sethook); + +/** + * This function will set a hook function, which will be invoked when a memory + * block is released to heap memory. + * + * @param hook the hook function + */ +void rt_free_sethook(void (*hook)(void *ptr)) +{ + rt_free_hook = hook; +} +RTM_EXPORT(rt_free_sethook); + +/**@}*/ + +#endif + +/* + * slab allocator implementation + * + * A slab allocator reserves a ZONE for each chunk size, then lays the + * chunks out in an array within the zone. Allocation and deallocation + * is nearly instantanious, and fragmentation/overhead losses are limited + * to a fixed worst-case amount. + * + * The downside of this slab implementation is in the chunk size + * multiplied by the number of zones. ~80 zones * 128K = 10MB of VM per cpu. + * In a kernel implementation all this memory will be physical so + * the zone size is adjusted downward on machines with less physical + * memory. The upside is that overhead is bounded... this is the *worst* + * case overhead. + * + * Slab management is done on a per-cpu basis and no locking or mutexes + * are required, only a critical section. When one cpu frees memory + * belonging to another cpu's slab manager an asynchronous IPI message + * will be queued to execute the operation. In addition, both the + * high level slab allocator and the low level zone allocator optimize + * M_ZERO requests, and the slab allocator does not have to pre initialize + * the linked list of chunks. + * + * XXX Balancing is needed between cpus. Balance will be handled through + * asynchronous IPIs primarily by reassigning the z_Cpu ownership of chunks. + * + * XXX If we have to allocate a new zone and M_USE_RESERVE is set, use of + * the new zone should be restricted to M_USE_RESERVE requests only. + * + * Alloc Size Chunking Number of zones + * 0-127 8 16 + * 128-255 16 8 + * 256-511 32 8 + * 512-1023 64 8 + * 1024-2047 128 8 + * 2048-4095 256 8 + * 4096-8191 512 8 + * 8192-16383 1024 8 + * 16384-32767 2048 8 + * (if RT_MM_PAGE_SIZE is 4K the maximum zone allocation is 16383) + * + * Allocations >= zone_limit go directly to kmem. + * + * API REQUIREMENTS AND SIDE EFFECTS + * + * To operate as a drop-in replacement to the FreeBSD-4.x malloc() we + * have remained compatible with the following API requirements: + * + * + small power-of-2 sized allocations are power-of-2 aligned (kern_tty) + * + all power-of-2 sized allocations are power-of-2 aligned (twe) + * + malloc(0) is allowed and returns non-RT_NULL (ahc driver) + * + ability to allocate arbitrarily large chunks of memory + */ + +/* + * Chunk structure for free elements + */ +typedef struct slab_chunk +{ + struct slab_chunk *c_next; +} slab_chunk; + +/* + * The IN-BAND zone header is placed at the beginning of each zone. + */ +typedef struct slab_zone +{ + rt_int32_t z_magic; /* magic number for sanity check */ + rt_int32_t z_nfree; /* total free chunks / ualloc space in zone */ + rt_int32_t z_nmax; /* maximum free chunks */ + + struct slab_zone *z_next; /* zoneary[] link if z_nfree non-zero */ + rt_uint8_t *z_baseptr; /* pointer to start of chunk array */ + + rt_int32_t z_uindex; /* current initial allocation index */ + rt_int32_t z_chunksize; /* chunk size for validation */ + + rt_int32_t z_zoneindex; /* zone index */ + slab_chunk *z_freechunk; /* free chunk list */ +} slab_zone; + +#define ZALLOC_SLAB_MAGIC 0x51ab51ab +#define ZALLOC_ZONE_LIMIT (16 * 1024) /* max slab-managed alloc */ +#define ZALLOC_MIN_ZONE_SIZE (32 * 1024) /* minimum zone size */ +#define ZALLOC_MAX_ZONE_SIZE (128 * 1024) /* maximum zone size */ +#define NZONES 72 /* number of zones */ +#define ZONE_RELEASE_THRESH 2 /* threshold number of zones */ + +static slab_zone *zone_array[NZONES]; /* linked list of zones NFree > 0 */ +static slab_zone *zone_free; /* whole zones that have become free */ + +static int zone_free_cnt; +static int zone_size; +static int zone_limit; +static int zone_page_cnt; + +/* + * Misc constants. Note that allocations that are exact multiples of + * RT_MM_PAGE_SIZE, or exceed the zone limit, fall through to the kmem module. + */ +#define MIN_CHUNK_SIZE 8 /* in bytes */ +#define MIN_CHUNK_MASK (MIN_CHUNK_SIZE - 1) + +/* + * Array of descriptors that describe the contents of each page + */ +#define PAGE_TYPE_FREE 0x00 +#define PAGE_TYPE_SMALL 0x01 +#define PAGE_TYPE_LARGE 0x02 +struct memusage +{ + rt_uint32_t type: 2 ; /* page type */ + rt_uint32_t size: 30; /* pages allocated or offset from zone */ +}; +static struct memusage *memusage = RT_NULL; +#define btokup(addr) \ + (&memusage[((rt_uint32_t)(addr) - heap_start) >> RT_MM_PAGE_BITS]) + +static rt_uint32_t heap_start, heap_end; + +/* page allocator */ +struct rt_page_head +{ + struct rt_page_head *next; /* next valid page */ + rt_size_t page; /* number of page */ + + /* dummy */ + char dummy[RT_MM_PAGE_SIZE - (sizeof(struct rt_page_head *) + sizeof(rt_size_t))]; +}; +static struct rt_page_head *rt_page_list; +static struct rt_semaphore heap_sem; + +void *rt_page_alloc(rt_size_t npages) +{ + struct rt_page_head *b, *n; + struct rt_page_head **prev; + + if (npages == 0) + return RT_NULL; + + /* lock heap */ + rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + for (prev = &rt_page_list; (b = *prev) != RT_NULL; prev = &(b->next)) + { + if (b->page > npages) + { + /* splite pages */ + n = b + npages; + n->next = b->next; + n->page = b->page - npages; + *prev = n; + break; + } + + if (b->page == npages) + { + /* this node fit, remove this node */ + *prev = b->next; + break; + } + } + + /* unlock heap */ + rt_sem_release(&heap_sem); + + return b; +} + +void rt_page_free(void *addr, rt_size_t npages) +{ + struct rt_page_head *b, *n; + struct rt_page_head **prev; + + RT_ASSERT(addr != RT_NULL); + RT_ASSERT((rt_uint32_t)addr % RT_MM_PAGE_SIZE == 0); + RT_ASSERT(npages != 0); + + n = (struct rt_page_head *)addr; + + /* lock heap */ + rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + + for (prev = &rt_page_list; (b = *prev) != RT_NULL; prev = &(b->next)) + { + RT_ASSERT(b->page > 0); + RT_ASSERT(b > n || b + b->page <= n); + + if (b + b->page == n) + { + if (b + (b->page += npages) == b->next) + { + b->page += b->next->page; + b->next = b->next->next; + } + + goto _return; + } + + if (b == n + npages) + { + n->page = b->page + npages; + n->next = b->next; + *prev = n; + + goto _return; + } + + if (b > n + npages) + break; + } + + n->page = npages; + n->next = b; + *prev = n; + +_return: + /* unlock heap */ + rt_sem_release(&heap_sem); +} + +/* + * Initialize the page allocator + */ +static void rt_page_init(void *addr, rt_size_t npages) +{ + RT_ASSERT(addr != RT_NULL); + RT_ASSERT(npages != 0); + + rt_page_list = RT_NULL; + rt_page_free(addr, npages); +} + +/** + * @ingroup SystemInit + * + * This function will init system heap + * + * @param begin_addr the beginning address of system page + * @param end_addr the end address of system page + */ +void rt_system_heap_init(void *begin_addr, void *end_addr) +{ + rt_uint32_t limsize, npages; + + RT_DEBUG_NOT_IN_INTERRUPT; + + /* align begin and end addr to page */ + heap_start = RT_ALIGN((rt_uint32_t)begin_addr, RT_MM_PAGE_SIZE); + heap_end = RT_ALIGN_DOWN((rt_uint32_t)end_addr, RT_MM_PAGE_SIZE); + + if (heap_start >= heap_end) + { + rt_kprintf("rt_system_heap_init, wrong address[0x%x - 0x%x]\n", + (rt_uint32_t)begin_addr, (rt_uint32_t)end_addr); + + return; + } + + limsize = heap_end - heap_start; + npages = limsize / RT_MM_PAGE_SIZE; + + /* initialize heap semaphore */ + rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_FIFO); + + RT_DEBUG_LOG(RT_DEBUG_SLAB, ("heap[0x%x - 0x%x], size 0x%x, 0x%x pages\n", + heap_start, heap_end, limsize, npages)); + + /* init pages */ + rt_page_init((void *)heap_start, npages); + + /* calculate zone size */ + zone_size = ZALLOC_MIN_ZONE_SIZE; + while (zone_size < ZALLOC_MAX_ZONE_SIZE && (zone_size << 1) < (limsize / 1024)) + zone_size <<= 1; + + zone_limit = zone_size / 4; + if (zone_limit > ZALLOC_ZONE_LIMIT) + zone_limit = ZALLOC_ZONE_LIMIT; + + zone_page_cnt = zone_size / RT_MM_PAGE_SIZE; + + RT_DEBUG_LOG(RT_DEBUG_SLAB, ("zone size 0x%x, zone page count 0x%x\n", + zone_size, zone_page_cnt)); + + /* allocate memusage array */ + limsize = npages * sizeof(struct memusage); + limsize = RT_ALIGN(limsize, RT_MM_PAGE_SIZE); + memusage = rt_page_alloc(limsize / RT_MM_PAGE_SIZE); + + RT_DEBUG_LOG(RT_DEBUG_SLAB, ("memusage 0x%x, size 0x%x\n", + (rt_uint32_t)memusage, limsize)); +} + +/* + * Calculate the zone index for the allocation request size and set the + * allocation request size to that particular zone's chunk size. + */ +rt_inline int zoneindex(rt_uint32_t *bytes) +{ + /* unsigned for shift opt */ + rt_uint32_t n = (rt_uint32_t) * bytes; + + if (n < 128) + { + *bytes = n = (n + 7) & ~7; + + /* 8 byte chunks, 16 zones */ + return (n / 8 - 1); + } + if (n < 256) + { + *bytes = n = (n + 15) & ~15; + + return (n / 16 + 7); + } + if (n < 8192) + { + if (n < 512) + { + *bytes = n = (n + 31) & ~31; + + return (n / 32 + 15); + } + if (n < 1024) + { + *bytes = n = (n + 63) & ~63; + + return (n / 64 + 23); + } + if (n < 2048) + { + *bytes = n = (n + 127) & ~127; + + return (n / 128 + 31); + } + if (n < 4096) + { + *bytes = n = (n + 255) & ~255; + + return (n / 256 + 39); + } + *bytes = n = (n + 511) & ~511; + + return (n / 512 + 47); + } + if (n < 16384) + { + *bytes = n = (n + 1023) & ~1023; + + return (n / 1024 + 55); + } + + rt_kprintf("Unexpected byte count %d", n); + + return 0; +} + +/** + * @addtogroup MM + */ + +/**@{*/ + +/** + * This function will allocate a block from system heap memory. + * - If the nbytes is less than zero, + * or + * - If there is no nbytes sized memory valid in system, + * the RT_NULL is returned. + * + * @param size the size of memory to be allocated + * + * @return the allocated memory + */ +void *rt_malloc(rt_size_t size) +{ + slab_zone *z; + rt_int32_t zi; + slab_chunk *chunk; + struct memusage *kup; + + /* zero size, return RT_NULL */ + if (size == 0) + return RT_NULL; + + /* + * Handle large allocations directly. There should not be very many of + * these so performance is not a big issue. + */ + if (size >= zone_limit) + { + size = RT_ALIGN(size, RT_MM_PAGE_SIZE); + + chunk = rt_page_alloc(size >> RT_MM_PAGE_BITS); + if (chunk == RT_NULL) + return RT_NULL; + + /* set kup */ + kup = btokup(chunk); + kup->type = PAGE_TYPE_LARGE; + kup->size = size >> RT_MM_PAGE_BITS; + + RT_DEBUG_LOG(RT_DEBUG_SLAB, + ("malloc a large memory 0x%x, page cnt %d, kup %d\n", + size, + size >> RT_MM_PAGE_BITS, + ((rt_uint32_t)chunk - heap_start) >> RT_MM_PAGE_BITS)); + + /* lock heap */ + rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + +#ifdef RT_MEM_STATS + used_mem += size; + if (used_mem > max_mem) + max_mem = used_mem; +#endif + goto done; + } + + /* lock heap */ + rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + + /* + * Attempt to allocate out of an existing zone. First try the free list, + * then allocate out of unallocated space. If we find a good zone move + * it to the head of the list so later allocations find it quickly + * (we might have thousands of zones in the list). + * + * Note: zoneindex() will panic of size is too large. + */ + zi = zoneindex(&size); + RT_ASSERT(zi < NZONES); + + RT_DEBUG_LOG(RT_DEBUG_SLAB, ("try to malloc 0x%x on zone: %d\n", size, zi)); + + if ((z = zone_array[zi]) != RT_NULL) + { + RT_ASSERT(z->z_nfree > 0); + + /* Remove us from the zone_array[] when we become empty */ + if (--z->z_nfree == 0) + { + zone_array[zi] = z->z_next; + z->z_next = RT_NULL; + } + + /* + * No chunks are available but nfree said we had some memory, so + * it must be available in the never-before-used-memory area + * governed by uindex. The consequences are very serious if our zone + * got corrupted so we use an explicit rt_kprintf rather then a KASSERT. + */ + if (z->z_uindex + 1 != z->z_nmax) + { + z->z_uindex = z->z_uindex + 1; + chunk = (slab_chunk *)(z->z_baseptr + z->z_uindex * size); + } + else + { + /* find on free chunk list */ + chunk = z->z_freechunk; + + /* remove this chunk from list */ + z->z_freechunk = z->z_freechunk->c_next; + } + +#ifdef RT_MEM_STATS + used_mem += z->z_chunksize; + if (used_mem > max_mem) + max_mem = used_mem; +#endif + + goto done; + } + + /* + * If all zones are exhausted we need to allocate a new zone for this + * index. + * + * At least one subsystem, the tty code (see CROUND) expects power-of-2 + * allocations to be power-of-2 aligned. We maintain compatibility by + * adjusting the base offset below. + */ + { + rt_int32_t off; + + if ((z = zone_free) != RT_NULL) + { + /* remove zone from free zone list */ + zone_free = z->z_next; + -- zone_free_cnt; + } + else + { + /* unlock heap, since page allocator will think about lock */ + rt_sem_release(&heap_sem); + + /* allocate a zone from page */ + z = rt_page_alloc(zone_size / RT_MM_PAGE_SIZE); + if (z == RT_NULL) + { + chunk = RT_NULL; + goto __exit; + } + + /* lock heap */ + rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + + RT_DEBUG_LOG(RT_DEBUG_SLAB, ("alloc a new zone: 0x%x\n", + (rt_uint32_t)z)); + + /* set message usage */ + for (off = 0, kup = btokup(z); off < zone_page_cnt; off ++) + { + kup->type = PAGE_TYPE_SMALL; + kup->size = off; + + kup ++; + } + } + + /* clear to zero */ + rt_memset(z, 0, sizeof(slab_zone)); + + /* offset of slab zone struct in zone */ + off = sizeof(slab_zone); + + /* + * Guarentee power-of-2 alignment for power-of-2-sized chunks. + * Otherwise just 8-byte align the data. + */ + if ((size | (size - 1)) + 1 == (size << 1)) + off = (off + size - 1) & ~(size - 1); + else + off = (off + MIN_CHUNK_MASK) & ~MIN_CHUNK_MASK; + + z->z_magic = ZALLOC_SLAB_MAGIC; + z->z_zoneindex = zi; + z->z_nmax = (zone_size - off) / size; + z->z_nfree = z->z_nmax - 1; + z->z_baseptr = (rt_uint8_t *)z + off; + z->z_uindex = 0; + z->z_chunksize = size; + + chunk = (slab_chunk *)(z->z_baseptr + z->z_uindex * size); + + /* link to zone array */ + z->z_next = zone_array[zi]; + zone_array[zi] = z; + +#ifdef RT_MEM_STATS + used_mem += z->z_chunksize; + if (used_mem > max_mem) + max_mem = used_mem; +#endif + } + +done: + rt_sem_release(&heap_sem); + RT_OBJECT_HOOK_CALL(rt_malloc_hook, ((char *)chunk, size)); + +__exit: + return chunk; +} +RTM_EXPORT(rt_malloc); + +/** + * This function will change the size of previously allocated memory block. + * + * @param ptr the previously allocated memory block + * @param size the new size of memory block + * + * @return the allocated memory + */ +void *rt_realloc(void *ptr, rt_size_t size) +{ + void *nptr; + slab_zone *z; + struct memusage *kup; + + if (ptr == RT_NULL) + return rt_malloc(size); + if (size == 0) + { + rt_free(ptr); + + return RT_NULL; + } + + /* + * Get the original allocation's zone. If the new request winds up + * using the same chunk size we do not have to do anything. + */ + kup = btokup((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK); + if (kup->type == PAGE_TYPE_LARGE) + { + rt_size_t osize; + + osize = kup->size << RT_MM_PAGE_BITS; + if ((nptr = rt_malloc(size)) == RT_NULL) + return RT_NULL; + rt_memcpy(nptr, ptr, size > osize ? osize : size); + rt_free(ptr); + + return nptr; + } + else if (kup->type == PAGE_TYPE_SMALL) + { + z = (slab_zone *)(((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK) - + kup->size * RT_MM_PAGE_SIZE); + RT_ASSERT(z->z_magic == ZALLOC_SLAB_MAGIC); + + zoneindex(&size); + if (z->z_chunksize == size) + return (ptr); /* same chunk */ + + /* + * Allocate memory for the new request size. Note that zoneindex has + * already adjusted the request size to the appropriate chunk size, which + * should optimize our bcopy(). Then copy and return the new pointer. + */ + if ((nptr = rt_malloc(size)) == RT_NULL) + return RT_NULL; + + rt_memcpy(nptr, ptr, size > z->z_chunksize ? z->z_chunksize : size); + rt_free(ptr); + + return nptr; + } + + return RT_NULL; +} +RTM_EXPORT(rt_realloc); + +/** + * This function will contiguously allocate enough space for count objects + * that are size bytes of memory each and returns a pointer to the allocated + * memory. + * + * The allocated memory is filled with bytes of value zero. + * + * @param count number of objects to allocate + * @param size size of the objects to allocate + * + * @return pointer to allocated memory / NULL pointer if there is an error + */ +void *rt_calloc(rt_size_t count, rt_size_t size) +{ + void *p; + + /* allocate 'count' objects of size 'size' */ + p = rt_malloc(count * size); + + /* zero the memory */ + if (p) + rt_memset(p, 0, count * size); + + return p; +} +RTM_EXPORT(rt_calloc); + +/** + * This function will release the previous allocated memory block by rt_malloc. + * The released memory block is taken back to system heap. + * + * @param ptr the address of memory which will be released + */ +void rt_free(void *ptr) +{ + slab_zone *z; + slab_chunk *chunk; + struct memusage *kup; + + /* free a RT_NULL pointer */ + if (ptr == RT_NULL) + return ; + + RT_OBJECT_HOOK_CALL(rt_free_hook, (ptr)); + + /* get memory usage */ +#if RT_DEBUG_SLAB + { + rt_uint32_t addr = ((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK); + RT_DEBUG_LOG(RT_DEBUG_SLAB, + ("free a memory 0x%x and align to 0x%x, kup index %d\n", + (rt_uint32_t)ptr, + (rt_uint32_t)addr, + ((rt_uint32_t)(addr) - heap_start) >> RT_MM_PAGE_BITS)); + } +#endif + + kup = btokup((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK); + /* release large allocation */ + if (kup->type == PAGE_TYPE_LARGE) + { + rt_uint32_t size; + + /* lock heap */ + rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + /* clear page counter */ + size = kup->size; + kup->size = 0; + +#ifdef RT_MEM_STATS + used_mem -= size * RT_MM_PAGE_SIZE; +#endif + rt_sem_release(&heap_sem); + + RT_DEBUG_LOG(RT_DEBUG_SLAB, + ("free large memory block 0x%x, page count %d\n", + (rt_uint32_t)ptr, size)); + + /* free this page */ + rt_page_free(ptr, size); + + return; + } + + /* lock heap */ + rt_sem_take(&heap_sem, RT_WAITING_FOREVER); + + /* zone case. get out zone. */ + z = (slab_zone *)(((rt_uint32_t)ptr & ~RT_MM_PAGE_MASK) - + kup->size * RT_MM_PAGE_SIZE); + RT_ASSERT(z->z_magic == ZALLOC_SLAB_MAGIC); + + chunk = (slab_chunk *)ptr; + chunk->c_next = z->z_freechunk; + z->z_freechunk = chunk; + +#ifdef RT_MEM_STATS + used_mem -= z->z_chunksize; +#endif + + /* + * Bump the number of free chunks. If it becomes non-zero the zone + * must be added back onto the appropriate list. + */ + if (z->z_nfree++ == 0) + { + z->z_next = zone_array[z->z_zoneindex]; + zone_array[z->z_zoneindex] = z; + } + + /* + * If the zone becomes totally free, and there are other zones we + * can allocate from, move this zone to the FreeZones list. Since + * this code can be called from an IPI callback, do *NOT* try to mess + * with kernel_map here. Hysteresis will be performed at malloc() time. + */ + if (z->z_nfree == z->z_nmax && + (z->z_next || zone_array[z->z_zoneindex] != z)) + { + slab_zone **pz; + + RT_DEBUG_LOG(RT_DEBUG_SLAB, ("free zone 0x%x\n", + (rt_uint32_t)z, z->z_zoneindex)); + + /* remove zone from zone array list */ + for (pz = &zone_array[z->z_zoneindex]; z != *pz; pz = &(*pz)->z_next) + ; + *pz = z->z_next; + + /* reset zone */ + z->z_magic = -1; + + /* insert to free zone list */ + z->z_next = zone_free; + zone_free = z; + + ++ zone_free_cnt; + + /* release zone to page allocator */ + if (zone_free_cnt > ZONE_RELEASE_THRESH) + { + register rt_base_t i; + + z = zone_free; + zone_free = z->z_next; + -- zone_free_cnt; + + /* set message usage */ + for (i = 0, kup = btokup(z); i < zone_page_cnt; i ++) + { + kup->type = PAGE_TYPE_FREE; + kup->size = 0; + kup ++; + } + + /* unlock heap */ + rt_sem_release(&heap_sem); + + /* release pages */ + rt_page_free(z, zone_size / RT_MM_PAGE_SIZE); + + return; + } + } + /* unlock heap */ + rt_sem_release(&heap_sem); +} +RTM_EXPORT(rt_free); + +#ifdef RT_MEM_STATS +void rt_memory_info(rt_uint32_t *total, + rt_uint32_t *used, + rt_uint32_t *max_used) +{ + if (total != RT_NULL) + *total = heap_end - heap_start; + + if (used != RT_NULL) + *used = used_mem; + + if (max_used != RT_NULL) + *max_used = max_mem; +} + +#ifdef RT_USING_FINSH +#include + +void list_mem(void) +{ + rt_kprintf("total memory: %d\n", heap_end - heap_start); + rt_kprintf("used memory : %d\n", used_mem); + rt_kprintf("maximum allocated memory: %d\n", max_mem); +} +FINSH_FUNCTION_EXPORT(list_mem, list memory usage information) +#endif +#endif + +/**@}*/ + +#endif diff --git a/rt-thread/src/thread.c b/rt-thread/src/thread.c new file mode 100644 index 0000000..6d79ece --- /dev/null +++ b/rt-thread/src/thread.c @@ -0,0 +1,797 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-03-28 Bernard first version + * 2006-04-29 Bernard implement thread timer + * 2006-04-30 Bernard added THREAD_DEBUG + * 2006-05-27 Bernard fixed the rt_thread_yield bug + * 2006-06-03 Bernard fixed the thread timer init bug + * 2006-08-10 Bernard fixed the timer bug in thread_sleep + * 2006-09-03 Bernard changed rt_timer_delete to rt_timer_detach + * 2006-09-03 Bernard implement rt_thread_detach + * 2008-02-16 Bernard fixed the rt_thread_timeout bug + * 2010-03-21 Bernard change the errno of rt_thread_delay/sleep to + * RT_EOK. + * 2010-11-10 Bernard add cleanup callback function in thread exit. + * 2011-09-01 Bernard fixed rt_thread_exit issue when the current + * thread preempted, which reported by Jiaxing Lee. + * 2011-09-08 Bernard fixed the scheduling issue in rt_thread_startup. + * 2012-12-29 Bernard fixed compiling warning. + * 2016-08-09 ArdaFu add thread suspend and resume hook. + * 2017-04-10 armink fixed the rt_thread_delete and rt_thread_detach + bug when thread has not startup. + */ + +#include +#include + +extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX]; +extern struct rt_thread *rt_current_thread; +extern rt_list_t rt_thread_defunct; + +#ifdef RT_USING_HOOK + +static void (*rt_thread_suspend_hook)(rt_thread_t thread); +static void (*rt_thread_resume_hook) (rt_thread_t thread); +static void (*rt_thread_inited_hook) (rt_thread_t thread); + +/** + * @ingroup Hook + * This function sets a hook function when the system suspend a thread. + * + * @param hook the specified hook function + * + * @note the hook function must be simple and never be blocked or suspend. + */ +void rt_thread_suspend_sethook(void (*hook)(rt_thread_t thread)) +{ + rt_thread_suspend_hook = hook; +} + +/** + * @ingroup Hook + * This function sets a hook function when the system resume a thread. + * + * @param hook the specified hook function + * + * @note the hook function must be simple and never be blocked or suspend. + */ +void rt_thread_resume_sethook(void (*hook)(rt_thread_t thread)) +{ + rt_thread_resume_hook = hook; +} + +/** + * @ingroup Hook + * This function sets a hook function when a thread is initialized. + * + * @param hook the specified hook function + */ +void rt_thread_inited_sethook(void (*hook)(rt_thread_t thread)) +{ + rt_thread_inited_hook = hook; +} + +#endif + +void rt_thread_exit(void) +{ + struct rt_thread *thread; + register rt_base_t level; + + /* get current thread */ + thread = rt_current_thread; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* remove from schedule */ + rt_schedule_remove_thread(thread); + /* change stat */ + thread->stat = RT_THREAD_CLOSE; + + /* remove it from timer list */ + rt_timer_detach(&thread->thread_timer); + + if ((rt_object_is_systemobject((rt_object_t)thread) == RT_TRUE) && + thread->cleanup == RT_NULL) + { + rt_object_detach((rt_object_t)thread); + } + else + { + /* insert to defunct thread list */ + rt_list_insert_after(&rt_thread_defunct, &(thread->tlist)); + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* switch to next task */ + rt_schedule(); +} + +static rt_err_t _rt_thread_init(struct rt_thread *thread, + const char *name, + void (*entry)(void *parameter), + void *parameter, + void *stack_start, + rt_uint32_t stack_size, + rt_uint8_t priority, + rt_uint32_t tick) +{ + /* init thread list */ + rt_list_init(&(thread->tlist)); + + thread->entry = (void *)entry; + thread->parameter = parameter; + + /* stack init */ + thread->stack_addr = stack_start; + thread->stack_size = stack_size; + + /* init thread stack */ + rt_memset(thread->stack_addr, '#', thread->stack_size); + thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter, + (void *)((char *)thread->stack_addr + thread->stack_size - 4), + (void *)rt_thread_exit); + + /* priority init */ + RT_ASSERT(priority < RT_THREAD_PRIORITY_MAX); + thread->init_priority = priority; + thread->current_priority = priority; + + thread->number_mask = 0; +#if RT_THREAD_PRIORITY_MAX > 32 + thread->number = 0; + thread->high_mask = 0; +#endif + + /* tick init */ + thread->init_tick = tick; + thread->remaining_tick = tick; + + /* error and flags */ + thread->error = RT_EOK; + thread->stat = RT_THREAD_INIT; + + /* initialize cleanup function and user data */ + thread->cleanup = 0; + thread->user_data = 0; + + /* init thread timer */ + rt_timer_init(&(thread->thread_timer), + thread->name, + rt_thread_timeout, + thread, + 0, + RT_TIMER_FLAG_ONE_SHOT); + + /* initialize signal */ +#ifdef RT_USING_SIGNALS + thread->sig_mask = 0x00; + thread->sig_pending = 0x00; + + thread->sig_ret = RT_NULL; + thread->sig_vectors = RT_NULL; + thread->si_list = RT_NULL; +#endif + +#ifdef RT_USING_LWP + thread->lwp = RT_NULL; +#endif + + RT_OBJECT_HOOK_CALL(rt_thread_inited_hook, (thread)); + + return RT_EOK; +} + +/** + * @addtogroup Thread + */ + +/**@{*/ + +/** + * This function will initialize a thread, normally it's used to initialize a + * static thread object. + * + * @param thread the static thread object + * @param name the name of thread, which shall be unique + * @param entry the entry function of thread + * @param parameter the parameter of thread enter function + * @param stack_start the start address of thread stack + * @param stack_size the size of thread stack + * @param priority the priority of thread + * @param tick the time slice if there are same priority thread + * + * @return the operation status, RT_EOK on OK, -RT_ERROR on error + */ +rt_err_t rt_thread_init(struct rt_thread *thread, + const char *name, + void (*entry)(void *parameter), + void *parameter, + void *stack_start, + rt_uint32_t stack_size, + rt_uint8_t priority, + rt_uint32_t tick) +{ + /* thread check */ + RT_ASSERT(thread != RT_NULL); + RT_ASSERT(stack_start != RT_NULL); + + /* init thread object */ + rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name); + + return _rt_thread_init(thread, + name, + entry, + parameter, + stack_start, + stack_size, + priority, + tick); +} +RTM_EXPORT(rt_thread_init); + +/** + * This function will return self thread object + * + * @return the self thread object + */ +rt_thread_t rt_thread_self(void) +{ + return rt_current_thread; +} +RTM_EXPORT(rt_thread_self); + +/** + * This function will start a thread and put it to system ready queue + * + * @param thread the thread to be started + * + * @return the operation status, RT_EOK on OK, -RT_ERROR on error + */ +rt_err_t rt_thread_startup(rt_thread_t thread) +{ + /* thread check */ + RT_ASSERT(thread != RT_NULL); + RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_INIT); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + + /* set current priority to init priority */ + thread->current_priority = thread->init_priority; + + /* calculate priority attribute */ +#if RT_THREAD_PRIORITY_MAX > 32 + thread->number = thread->current_priority >> 3; /* 5bit */ + thread->number_mask = 1L << thread->number; + thread->high_mask = 1L << (thread->current_priority & 0x07); /* 3bit */ +#else + thread->number_mask = 1L << thread->current_priority; +#endif + + RT_DEBUG_LOG(RT_DEBUG_THREAD, ("startup a thread:%s with priority:%d\n", + thread->name, thread->init_priority)); + /* change thread stat */ + thread->stat = RT_THREAD_SUSPEND; + /* then resume it */ + rt_thread_resume(thread); + if (rt_thread_self() != RT_NULL) + { + /* do a scheduling */ + rt_schedule(); + } + + return RT_EOK; +} +RTM_EXPORT(rt_thread_startup); + +/** + * This function will detach a thread. The thread object will be removed from + * thread queue and detached/deleted from system object management. + * + * @param thread the thread to be deleted + * + * @return the operation status, RT_EOK on OK, -RT_ERROR on error + */ +rt_err_t rt_thread_detach(rt_thread_t thread) +{ + rt_base_t lock; + + /* thread check */ + RT_ASSERT(thread != RT_NULL); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread)); + + if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT) + { + /* remove from schedule */ + rt_schedule_remove_thread(thread); + } + + /* release thread timer */ + rt_timer_detach(&(thread->thread_timer)); + + /* change stat */ + thread->stat = RT_THREAD_CLOSE; + + /* detach object */ + rt_object_detach((rt_object_t)thread); + + if (thread->cleanup != RT_NULL) + { + /* disable interrupt */ + lock = rt_hw_interrupt_disable(); + + /* insert to defunct thread list */ + rt_list_insert_after(&rt_thread_defunct, &(thread->tlist)); + + /* enable interrupt */ + rt_hw_interrupt_enable(lock); + } + + return RT_EOK; +} +RTM_EXPORT(rt_thread_detach); + + +#ifdef RT_USING_HEAP +/** + * This function will create a thread object and allocate thread object memory + * and stack. + * + * @param name the name of thread, which shall be unique + * @param entry the entry function of thread + * @param parameter the parameter of thread enter function + * @param stack_size the size of thread stack + * @param priority the priority of thread + * @param tick the time slice if there are same priority thread + * + * @return the created thread object + */ +rt_thread_t rt_thread_create(const char *name, + void (*entry)(void *parameter), + void *parameter, + rt_uint32_t stack_size, + rt_uint8_t priority, + rt_uint32_t tick) +{ + struct rt_thread *thread; + void *stack_start; + + thread = (struct rt_thread *)rt_object_allocate(RT_Object_Class_Thread, + name); + if (thread == RT_NULL) + return RT_NULL; + + stack_start = (void *)RT_KERNEL_MALLOC(stack_size); + if (stack_start == RT_NULL) + { + /* allocate stack failure */ + rt_object_delete((rt_object_t)thread); + + return RT_NULL; + } + + _rt_thread_init(thread, + name, + entry, + parameter, + stack_start, + stack_size, + priority, + tick); + + return thread; +} +RTM_EXPORT(rt_thread_create); + +/** + * This function will delete a thread. The thread object will be removed from + * thread queue and deleted from system object management in the idle thread. + * + * @param thread the thread to be deleted + * + * @return the operation status, RT_EOK on OK, -RT_ERROR on error + */ +rt_err_t rt_thread_delete(rt_thread_t thread) +{ + rt_base_t lock; + + /* thread check */ + RT_ASSERT(thread != RT_NULL); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + RT_ASSERT(rt_object_is_systemobject((rt_object_t)thread) == RT_FALSE); + + if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_INIT) + { + /* remove from schedule */ + rt_schedule_remove_thread(thread); + } + + /* release thread timer */ + rt_timer_detach(&(thread->thread_timer)); + + /* change stat */ + thread->stat = RT_THREAD_CLOSE; + + /* disable interrupt */ + lock = rt_hw_interrupt_disable(); + + /* insert to defunct thread list */ + rt_list_insert_after(&rt_thread_defunct, &(thread->tlist)); + + /* enable interrupt */ + rt_hw_interrupt_enable(lock); + + return RT_EOK; +} +RTM_EXPORT(rt_thread_delete); +#endif + +/** + * This function will let current thread yield processor, and scheduler will + * choose a highest thread to run. After yield processor, the current thread + * is still in READY state. + * + * @return RT_EOK + */ +rt_err_t rt_thread_yield(void) +{ + register rt_base_t level; + struct rt_thread *thread; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + /* set to current thread */ + thread = rt_current_thread; + + /* if the thread stat is READY and on ready queue list */ + if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY && + thread->tlist.next != thread->tlist.prev) + { + /* remove thread from thread list */ + rt_list_remove(&(thread->tlist)); + + /* put thread to end of ready queue */ + rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]), + &(thread->tlist)); + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_schedule(); + + return RT_EOK; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + return RT_EOK; +} +RTM_EXPORT(rt_thread_yield); + +/** + * This function will let current thread sleep for some ticks. + * + * @param tick the sleep ticks + * + * @return RT_EOK + */ +rt_err_t rt_thread_sleep(rt_tick_t tick) +{ + register rt_base_t temp; + struct rt_thread *thread; + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + /* set to current thread */ + thread = rt_current_thread; + RT_ASSERT(thread != RT_NULL); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + + /* suspend thread */ + rt_thread_suspend(thread); + + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick); + rt_timer_start(&(thread->thread_timer)); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + rt_schedule(); + + /* clear error number of this thread to RT_EOK */ + if (thread->error == -RT_ETIMEOUT) + thread->error = RT_EOK; + + return RT_EOK; +} + +/** + * This function will let current thread delay for some ticks. + * + * @param tick the delay ticks + * + * @return RT_EOK + */ +rt_err_t rt_thread_delay(rt_tick_t tick) +{ + return rt_thread_sleep(tick); +} +RTM_EXPORT(rt_thread_delay); + +/** + * This function will let current thread delay for some milliseconds. + * + * @param tick the delay time + * + * @return RT_EOK + */ +rt_err_t rt_thread_mdelay(rt_int32_t ms) +{ + rt_tick_t tick; + + tick = rt_tick_from_millisecond(ms); + + return rt_thread_sleep(tick); +} +RTM_EXPORT(rt_thread_mdelay); + +/** + * This function will control thread behaviors according to control command. + * + * @param thread the specified thread to be controlled + * @param cmd the control command, which includes + * RT_THREAD_CTRL_CHANGE_PRIORITY for changing priority level of thread; + * RT_THREAD_CTRL_STARTUP for starting a thread; + * RT_THREAD_CTRL_CLOSE for delete a thread. + * @param arg the argument of control command + * + * @return RT_EOK + */ +rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg) +{ + register rt_base_t temp; + + /* thread check */ + RT_ASSERT(thread != RT_NULL); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + + switch (cmd) + { + case RT_THREAD_CTRL_CHANGE_PRIORITY: + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* for ready thread, change queue */ + if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY) + { + /* remove thread from schedule queue first */ + rt_schedule_remove_thread(thread); + + /* change thread priority */ + thread->current_priority = *(rt_uint8_t *)arg; + + /* recalculate priority attribute */ +#if RT_THREAD_PRIORITY_MAX > 32 + thread->number = thread->current_priority >> 3; /* 5bit */ + thread->number_mask = 1 << thread->number; + thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */ +#else + thread->number_mask = 1 << thread->current_priority; +#endif + + /* insert thread to schedule queue again */ + rt_schedule_insert_thread(thread); + } + else + { + thread->current_priority = *(rt_uint8_t *)arg; + + /* recalculate priority attribute */ +#if RT_THREAD_PRIORITY_MAX > 32 + thread->number = thread->current_priority >> 3; /* 5bit */ + thread->number_mask = 1 << thread->number; + thread->high_mask = 1 << (thread->current_priority & 0x07); /* 3bit */ +#else + thread->number_mask = 1 << thread->current_priority; +#endif + } + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + break; + + case RT_THREAD_CTRL_STARTUP: + return rt_thread_startup(thread); + +#ifdef RT_USING_HEAP + case RT_THREAD_CTRL_CLOSE: + return rt_thread_delete(thread); +#endif + + default: + break; + } + + return RT_EOK; +} +RTM_EXPORT(rt_thread_control); + +/** + * This function will suspend the specified thread. + * + * @param thread the thread to be suspended + * + * @return the operation status, RT_EOK on OK, -RT_ERROR on error + * + * @note if suspend self thread, after this function call, the + * rt_schedule() must be invoked. + */ +rt_err_t rt_thread_suspend(rt_thread_t thread) +{ + register rt_base_t temp; + + /* thread check */ + RT_ASSERT(thread != RT_NULL); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + + RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: %s\n", thread->name)); + + if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY) + { + RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread suspend: thread disorder, 0x%2x\n", + thread->stat)); + + return -RT_ERROR; + } + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* change thread stat */ + thread->stat = RT_THREAD_SUSPEND | (thread->stat & ~RT_THREAD_STAT_MASK); + rt_schedule_remove_thread(thread); + + /* stop thread timer anyway */ + rt_timer_stop(&(thread->thread_timer)); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + RT_OBJECT_HOOK_CALL(rt_thread_suspend_hook, (thread)); + return RT_EOK; +} +RTM_EXPORT(rt_thread_suspend); + +/** + * This function will resume a thread and put it to system ready queue. + * + * @param thread the thread to be resumed + * + * @return the operation status, RT_EOK on OK, -RT_ERROR on error + */ +rt_err_t rt_thread_resume(rt_thread_t thread) +{ + register rt_base_t temp; + + /* thread check */ + RT_ASSERT(thread != RT_NULL); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + + RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: %s\n", thread->name)); + + if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND) + { + RT_DEBUG_LOG(RT_DEBUG_THREAD, ("thread resume: thread disorder, %d\n", + thread->stat)); + + return -RT_ERROR; + } + + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* remove from suspend list */ + rt_list_remove(&(thread->tlist)); + + rt_timer_stop(&thread->thread_timer); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + + /* insert to schedule ready list */ + rt_schedule_insert_thread(thread); + + RT_OBJECT_HOOK_CALL(rt_thread_resume_hook, (thread)); + return RT_EOK; +} +RTM_EXPORT(rt_thread_resume); + +/** + * This function is the timeout function for thread, normally which is invoked + * when thread is timeout to wait some resource. + * + * @param parameter the parameter of thread timeout function + */ +void rt_thread_timeout(void *parameter) +{ + struct rt_thread *thread; + + thread = (struct rt_thread *)parameter; + + /* thread check */ + RT_ASSERT(thread != RT_NULL); + RT_ASSERT((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND); + RT_ASSERT(rt_object_get_type((rt_object_t)thread) == RT_Object_Class_Thread); + + /* set error number */ + thread->error = -RT_ETIMEOUT; + + /* remove from suspend list */ + rt_list_remove(&(thread->tlist)); + + /* insert to schedule ready list */ + rt_schedule_insert_thread(thread); + + /* do schedule */ + rt_schedule(); +} +RTM_EXPORT(rt_thread_timeout); + +/** + * This function will find the specified thread. + * + * @param name the name of thread finding + * + * @return the found thread + * + * @note please don't invoke this function in interrupt status. + */ +rt_thread_t rt_thread_find(char *name) +{ + struct rt_object_information *information; + struct rt_object *object; + struct rt_list_node *node; + + /* enter critical */ + if (rt_thread_self() != RT_NULL) + rt_enter_critical(); + + /* try to find device object */ + information = rt_object_get_information(RT_Object_Class_Thread); + RT_ASSERT(information != RT_NULL); + for (node = information->object_list.next; + node != &(information->object_list); + node = node->next) + { + object = rt_list_entry(node, struct rt_object, list); + if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0) + { + /* leave critical */ + if (rt_thread_self() != RT_NULL) + rt_exit_critical(); + + return (rt_thread_t)object; + } + } + + /* leave critical */ + if (rt_thread_self() != RT_NULL) + rt_exit_critical(); + + /* not found */ + return RT_NULL; +} +RTM_EXPORT(rt_thread_find); + +/**@}*/ diff --git a/rt-thread/src/timer.c b/rt-thread/src/timer.c new file mode 100644 index 0000000..dc489a2 --- /dev/null +++ b/rt-thread/src/timer.c @@ -0,0 +1,707 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2006-03-12 Bernard first version + * 2006-04-29 Bernard implement thread timer + * 2006-06-04 Bernard implement rt_timer_control + * 2006-08-10 Bernard fix the periodic timer bug + * 2006-09-03 Bernard implement rt_timer_detach + * 2009-11-11 LiJin add soft timer + * 2010-05-12 Bernard fix the timer check bug. + * 2010-11-02 Charlie re-implement tick overflow issue + * 2012-12-15 Bernard fix the next timeout issue in soft timer + * 2014-07-12 Bernard does not lock scheduler when invoking soft-timer + * timeout function. + */ + +#include +#include + +/* hard timer list */ +static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL]; + +#ifdef RT_USING_TIMER_SOFT +#ifndef RT_TIMER_THREAD_STACK_SIZE +#define RT_TIMER_THREAD_STACK_SIZE 512 +#endif + +#ifndef RT_TIMER_THREAD_PRIO +#define RT_TIMER_THREAD_PRIO 0 +#endif + +/* soft timer list */ +static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL]; +static struct rt_thread timer_thread; +ALIGN(RT_ALIGN_SIZE) +static rt_uint8_t timer_thread_stack[RT_TIMER_THREAD_STACK_SIZE]; +#endif + +#ifdef RT_USING_HOOK +extern void (*rt_object_take_hook)(struct rt_object *object); +extern void (*rt_object_put_hook)(struct rt_object *object); +static void (*rt_timer_timeout_hook)(struct rt_timer *timer); + +/** + * @addtogroup Hook + */ + +/**@{*/ + +/** + * This function will set a hook function, which will be invoked when timer + * is timeout. + * + * @param hook the hook function + */ +void rt_timer_timeout_sethook(void (*hook)(struct rt_timer *timer)) +{ + rt_timer_timeout_hook = hook; +} + +/**@}*/ +#endif + +static void _rt_timer_init(rt_timer_t timer, + void (*timeout)(void *parameter), + void *parameter, + rt_tick_t time, + rt_uint8_t flag) +{ + int i; + + /* set flag */ + timer->parent.flag = flag; + + /* set deactivated */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + + timer->timeout_func = timeout; + timer->parameter = parameter; + + timer->timeout_tick = 0; + timer->init_tick = time; + + /* initialize timer list */ + for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++) + { + rt_list_init(&(timer->row[i])); + } +} + +/* the fist timer always in the last row */ +static rt_tick_t rt_timer_list_next_timeout(rt_list_t timer_list[]) +{ + struct rt_timer *timer; + + if (rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])) + return RT_TICK_MAX; + + timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next, + struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); + + return timer->timeout_tick; +} + +rt_inline void _rt_timer_remove(rt_timer_t timer) +{ + int i; + + for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++) + { + rt_list_remove(&timer->row[i]); + } +} + +#if RT_DEBUG_TIMER +static int rt_timer_count_height(struct rt_timer *timer) +{ + int i, cnt = 0; + + for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++) + { + if (!rt_list_isempty(&timer->row[i])) + cnt++; + } + return cnt; +} + +void rt_timer_dump(rt_list_t timer_heads[]) +{ + rt_list_t *list; + + for (list = timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1].next; + list != &timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1]; + list = list->next) + { + struct rt_timer *timer = rt_list_entry(list, + struct rt_timer, + row[RT_TIMER_SKIP_LIST_LEVEL - 1]); + rt_kprintf("%d", rt_timer_count_height(timer)); + } + rt_kprintf("\n"); +} +#endif + +/** + * @addtogroup Clock + */ + +/**@{*/ + +/** + * This function will initialize a timer, normally this function is used to + * initialize a static timer object. + * + * @param timer the static timer object + * @param name the name of timer + * @param timeout the timeout function + * @param parameter the parameter of timeout function + * @param time the tick of timer + * @param flag the flag of timer + */ +void rt_timer_init(rt_timer_t timer, + const char *name, + void (*timeout)(void *parameter), + void *parameter, + rt_tick_t time, + rt_uint8_t flag) +{ + /* timer check */ + RT_ASSERT(timer != RT_NULL); + + /* timer object initialization */ + rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name); + + _rt_timer_init(timer, timeout, parameter, time, flag); +} +RTM_EXPORT(rt_timer_init); + +/** + * This function will detach a timer from timer management. + * + * @param timer the static timer object + * + * @return the operation status, RT_EOK on OK; RT_ERROR on error + */ +rt_err_t rt_timer_detach(rt_timer_t timer) +{ + register rt_base_t level; + + /* timer check */ + RT_ASSERT(timer != RT_NULL); + RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); + RT_ASSERT(rt_object_is_systemobject(&timer->parent)); + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + _rt_timer_remove(timer); + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_object_detach((rt_object_t)timer); + + return RT_EOK; +} +RTM_EXPORT(rt_timer_detach); + +#ifdef RT_USING_HEAP +/** + * This function will create a timer + * + * @param name the name of timer + * @param timeout the timeout function + * @param parameter the parameter of timeout function + * @param time the tick of timer + * @param flag the flag of timer + * + * @return the created timer object + */ +rt_timer_t rt_timer_create(const char *name, + void (*timeout)(void *parameter), + void *parameter, + rt_tick_t time, + rt_uint8_t flag) +{ + struct rt_timer *timer; + + /* allocate a object */ + timer = (struct rt_timer *)rt_object_allocate(RT_Object_Class_Timer, name); + if (timer == RT_NULL) + { + return RT_NULL; + } + + _rt_timer_init(timer, timeout, parameter, time, flag); + + return timer; +} +RTM_EXPORT(rt_timer_create); + +/** + * This function will delete a timer and release timer memory + * + * @param timer the timer to be deleted + * + * @return the operation status, RT_EOK on OK; RT_ERROR on error + */ +rt_err_t rt_timer_delete(rt_timer_t timer) +{ + register rt_base_t level; + + /* timer check */ + RT_ASSERT(timer != RT_NULL); + RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); + RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE); + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + _rt_timer_remove(timer); + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + rt_object_delete((rt_object_t)timer); + + return RT_EOK; +} +RTM_EXPORT(rt_timer_delete); +#endif + +/** + * This function will start the timer + * + * @param timer the timer to be started + * + * @return the operation status, RT_EOK on OK, -RT_ERROR on error + */ +rt_err_t rt_timer_start(rt_timer_t timer) +{ + unsigned int row_lvl; + rt_list_t *timer_list; + register rt_base_t level; + rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL]; + unsigned int tst_nr; + static unsigned int random_nr; + + /* timer check */ + RT_ASSERT(timer != RT_NULL); + RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); + + /* stop timer firstly */ + level = rt_hw_interrupt_disable(); + /* remove timer from list */ + _rt_timer_remove(timer); + /* change status of timer */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + rt_hw_interrupt_enable(level); + + RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent))); + + /* + * get timeout tick, + * the max timeout tick shall not great than RT_TICK_MAX/2 + */ + RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2); + timer->timeout_tick = rt_tick_get() + timer->init_tick; + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + +#ifdef RT_USING_TIMER_SOFT + if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) + { + /* insert timer to soft timer list */ + timer_list = rt_soft_timer_list; + } + else +#endif + { + /* insert timer to system timer list */ + timer_list = rt_timer_list; + } + + row_head[0] = &timer_list[0]; + for (row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL; row_lvl++) + { + for (; row_head[row_lvl] != timer_list[row_lvl].prev; + row_head[row_lvl] = row_head[row_lvl]->next) + { + struct rt_timer *t; + rt_list_t *p = row_head[row_lvl]->next; + + /* fix up the entry pointer */ + t = rt_list_entry(p, struct rt_timer, row[row_lvl]); + + /* If we have two timers that timeout at the same time, it's + * preferred that the timer inserted early get called early. + * So insert the new timer to the end the the some-timeout timer + * list. + */ + if ((t->timeout_tick - timer->timeout_tick) == 0) + { + continue; + } + else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2) + { + break; + } + } + if (row_lvl != RT_TIMER_SKIP_LIST_LEVEL - 1) + row_head[row_lvl + 1] = row_head[row_lvl] + 1; + } + + /* Interestingly, this super simple timer insert counter works very very + * well on distributing the list height uniformly. By means of "very very + * well", I mean it beats the randomness of timer->timeout_tick very easily + * (actually, the timeout_tick is not random and easy to be attacked). */ + random_nr++; + tst_nr = random_nr; + + rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - 1], + &(timer->row[RT_TIMER_SKIP_LIST_LEVEL - 1])); + for (row_lvl = 2; row_lvl <= RT_TIMER_SKIP_LIST_LEVEL; row_lvl++) + { + if (!(tst_nr & RT_TIMER_SKIP_LIST_MASK)) + rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - row_lvl], + &(timer->row[RT_TIMER_SKIP_LIST_LEVEL - row_lvl])); + else + break; + /* Shift over the bits we have tested. Works well with 1 bit and 2 + * bits. */ + tst_nr >>= (RT_TIMER_SKIP_LIST_MASK + 1) >> 1; + } + + timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED; + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + +#ifdef RT_USING_TIMER_SOFT + if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) + { + /* check whether timer thread is ready */ + if ((timer_thread.stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY) + { + /* resume timer thread to check soft timer */ + rt_thread_resume(&timer_thread); + rt_schedule(); + } + } +#endif + + return RT_EOK; +} +RTM_EXPORT(rt_timer_start); + +/** + * This function will stop the timer + * + * @param timer the timer to be stopped + * + * @return the operation status, RT_EOK on OK, -RT_ERROR on error + */ +rt_err_t rt_timer_stop(rt_timer_t timer) +{ + register rt_base_t level; + + /* timer check */ + RT_ASSERT(timer != RT_NULL); + RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); + + if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) + return -RT_ERROR; + + RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent))); + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + _rt_timer_remove(timer); + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* change stat */ + timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + + return RT_EOK; +} +RTM_EXPORT(rt_timer_stop); + +/** + * This function will get or set some options of the timer + * + * @param timer the timer to be get or set + * @param cmd the control command + * @param arg the argument + * + * @return RT_EOK + */ +rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg) +{ + /* timer check */ + RT_ASSERT(timer != RT_NULL); + RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer); + + switch (cmd) + { + case RT_TIMER_CTRL_GET_TIME: + *(rt_tick_t *)arg = timer->init_tick; + break; + + case RT_TIMER_CTRL_SET_TIME: + timer->init_tick = *(rt_tick_t *)arg; + break; + + case RT_TIMER_CTRL_SET_ONESHOT: + timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC; + break; + + case RT_TIMER_CTRL_SET_PERIODIC: + timer->parent.flag |= RT_TIMER_FLAG_PERIODIC; + break; + } + + return RT_EOK; +} +RTM_EXPORT(rt_timer_control); + +/** + * This function will check timer list, if a timeout event happens, the + * corresponding timeout function will be invoked. + * + * @note this function shall be invoked in operating system timer interrupt. + */ +void rt_timer_check(void) +{ + struct rt_timer *t; + rt_tick_t current_tick; + register rt_base_t level; + + RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n")); + + current_tick = rt_tick_get(); + + /* disable interrupt */ + level = rt_hw_interrupt_disable(); + + while (!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1])) + { + t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next, + struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); + + /* + * It supposes that the new tick shall less than the half duration of + * tick max. + */ + if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2) + { + RT_OBJECT_HOOK_CALL(rt_timer_timeout_hook, (t)); + + /* remove timer from timer list firstly */ + _rt_timer_remove(t); + + /* call timeout function */ + t->timeout_func(t->parameter); + + /* re-get tick */ + current_tick = rt_tick_get(); + + RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick)); + + if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) && + (t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) + { + /* start it */ + t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + rt_timer_start(t); + } + else + { + /* stop timer */ + t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + } + } + else + break; + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n")); +} + +/** + * This function will return the next timeout tick in the system. + * + * @return the next timeout tick in the system + */ +rt_tick_t rt_timer_next_timeout_tick(void) +{ + return rt_timer_list_next_timeout(rt_timer_list); +} + +#ifdef RT_USING_TIMER_SOFT +/** + * This function will check timer list, if a timeout event happens, the + * corresponding timeout function will be invoked. + */ +void rt_soft_timer_check(void) +{ + rt_tick_t current_tick; + rt_list_t *n; + struct rt_timer *t; + + RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n")); + + current_tick = rt_tick_get(); + + /* lock scheduler */ + rt_enter_critical(); + + for (n = rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next; + n != &(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]);) + { + t = rt_list_entry(n, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]); + + /* + * It supposes that the new tick shall less than the half duration of + * tick max. + */ + if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2) + { + RT_OBJECT_HOOK_CALL(rt_timer_timeout_hook, (t)); + + /* move node to the next */ + n = n->next; + + /* remove timer from timer list firstly */ + _rt_timer_remove(t); + + /* not lock scheduler when performing timeout function */ + rt_exit_critical(); + /* call timeout function */ + t->timeout_func(t->parameter); + + /* re-get tick */ + current_tick = rt_tick_get(); + + RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick)); + + /* lock scheduler */ + rt_enter_critical(); + + if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) && + (t->parent.flag & RT_TIMER_FLAG_ACTIVATED)) + { + /* start it */ + t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + rt_timer_start(t); + } + else + { + /* stop timer */ + t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED; + } + } + else break; /* not check anymore */ + } + + /* unlock scheduler */ + rt_exit_critical(); + + RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n")); +} + +/* system timer thread entry */ +static void rt_thread_timer_entry(void *parameter) +{ + rt_tick_t next_timeout; + + while (1) + { + /* get the next timeout tick */ + next_timeout = rt_timer_list_next_timeout(rt_soft_timer_list); + if (next_timeout == RT_TICK_MAX) + { + /* no software timer exist, suspend self. */ + rt_thread_suspend(rt_thread_self()); + rt_schedule(); + } + else + { + rt_tick_t current_tick; + + /* get current tick */ + current_tick = rt_tick_get(); + + if ((next_timeout - current_tick) < RT_TICK_MAX / 2) + { + /* get the delta timeout tick */ + next_timeout = next_timeout - current_tick; + rt_thread_delay(next_timeout); + } + } + + /* check software timer */ + rt_soft_timer_check(); + } +} +#endif + +/** + * @ingroup SystemInit + * + * This function will initialize system timer + */ +void rt_system_timer_init(void) +{ + int i; + + for (i = 0; i < sizeof(rt_timer_list) / sizeof(rt_timer_list[0]); i++) + { + rt_list_init(rt_timer_list + i); + } +} + +/** + * @ingroup SystemInit + * + * This function will initialize system timer thread + */ +void rt_system_timer_thread_init(void) +{ +#ifdef RT_USING_TIMER_SOFT + int i; + + for (i = 0; + i < sizeof(rt_soft_timer_list) / sizeof(rt_soft_timer_list[0]); + i++) + { + rt_list_init(rt_soft_timer_list + i); + } + + /* start software timer thread */ + rt_thread_init(&timer_thread, + "timer", + rt_thread_timer_entry, + RT_NULL, + &timer_thread_stack[0], + sizeof(timer_thread_stack), + RT_TIMER_THREAD_PRIO, + 10); + + /* startup */ + rt_thread_startup(&timer_thread); +#endif +} + +/**@}*/