├── .github └── workflows │ └── makefile.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md └── src └── c ├── Makefile ├── ports ├── hostemu │ ├── hostemu.c │ ├── pl080.c │ └── pl080.h ├── lpc176x │ └── keil │ │ ├── .gitignore │ │ ├── RTE │ │ ├── Device │ │ │ └── LPC1769 │ │ │ │ ├── RTE_Device.h │ │ │ │ ├── startup_LPC17xx.s │ │ │ │ └── system_LPC17xx.c │ │ └── _Release │ │ │ └── RTE_Components.h │ │ ├── Release │ │ └── dmac_lpc176x.hex │ │ ├── dmac_lpc176x.uvoptx │ │ ├── dmac_lpc176x.uvprojx │ │ ├── lpc176x.c │ │ └── lpc176x.sct └── qemu │ └── versatile.c └── vcpu ├── dmacu.h ├── dmacu_instance.c ├── dmacu_instance.h ├── dmacu_shared.c ├── mc ├── .gitignore ├── demo.code.inc ├── demo.data.inc ├── demo.mc ├── dmacu.inc ├── pl080.code.inc ├── pl080.data.inc └── pl080.mc ├── rt.c ├── utils.c └── vpl080.c /.github/workflows/makefile.yml: -------------------------------------------------------------------------------- 1 | name: Makefile CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | 17 | - name: Install ARM toolchain 18 | uses: fiam/arm-none-eabi-gcc@v1 19 | with: 20 | release: '10-2020-q4' 21 | 22 | - name: Build QEMU simulation target 23 | run: make -C src/c/ dmacu_qemu_versatilepb.elf 24 | 25 | - name: Archive build artifacts 26 | uses: actions/upload-artifact@v3 27 | with: 28 | name: dmacu-qemu 29 | path: src/c/dmacu_qemu_versatilepb.elf 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Backup files 55 | *~ 56 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jowinter/dmacu/31f662dcd39f8a9d1ab34ed3380ecc086c37f205/.gitmodules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2022 Johannes Winter 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minimal CPU Emulator Powered by the ARM PL080 DMA Controller (dmacu) 2 | 3 | [![Makefile CI](https://github.com/jowinter/dmacu/actions/workflows/makefile.yml/badge.svg)](https://github.com/jowinter/dmacu/actions/workflows/makefile.yml) 4 | 5 | ## Overview 6 | `dmacu` is an emulator for a simple hypothetical RISC-like processor intended to run on an ARM platform including a PL080 DMA controller. 7 | The `dmacu` emulator itself executes on a DMA channel of the host system's PL080 DMA controller. Interaction from the host system's ARM core 8 | is only needed to configure and start the DMA channel on which `dmacu` executes. No further interaction is needed from the host system's ARM 9 | core once the DMA channel is up and running. The `dmacu` emulator remains operational while the host system's ARM core is in an active sleep 10 | state (WFI/WFE), or while the ARM core is halted via an external debug interface. 11 | -------------------------------------------------------------------------------- /src/c/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Minimal CPU Emulator Powered by the ARM PL080 DMA Controller (dmacu) 3 | # 4 | # Copyright (c) 2019-2022 Johannes Winter 5 | # 6 | # This file is licensed under the MIT License. See LICENSE in the root directory 7 | # of the prohect for the license text. 8 | # 9 | 10 | #-------------------------------------------------------------------------------------------------- 11 | # Common (host and target) options 12 | # 13 | COMMON_CPPFLAGS := -I./vcpu/ 14 | 15 | COMMON_C_SOURCES := ./vcpu/dmacu_shared.c 16 | COMMON_C_SOURCES += ./vcpu/dmacu_instance.c 17 | COMMON_C_SOURCES += ./vcpu/vpl080.c 18 | COMMON_C_SOURCES += ./vcpu/rt.c 19 | COMMON_C_SOURCES += ./vcpu/utils.c 20 | 21 | # Enable experimental "virtual PL080" mode (if DMACU_VIRTUAL_PL080=1 is given as make parameter) 22 | ifeq ($(DMACU_VIRTUAL_PL080),1) 23 | COMMON_CPPFLAGS += -DDMACU_VIRTUAL_PL080=1 24 | endif 25 | 26 | #-------------------------------------------------------------------------------------------------- 27 | # Compilation to an ARM target (via an arm-none-eabi toolchain) 28 | # 29 | # TODO: Investigate a clang setup (easy for armclang from Keil MDK; how can we deal with a 30 | # typical clang on, e.g. Debian, w.r.t. to the runtime lib?) 31 | # 32 | 33 | CROSS_PREFIX := arm-none-eabi- 34 | 35 | CROSS_CC := $(CROSS_PREFIX)gcc 36 | CROSS_AS := $(CROSS_PREFIX)gcc -x assembler-with-cpp 37 | CROSS_LD := $(CROSS_PREFIX)gcc 38 | CROSS_OBJCOPY := $(CROSS_PREFIX)objcopy 39 | 40 | CROSS_CPUFLAGS := -mcpu=arm926ej-s 41 | CROSS_CPPFLAGS := $(COMMON_CPPFLAGS) 42 | 43 | CROSS_CFLAGS := $(CROSS_CPUFLAGS) $(CROSS_CPPFLAGS) -Wall -std=c99 -pedantic -g -O1 -ffunction-sections -fdata-sections 44 | CROSS_LDFLAGS := $(CROSS_CPUFLAGS) --specs=nano.specs --specs=rdimon.specs 45 | CROSS_LIBS := 46 | 47 | C_SOURCES := $(COMMON_C_SOURCES) 48 | C_SOURCES += ./ports/qemu/versatile.c 49 | 50 | EXECUTABLE := dmacu_qemu_versatilepb.elf 51 | OBJECTS := $(C_SOURCES:%.c=%.o) 52 | 53 | #-------------------------------------------------------------------------------------------------- 54 | # Compilation of microcode files 55 | # 56 | 57 | MC_AS := $(CROSS_AS) 58 | MC_ASFLAGS := -nostartfiles -nodefaultlibs -I ./vcpu/mc/ -Ttext=0x00000000 -e 0x00000000 59 | MC_OBJCOPY := $(CROSS_OBJCOPY) 60 | MC_OCFLAGS_CODE := -Obinary -j .microcode.program 61 | MC_OCFLAGS_DATA := -Obinary -j .microcode.data 62 | 63 | # Source files for microcode compilation 64 | MC_SOURCES := ./vcpu/mc/demo.mc 65 | MC_SOURCES += ./vcpu/mc/pl080.mc 66 | 67 | # Raw object files resulting from microcode compilation 68 | MC_OBJECTS := $(MC_SOURCES:%.mc=%.o) 69 | 70 | # Raw binaries for microcode program and data images 71 | MC_BINARIES := $(MC_OBJECTS:%.o=%.code.bin) # Code segment images 72 | MC_BINARIES += $(MC_OBJECTS:%.o=%.data.bin) # Data segment images 73 | 74 | # Raw microcode program and data images prepared for inclusion in C initializers 75 | MC_INCS := $(MC_BINARIES:%.bin=%.inc) 76 | 77 | #-------------------------------------------------------------------------------------------------- 78 | # Compilation on the host (via clang) 79 | # 80 | 81 | # Build as 32 bit binary (PL080 emulation does currently not work on 64-bit) 82 | # 83 | # FIXME: We currently force the maximum RAM alignment to 4K (instead of 64K) due to limitation 84 | # with qemu-i386 running on WSL. This might cause bugs ... 85 | # 86 | HOST_CC := clang 87 | HOST_CPUFLAGS := -m32 -DDMACU_RAM_ALIGNMENT=0x1000 -DDMACU_ROM_ALIGNMENT=0x1000 88 | HOST_OPTFLAGS := -g -O1 -flto 89 | HOST_CFLAGS := $(HOST_CPUFLAGS) $(COMMON_CPPFLAGS) -Wall -std=c99 -pedantic $(HOST_OPTFLAGS) 90 | 91 | HOST_C_SOURCES := $(COMMON_C_SOURCES) 92 | HOST_C_SOURCES += ./ports/hostemu/pl080.c 93 | HOST_C_SOURCES += ./ports/hostemu/hostemu.c 94 | 95 | HOST_EXECUTABLE := hostemu32.elf 96 | 97 | #-------------------------------------------------------------------------------------------------- 98 | 99 | # Build all targets 100 | all: $(EXECUTABLE) $(HOST_EXECUTABLE) 101 | 102 | # Cleanup 103 | clean: 104 | rm -f $(HOST_EXECUTABLE) $(EXECUTABLE) $(OBJECTS) 105 | rm -f $(MC_INCS) $(MC_BINARIES) $(MC_OBJECTS) 106 | 107 | # Build the target image and call-out to QEMU 108 | sim: $(EXECUTABLE) 109 | qemu-system-arm -machine versatilepb -semihosting -nographic -kernel $(EXECUTABLE) 110 | 111 | # Host-side simulation (using qemu-i386 to support 64-bit hosts such as WSL on Windows 10) 112 | host-sim: $(HOST_EXECUTABLE) 113 | qemu-i386 $(HOST_EXECUTABLE) 114 | 115 | # Link the target binary 116 | $(EXECUTABLE): $(OBJECTS) 117 | $(CROSS_LD) $(CROSS_LDFLAGS) -o $@ $(OBJECTS) $(CROSS_LIBS) 118 | 119 | # Compiler a target object file (form C sources) 120 | %.o: %.c 121 | $(CROSS_CC) $(CROSS_CFLAGS) -o $@ -c $< 122 | 123 | # Compile and link the hostemu target 124 | $(HOST_EXECUTABLE): $(HOST_C_SOURCES) $(MC_INCS) 125 | $(HOST_CC) -o $@ $(HOST_CFLAGS) $(HOST_C_SOURCES) 126 | 127 | # Explicitly declare the dependecy for utils.o and vpl080.o (test program) 128 | vcpu/utils.o: $(MC_INCS) 129 | vcpu/vpl080.o: $(MC_INCS) 130 | 131 | # Special purpose testing 132 | hostemu-arm: 133 | $(MAKE) -C . HOST_CC=arm-none-eabi-gcc HOST_CPUFLAGS="-mcpu=arm926ej-s --specs=nano.specs --specs=rdimon.specs" clean hostemu32.elf 134 | 135 | #-------------------------------------------------------------------------------------------------- 136 | # Build the microcode 137 | # 138 | microcode: $(MC_INCS) 139 | 140 | # Compile a microcode program (into a binary file) 141 | # 142 | # We use a two step approach: 143 | # 1. Compile+link an assembler program (at address 0) 144 | # 2. Extract a binary image (via objcopy) 145 | # 146 | %.o: %.mc 147 | $(MC_AS) -o $@ $(MC_ASFLAGS) $< 148 | 149 | # Extract the code segment 150 | %.code.bin: %.o 151 | $(MC_OBJCOPY) $(MC_OCFLAGS_CODE) $< $@ 152 | 153 | # Extract the data segment 154 | %.data.bin: %.o 155 | $(MC_OBJCOPY) $(MC_OCFLAGS_DATA) $< $@ 156 | 157 | # Prepare for inclusion in C source code 158 | # 159 | # We use the output of "xxd -i" bar the header/footer lines that are added by the tool 160 | %.inc: %.bin 161 | xxd -i $< | head --lines=-2 | tail --lines=+2 > $@ 162 | -------------------------------------------------------------------------------- /src/c/ports/hostemu/hostemu.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Minimal CPU Emulator Powered by the ARM PL080 DMA Controller (dmacu) 3 | * 4 | * This file implements a minimalistic standalone emulator that is runnable 5 | * on non-ARM systems. 6 | * 7 | * Copyright (c) 2019-2022 Johannes Winter 8 | * 9 | * This file is licensed under the MIT License. See LICENSE in the root directory 10 | * of the prohect for the license text. 11 | * 12 | * This program can only be built as 32-bit binary (due to the way how the PL080 DMA and our emulation 13 | * thereof works). To run it on a native 64-bit environment one can alway's resort to QEMU's i386 user-mode 14 | * emulator (qemu-i386) 15 | */ 16 | #include 17 | #include "pl080.h" 18 | 19 | #include // primary instance 20 | 21 | #include 22 | #include 23 | 24 | //------------------------------------------------------------------------------------------------- 25 | // Dummy HAL configuration 26 | // 27 | const Hal_Config_t gHalConfig = 28 | { 29 | .platform_id = HAL_PLATFORM_HOST 30 | }; 31 | 32 | //----------------------------------------------------------------------------------------- 33 | void Hal_Init(void) 34 | { 35 | // No special initialization needed. 36 | } 37 | 38 | //----------------------------------------------------------------------------------------- 39 | void Hal_DmaTransfer(const Dma_Descriptor_t *entry) 40 | { 41 | Dmacu_Cpu_t *cpu = Dmacu_GetCpu(); 42 | 43 | // Virtual DMA channel 44 | PL080_Channel_t ch0 = 45 | { 46 | // Setup DMA channel #0 (using the first descriptor) 47 | .src_addr = entry->src, 48 | .dst_addr = entry->dst, 49 | .lli = entry->lli, 50 | .control = entry->ctrl, 51 | 52 | // Set the channel configuration for channel 0 (and enable) 53 | .config = UINT32_C(0x0000000001) 54 | }; 55 | 56 | uint32_t old_state = cpu->DbgState; 57 | 58 | while (PL080_Channel_Process(&ch0)) 59 | { 60 | if (cpu->DbgState != old_state) 61 | { 62 | if (cpu->DbgState == 0x65786563u) 63 | { 64 | // Entry to debug state 65 | puts("-------------------------------"); 66 | Dmacu_DumpCpuState("vcpu[exec]", cpu); 67 | } 68 | 69 | old_state = cpu->DbgState; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/c/ports/hostemu/pl080.c: -------------------------------------------------------------------------------- 1 | // 2 | // Minimal CPU Emulator Powered by the ARM PL080 DMA Controller (dmacu) 3 | // 4 | // This file implements a minimalistic model of the PL080 DMA controller. 5 | // 6 | // Copyright (c) 2019-2022 Johannes Winter 7 | // 8 | // This file is licensed under the MIT License. See LICENSE in the root directory 9 | // of the prohect for the license text. 10 | // 11 | // FIXME: This currently requires a 32-bit CPU (build with "-m32") :( 12 | // 13 | // Typical build: gcc -m32 -Wall -pedantic -std=c99 dmacu_standalone_emu.c -x assembler-with-cpp dmacu_pl080.s 14 | // 15 | // Note: This MAY (read: worked once, likely to break in funny ways, expect the bugs to invade) on 64-bit systems with: 16 | // gcc -no-pie -Wall -pedantic -std=c99 dmacu_standalone_emu.c -x assembler-with-cpp dmacu_pl080.s 17 | // The no-pie option allows R_X86_64_32 to work, which helps us :) 18 | // 19 | #include "pl080.h" 20 | 21 | #include 22 | 23 | /// \brief Enable logging of DMA transactions (for debugging) 24 | #define LOG_DMA (0) 25 | 26 | //---------------------------------------------------------------------- 27 | bool PL080_Channel_Process(PL080_Channel_t *ch) 28 | { 29 | bool progress = false; 30 | 31 | // Is the channel enabled? 32 | if (0u != (ch->config & PL080_CH_CONFIG_E)) 33 | { 34 | // TODO: Check for channel control, we currently ignore most of it and 35 | // statically assume byte transfers. 36 | uint32_t ctrl = ch->control; 37 | uint32_t size = (ctrl & PL080_CH_CTRL_SIZE_MASK) >> PL080_CH_CTRL_SIZE_POS; 38 | 39 | // Extract source and destination width (in bytes) 40 | uint32_t dwidth = 1u << ((ctrl & PL080_CH_CTRL_DWIDTH_MASK) >> PL080_CH_CTRL_DWIDTH_POS); 41 | uint32_t swidth = 1u << ((ctrl & PL080_CH_CTRL_SWIDTH_MASK) >> PL080_CH_CTRL_SWIDTH_POS); 42 | 43 | if (size > 0u) 44 | { 45 | // Update control (we will consume the size) 46 | ch->control = ctrl & ~PL080_CH_CTRL_SIZE_MASK; 47 | 48 | volatile const uint8_t *const src = (const uint8_t *) ch->src_addr; 49 | volatile uint8_t *const dst = (uint8_t *) ch->dst_addr; 50 | 51 | #if (LOG_DMA >= 2) 52 | printf ("dma[copy] %p -> %p size:%u dwidth:%u swidth:%u data:[", (void *) src, (void *) dst, 53 | size, dwidth, swidth); 54 | 55 | // We only support the swidth==dwidth case properly (at the moment). 56 | if (dwidth != swidth) 57 | { 58 | printf("dma[copy]: critical warning: pl080 model only supports dwidth==swidth\n"); 59 | } 60 | #else 61 | (void) swidth; 62 | (void) dwidth; 63 | #endif 64 | 65 | // Scale the size by our destination width (this likely produces strange effects if swidth != dwidth) 66 | size *= dwidth; 67 | 68 | // Process any data to copy 69 | uint32_t src_off = 0u; 70 | uint32_t dst_off = 0u; 71 | 72 | for (uint32_t i = 0u; i < size; ++i) 73 | { 74 | #if (LOG_DMA >= 3) 75 | printf(" %02X", (unsigned) (src[src_off] & 0xFFu)); 76 | #endif 77 | dst[dst_off] = src[src_off]; 78 | 79 | if (0u != (ctrl & 0x04000000)) 80 | { 81 | // Source increment 82 | src_off += 1u; 83 | } 84 | 85 | if (0u != (ctrl & 0x08000000)) 86 | { 87 | // Destination increment 88 | dst_off += 1u; 89 | } 90 | } 91 | #if (LOG_DMA >= 2) 92 | printf(" ]\n"); 93 | #endif 94 | // No more data to transfer (try to fetch next channel descriptor) 95 | if (ch->lli != 0u) 96 | { 97 | const uint32_t *const next = (const uint32_t *) ch->lli; 98 | #if (LOG_DMA >= 1) 99 | printf ("dma[link] %p -> src:%08X dst:%08X lli:%08X control:%08X\n", 100 | (void*) ch->lli, (unsigned) next[0u], (unsigned) next[1u], 101 | (unsigned) next[2u], (unsigned) next[3u]); 102 | #endif 103 | ch->src_addr = next[0u]; 104 | ch->dst_addr = next[1u]; 105 | ch->lli = next[2u]; 106 | ch->control = next[3u]; 107 | } 108 | 109 | // We made some progress 110 | progress = true; 111 | } 112 | } 113 | 114 | return progress; 115 | } 116 | -------------------------------------------------------------------------------- /src/c/ports/hostemu/pl080.h: -------------------------------------------------------------------------------- 1 | // 2 | // Minimal CPU Emulator Powered by the ARM PL080 DMA Controller (dmacu) 3 | // 4 | // This file implements a minimalistic model of the PL080 DMA controller. 5 | // 6 | // Copyright (c) 2019-2022 Johannes Winter 7 | // 8 | // This file is licensed under the MIT License. See LICENSE in the root directory 9 | // of the prohect for the license text. 10 | // 11 | // FIXME: This currently requires a 32-bit CPU (build with "-m32") :( 12 | // 13 | // Typical build: gcc -m32 -Wall -pedantic -std=c99 dmacu_standalone_emu.c -x assembler-with-cpp dmacu_pl080.s 14 | // 15 | // Note: This MAY (read: worked once, likely to break in funny ways, expect the bugs to invade) on 64-bit systems with: 16 | // gcc -no-pie -Wall -pedantic -std=c99 dmacu_standalone_emu.c -x assembler-with-cpp dmacu_pl080.s 17 | // The no-pie option allows R_X86_64_32 to work, which helps us :) 18 | // 19 | 20 | #ifndef PL080_H_ 21 | #define PL080_H_ 1 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | /// \brief Simplified PL080 channel emulation 28 | typedef struct 29 | { 30 | uint32_t src_addr; 31 | uint32_t dst_addr; 32 | uint32_t lli; 33 | uint32_t control; 34 | uint32_t config; 35 | } PL080_Channel_t; 36 | 37 | #define PL080_CH_CTRL_SIZE_MASK UINT32_C(0x00000FFF) 38 | #define PL080_CH_CTRL_SIZE_POS UINT32_C(0) 39 | #define PL080_CH_CONFIG_E UINT32_C(0x00000001) 40 | 41 | #define PL080_CH_CTRL_DWIDTH_MASK UINT32_C(0x00E00000) 42 | #define PL080_CH_CTRL_DWIDTH_POS UINT32_C(21) 43 | 44 | #define PL080_CH_CTRL_SWIDTH_MASK UINT32_C(0x001C0000) 45 | #define PL080_CH_CTRL_SWIDTH_POS UINT32_C(18) 46 | 47 | /// \brief Processes a transfer descriptor on a PL080 DMA channel 48 | /// 49 | /// \param[in,out] ch points to the emulated PL080 DMA channel to be updated. 50 | /// 51 | /// \return True if the channel made progress, false if the channel is idle. 52 | extern bool PL080_Channel_Process(PL080_Channel_t *ch); 53 | 54 | #endif // PL080_H_ 55 | -------------------------------------------------------------------------------- /src/c/ports/lpc176x/keil/.gitignore: -------------------------------------------------------------------------------- 1 | /DebugConfig/ 2 | /Release/ 3 | *.uvgui* 4 | *.scvd 5 | -------------------------------------------------------------------------------- /src/c/ports/lpc176x/keil/RTE/Device/LPC1769/startup_LPC17xx.s: -------------------------------------------------------------------------------- 1 | ;/**************************************************************************//** 2 | ; * @file startup_LPC17xx.s 3 | ; * @brief CMSIS Cortex-M3 Core Device Startup File for 4 | ; * NXP LPC17xx Device Series 5 | ; * @version V1.10 6 | ; * @date 06. April 2011 7 | ; * 8 | ; * @note 9 | ; * Copyright (C) 2009-2011 ARM Limited. All rights reserved. 10 | ; * 11 | ; * @par 12 | ; * ARM Limited (ARM) is supplying this software for use with Cortex-M 13 | ; * processor based microcontrollers. This file can be freely distributed 14 | ; * within development tools that are supporting such ARM based processors. 15 | ; * 16 | ; * @par 17 | ; * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED 18 | ; * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF 19 | ; * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. 20 | ; * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR 21 | ; * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. 22 | ; * 23 | ; ******************************************************************************/ 24 | 25 | ; *------- <<< Use Configuration Wizard in Context Menu >>> ------------------ 26 | 27 | ; Stack Configuration 28 | ; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8> 29 | ; 30 | 31 | Stack_Size EQU 0x00000400 32 | 33 | AREA STACK, NOINIT, READWRITE, ALIGN=3 34 | Stack_Mem SPACE Stack_Size 35 | __initial_sp 36 | 37 | 38 | ; Heap Configuration 39 | ; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8> 40 | ; 41 | 42 | Heap_Size EQU 0x00000400 43 | 44 | AREA HEAP, NOINIT, READWRITE, ALIGN=3 45 | __heap_base 46 | Heap_Mem SPACE Heap_Size 47 | __heap_limit 48 | 49 | 50 | PRESERVE8 51 | THUMB 52 | 53 | 54 | ; Vector Table Mapped to Address 0 at Reset 55 | 56 | AREA RESET, DATA, READONLY 57 | EXPORT __Vectors 58 | 59 | __Vectors DCD __initial_sp ; Top of Stack 60 | DCD Reset_Handler ; Reset Handler 61 | DCD NMI_Handler ; NMI Handler 62 | DCD HardFault_Handler ; Hard Fault Handler 63 | DCD MemManage_Handler ; MPU Fault Handler 64 | DCD BusFault_Handler ; Bus Fault Handler 65 | DCD UsageFault_Handler ; Usage Fault Handler 66 | DCD 0 ; Reserved 67 | DCD 0 ; Reserved 68 | DCD 0 ; Reserved 69 | DCD 0 ; Reserved 70 | DCD SVC_Handler ; SVCall Handler 71 | DCD DebugMon_Handler ; Debug Monitor Handler 72 | DCD 0 ; Reserved 73 | DCD PendSV_Handler ; PendSV Handler 74 | DCD SysTick_Handler ; SysTick Handler 75 | 76 | ; External Interrupts 77 | DCD WDT_IRQHandler ; 16: Watchdog Timer 78 | DCD TIMER0_IRQHandler ; 17: Timer0 79 | DCD TIMER1_IRQHandler ; 18: Timer1 80 | DCD TIMER2_IRQHandler ; 19: Timer2 81 | DCD TIMER3_IRQHandler ; 20: Timer3 82 | DCD UART0_IRQHandler ; 21: UART0 83 | DCD UART1_IRQHandler ; 22: UART1 84 | DCD UART2_IRQHandler ; 23: UART2 85 | DCD UART3_IRQHandler ; 24: UART3 86 | DCD PWM1_IRQHandler ; 25: PWM1 87 | DCD I2C0_IRQHandler ; 26: I2C0 88 | DCD I2C1_IRQHandler ; 27: I2C1 89 | DCD I2C2_IRQHandler ; 28: I2C2 90 | DCD SPI_IRQHandler ; 29: SPI 91 | DCD SSP0_IRQHandler ; 30: SSP0 92 | DCD SSP1_IRQHandler ; 31: SSP1 93 | DCD PLL0_IRQHandler ; 32: PLL0 Lock (Main PLL) 94 | DCD RTC_IRQHandler ; 33: Real Time Clock 95 | DCD EINT0_IRQHandler ; 34: External Interrupt 0 96 | DCD EINT1_IRQHandler ; 35: External Interrupt 1 97 | DCD EINT2_IRQHandler ; 36: External Interrupt 2 98 | DCD EINT3_IRQHandler ; 37: External Interrupt 3 99 | DCD ADC_IRQHandler ; 38: A/D Converter 100 | DCD BOD_IRQHandler ; 39: Brown-Out Detect 101 | DCD USB_IRQHandler ; 40: USB 102 | DCD CAN_IRQHandler ; 41: CAN 103 | DCD DMA_IRQHandler ; 42: General Purpose DMA 104 | DCD I2S_IRQHandler ; 43: I2S 105 | DCD ENET_IRQHandler ; 44: Ethernet 106 | DCD RIT_IRQHandler ; 45: Repetitive Interrupt Timer 107 | DCD MCPWM_IRQHandler ; 46: Motor Control PWM 108 | DCD QEI_IRQHandler ; 47: Quadrature Encoder Interface 109 | DCD PLL1_IRQHandler ; 48: PLL1 Lock (USB PLL) 110 | DCD USBActivity_IRQHandler ; 49: USB Activity interrupt to wakeup 111 | DCD CANActivity_IRQHandler ; 50: CAN Activity interrupt to wakeup 112 | 113 | 114 | IF :LNOT::DEF:NO_CRP 115 | AREA |.ARM.__at_0x02FC|, CODE, READONLY 116 | CRP_Key DCD 0xFFFFFFFF 117 | ENDIF 118 | 119 | 120 | AREA |.text|, CODE, READONLY 121 | 122 | 123 | ; Reset Handler 124 | 125 | Reset_Handler PROC 126 | EXPORT Reset_Handler [WEAK] 127 | IMPORT SystemInit 128 | IMPORT __main 129 | LDR R0, =SystemInit 130 | BLX R0 131 | LDR R0, =__main 132 | BX R0 133 | ENDP 134 | 135 | 136 | ; Dummy Exception Handlers (infinite loops which can be modified) 137 | 138 | NMI_Handler PROC 139 | EXPORT NMI_Handler [WEAK] 140 | B . 141 | ENDP 142 | HardFault_Handler\ 143 | PROC 144 | EXPORT HardFault_Handler [WEAK] 145 | B . 146 | ENDP 147 | MemManage_Handler\ 148 | PROC 149 | EXPORT MemManage_Handler [WEAK] 150 | B . 151 | ENDP 152 | BusFault_Handler\ 153 | PROC 154 | EXPORT BusFault_Handler [WEAK] 155 | B . 156 | ENDP 157 | UsageFault_Handler\ 158 | PROC 159 | EXPORT UsageFault_Handler [WEAK] 160 | B . 161 | ENDP 162 | SVC_Handler PROC 163 | EXPORT SVC_Handler [WEAK] 164 | B . 165 | ENDP 166 | DebugMon_Handler\ 167 | PROC 168 | EXPORT DebugMon_Handler [WEAK] 169 | B . 170 | ENDP 171 | PendSV_Handler PROC 172 | EXPORT PendSV_Handler [WEAK] 173 | B . 174 | ENDP 175 | SysTick_Handler PROC 176 | EXPORT SysTick_Handler [WEAK] 177 | B . 178 | ENDP 179 | 180 | Default_Handler PROC 181 | 182 | EXPORT WDT_IRQHandler [WEAK] 183 | EXPORT TIMER0_IRQHandler [WEAK] 184 | EXPORT TIMER1_IRQHandler [WEAK] 185 | EXPORT TIMER2_IRQHandler [WEAK] 186 | EXPORT TIMER3_IRQHandler [WEAK] 187 | EXPORT UART0_IRQHandler [WEAK] 188 | EXPORT UART1_IRQHandler [WEAK] 189 | EXPORT UART2_IRQHandler [WEAK] 190 | EXPORT UART3_IRQHandler [WEAK] 191 | EXPORT PWM1_IRQHandler [WEAK] 192 | EXPORT I2C0_IRQHandler [WEAK] 193 | EXPORT I2C1_IRQHandler [WEAK] 194 | EXPORT I2C2_IRQHandler [WEAK] 195 | EXPORT SPI_IRQHandler [WEAK] 196 | EXPORT SSP0_IRQHandler [WEAK] 197 | EXPORT SSP1_IRQHandler [WEAK] 198 | EXPORT PLL0_IRQHandler [WEAK] 199 | EXPORT RTC_IRQHandler [WEAK] 200 | EXPORT EINT0_IRQHandler [WEAK] 201 | EXPORT EINT1_IRQHandler [WEAK] 202 | EXPORT EINT2_IRQHandler [WEAK] 203 | EXPORT EINT3_IRQHandler [WEAK] 204 | EXPORT ADC_IRQHandler [WEAK] 205 | EXPORT BOD_IRQHandler [WEAK] 206 | EXPORT USB_IRQHandler [WEAK] 207 | EXPORT CAN_IRQHandler [WEAK] 208 | EXPORT DMA_IRQHandler [WEAK] 209 | EXPORT I2S_IRQHandler [WEAK] 210 | EXPORT ENET_IRQHandler [WEAK] 211 | EXPORT RIT_IRQHandler [WEAK] 212 | EXPORT MCPWM_IRQHandler [WEAK] 213 | EXPORT QEI_IRQHandler [WEAK] 214 | EXPORT PLL1_IRQHandler [WEAK] 215 | EXPORT USBActivity_IRQHandler [WEAK] 216 | EXPORT CANActivity_IRQHandler [WEAK] 217 | 218 | WDT_IRQHandler 219 | TIMER0_IRQHandler 220 | TIMER1_IRQHandler 221 | TIMER2_IRQHandler 222 | TIMER3_IRQHandler 223 | UART0_IRQHandler 224 | UART1_IRQHandler 225 | UART2_IRQHandler 226 | UART3_IRQHandler 227 | PWM1_IRQHandler 228 | I2C0_IRQHandler 229 | I2C1_IRQHandler 230 | I2C2_IRQHandler 231 | SPI_IRQHandler 232 | SSP0_IRQHandler 233 | SSP1_IRQHandler 234 | PLL0_IRQHandler 235 | RTC_IRQHandler 236 | EINT0_IRQHandler 237 | EINT1_IRQHandler 238 | EINT2_IRQHandler 239 | EINT3_IRQHandler 240 | ADC_IRQHandler 241 | BOD_IRQHandler 242 | USB_IRQHandler 243 | CAN_IRQHandler 244 | DMA_IRQHandler 245 | I2S_IRQHandler 246 | ENET_IRQHandler 247 | RIT_IRQHandler 248 | MCPWM_IRQHandler 249 | QEI_IRQHandler 250 | PLL1_IRQHandler 251 | USBActivity_IRQHandler 252 | CANActivity_IRQHandler 253 | 254 | B . 255 | 256 | ENDP 257 | 258 | 259 | ALIGN 260 | 261 | 262 | ; User Initial Stack & Heap 263 | 264 | IF :DEF:__MICROLIB 265 | 266 | EXPORT __initial_sp 267 | EXPORT __heap_base 268 | EXPORT __heap_limit 269 | 270 | ELSE 271 | 272 | IMPORT __use_two_region_memory 273 | EXPORT __user_initial_stackheap 274 | __user_initial_stackheap 275 | 276 | LDR R0, = Heap_Mem 277 | LDR R1, =(Stack_Mem + Stack_Size) 278 | LDR R2, = (Heap_Mem + Heap_Size) 279 | LDR R3, = Stack_Mem 280 | BX LR 281 | 282 | ALIGN 283 | 284 | ENDIF 285 | 286 | 287 | END 288 | -------------------------------------------------------------------------------- /src/c/ports/lpc176x/keil/RTE/Device/LPC1769/system_LPC17xx.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file system_LPC17xx.c 3 | * @brief CMSIS Device System Source File for 4 | * NXP LPC17xx Device Series 5 | * @version V1.14 6 | * @date 05. April 2016 7 | ******************************************************************************/ 8 | /* Copyright (c) 2012 - 2016 ARM LIMITED 9 | 10 | All rights reserved. 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | - Redistributions of source code must retain the above copyright 14 | notice, this list of conditions and the following disclaimer. 15 | - Redistributions in binary form must reproduce the above copyright 16 | notice, this list of conditions and the following disclaimer in the 17 | documentation and/or other materials provided with the distribution. 18 | - Neither the name of ARM nor the names of its contributors may be used 19 | to endorse or promote products derived from this software without 20 | specific prior written permission. 21 | * 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE 26 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | ---------------------------------------------------------------------------*/ 34 | 35 | #include 36 | #include "LPC17xx.h" 37 | 38 | /* 39 | //-------- <<< Use Configuration Wizard in Context Menu >>> ------------------ 40 | */ 41 | 42 | /*--------------------- Clock Configuration ---------------------------------- 43 | // 44 | // Clock Configuration 45 | // System Controls and Status Register (SCS) 46 | // OSCRANGE: Main Oscillator Range Select 47 | // <0=> 1 MHz to 20 MHz 48 | // <1=> 15 MHz to 25 MHz 49 | // OSCEN: Main Oscillator Enable 50 | // 51 | // 52 | // 53 | // Clock Source Select Register (CLKSRCSEL) 54 | // CLKSRC: PLL Clock Source Selection 55 | // <0=> Internal RC oscillator 56 | // <1=> Main oscillator 57 | // <2=> RTC oscillator 58 | // 59 | // 60 | // PLL0 Configuration (Main PLL) 61 | // PLL0 Configuration Register (PLL0CFG) 62 | // F_cco0 = (2 * M * F_in) / N 63 | // F_in must be in the range of 32 kHz to 50 MHz 64 | // F_cco0 must be in the range of 275 MHz to 550 MHz 65 | // MSEL: PLL Multiplier Selection 66 | // <6-32768><#-1> 67 | // M Value 68 | // NSEL: PLL Divider Selection 69 | // <1-256><#-1> 70 | // N Value 71 | // 72 | // 73 | // 74 | // PLL1 Configuration (USB PLL) 75 | // PLL1 Configuration Register (PLL1CFG) 76 | // F_usb = M * F_osc or F_usb = F_cco1 / (2 * P) 77 | // F_cco1 = F_osc * M * 2 * P 78 | // F_cco1 must be in the range of 156 MHz to 320 MHz 79 | // MSEL: PLL Multiplier Selection 80 | // <1-32><#-1> 81 | // M Value (for USB maximum value is 4) 82 | // PSEL: PLL Divider Selection 83 | // <0=> 1 84 | // <1=> 2 85 | // <2=> 4 86 | // <3=> 8 87 | // P Value 88 | // 89 | // 90 | // 91 | // CPU Clock Configuration Register (CCLKCFG) 92 | // CCLKSEL: Divide Value for CPU Clock from PLL0 93 | // <1-256><#-1> 94 | // 95 | // 96 | // USB Clock Configuration Register (USBCLKCFG) 97 | // USBSEL: Divide Value for USB Clock from PLL0 98 | // <0-15> 99 | // Divide is USBSEL + 1 100 | // 101 | // 102 | // Peripheral Clock Selection Register 0 (PCLKSEL0) 103 | // PCLK_WDT: Peripheral Clock Selection for WDT 104 | // <0=> Pclk = Cclk / 4 105 | // <1=> Pclk = Cclk 106 | // <2=> Pclk = Cclk / 2 107 | // <3=> Pclk = Cclk / 8 108 | // PCLK_TIMER0: Peripheral Clock Selection for TIMER0 109 | // <0=> Pclk = Cclk / 4 110 | // <1=> Pclk = Cclk 111 | // <2=> Pclk = Cclk / 2 112 | // <3=> Pclk = Cclk / 8 113 | // PCLK_TIMER1: Peripheral Clock Selection for TIMER1 114 | // <0=> Pclk = Cclk / 4 115 | // <1=> Pclk = Cclk 116 | // <2=> Pclk = Cclk / 2 117 | // <3=> Pclk = Cclk / 8 118 | // PCLK_UART0: Peripheral Clock Selection for UART0 119 | // <0=> Pclk = Cclk / 4 120 | // <1=> Pclk = Cclk 121 | // <2=> Pclk = Cclk / 2 122 | // <3=> Pclk = Cclk / 8 123 | // PCLK_UART1: Peripheral Clock Selection for UART1 124 | // <0=> Pclk = Cclk / 4 125 | // <1=> Pclk = Cclk 126 | // <2=> Pclk = Cclk / 2 127 | // <3=> Pclk = Cclk / 8 128 | // PCLK_PWM1: Peripheral Clock Selection for PWM1 129 | // <0=> Pclk = Cclk / 4 130 | // <1=> Pclk = Cclk 131 | // <2=> Pclk = Cclk / 2 132 | // <3=> Pclk = Cclk / 8 133 | // PCLK_I2C0: Peripheral Clock Selection for I2C0 134 | // <0=> Pclk = Cclk / 4 135 | // <1=> Pclk = Cclk 136 | // <2=> Pclk = Cclk / 2 137 | // <3=> Pclk = Cclk / 8 138 | // PCLK_SPI: Peripheral Clock Selection for SPI 139 | // <0=> Pclk = Cclk / 4 140 | // <1=> Pclk = Cclk 141 | // <2=> Pclk = Cclk / 2 142 | // <3=> Pclk = Cclk / 8 143 | // PCLK_SSP1: Peripheral Clock Selection for SSP1 144 | // <0=> Pclk = Cclk / 4 145 | // <1=> Pclk = Cclk 146 | // <2=> Pclk = Cclk / 2 147 | // <3=> Pclk = Cclk / 8 148 | // PCLK_DAC: Peripheral Clock Selection for DAC 149 | // <0=> Pclk = Cclk / 4 150 | // <1=> Pclk = Cclk 151 | // <2=> Pclk = Cclk / 2 152 | // <3=> Pclk = Cclk / 8 153 | // PCLK_ADC: Peripheral Clock Selection for ADC 154 | // <0=> Pclk = Cclk / 4 155 | // <1=> Pclk = Cclk 156 | // <2=> Pclk = Cclk / 2 157 | // <3=> Pclk = Cclk / 8 158 | // PCLK_CAN1: Peripheral Clock Selection for CAN1 159 | // <0=> Pclk = Cclk / 4 160 | // <1=> Pclk = Cclk 161 | // <2=> Pclk = Cclk / 2 162 | // <3=> Pclk = Cclk / 6 163 | // PCLK_CAN2: Peripheral Clock Selection for CAN2 164 | // <0=> Pclk = Cclk / 4 165 | // <1=> Pclk = Cclk 166 | // <2=> Pclk = Cclk / 2 167 | // <3=> Pclk = Cclk / 6 168 | // PCLK_ACF: Peripheral Clock Selection for ACF 169 | // <0=> Pclk = Cclk / 4 170 | // <1=> Pclk = Cclk 171 | // <2=> Pclk = Cclk / 2 172 | // <3=> Pclk = Cclk / 6 173 | // 174 | // 175 | // Peripheral Clock Selection Register 1 (PCLKSEL1) 176 | // PCLK_QEI: Peripheral Clock Selection for the Quadrature Encoder Interface 177 | // <0=> Pclk = Cclk / 4 178 | // <1=> Pclk = Cclk 179 | // <2=> Pclk = Cclk / 2 180 | // <3=> Pclk = Cclk / 8 181 | // PCLK_GPIO: Peripheral Clock Selection for GPIOs 182 | // <0=> Pclk = Cclk / 4 183 | // <1=> Pclk = Cclk 184 | // <2=> Pclk = Cclk / 2 185 | // <3=> Pclk = Cclk / 8 186 | // PCLK_PCB: Peripheral Clock Selection for the Pin Connect Block 187 | // <0=> Pclk = Cclk / 4 188 | // <1=> Pclk = Cclk 189 | // <2=> Pclk = Cclk / 2 190 | // <3=> Pclk = Cclk / 8 191 | // PCLK_I2C1: Peripheral Clock Selection for I2C1 192 | // <0=> Pclk = Cclk / 4 193 | // <1=> Pclk = Cclk 194 | // <2=> Pclk = Cclk / 2 195 | // <3=> Pclk = Cclk / 8 196 | // PCLK_SSP0: Peripheral Clock Selection for SSP0 197 | // <0=> Pclk = Cclk / 4 198 | // <1=> Pclk = Cclk 199 | // <2=> Pclk = Cclk / 2 200 | // <3=> Pclk = Cclk / 8 201 | // PCLK_TIMER2: Peripheral Clock Selection for TIMER2 202 | // <0=> Pclk = Cclk / 4 203 | // <1=> Pclk = Cclk 204 | // <2=> Pclk = Cclk / 2 205 | // <3=> Pclk = Cclk / 8 206 | // PCLK_TIMER3: Peripheral Clock Selection for TIMER3 207 | // <0=> Pclk = Cclk / 4 208 | // <1=> Pclk = Cclk 209 | // <2=> Pclk = Cclk / 2 210 | // <3=> Pclk = Cclk / 8 211 | // PCLK_UART2: Peripheral Clock Selection for UART2 212 | // <0=> Pclk = Cclk / 4 213 | // <1=> Pclk = Cclk 214 | // <2=> Pclk = Cclk / 2 215 | // <3=> Pclk = Cclk / 8 216 | // PCLK_UART3: Peripheral Clock Selection for UART3 217 | // <0=> Pclk = Cclk / 4 218 | // <1=> Pclk = Cclk 219 | // <2=> Pclk = Cclk / 2 220 | // <3=> Pclk = Cclk / 8 221 | // PCLK_I2C2: Peripheral Clock Selection for I2C2 222 | // <0=> Pclk = Cclk / 4 223 | // <1=> Pclk = Cclk 224 | // <2=> Pclk = Cclk / 2 225 | // <3=> Pclk = Cclk / 8 226 | // PCLK_I2S: Peripheral Clock Selection for I2S 227 | // <0=> Pclk = Cclk / 4 228 | // <1=> Pclk = Cclk 229 | // <2=> Pclk = Cclk / 2 230 | // <3=> Pclk = Cclk / 8 231 | // PCLK_RIT: Peripheral Clock Selection for the Repetitive Interrupt Timer 232 | // <0=> Pclk = Cclk / 4 233 | // <1=> Pclk = Cclk 234 | // <2=> Pclk = Cclk / 2 235 | // <3=> Pclk = Cclk / 8 236 | // PCLK_SYSCON: Peripheral Clock Selection for the System Control Block 237 | // <0=> Pclk = Cclk / 4 238 | // <1=> Pclk = Cclk 239 | // <2=> Pclk = Cclk / 2 240 | // <3=> Pclk = Cclk / 8 241 | // PCLK_MC: Peripheral Clock Selection for the Motor Control PWM 242 | // <0=> Pclk = Cclk / 4 243 | // <1=> Pclk = Cclk 244 | // <2=> Pclk = Cclk / 2 245 | // <3=> Pclk = Cclk / 8 246 | // 247 | // 248 | // Power Control for Peripherals Register (PCONP) 249 | // PCTIM0: Timer/Counter 0 power/clock enable 250 | // PCTIM1: Timer/Counter 1 power/clock enable 251 | // PCUART0: UART 0 power/clock enable 252 | // PCUART1: UART 1 power/clock enable 253 | // PCPWM1: PWM 1 power/clock enable 254 | // PCI2C0: I2C interface 0 power/clock enable 255 | // PCSPI: SPI interface power/clock enable 256 | // PCRTC: RTC power/clock enable 257 | // PCSSP1: SSP interface 1 power/clock enable 258 | // PCAD: A/D converter power/clock enable 259 | // PCCAN1: CAN controller 1 power/clock enable 260 | // PCCAN2: CAN controller 2 power/clock enable 261 | // PCGPIO: GPIOs power/clock enable 262 | // PCRIT: Repetitive interrupt timer power/clock enable 263 | // PCMC: Motor control PWM power/clock enable 264 | // PCQEI: Quadrature encoder interface power/clock enable 265 | // PCI2C1: I2C interface 1 power/clock enable 266 | // PCSSP0: SSP interface 0 power/clock enable 267 | // PCTIM2: Timer 2 power/clock enable 268 | // PCTIM3: Timer 3 power/clock enable 269 | // PCUART2: UART 2 power/clock enable 270 | // PCUART3: UART 3 power/clock enable 271 | // PCI2C2: I2C interface 2 power/clock enable 272 | // PCI2S: I2S interface power/clock enable 273 | // PCGPDMA: GP DMA function power/clock enable 274 | // PCENET: Ethernet block power/clock enable 275 | // PCUSB: USB interface power/clock enable 276 | // 277 | // 278 | // Clock Output Configuration Register (CLKOUTCFG) 279 | // CLKOUTSEL: Selects clock source for CLKOUT 280 | // <0=> CPU clock 281 | // <1=> Main oscillator 282 | // <2=> Internal RC oscillator 283 | // <3=> USB clock 284 | // <4=> RTC oscillator 285 | // CLKOUTDIV: Selects clock divider for CLKOUT 286 | // <1-16><#-1> 287 | // CLKOUT_EN: CLKOUT enable control 288 | // 289 | // 290 | // 291 | */ 292 | 293 | 294 | 295 | #define CLOCK_SETUP 1 296 | #define SCS_Val 0x00000020 297 | #define CLKSRCSEL_Val 0x00000001 298 | #define PLL0_SETUP 1 299 | #define PLL0CFG_Val 0x00050063 300 | #define PLL1_SETUP 0 301 | #define PLL1CFG_Val 0x00000023 302 | #define CCLKCFG_Val 0x00000003 303 | #define USBCLKCFG_Val 0x00000000 304 | #define PCLKSEL0_Val 0x00000000 305 | #define PCLKSEL1_Val 0x00000000 306 | #define PCONP_Val 0x00208000 307 | #define CLKOUTCFG_Val 0x00000000 308 | 309 | 310 | /*--------------------- Flash Accelerator Configuration ---------------------- 311 | // 312 | // Flash Accelerator Configuration 313 | // FLASHTIM: Flash Access Time 314 | // <0=> 1 CPU clock (for CPU clock up to 20 MHz) 315 | // <1=> 2 CPU clocks (for CPU clock up to 40 MHz) 316 | // <2=> 3 CPU clocks (for CPU clock up to 60 MHz) 317 | // <3=> 4 CPU clocks (for CPU clock up to 80 MHz) 318 | // <4=> 5 CPU clocks (for CPU clock up to 100 MHz) 319 | // <5=> 6 CPU clocks (for any CPU clock) 320 | // 321 | */ 322 | #define FLASH_SETUP 1 323 | #define FLASHCFG_Val 0x00004000 324 | 325 | /* 326 | //-------- <<< end of configuration section >>> ------------------------------ 327 | */ 328 | 329 | /*---------------------------------------------------------------------------- 330 | Check the register settings 331 | *----------------------------------------------------------------------------*/ 332 | #define CHECK_RANGE(val, min, max) ((val < min) || (val > max)) 333 | #define CHECK_RSVD(val, mask) (val & mask) 334 | 335 | /* Clock Configuration -------------------------------------------------------*/ 336 | #if (CHECK_RSVD((SCS_Val), ~0x00000030)) 337 | #error "SCS: Invalid values of reserved bits!" 338 | #endif 339 | 340 | #if (CHECK_RANGE((CLKSRCSEL_Val), 0, 2)) 341 | #error "CLKSRCSEL: Value out of range!" 342 | #endif 343 | 344 | #if (CHECK_RSVD((PLL0CFG_Val), ~0x00FF7FFF)) 345 | #error "PLL0CFG: Invalid values of reserved bits!" 346 | #endif 347 | 348 | #if (CHECK_RSVD((PLL1CFG_Val), ~0x0000007F)) 349 | #error "PLL1CFG: Invalid values of reserved bits!" 350 | #endif 351 | 352 | #if (PLL0_SETUP) /* if PLL0 is used */ 353 | #if (CCLKCFG_Val < 2) /* CCLKSEL must be greater then 1 */ 354 | #error "CCLKCFG: CCLKSEL must be greater then 1 if PLL0 is used!" 355 | #endif 356 | #endif 357 | 358 | #if (CHECK_RANGE((CCLKCFG_Val), 0, 255)) 359 | #error "CCLKCFG: Value out of range!" 360 | #endif 361 | 362 | #if (CHECK_RSVD((USBCLKCFG_Val), ~0x0000000F)) 363 | #error "USBCLKCFG: Invalid values of reserved bits!" 364 | #endif 365 | 366 | #if (CHECK_RSVD((PCLKSEL0_Val), 0x000C0C00)) 367 | #error "PCLKSEL0: Invalid values of reserved bits!" 368 | #endif 369 | 370 | #if (CHECK_RSVD((PCLKSEL1_Val), 0x03000300)) 371 | #error "PCLKSEL1: Invalid values of reserved bits!" 372 | #endif 373 | 374 | #if (CHECK_RSVD((PCONP_Val), 0x10100821)) 375 | #error "PCONP: Invalid values of reserved bits!" 376 | #endif 377 | 378 | #if (CHECK_RSVD((CLKOUTCFG_Val), ~0x000001FF)) 379 | #error "CLKOUTCFG: Invalid values of reserved bits!" 380 | #endif 381 | 382 | /* Flash Accelerator Configuration -------------------------------------------*/ 383 | #if (CHECK_RSVD((FLASHCFG_Val), ~0x0000F000)) 384 | #error "FLASHCFG: Invalid values of reserved bits!" 385 | #endif 386 | 387 | 388 | /*---------------------------------------------------------------------------- 389 | DEFINES 390 | *----------------------------------------------------------------------------*/ 391 | 392 | /*---------------------------------------------------------------------------- 393 | Define clocks 394 | *----------------------------------------------------------------------------*/ 395 | #define XTAL (12000000UL) /* Oscillator frequency */ 396 | #define OSC_CLK ( XTAL) /* Main oscillator frequency */ 397 | #define RTC_CLK ( 32768UL) /* RTC oscillator frequency */ 398 | #define IRC_OSC ( 4000000UL) /* Internal RC oscillator frequency */ 399 | 400 | 401 | /* F_cco0 = (2 * M * F_in) / N */ 402 | #define __M (((PLL0CFG_Val ) & 0x7FFF) + 1) 403 | #define __N (((PLL0CFG_Val >> 16) & 0x00FF) + 1) 404 | #define __FCCO(__F_IN) ((2ULL * __M * __F_IN) / __N) 405 | #define __CCLK_DIV (((CCLKCFG_Val ) & 0x00FF) + 1) 406 | 407 | /* Determine core clock frequency according to settings */ 408 | #if (PLL0_SETUP) 409 | #if ((CLKSRCSEL_Val & 0x03) == 1) 410 | #define __CORE_CLK (__FCCO(OSC_CLK) / __CCLK_DIV) 411 | #elif ((CLKSRCSEL_Val & 0x03) == 2) 412 | #define __CORE_CLK (__FCCO(RTC_CLK) / __CCLK_DIV) 413 | #else 414 | #define __CORE_CLK (__FCCO(IRC_OSC) / __CCLK_DIV) 415 | #endif 416 | #else 417 | #if ((CLKSRCSEL_Val & 0x03) == 1) 418 | #define __CORE_CLK (OSC_CLK / __CCLK_DIV) 419 | #elif ((CLKSRCSEL_Val & 0x03) == 2) 420 | #define __CORE_CLK (RTC_CLK / __CCLK_DIV) 421 | #else 422 | #define __CORE_CLK (IRC_OSC / __CCLK_DIV) 423 | #endif 424 | #endif 425 | 426 | 427 | 428 | /*---------------------------------------------------------------------------- 429 | System Core Clock Variable 430 | *----------------------------------------------------------------------------*/ 431 | uint32_t SystemCoreClock = __CORE_CLK; 432 | 433 | 434 | /*---------------------------------------------------------------------------- 435 | SystemCoreClockUpdate 436 | *----------------------------------------------------------------------------*/ 437 | void SystemCoreClockUpdate (void) /* Get Core Clock Frequency */ 438 | { 439 | /* Determine clock frequency according to clock register values */ 440 | if (((LPC_SC->PLL0STAT >> 24) & 3) == 3) { /* If PLL0 enabled and connected */ 441 | switch (LPC_SC->CLKSRCSEL & 0x03) { 442 | case 0: /* Int. RC oscillator => PLL0 */ 443 | case 3: /* Reserved, default to Int. RC */ 444 | SystemCoreClock = (IRC_OSC * 445 | ((2ULL * ((LPC_SC->PLL0STAT & 0x7FFF) + 1))) / 446 | (((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1) / 447 | ((LPC_SC->CCLKCFG & 0xFF)+ 1)); 448 | break; 449 | case 1: /* Main oscillator => PLL0 */ 450 | SystemCoreClock = (OSC_CLK * 451 | ((2ULL * ((LPC_SC->PLL0STAT & 0x7FFF) + 1))) / 452 | (((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1) / 453 | ((LPC_SC->CCLKCFG & 0xFF)+ 1)); 454 | break; 455 | case 2: /* RTC oscillator => PLL0 */ 456 | SystemCoreClock = (RTC_CLK * 457 | ((2ULL * ((LPC_SC->PLL0STAT & 0x7FFF) + 1))) / 458 | (((LPC_SC->PLL0STAT >> 16) & 0xFF) + 1) / 459 | ((LPC_SC->CCLKCFG & 0xFF)+ 1)); 460 | break; 461 | } 462 | } else { 463 | switch (LPC_SC->CLKSRCSEL & 0x03) { 464 | case 0: /* Int. RC oscillator => PLL0 */ 465 | case 3: /* Reserved, default to Int. RC */ 466 | SystemCoreClock = IRC_OSC / ((LPC_SC->CCLKCFG & 0xFF)+ 1); 467 | break; 468 | case 1: /* Main oscillator => PLL0 */ 469 | SystemCoreClock = OSC_CLK / ((LPC_SC->CCLKCFG & 0xFF)+ 1); 470 | break; 471 | case 2: /* RTC oscillator => PLL0 */ 472 | SystemCoreClock = RTC_CLK / ((LPC_SC->CCLKCFG & 0xFF)+ 1); 473 | break; 474 | } 475 | } 476 | 477 | } 478 | 479 | /*---------------------------------------------------------------------------- 480 | SystemInit 481 | *----------------------------------------------------------------------------*/ 482 | void SystemInit (void) 483 | { 484 | #if (CLOCK_SETUP) /* Clock Setup */ 485 | LPC_SC->SCS = SCS_Val; 486 | if (LPC_SC->SCS & (1 << 5)) { /* If Main Oscillator is enabled */ 487 | while ((LPC_SC->SCS & (1<<6)) == 0);/* Wait for Oscillator to be ready */ 488 | } 489 | 490 | LPC_SC->CCLKCFG = CCLKCFG_Val; /* Setup Clock Divider */ 491 | /* Periphral clock must be selected before PLL0 enabling and connecting 492 | * - according errata.lpc1768-16.March.2010 - 493 | */ 494 | LPC_SC->PCLKSEL0 = PCLKSEL0_Val; /* Peripheral Clock Selection */ 495 | LPC_SC->PCLKSEL1 = PCLKSEL1_Val; 496 | 497 | LPC_SC->CLKSRCSEL = CLKSRCSEL_Val; /* Select Clock Source sysclk / PLL0 */ 498 | 499 | #if (PLL0_SETUP) 500 | LPC_SC->PLL0CFG = PLL0CFG_Val; /* configure PLL0 */ 501 | LPC_SC->PLL0FEED = 0xAA; 502 | LPC_SC->PLL0FEED = 0x55; 503 | 504 | LPC_SC->PLL0CON = 0x01; /* PLL0 Enable */ 505 | LPC_SC->PLL0FEED = 0xAA; 506 | LPC_SC->PLL0FEED = 0x55; 507 | while (!(LPC_SC->PLL0STAT & (1<<26)));/* Wait for PLOCK0 */ 508 | 509 | LPC_SC->PLL0CON = 0x03; /* PLL0 Enable & Connect */ 510 | LPC_SC->PLL0FEED = 0xAA; 511 | LPC_SC->PLL0FEED = 0x55; 512 | while ((LPC_SC->PLL0STAT & ((1<<25) | (1<<24))) != ((1<<25) | (1<<24))); /* Wait for PLLC0_STAT & PLLE0_STAT */ 513 | #endif 514 | 515 | #if (PLL1_SETUP) 516 | LPC_SC->PLL1CFG = PLL1CFG_Val; 517 | LPC_SC->PLL1FEED = 0xAA; 518 | LPC_SC->PLL1FEED = 0x55; 519 | 520 | LPC_SC->PLL1CON = 0x01; /* PLL1 Enable */ 521 | LPC_SC->PLL1FEED = 0xAA; 522 | LPC_SC->PLL1FEED = 0x55; 523 | while (!(LPC_SC->PLL1STAT & (1<<10)));/* Wait for PLOCK1 */ 524 | 525 | LPC_SC->PLL1CON = 0x03; /* PLL1 Enable & Connect */ 526 | LPC_SC->PLL1FEED = 0xAA; 527 | LPC_SC->PLL1FEED = 0x55; 528 | while ((LPC_SC->PLL1STAT & ((1<< 9) | (1<< 8))) != ((1<< 9) | (1<< 8))); /* Wait for PLLC1_STAT & PLLE1_STAT */ 529 | #else 530 | LPC_SC->USBCLKCFG = USBCLKCFG_Val; /* Setup USB Clock Divider */ 531 | #endif 532 | 533 | LPC_SC->PCONP = PCONP_Val; /* Power Control for Peripherals */ 534 | 535 | LPC_SC->CLKOUTCFG = CLKOUTCFG_Val; /* Clock Output Configuration */ 536 | #endif 537 | 538 | #if (FLASH_SETUP == 1) /* Flash Accelerator Setup */ 539 | LPC_SC->FLASHCFG = (LPC_SC->FLASHCFG & ~0x0000F000) | FLASHCFG_Val; 540 | #endif 541 | } 542 | -------------------------------------------------------------------------------- /src/c/ports/lpc176x/keil/RTE/_Release/RTE_Components.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Auto generated Run-Time-Environment Configuration File 4 | * *** Do not modify ! *** 5 | * 6 | * Project: 'dmac_lpc176x' 7 | * Target: 'Release' 8 | */ 9 | 10 | #ifndef RTE_COMPONENTS_H 11 | #define RTE_COMPONENTS_H 12 | 13 | 14 | /* 15 | * Define the Device Header File: 16 | */ 17 | #define CMSIS_device_header "LPC17xx.h" 18 | 19 | /* Keil::Device:Startup:1.0.0 */ 20 | #define RTE_DEVICE_STARTUP_LPC17XX /* Device Startup for NXP17XX */ 21 | 22 | 23 | #endif /* RTE_COMPONENTS_H */ 24 | -------------------------------------------------------------------------------- /src/c/ports/lpc176x/keil/Release/dmac_lpc176x.hex: -------------------------------------------------------------------------------- 1 | :020000040000FA 2 | :1000000080080010C5010000CD010000CF010000F4 3 | :10001000D1010000D3010000D50100000000000064 4 | :10002000000000000000000000000000D7010000F8 5 | :10003000D901000000000000DB010000A70600005D 6 | :10004000DF010000DF010000DF010000DF01000030 7 | :10005000DF010000DF010000DF010000DF01000020 8 | :10006000DF010000DF010000DF010000DF01000010 9 | :10007000DF010000DF010000DF010000DF01000000 10 | :10008000DF010000DF010000DF010000DF010000F0 11 | :10009000DF010000DF010000DF010000DF010000E0 12 | :1000A000DF010000DF01000049040000DF01000063 13 | :1000B000DF010000DF010000DF010000DF010000C0 14 | :1000C000DF010000DF010000DF01000000F002F8A6 15 | :1000D00000F068F80AA090E8000C82448344AAF17A 16 | :1000E0000107DA4501D100F05DF8AFF2090EBAE878 17 | :1000F0000F0013F0010F18BFFB1A43F0010318475C 18 | :100100000C0800006C0800000A444FF0000C10F8C6 19 | :10011000013B13F0070408BF10F8014B1D1108BF85 20 | :1001200010F8015B641E05D010F8016B641E01F825 21 | :10013000016BF9D113F0080F1EBF10F8014BAD1C75 22 | :100140000C1B09D16D1E58BF01F801CBFAD505E093 23 | :1001500014F8016B01F8016B6D1EF9D59142D6D3ED 24 | :1001600070470000103A24BF78C878C1FAD8520707 25 | :1001700024BF30C830C144BF04680C607047000021 26 | :100180000023002400250026103A28BF78C1FBD8A0 27 | :10019000520728BF30C148BF0B6070471FB51FBD55 28 | :1001A00010B510BD00F004F91146FFF7F7FF00F09D 29 | :1001B00093FB00F022F903B4FFF7F2FF03BC00F059 30 | :1001C0006CFB00000948804709480047FEE7FEE74E 31 | :1001D000FEE7FEE7FEE7FEE7FEE7FEE7FEE7FEE7F7 32 | :1001E00004480549054A064B70470000FF07000018 33 | :1001F000CD00000080000010800800108004001076 34 | :1002000080040010704753EA020C00F069802DE969 35 | :10021000F04B4FF00006002B1FBFB3FA83F503FA33 36 | :1002200005F424FA05F65E4012BF1643B2FA82F5D1 37 | :1002300002FA05F4C5F120051EBF22FA05FC44EAC6 38 | :100240000C04203556EA044C4FEA144418BF641CD1 39 | :100250004FF000084FF00009904271EB030C39D3C6 40 | :10026000002919BFB1FA81F701FA07F6B0FA80F751 41 | :1002700000FA07F6C7F120071EBF20FA07FC46EA7E 42 | :100280000C062037B6FBF4FCA7EB0507103F07F080 43 | :100290001F0BCBF120062CFA06F60CFA0BFB44BF21 44 | :1002A000B3460026202FA4BF5E464FF0000B5BEA4A 45 | :1002B000060C08BF4FF0010B19EB0B0948EB0608C1 46 | :1002C000ABFB027C06FB02CC0BFB03CCC01B71EB2F 47 | :1002D0000C01C1E70B46024641464846BDE8F08B9B 48 | :1002E00013B5084318BF4FF0FF300146AFF300804D 49 | :1002F000BDE81C407047704770477047FFFFFFFF25 50 | :1003000010B5002000F02FF8FFF74AFFBDE81040BD 51 | :10031000012000F0C2BA4FF0000200B51346944627 52 | :100320009646203922BFA0E80C50A0E80C50B1F14D 53 | :100330002001BFF4F7AF090728BFA0E80C5048BF61 54 | :100340000CC05DF804EB890028BF40F8042B08BFFF 55 | :10035000704748BF20F8022B11F0804F18BF00F8FB 56 | :10036000012B7047704710B500F00AF8BDE8104047 57 | :10037000AFF30080002801D000F08FBA7047000072 58 | :1003800010B5002102A000F041F8012010BD0000CE 59 | :10039000534947414252543A2041626E6F726D6137 60 | :1003A0006C207465726D696E6174696F6E00000017 61 | :1003B000754600F045F8AE4605006946534620F004 62 | :1003C0000700854618B020B5FFF70AFFBDE82040BA 63 | :1003D0004FF000064FF000074FF000084FF0000B01 64 | :1003E000AC46ACE8C009ACE8C009ACE8C009ACE870 65 | :1003F000C00921F007018D46704710B50446AFF3E0 66 | :1004000000802046BDE81040FFF7D5BE70B5054618 67 | :100410000C460A2000E06D1C00F049FA35B128783E 68 | :100420000028F8D102E0641C00F041FA14B12078F1 69 | :100430000028F8D1BDE870400A2000F038BA00006A 70 | :10044000004870471800001044F20000C5F2000098 71 | :100450000168CA0706D040F278020123C1F2000207 72 | :10046000136040BF0161816070474CF6B000C2F27A 73 | :10047000070070474EF20060C2F207007047BCB53B 74 | :10048000FFF7F8FF00F029F8FFF7EFFF00F07FF823 75 | :1004900040F2000140F6E7020020C2F20801C0F27B 76 | :1004A0000002B0F5807F15D00B5C8DF807309DF809 77 | :1004B00007307BB121280BD89DF807409DF80750E5 78 | :1004C000135C640865F3C71484F0C3049C4202D132 79 | :1004D0000130E6E7BCBDFFF713FF10B54FF496718E 80 | :1004E0000446FFF718FF4DF60030C2F20700C4F8CB 81 | :1004F0000401C4F80C010020B0F5807F07D0C107CB 82 | :100500006FF05A0108BF5A2121540130F4E74BF62D 83 | :10051000D1214BF6D0224BF6D220C4E9462140F639 84 | :10052000E601C4F820014AF6DE50C0F20001CDF623 85 | :10053000C0600978C4F8E0000020A4F8FC0084F84A 86 | :10054000F71040F20001C2F208010A0E84F8FF2001 87 | :100550000A0C84F8FE20D4F80C21130E84F8F8203D 88 | :1005600084F8FB30130C120A84F8F92040F6E702F5 89 | :1005700084F8FA30C0F20002B0F5807F08BF10BDE9 90 | :10058000212894BF135C00230B540130F4E7B0B56D 91 | :1005900044F21001C5F200010A6A42F001020A6247 92 | :1005A000D1F8002142F48022C1F80021D1F80021C5 93 | :1005B000920301D500BFF9E70023C1F8003190E8AC 94 | :1005C0003400C068C1F8F020C1F8F440C1F8F85018 95 | :1005D000C1F8FC004CF200004FF480024FF0806440 96 | :1005E000C2F209008261012241F8082C0A6040F23F 97 | :1005F0007802C1F2000213604EF20013CEF2000343 98 | :100600001C6048F20104D1F800312343C1F80031E5 99 | :10061000116809B920BFFBE7016821F4800101607E 100 | :10062000B0BD80B54CF2C400C4F20F00016841F0C7 101 | :10063000005101604CF20400C4F20200016821F490 102 | :10064000405101604CF200004FF48001C2F20900F9 103 | :100650008161016841F4800101604FF0C0618167F0 104 | :10066000016E41F0C061016600F054F840F21000E4 105 | :1006700042F21071C1F200000068B0FBF1F0411EBF 106 | :100680000020B0EB116F0DD14EF21002F823CEF224 107 | :10069000000251604EF62351CEF200010B709060C3 108 | :1006A0000720106080BD40F20000C1F20000D0E9D8 109 | :1006B00000124B1E00294CF2780108BF632303602F 110 | :1006C0009342C2F209014FF080622CBF0A604A6077 111 | :1006D000826822B1C16881B10139C16070470022CE 112 | :1006E00042604EF21000CEF20000026822F00102D9 113 | :1006F00002604FF080600860704741F28731C1604E 114 | :10070000511E012281604168012908BF0A2242600E 115 | :100710007047000010B54CF28804C4F20F04216841 116 | :10072000D4F8840001F0407100F00300B1F1407F83 117 | :1007300012D10FF2080101EB80018F4600F006B8DC 118 | :1007400000F01EB800F034B800F000B8206840F6A1 119 | :100750000011C0F23D0118E00FF2080101EB800129 120 | :100760008F4600BF00F006B800F036B800F03AB887 121 | :1007700000F000B8E06F40F60011C0F23D0134E037 122 | :10078000206841F60031C0F2B701400080B202306B 123 | :100790002268A0FB01010023C2F307420132FFF7E8 124 | :1007A00032FDE26F0023D2B20132FFF72CFD20E0D0 125 | :1007B00000212068C7F6FF7101EA0040216800F5BA 126 | :1007C0008030C1F307410131B0FBF1F0E16FC9B2F4 127 | :1007D0000131B0FBF1F00CE0E06F41F60031C0F206 128 | :1007E000B70102E0E06F4FF40041C0B20130B1FB4D 129 | :1007F000F0F040F21001C1F20001086010BD4CF2AF 130 | :1008000000002021C4F20F00C0F8A011D0F8A01100 131 | :10081000890603D5D0F8A0114906FBD50321632230 132 | :100820005523C0F804110021C0F20502C0F8A81138 133 | :10083000C0F8AC110121C0F80C11C0F88420AA2224 134 | :10084000C0F88C20C0F88C30C0F88010C0F88C2024 135 | :10085000C0F88C30D0F888104901FBD50321C0F8CE 136 | :100860008010AA21C0F88C105521C0F88C10D0F847 137 | :10087000881001F04071B1F1407FF8D100214FF4B0 138 | :100880000212C0F80811C0F8C420C0F8C811042230 139 | :10089000016862F30F31016070474EF6F050CEF2FE 140 | :1008A00000000168C90700D000BE20BFF9E740F68C 141 | :1008B0000061CEF20001D1F88020D2070BD0096888 142 | :1008C000C90708D04FF060410A680AB900BFFBE7CA 143 | :1008D0004FF060410870704780B5FFF7A2FEFFF748 144 | :1008E000CEFD002080BD41E771F5F574D3F2FA73B7 145 | :1008F000F871D3F47178D3EBE5DBDFDBD3E165632B 146 | :10090000D37874FAF5F153C6C300000070090000F3 147 | :10091000000000101800000064010000000A000040 148 | :1009200000C00720701C0000640100007026000059 149 | :1009300070DC072090070000080100008809000013 150 | :1009400018000010680800008001000070290000F5 151 | :1009500000E407202C030000800100007029000043 152 | :1009600000000820000100008001000000000000DD 153 | :100970006300000001000000050000008713000074 154 | :1009800000E1F5050000000000000000000000008C 155 | :100990000000000000000000000000000000000057 156 | :1009A0000000000000000000000000000000000047 157 | :1009B0000000000000000000000000000000000037 158 | :1009C0000000000000000000000000000000000027 159 | :1009D0000000000000000000000000000000000017 160 | :1009E0000000000000000000000000000000000007 161 | :1009F00000000000000000000000000000000000F7 162 | :100A000017E7072070DC072070DC07200100000CCE 163 | :100A100000D4072018E7072020C007200C0000089A 164 | :100A200014E7072090DC072090DC07200100000C71 165 | :100A300015E70720A0DC0720A0DC07200100000C40 166 | :100A400016E70720B0DC0720B0DC07200100000C0F 167 | :100A500004E70720C0DC0720C0DC07200400000CEE 168 | :100A600004D0072000E50720B0C007200001000CDB 169 | :100A700005E70720D0DC0720D0DC07200100000CB0 170 | :100A800024E70720E0DC0720E0DC07200100000C61 171 | :100A900004D4072000E50720A0C007200001000CB7 172 | :100AA00004E70720F0DC0720F0DC07200100000C41 173 | :100AB00004E7072000DD072000DD07200100000C0F 174 | :100AC00006E707200AE7072000C007200100240CE2 175 | :100AD0001CE7072010DD072010DD07200100000CB7 176 | :100AE00014E7072020DD072020DD07200100000C8F 177 | :100AF0001CE7072030DD072030DD07200100000C57 178 | :100B000018E7072040DD072040DD07200100000C2A 179 | :100B10001CE7072050DD072050DD07200100000CF6 180 | :100B200014E7072060DD072060DD07200100000CCE 181 | :100B30001CE7072070DD072070DD07200100000C96 182 | :100B400018E7072080DD072080DD07200100000C6A 183 | :100B50001CE7072070DE072070DE07200100000C74 184 | :100B60001CE7072090DD072090DD07200100000C26 185 | :100B700018E70720A0DD0720A0DD07200100000CFA 186 | :100B800001E40720B0DD0720B0DD07200100000CE4 187 | :100B900001E40720C0DD0720C0DD07200100000CB4 188 | :100BA00000E40720D0DD0720D0DD07200100000C85 189 | :100BB00001E40720E0DD0720E0DD07200100000C54 190 | :100BC00001E40720F0DD0720F0DD07200100000C24 191 | :100BD00018E7072000DE072000DE07200100000CD8 192 | :100BE00001E4072010DE072010DE07200100000CC2 193 | :100BF00001E4072020DE072020DE07200100000C92 194 | :100C000000E4072030DE072030DE07200100000C62 195 | :100C100002E4072040DE072040DE07200100000C30 196 | :100C200001E4072050DE072050DE07200100000C01 197 | :100C300002E4072060DE072060DE07200100000CD0 198 | :100C40001CE7072060DF072060DF07200100000CA1 199 | :100C50001CE7072080DE072080DE07200100000C53 200 | :100C600018E7072090DE072090DE07200100000C27 201 | :100C700001E40720A0DE0720A0DE07200100000C11 202 | :100C800001E40720B0DE0720B0DE07200100000CE1 203 | :100C900000E40720C0DE0720C0DE07200100000CB2 204 | :100CA00001E40720D0DE0720D0DE07200100000C81 205 | :100CB00001E40720E0DE0720E0DE07200100000C51 206 | :100CC00018E70720F0DE0720F0DE07200100000C07 207 | :100CD00001E4072000DF072000DF07200100000CEF 208 | :100CE00001E4072010DF072010DF07200100000CBF 209 | :100CF00000E4072020DF072020DF07200100000C90 210 | :100D000002E4072030DF072030DF07200100000C5D 211 | :100D100001E4072040DF072040DF07200100000C2E 212 | :100D200002E4072050DF072050DF07200100000CFD 213 | :100D30001CE7072070DF072070DF07200100000C90 214 | :100D40001CE7072060E0072060E007200100000C9E 215 | :100D50001CE7072080DF072080DF07200100000C50 216 | :100D600018E7072090DF072090DF07200100000C24 217 | :100D700001E40720A0DF0720A0DF07200100000C0E 218 | :100D800001E40720B0DF0720B0DF07200100000CDE 219 | :100D900000E40720C0DF0720C0DF07200100000CAF 220 | :100DA00001E40720D0DF0720D0DF07200100000C7E 221 | :100DB00001E40720E0DF0720E0DF07200100000C4E 222 | :100DC00018E70720F0DF0720F0DF07200100000C04 223 | :100DD00001E4072000E0072000E007200100000CEC 224 | :100DE00001E4072010E0072010E007200100000CBC 225 | :100DF00000E4072020E0072020E007200100000C8D 226 | :100E000002E4072030E0072030E007200100000C5A 227 | :100E100001E4072040E0072040E007200100000C2B 228 | :100E200002E4072050E0072050E007200100000CFA 229 | :100E300004D4072000E5072040C407200001000873 230 | :100E400015E7072074E0072070E007200100000C80 231 | :100E50001CE7072015E7072030C407200100000C1D 232 | :100E600014E7072000E5072070C4072000010008F0 233 | :100E700015E7072084E0072080E007200100000C30 234 | :100E800020E7072090E0072090E007200100000CF9 235 | :100E900004E70720E0E00720E0E007200100000C65 236 | :100EA00005E70720A0E00720A0E007200100000CD4 237 | :100EB00024E70720B0E00720B0E007200100000C85 238 | :100EC00004E70720C0E00720C0E007200100000C75 239 | :100ED00025E70720D0E00720D0E007200100000C24 240 | :100EE00025E70720F0E00720F0E007200100000CD4 241 | :100EF00006E707200AE70720F0C807200200000CD9 242 | :100F00001CE7072015E7072060C407200100000C3C 243 | :100F100020E7072004E1072020C507200100480C36 244 | :100F20001CE7072000E1072030C507200100480C1E 245 | :100F300018E707200CE1072000E107200100480C1A 246 | :100F40001CE7072010E1072010E107200100000C3A 247 | :100F500008E7072020E7072060C507200200000CF3 248 | :100F600016E7072024E1072020E107200100000CFC 249 | :100F70000CE7072008E7072080C507200400000CC5 250 | :100F80000CE7072070E1072070E107200100000C4A 251 | :100F90000DE7072030E1072030E107200100000CB9 252 | :100FA00024E7072040E1072040E107200100000C72 253 | :100FB0000CE7072050E1072050E107200100000C5A 254 | :100FC00014E7072060E1072060E107200100000C22 255 | :100FD00014E7072080E1072080E107200100000CD2 256 | :100FE00009E70720D0E10720D0E107200100000C2D 257 | :100FF0000AE7072090E1072090E107200100000C9C 258 | :1010000024E70720A0E10720A0E107200100000C51 259 | :1010100009E70720B0E10720B0E107200100000C3C 260 | :1010200015E70720C0E10720C0E107200100000C00 261 | :1010300015E70720E0E10720E0E107200100000CB0 262 | :101040000EE707200AE70720F0C807200200000C7F 263 | :1010500018E7072008E7072060C607200100000CFA 264 | :101060001CE7072009E7072070C607200100000CD5 265 | :101070000EE707200AE70720F0C807200200000C4F 266 | :101080000CE70720B0E2072090C607200400000C00 267 | :101090000CE7072030E2072030E207200100000CB7 268 | :1010A0000DE70720F0E10720F0E107200100000C28 269 | :1010B00024E7072000E2072000E207200100000CDF 270 | :1010C0000CE7072010E2072010E207200100000CC7 271 | :1010D00014E7072020E2072020E207200100000C8F 272 | :1010E00014E7072040E2072040E207200100000C3F 273 | :1010F000B1E2072090E2072090E207200100000CF7 274 | :10110000B2E2072050E2072050E207200100000C65 275 | :1011100024E7072060E2072060E207200100000CBE 276 | :10112000B1E2072070E2072070E207200100000C06 277 | :1011300015E7072080E2072080E207200100000C6D 278 | :1011400015E70720A0E20720A0E207200100000C1D 279 | :101150001CE70720C0E20720C0E207200100000CC6 280 | :1011600018E70720D0E2072070C707200200000C14 281 | :101170001CE70720D2E20720D0E207200200000C83 282 | :1011800018E70720E0E2072090C707200200000CC4 283 | :101190001CE70720E2E20720E0E207200200000C43 284 | :1011A00018E70720F0E20720B0C707200200000C74 285 | :1011B0001CE70720F2E20720F0E207200200000C03 286 | :1011C00014E7072020E7072000C907200200000CD1 287 | :1011D00018E7072020E70720E0C707200100000CE0 288 | :1011E0001CE7072021E7072000C907200100000CA9 289 | :1011F00014E7072020E70720E0C807200100000CC3 290 | :1012000024E7072024E70720F0C807200100000C8E 291 | :101210001CE7072000E3072000E307200100000C83 292 | :101220001CE7072010E3072010E307200100000C53 293 | :101230001CE7072020E3072020E307200100000C23 294 | :1012400018E7072034E3072050C807200200000CED 295 | :101250001CE7072036E3072030E307200200000CDC 296 | :1012600018E7072044E3072070C807200200000C9D 297 | :101270001CE7072046E3072040E307200200000C9C 298 | :1012800018E7072054E3072090C807200200000C4D 299 | :101290001CE7072056E3072050E307200200000C5C 300 | :1012A00010C9072008E70720000000000100488C53 301 | :1012B00004E707200CE70720C0C807200100480CFE 302 | :1012C00000D4072000E6072050C00720E0000008F7 303 | :1012D00016E7072064E3072060E307200100000C05 304 | :1012E00016E7072074E3072070E307200100000CD5 305 | :1012F00008E7072004E7072050C007200400000C7F 306 | :1013000016E7072084E3072080E307200100000C94 307 | :10131000DEC0ADDE000000000000000000000000A4 308 | :1013200000000000000000000000000000000000BD 309 | :1013300000000000000000000000000000000000AD 310 | :10134000000000000000000000000000000000009D 311 | :10135000000000000000000000000000000000008D 312 | :10136000000000000000000000000000000000007D 313 | :10137000000000000000000000000000000000006D 314 | :10138000000000000000000000000000000000005D 315 | :10139000000000000000000000000000000000004D 316 | :1013A000000000000000000000000000000000003D 317 | :1013B000000000000000000000000000000000002D 318 | :1013C000000000000000000000000000000000001D 319 | :1013D000000000000000000000000000000000000D 320 | :1013E00000000000000000000000000000000000FD 321 | :1013F00000000000000000000000000000000000ED 322 | :1014000000C80720F0C70720C0C70720D0C70720A3 323 | :1014100010C10720D0C0072030C10720F0C007202E 324 | :1014200070C5072050C6072000C5072050C40720FC 325 | :1014300060C4072030C4072030C3072050C10720F4 326 | :1014400040C3072040C2072020C8072010C807203B 327 | :1014500050C7072040C5072030C8072050C50720C7 328 | :1014600080C6072060C7072040C8072080C7072024 329 | :1014700060C80720A0C7072080C80720A0C8072091 330 | :1014800010C50720A0C80720A0C80720A0C80720B3 331 | :10149000A0C80720A0C80720A0C80720A0C8072010 332 | :1014A000A0C80720A0C80720A0C80720A0C8072000 333 | :1014B000A0C80720A0C80720A0C80720A0C80720F0 334 | :1014C000A0C80720A0C80720A0C80720A0C80720E0 335 | :1014D000A0C80720A0C80720A0C80720A0C80720D0 336 | :1014E000A0C80720A0C80720A0C80720A0C80720C0 337 | :1014F000A0C80720A0C80720A0C80720A0C80720B0 338 | :1015000000000000000000000000000000000000DB 339 | :1015100000010001000100010001000100010001C3 340 | :1015200000000202000002020000020200000202AB 341 | :101530000001020300010203000102030001020393 342 | :10154000000000000404040400000000040404047B 343 | :101550000001000104050405000100010405040563 344 | :10156000000002020404060600000202040406064B 345 | :101570000001020304050607000102030405060733 346 | :10158000000000000000000008080808080808081B 347 | :101590000001000100010001080908090809080903 348 | :1015A000000002020000020208080A0A08080A0AEB 349 | :1015B000000102030001020308090A0B08090A0BD3 350 | :1015C0000000000004040404080808080C0C0C0CBB 351 | :1015D0000001000104050405080908090C0D0C0DA3 352 | :1015E000000002020404060608080A0A0C0C0E0E8B 353 | :1015F000000102030405060708090A0B0C0D0E0F73 354 | :10160000000102030405060708090A0B0C0D0E0F62 355 | :10161000010003020504070609080B0A0D0C0F0E52 356 | :1016200002030001060704050A0B08090E0F0C0D42 357 | :1016300003020100070605040B0A09080F0E0D0C32 358 | :1016400004050607000102030C0D0E0F08090A0B22 359 | :1016500005040706010003020D0C0F0E09080B0A12 360 | :1016600006070405020300010E0F0C0D0A0B080902 361 | :1016700007060504030201000F0E0D0C0B0A0908F2 362 | :1016800008090A0B0C0D0E0F0001020304050607E2 363 | :1016900009080B0A0D0C0F0E0100030205040706D2 364 | :1016A0000A0B08090E0F0C0D0203000106070405C2 365 | :1016B0000B0A09080F0E0D0C0302010007060504B2 366 | :1016C0000C0D0E0F08090A0B0405060700010203A2 367 | :1016D0000D0C0F0E09080B0A050407060100030292 368 | :1016E0000E0F0C0D0A0B0809060704050203000182 369 | :1016F0000F0E0D0C0B0A0908070605040302010072 370 | :10170000FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F061 371 | :10171000EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E051 372 | :10172000DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D041 373 | :10173000CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C031 374 | :10174000BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B021 375 | :10175000AFAEADACABAAA9A8A7A6A5A4A3A2A1A011 376 | :101760009F9E9D9C9B9A9998979695949392919001 377 | :101770008F8E8D8C8B8A89888786858483828180F1 378 | :101780007F7E7D7C7B7A79787776757473727170E1 379 | :101790006F6E6D6C6B6A69686766656463626160D1 380 | :1017A0005F5E5D5C5B5A59585756555453525150C1 381 | :1017B0004F4E4D4C4B4A49484746454443424140B1 382 | :1017C0003F3E3D3C3B3A39383736353433323130A1 383 | :1017D0002F2E2D2C2B2A2928272625242322212091 384 | :1017E0001F1E1D1C1B1A1918171615141312111081 385 | :1017F0000F0E0D0C0B0A0908070605040302010071 386 | :10180000000102030405060708090A0B0C0D0E0F60 387 | :10181000010103030505070709090B0B0D0D0F0F48 388 | :1018200002030203060706070A0B0A0B0E0F0E0F30 389 | :1018300003030303070707070B0B0B0B0F0F0F0F18 390 | :1018400004050607040506070C0D0E0F0C0D0E0F00 391 | :1018500005050707050507070D0D0F0F0D0D0F0FE8 392 | :1018600006070607060706070E0F0E0F0E0F0E0FD0 393 | :1018700007070707070707070F0F0F0F0F0F0F0FB8 394 | :1018800008090A0B0C0D0E0F08090A0B0C0D0E0FA0 395 | :1018900009090B0B0D0D0F0F09090B0B0D0D0F0F88 396 | :1018A0000A0B0A0B0E0F0E0F0A0B0A0B0E0F0E0F70 397 | :1018B0000B0B0B0B0F0F0F0F0B0B0B0B0F0F0F0F58 398 | :1018C0000C0D0E0F0C0D0E0F0C0D0E0F0C0D0E0F40 399 | :1018D0000D0D0F0F0D0D0F0F0D0D0F0F0D0D0F0F28 400 | :1018E0000E0F0E0F0E0F0E0F0E0F0E0F0E0F0E0F10 401 | :1018F0000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FF8 402 | :1019000000000000000000000000000000000000D7 403 | :1019100000000000000000000000000000000000C7 404 | :1019200000000000000000000000000000000000B7 405 | :1019300000000000000000000000000000000000A7 406 | :101940000000000000000000000000000000000097 407 | :101950000000000000000000000000000000000087 408 | :101960000000000000000000000000000000000077 409 | :101970000000000000000000000000000000000067 410 | :101980000000000000000000000000000000000057 411 | :101990000000000000000000000000000000000047 412 | :1019A0000000000000000000000000000000000037 413 | :1019B0000000000000000000000000000000000027 414 | :1019C0000000000000000000000000000000000017 415 | :1019D0000000000000000000000000000000000007 416 | :1019E00000000000000000000000000000000000F7 417 | :1019F00000000000000000000000000000000000E7 418 | :101A000000000000000000000000000000000000D6 419 | :101A100000000000000000000000000000000000C6 420 | :101A200000000000000000000000000000000000B6 421 | :101A300000000000000000000000000000000000A6 422 | :101A40000000000000000000000000000000000096 423 | :101A50000000000000000000000000000000000086 424 | :101A60000000000000000000000000000000000076 425 | :101A70000000000000000000000000000000000066 426 | :101A80000000000000000000000000000000000056 427 | :101A90000000000000000000000000000000000046 428 | :101AA0000000000000000000000000000000000036 429 | :101AB0000000000000000000000000000000000026 430 | :101AC0000000000000000000000000000000000016 431 | :101AD0000000000000000000000000000000000006 432 | :101AE00000000000000000000000000000000000F6 433 | :101AF00000000000000000000000000000000000E6 434 | :101B000001010101010101010101010101010101C5 435 | :101B100001010101010101010101010101010101B5 436 | :101B200001010101010101010101010101010101A5 437 | :101B30000101010101010101010101010101010195 438 | :101B40000101010101010101010101010101010185 439 | :101B50000101010101010101010101010101010175 440 | :101B60000101010101010101010101010101010165 441 | :101B70000101010101010101010101010101010155 442 | :101B80000101010101010101010101010101010145 443 | :101B90000101010101010101010101010101010135 444 | :101BA0000101010101010101010101010101010125 445 | :101BB0000101010101010101010101010101010115 446 | :101BC0000101010101010101010101010101010105 447 | :101BD00001010101010101010101010101010101F5 448 | :101BE00001010101010101010101010101010101E5 449 | :101BF00001010101010101010101010101010101D5 450 | :101C000000000000000000000000000000000000D4 451 | :101C100001010101010101010101010101010101B4 452 | :101C20000202020202020202020202020202020294 453 | :101C30000303030303030303030303030303030374 454 | :101C40000404040404040404040404040404040454 455 | :101C50000505050505050505050505050505050534 456 | :101C60000606060606060606060606060606060614 457 | :101C700007070707070707070707070707070707F4 458 | :101C800008080808080808080808080808080808D4 459 | :101C900009090909090909090909090909090909B4 460 | :101CA0000A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A94 461 | :101CB0000B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B74 462 | :101CC0000C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C54 463 | :101CD0000D0D0D0D0D0D0D0D0D0D0D0D0D0D0D0D34 464 | :101CE0000E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E14 465 | :101CF0000F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FF4 466 | :101D000000000000000000000000000000000000D3 467 | :101D100000000000000000000000000000000000C3 468 | :101D200000000000000000000000000000000000B3 469 | :101D300000000000000000000000000000000000A3 470 | :101D40000000000000000000000000000000000093 471 | :101D50000000000000000000000000000000000083 472 | :101D60000000000000000000000000000000000073 473 | :101D70000000000000000000000000000000000063 474 | :101D80000000000000000000000000000000000053 475 | :101D90000000000000000000000000000000000043 476 | :101DA0000000000000000000000000000000000033 477 | :101DB0000000000000000000000000000000000023 478 | :101DC0000000000000000000000000000000000013 479 | :101DD0000000000000000000000000000000000003 480 | :101DE00000000000000000000000000000000000F3 481 | :101DF00000000000000000000000000000000000E3 482 | :101E0000000102030405060708090A0B0C0D0E0F5A 483 | :101E1000101112131415161718191A1B1C1D1E1F4A 484 | :101E2000202122232425262728292A2B2C2D2E2F3A 485 | :101E3000303132333435363738393A3B3C3D3E3F2A 486 | :101E4000404142434445464748494A4B4C4D4E4F1A 487 | :101E5000505152535455565758595A5B5C5D5E5F0A 488 | :101E6000606162636465666768696A6B6C6D6E6FFA 489 | :101E7000707172737475767778797A7B7C7D7E7FEA 490 | :101E8000808182838485868788898A8B8C8D8E8FDA 491 | :101E9000909192939495969798999A9B9C9D9E9FCA 492 | :101EA000A0A1A2A3A4A5A6A7A8A9AAABACADAEAFBA 493 | :101EB000B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFAA 494 | :101EC000C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF9A 495 | :101ED000D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF8A 496 | :101EE000E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF7A 497 | :101EF000F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF6A 498 | :101F0000000102030405060708090A0B0C0D0E0F59 499 | :101F1000101112131415161718191A1B1C1D1E1F49 500 | :101F2000202122232425262728292A2B2C2D2E2F39 501 | :101F3000303132333435363738393A3B3C3D3E3F29 502 | :101F4000404142434445464748494A4B4C4D4E4F19 503 | :101F5000505152535455565758595A5B5C5D5E5F09 504 | :101F6000606162636465666768696A6B6C6D6E6FF9 505 | :101F7000707172737475767778797A7B7C7D7E7FE9 506 | :101F8000808182838485868788898A8B8C8D8E8FD9 507 | :101F9000909192939495969798999A9B9C9D9E9FC9 508 | :101FA000A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB9 509 | :101FB000B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFA9 510 | :101FC000C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF99 511 | :101FD000D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF89 512 | :101FE000E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF79 513 | :101FF000F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF69 514 | :10200000000102030405060708090A0B0C0D0E0F58 515 | :10201000000102030405060708090A0B0C0D0E0F48 516 | :10202000000102030405060708090A0B0C0D0E0F38 517 | :10203000000102030405060708090A0B0C0D0E0F28 518 | :10204000000102030405060708090A0B0C0D0E0F18 519 | :10205000000102030405060708090A0B0C0D0E0F08 520 | :10206000000102030405060708090A0B0C0D0E0FF8 521 | :10207000000102030405060708090A0B0C0D0E0FE8 522 | :10208000000102030405060708090A0B0C0D0E0FD8 523 | :10209000000102030405060708090A0B0C0D0E0FC8 524 | :1020A000000102030405060708090A0B0C0D0E0FB8 525 | :1020B000000102030405060708090A0B0C0D0E0FA8 526 | :1020C000000102030405060708090A0B0C0D0E0F98 527 | :1020D000000102030405060708090A0B0C0D0E0F88 528 | :1020E000000102030405060708090A0B0C0D0E0F78 529 | :1020F000000102030405060708090A0B0C0D0E0F68 530 | :1021000000102030405060708090A0B0C0D0E0F04F 531 | :1021100000102030405060708090A0B0C0D0E0F03F 532 | :1021200000102030405060708090A0B0C0D0E0F02F 533 | :1021300000102030405060708090A0B0C0D0E0F01F 534 | :1021400000102030405060708090A0B0C0D0E0F00F 535 | :1021500000102030405060708090A0B0C0D0E0F0FF 536 | :1021600000102030405060708090A0B0C0D0E0F0EF 537 | :1021700000102030405060708090A0B0C0D0E0F0DF 538 | :1021800000102030405060708090A0B0C0D0E0F0CF 539 | :1021900000102030405060708090A0B0C0D0E0F0BF 540 | :1021A00000102030405060708090A0B0C0D0E0F0AF 541 | :1021B00000102030405060708090A0B0C0D0E0F09F 542 | :1021C00000102030405060708090A0B0C0D0E0F08F 543 | :1021D00000102030405060708090A0B0C0D0E0F07F 544 | :1021E00000102030405060708090A0B0C0D0E0F06F 545 | :1021F00000102030405060708090A0B0C0D0E0F05F 546 | :102200000004080C1014181C2024282C3034383CEE 547 | :102210004044484C5054585C6064686C7074787CDE 548 | :102220008084888C9094989CA0A4A8ACB0B4B8BCCE 549 | :10223000C0C4C8CCD0D4D8DCE0E4E8ECF0F4F8FCBE 550 | :102240000004080C1014181C2024282C3034383CAE 551 | :102250004044484C5054585C6064686C7074787C9E 552 | :102260008084888C9094989CA0A4A8ACB0B4B8BC8E 553 | :10227000C0C4C8CCD0D4D8DCE0E4E8ECF0F4F8FC7E 554 | :102280000004080C1014181C2024282C3034383C6E 555 | :102290004044484C5054585C6064686C7074787C5E 556 | :1022A0008084888C9094989CA0A4A8ACB0B4B8BC4E 557 | :1022B000C0C4C8CCD0D4D8DCE0E4E8ECF0F4F8FC3E 558 | :1022C0000004080C1014181C2024282C3034383C2E 559 | :1022D0004044484C5054585C6064686C7074787C1E 560 | :1022E0008084888C9094989CA0A4A8ACB0B4B8BC0E 561 | :1022F000C0C4C8CCD0D4D8DCE0E4E8ECF0F4F8FCFE 562 | :1023000000020406080A0C0E10121416181A1C1EDD 563 | :1023100020222426282A2C2E30323436383A3C3ECD 564 | :1023200040424446484A4C4E50525456585A5C5EBD 565 | :1023300060626466686A6C6E70727476787A7C7EAD 566 | :1023400080828486888A8C8E90929496989A9C9E9D 567 | :10235000A0A2A4A6A8AAACAEB0B2B4B6B8BABCBE8D 568 | :10236000C0C2C4C6C8CACCCED0D2D4D6D8DADCDE7D 569 | :10237000E0E2E4E6E8EAECEEF0F2F4F6F8FAFCFE6D 570 | :1023800001030507090B0D0F11131517191B1D1F4D 571 | :1023900021232527292B2D2F31333537393B3D3F3D 572 | :1023A00041434547494B4D4F51535557595B5D5F2D 573 | :1023B00061636567696B6D6F71737577797B7D7F1D 574 | :1023C00081838587898B8D8F91939597999B9D9F0D 575 | :1023D000A1A3A5A7A9ABADAFB1B3B5B7B9BBBDBFFD 576 | :1023E000C1C3C5C7C9CBCDCFD1D3D5D7D9DBDDDFED 577 | :1023F000E1E3E5E7E9EBEDEFF1F3F5F7F9FBFDFFDD 578 | :102400000080018102820383048405850686078794 579 | :10241000088809890A8A0B8B0C8C0D8D0E8E0F8F04 580 | :102420001090119112921393149415951696179774 581 | :10243000189819991A9A1B9B1C9C1D9D1E9E1F9FE4 582 | :1024400020A021A122A223A324A425A526A627A754 583 | :1024500028A829A92AAA2BAB2CAC2DAD2EAE2FAFC4 584 | :1024600030B031B132B233B334B435B536B637B734 585 | :1024700038B839B93ABA3BBB3CBC3DBD3EBE3FBFA4 586 | :1024800040C041C142C243C344C445C546C647C714 587 | :1024900048C849C94ACA4BCB4CCC4DCD4ECE4FCF84 588 | :1024A00050D051D152D253D354D455D556D657D7F4 589 | :1024B00058D859D95ADA5BDB5CDC5DDD5EDE5FDF64 590 | :1024C00060E061E162E263E364E465E566E667E7D4 591 | :1024D00068E869E96AEA6BEB6CEC6DED6EEE6FEF44 592 | :1024E00070F071F172F273F374F475F576F677F7B4 593 | :1024F00078F879F97AFA7BFB7CFC7DFD7EFE7FFF24 594 | :102500001000F70D2451F70D3441F70DEEEE001FCA 595 | :10251000FC00E401E4FDE403FEFFE6030100E80241 596 | :102520000000EA02500000080800E4020010E60281 597 | :102530000100E8020000EA025000000814C0E402B2 598 | :102540000920E6020000E8024000EA02500000080C 599 | :1025500008000001000001011000000DFF00000450 600 | :1025600001010104580000080804010C840000085F 601 | :1025700001000004FF0101040000020E010203112A 602 | :102580006800000810DEE00C0CADE10C08C0E20CA5 603 | :1025900008DEE30D01E0001FFDFC10030100010156 604 | :1025A000C300020110FE0319020303110003031309 605 | :1025B000032322033801201703232203DC00201702 606 | :1025C00010FE031A1400030D011004070110100679 607 | :1025D00004111106A4000008646E651F01002301A8 608 | :1025E00000E8250E00E9260E00EA270E00EB280E73 609 | :1025F0002322240FE4E6291D1800240DE8292910C0 610 | :10260000E92A2A10EA2B2B10EB2C2C1024010008AD 611 | :102610002529290F262A2A0F272B2B0F282C2C0F90 612 | :1026200024010008E4E6291E0C80230D0023231357 613 | :10263000F0000008202100090851F70D20210009B1 614 | :102640001F102302001025021810270280002D0100 615 | :102650002723291D2D29290FF800290D2523221AAA 616 | :102660002021000900000000000000000000000020 617 | :10267000114ED8072080DC042201120C1DCA07204D 618 | :10268000B80C2E10C0072004109809E6072018E7A0 619 | :10269000072030101A1C109A40101A2010413910CF 620 | :1026A000311A14101A6020120113480C1AD41C1A83 621 | :1026B000E5601910111A0120190C1A09203AC020DE 622 | :1026C00049101A08109A70101A24106A90104AD0F3 623 | :1026D000409AE0402970CBE0C820110A15C120596A 624 | :1026E000800A1D20200A1640201AD2181AE4A019C8 625 | :1026F0002069101A01106A80104AD7106A90105988 626 | :10270000509AA05029206AB0204ACB10DAC0405B12 627 | :1027100020C2104AD610DAE020DAF06011193069D0 628 | :10272000601A02206A104019602910DA60309A306D 629 | :1027300030B9E0197029E09AD0E029106A60505948 630 | :10274000F06A701059906A801059609A9060292040 631 | :102750006AA0204ACC10DAB040CB10C3F0DAD02007 632 | :10276000DAE060DAF0F011694019602910DA5030CF 633 | :102770001A2020091AF06AC030DACD2019F0292079 634 | :102780006A6060191029906A701059A06A80105907 635 | :10279000709A907029206AA0204ACE10DAB0408B3F 636 | :1027A00010C4902910DAD020DAE0609AF06029F0A5 637 | :1027B00011694019602910DA50301A20206930B9A7 638 | :1027C000E0197029E05AC0301A141C29245A80508C 639 | :1027D0005A04406910290C1A25246A901059209A2D 640 | :1027E000B0601A0920DAF0209AD0201A08206AA0D6 641 | :1027F000204AD0209AE0201A24206AC020711AF0C2 642 | :10280000B031120CCAD2C0290C111EE6072070C5C7 643 | :10281000F899701AA010A9901AE010A9909AC020F7 644 | :1028200029906A902059909AD0202990DAB04011CE 645 | :102830008AC6201A0A201A4010A9209A202029802E 646 | :10284000DAF0609A30202960DA10409AB0201BB18B 647 | :10285000E240D9209AD0201AB0206AA0205960DA2C 648 | :10286000E060DAC0408B10C7201AB2402944A9208A 649 | :102870009A30202980111910A9609A402029606A95 650 | :102880002020311A20102ED0C8072004101AD61C80 651 | :1028900019101AE010A920E910112AC910BA244011 652 | :1028A000120113480CDAD940DADA10CAD710394CC1 653 | :1028B000310A13F010DA24104A48102CE6072010D1 654 | :1028C00029B0A910794059105A02B0016C000000DB 655 | :1028D00000000000000000000000000000000000F8 656 | :1028E00000000000000000000000000000000000E8 657 | :1028F00000000000000000000000000000000000D8 658 | :1029000000000000000000000000000000000000C7 659 | :1029100000000000000000000000000000000000B7 660 | :1029200000000000000000000000000000000000A7 661 | :102930000000000000000000000000000000000097 662 | :102940000000000000000000000000000000000087 663 | :102950000000000000000000000000000000000077 664 | :102960000000000000000000000000000000000067 665 | :04000005000000CD2A 666 | :00000001FF 667 | -------------------------------------------------------------------------------- /src/c/ports/lpc176x/keil/dmac_lpc176x.uvoptx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1.0 5 | 6 |
### uVision Project, (C) Keil Software
7 | 8 | 9 | *.c 10 | *.s*; *.src; *.a* 11 | *.obj; *.o 12 | *.lib 13 | *.txt; *.h; *.inc; *.md 14 | *.plm 15 | *.cpp 16 | 0 17 | 18 | 19 | 20 | 0 21 | 0 22 | 23 | 24 | 25 | Release 26 | 0x4 27 | ARM-ADS 28 | 29 | 12000000 30 | 31 | 1 32 | 0 33 | 0 34 | 1 35 | 0 36 | 37 | 38 | 1 39 | 65535 40 | 0 41 | 0 42 | 0 43 | 44 | 45 | 79 46 | 66 47 | 8 48 | .\Release\ 49 | 50 | 51 | 1 52 | 1 53 | 1 54 | 0 55 | 1 56 | 1 57 | 0 58 | 1 59 | 0 60 | 0 61 | 0 62 | 0 63 | 64 | 65 | 1 66 | 1 67 | 1 68 | 1 69 | 1 70 | 1 71 | 1 72 | 0 73 | 0 74 | 75 | 76 | 1 77 | 0 78 | 1 79 | 80 | 8 81 | 82 | 0 83 | 1 84 | 1 85 | 1 86 | 1 87 | 1 88 | 1 89 | 1 90 | 1 91 | 1 92 | 1 93 | 1 94 | 1 95 | 1 96 | 0 97 | 1 98 | 1 99 | 1 100 | 1 101 | 0 102 | 0 103 | 1 104 | 0 105 | 1 106 | 3 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | BIN\CMSIS_AGDI.dll 118 | 119 | 120 | 121 | 0 122 | ARMRTXEVENTFLAGS 123 | -L70 -Z18 -C0 -M0 -T1 124 | 125 | 126 | 0 127 | DLGTARM 128 | (1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)(1012=-1,-1,-1,-1,0) 129 | 130 | 131 | 0 132 | ARMDBGFLAGS 133 | 134 | 135 | 136 | 0 137 | DLGUARM 138 | 139 | 140 | 141 | 0 142 | CMSIS_AGDI 143 | -X"LPC-LINK2 CMSIS-DAP V5.224" -UFTCQHXMT -O206 -S8 -C0 -P00000000 -N00("ARM CoreSight SW-DP") -D00(2BA01477) -L00(0) -TO65554 -TC10000000 -TT10000000 -TP20 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD10000000 -FCFE0 -FN1 -FF0LPC_IAP_512.FLM -FS00 -FL080000 -FP0($$Device:LPC1769$Flash\LPC_IAP_512.FLM) 144 | 145 | 146 | 0 147 | UL2CM3 148 | UL2CM3(-S0 -C0 -P0 -FD10000000 -FCFE0 -FN1 -FF0LPC_IAP_512 -FS00 -FL080000 -FP0($$Device:LPC1769$Flash\LPC_IAP_512.FLM)) 149 | 150 | 151 | 152 | 153 | 154 | 0 155 | 1 156 | Dmacu_gCpu 157 | 158 | 159 | 1 160 | 1 161 | SlaveCpu_gCpu 162 | 163 | 164 | 165 | 166 | 1 167 | 8 168 | 0x20080000 169 | 0 170 | 171 | 172 | 173 | 0 174 | 175 | 176 | 0 177 | 1 178 | 1 179 | 0 180 | 0 181 | 0 182 | 0 183 | 1 184 | 0 185 | 0 186 | 0 187 | 0 188 | 0 189 | 0 190 | 0 191 | 0 192 | 0 193 | 0 194 | 0 195 | 1 196 | 0 197 | 0 198 | 0 199 | 0 200 | 201 | 202 | 203 | 0 204 | 0 205 | 0 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 1 216 | 1 217 | 0 218 | 2 219 | 10000000 220 | 221 | 222 | 223 | 224 | 225 | vcpu 226 | 1 227 | 0 228 | 0 229 | 0 230 | 231 | 1 232 | 1 233 | 5 234 | 0 235 | 0 236 | 0 237 | ..\..\..\vcpu\dmacu.h 238 | dmacu.h 239 | 0 240 | 0 241 | 242 | 243 | 1 244 | 2 245 | 1 246 | 0 247 | 0 248 | 0 249 | ..\..\..\vcpu\dmacu_instance.c 250 | dmacu_instance.c 251 | 0 252 | 0 253 | 254 | 255 | 1 256 | 3 257 | 5 258 | 0 259 | 0 260 | 0 261 | ..\..\..\vcpu\dmacu_instance.h 262 | dmacu_instance.h 263 | 0 264 | 0 265 | 266 | 267 | 1 268 | 4 269 | 1 270 | 0 271 | 0 272 | 0 273 | ..\..\..\vcpu\dmacu_shared.c 274 | dmacu_shared.c 275 | 0 276 | 0 277 | 278 | 279 | 1 280 | 5 281 | 1 282 | 0 283 | 0 284 | 0 285 | ..\..\..\vcpu\rt.c 286 | rt.c 287 | 0 288 | 0 289 | 290 | 291 | 1 292 | 6 293 | 1 294 | 0 295 | 0 296 | 0 297 | ..\..\..\vcpu\utils.c 298 | utils.c 299 | 0 300 | 0 301 | 302 | 303 | 1 304 | 7 305 | 1 306 | 0 307 | 0 308 | 0 309 | ..\..\..\vcpu\vpl080.c 310 | vpl080.c 311 | 0 312 | 0 313 | 314 | 315 | 316 | 317 | port 318 | 1 319 | 0 320 | 0 321 | 0 322 | 323 | 2 324 | 8 325 | 1 326 | 0 327 | 0 328 | 0 329 | .\lpc176x.c 330 | lpc176x.c 331 | 0 332 | 0 333 | 334 | 335 | 2 336 | 9 337 | 5 338 | 0 339 | 0 340 | 0 341 | .\lpc176x.sct 342 | lpc176x.sct 343 | 0 344 | 0 345 | 346 | 347 | 348 | 349 | mc 350 | 1 351 | 0 352 | 0 353 | 0 354 | 355 | 3 356 | 10 357 | 5 358 | 0 359 | 0 360 | 0 361 | ..\..\..\vcpu\mc\demo.code.inc 362 | demo.code.inc 363 | 0 364 | 0 365 | 366 | 367 | 3 368 | 11 369 | 5 370 | 0 371 | 0 372 | 0 373 | ..\..\..\vcpu\mc\demo.data.inc 374 | demo.data.inc 375 | 0 376 | 0 377 | 378 | 379 | 380 | 381 | ::CMSIS 382 | 0 383 | 0 384 | 0 385 | 1 386 | 387 | 388 | 389 | ::Device 390 | 0 391 | 0 392 | 0 393 | 1 394 | 395 | 396 |
397 | -------------------------------------------------------------------------------- /src/c/ports/lpc176x/keil/dmac_lpc176x.uvprojx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.1 5 | 6 |
### uVision Project, (C) Keil Software
7 | 8 | 9 | 10 | Release 11 | 0x4 12 | ARM-ADS 13 | 6150000::V6.15::ARMCLANG 14 | 1 15 | 16 | 17 | LPC1769 18 | NXP 19 | Keil.LPC1700_DFP.2.6.0 20 | http://www.keil.com/pack/ 21 | IRAM(0x10000000,0x8000) IRAM2(0x2007C000,0x8000) IROM(0x00000000,0x80000) CPUTYPE("Cortex-M3") CLOCK(12000000) ELITTLE 22 | 23 | 24 | UL2CM3(-S0 -C0 -P0 -FD10000000 -FCFE0 -FN1 -FF0LPC_IAP_512 -FS00 -FL080000 -FP0($$Device:LPC1769$Flash\LPC_IAP_512.FLM)) 25 | 0 26 | $$Device:LPC1769$Device\Include\LPC17xx.h 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | $$Device:LPC1769$SVD\LPC176x5x.svd 37 | 0 38 | 0 39 | 40 | 41 | 42 | 43 | 44 | 45 | 0 46 | 0 47 | 0 48 | 0 49 | 1 50 | 51 | .\Release\ 52 | dmac_lpc176x 53 | 1 54 | 0 55 | 1 56 | 1 57 | 1 58 | .\Release\ 59 | 1 60 | 0 61 | 0 62 | 63 | 0 64 | 0 65 | 66 | 67 | 0 68 | 0 69 | 0 70 | 0 71 | 72 | 73 | 0 74 | 0 75 | 76 | 77 | 0 78 | 0 79 | 0 80 | 0 81 | 82 | 83 | 0 84 | 0 85 | 86 | 87 | 0 88 | 0 89 | 0 90 | 0 91 | 92 | 0 93 | 94 | 95 | 96 | 0 97 | 0 98 | 0 99 | 0 100 | 0 101 | 1 102 | 0 103 | 0 104 | 0 105 | 0 106 | 3 107 | 108 | 109 | 1 110 | 111 | 112 | SARMCM3.DLL 113 | -MPU 114 | DCM.DLL 115 | -pCM3 116 | SARMCM3.DLL 117 | -MPU 118 | TCM.DLL 119 | -pCM3 120 | 121 | 122 | 123 | 1 124 | 0 125 | 0 126 | 0 127 | 16 128 | 129 | 130 | 131 | 132 | 1 133 | 0 134 | 0 135 | 1 136 | 1 137 | 4096 138 | 139 | 1 140 | BIN\UL2CM3.DLL 141 | "" () 142 | 143 | 144 | 145 | 146 | 0 147 | 148 | 149 | 150 | 0 151 | 1 152 | 1 153 | 1 154 | 1 155 | 1 156 | 1 157 | 1 158 | 0 159 | 1 160 | 1 161 | 0 162 | 1 163 | 1 164 | 0 165 | 0 166 | 1 167 | 1 168 | 1 169 | 1 170 | 1 171 | 1 172 | 1 173 | 1 174 | 1 175 | 0 176 | 0 177 | "Cortex-M3" 178 | 179 | 0 180 | 0 181 | 0 182 | 1 183 | 1 184 | 0 185 | 0 186 | 0 187 | 0 188 | 0 189 | 1 190 | 0 191 | 8 192 | 0 193 | 0 194 | 0 195 | 0 196 | 3 197 | 4 198 | 0 199 | 0 200 | 0 201 | 0 202 | 0 203 | 0 204 | 0 205 | 0 206 | 0 207 | 0 208 | 1 209 | 0 210 | 0 211 | 0 212 | 0 213 | 1 214 | 1 215 | 216 | 217 | 0 218 | 0x0 219 | 0x0 220 | 221 | 222 | 0 223 | 0x0 224 | 0x0 225 | 226 | 227 | 0 228 | 0x0 229 | 0x0 230 | 231 | 232 | 0 233 | 0x0 234 | 0x0 235 | 236 | 237 | 0 238 | 0x0 239 | 0x0 240 | 241 | 242 | 0 243 | 0x0 244 | 0x0 245 | 246 | 247 | 0 248 | 0x10000000 249 | 0x8000 250 | 251 | 252 | 1 253 | 0x0 254 | 0x80000 255 | 256 | 257 | 0 258 | 0x0 259 | 0x0 260 | 261 | 262 | 1 263 | 0x0 264 | 0x0 265 | 266 | 267 | 1 268 | 0x0 269 | 0x0 270 | 271 | 272 | 1 273 | 0x0 274 | 0x0 275 | 276 | 277 | 1 278 | 0x0 279 | 0x80000 280 | 281 | 282 | 1 283 | 0x0 284 | 0x0 285 | 286 | 287 | 0 288 | 0x0 289 | 0x0 290 | 291 | 292 | 0 293 | 0x0 294 | 0x0 295 | 296 | 297 | 0 298 | 0x0 299 | 0x0 300 | 301 | 302 | 0 303 | 0x10000000 304 | 0x8000 305 | 306 | 307 | 0 308 | 0x2007c000 309 | 0x8000 310 | 311 | 312 | 313 | 314 | 315 | 1 316 | 7 317 | 0 318 | 0 319 | 1 320 | 0 321 | 0 322 | 0 323 | 0 324 | 0 325 | 0 326 | 0 327 | 0 328 | 0 329 | 0 330 | 1 331 | 3 332 | 3 333 | 1 334 | 1 335 | 0 336 | 0 337 | 0 338 | 339 | -Wall -Wno-c11-extensions -pedantic 340 | DMACU_QUIET=1,DMACU_ROM_ALIGNMENT=0x4,DMACU_VIRTUAL_PL080=0 341 | 342 | ..\..\..\vcpu 343 | 344 | 345 | 346 | 1 347 | 0 348 | 0 349 | 0 350 | 0 351 | 0 352 | 0 353 | 0 354 | 0 355 | 1 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 0 365 | 0 366 | 0 367 | 0 368 | 1 369 | 0 370 | 0x00000000 371 | 0x10000000 372 | 373 | .\lpc176x.sct 374 | 375 | 376 | --predefine="-DDMACU_VIRTUAL_PL080=0" 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | vcpu 385 | 386 | 387 | dmacu.h 388 | 5 389 | ..\..\..\vcpu\dmacu.h 390 | 391 | 392 | dmacu_instance.c 393 | 1 394 | ..\..\..\vcpu\dmacu_instance.c 395 | 396 | 397 | dmacu_instance.h 398 | 5 399 | ..\..\..\vcpu\dmacu_instance.h 400 | 401 | 402 | dmacu_shared.c 403 | 1 404 | ..\..\..\vcpu\dmacu_shared.c 405 | 406 | 407 | rt.c 408 | 1 409 | ..\..\..\vcpu\rt.c 410 | 411 | 412 | utils.c 413 | 1 414 | ..\..\..\vcpu\utils.c 415 | 416 | 417 | vpl080.c 418 | 1 419 | ..\..\..\vcpu\vpl080.c 420 | 421 | 422 | 423 | 424 | port 425 | 426 | 427 | lpc176x.c 428 | 1 429 | .\lpc176x.c 430 | 431 | 432 | lpc176x.sct 433 | 5 434 | .\lpc176x.sct 435 | 436 | 437 | 438 | 439 | mc 440 | 441 | 442 | demo.code.inc 443 | 5 444 | ..\..\..\vcpu\mc\demo.code.inc 445 | 446 | 447 | demo.data.inc 448 | 5 449 | ..\..\..\vcpu\mc\demo.data.inc 450 | 451 | 452 | 453 | 454 | ::CMSIS 455 | 456 | 457 | ::Device 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | -Wno-sign-conversion 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | RTE\Device\LPC1769\RTE_Device.h 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | RTE\Device\LPC1769\startup_LPC17xx.s 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | RTE\Device\LPC1769\system_LPC17xx.c 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | dmac_lpc176x 515 | 1 516 | 517 | 518 | 519 | 520 |
521 | -------------------------------------------------------------------------------- /src/c/ports/lpc176x/keil/lpc176x.c: -------------------------------------------------------------------------------- 1 | /** 2 | * Port of the DMACU virtual CPU to the LPC176x series of microcontrollers. 3 | * 4 | * Copyright (c) 2019-2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the project for the license text. 8 | */ 9 | 10 | /** 11 | * @file dmacu.c 12 | * @brief Virtual CPU emulator core (PL080 backend) 13 | */ 14 | #include 15 | 16 | #include "RTE_Components.h" 17 | #include "RTE_Device.h" 18 | #include CMSIS_device_header 19 | 20 | #ifndef DMACU_DMA_CHANNEL 21 | # define DMACU_DMA_CHANNEL (0u) 22 | #endif 23 | 24 | // GPDMA Configuration register definitions 25 | #define GPDMA_CONFIG_E (1U << 0) 26 | #define GPDMA_CONFIG_M0 (1U << 1) 27 | #define GPDMA_CONFIG_M1 (1U << 2) 28 | 29 | // GPDMA Channel Configuration registers definitions 30 | #define GPDMA_CH_CONFIG_E (1U << 0) 31 | #define GPDMA_CH_CONFIG_ITC (1U << 15) 32 | #define GPDMA_CH_CONFIG_A (1U << 17) 33 | #define GPDMA_CH_CONFIG_H (1U << 18) 34 | 35 | #define GPIO_LED_MASK (1u << 22) 36 | 37 | // Override the IRQ handler 38 | extern void DMA_IRQHandler(void); 39 | 40 | // PL080 status flag (for Hal_DmaTransfer) 41 | static volatile uint32_t gHal_DmaTransferDone; 42 | 43 | // Bit-masks for the red, green, and blue LEDs (RGB LED1) on the LPXxpress1769 eval board 44 | #define GPIO0_RED_LED_Msk (1u << 22u) 45 | 46 | #define GPIO3_GREEN_LED_Msk (1u << 25u) 47 | #define GPIO3_BLUE_LED_Msk (1u << 26u) 48 | 49 | //------------------------------------------------------------------------------------------------- 50 | // Disable semihosting 51 | // 52 | 53 | extern void _sys_exit(int status); 54 | extern void _ttywrch(int ch); 55 | 56 | __asm__ (".global __use_no_semihosting"); 57 | 58 | __NO_RETURN void _sys_exit(int status) 59 | { 60 | // Sleep forever 61 | while (true) 62 | { 63 | if (0u != (CoreDebug->DHCSR & CoreDebug_DHCSR_C_DEBUGEN_Msk)) 64 | { 65 | // A debugger is presenz 66 | __BKPT(0); 67 | } 68 | 69 | __WFE(); 70 | } 71 | } 72 | 73 | void _ttywrch(int ch) 74 | { 75 | // Print via ITM (if enabled) 76 | (void) ITM_SendChar(ch & 0xFFu); 77 | } 78 | 79 | //------------------------------------------------------------------------------------------------- 80 | const Hal_Config_t gHalConfig = 81 | { 82 | .platform_id = HAL_PLATFORM_LPCXPRESSO_1769 83 | }; 84 | 85 | //------------------------------------------------------------------------------------------------- 86 | void Hal_Init(void) 87 | { 88 | // Enable DMA clock 89 | LPC_SC->PCONP |= (1U << 29); 90 | 91 | // For simplicity: Setup GPIOs for blinking the on-board led of the LPC1769 LPCXpresso board 92 | LPC_PINCON->PINSEL1 &= ~(3u << 12u); 93 | 94 | // Disable the red LED 95 | LPC_GPIO0->FIOSET = GPIO0_RED_LED_Msk; 96 | LPC_GPIO0->FIODIR |= GPIO0_RED_LED_Msk; 97 | 98 | // Disable the green and blue LEDs 99 | LPC_GPIO3->FIOSET = (GPIO3_GREEN_LED_Msk | GPIO3_BLUE_LED_Msk); 100 | LPC_GPIO3->FIODIR |= (GPIO3_GREEN_LED_Msk | GPIO3_BLUE_LED_Msk); 101 | 102 | // Start the SysTick timer (10 kHz) 103 | SystemCoreClockUpdate(); 104 | SysTick_Config(SystemCoreClock / 10000u); 105 | 106 | } 107 | 108 | //------------------------------------------------------------------------------------------------- 109 | // Simple software PWM (blue LED) + heart beat using the SysTick timer 110 | // 111 | // - We implement a simple heartbeat LED blinking at ~2 Hz 112 | // - In the "dark" state the blue LED is driven by a software PWM at ~1% duty cycle 113 | // - In the "bright" state the blue LED is driven by a software PWM at ~10% duty cycle 114 | // 115 | // - The heartbeat counter disables itself after 3 full cycles 116 | 117 | // Reload value for the software PWM 118 | #define SOFT_PWM_RELOAD 100u 119 | 120 | #define SOFT_PWM_LED_DARK ((1u * SOFT_PWM_RELOAD) / 100u) // ~1% Duty Cycle 121 | #define SOFT_PWM_LED_BRIGHT ((10u * SOFT_PWM_RELOAD) / 100u) // ~10% Duty Cycle 122 | 123 | static uint32_t gSoftPwmCounter = SOFT_PWM_RELOAD - 1u; 124 | static uint32_t gSoftPwmDutyCycle = SOFT_PWM_LED_DARK; 125 | 126 | // Reload value for the heart-beat counter 127 | #define HEARTBEAT_RELOAD 5000u 128 | #define HEARTBEAT_FULL_CYCLES 6u 129 | 130 | static uint32_t gHeartBeatCounter = HEARTBEAT_RELOAD - 1u; 131 | static uint32_t gRemainingHeartBeats = HEARTBEAT_FULL_CYCLES - 1u; 132 | 133 | void SysTick_Handler(void) 134 | { 135 | // Update the soft PWM counter 136 | if (gSoftPwmCounter > 0u) 137 | { 138 | gSoftPwmCounter -= 1u; 139 | } 140 | else 141 | { 142 | gSoftPwmCounter = SOFT_PWM_RELOAD - 1u; 143 | } 144 | 145 | // Update the LED output status (based on softare PWM duty-cycle) 146 | if (gSoftPwmCounter < gSoftPwmDutyCycle) 147 | { 148 | // LED on 149 | LPC_GPIO3->FIOCLR = GPIO3_BLUE_LED_Msk; 150 | } 151 | else 152 | { 153 | // LED off 154 | LPC_GPIO3->FIOSET = GPIO3_BLUE_LED_Msk; 155 | } 156 | 157 | // Heart-beat counter 158 | if (gRemainingHeartBeats > 0u) 159 | { 160 | // More heartbeats to come 161 | if (gHeartBeatCounter > 0u) 162 | { 163 | gHeartBeatCounter -= 1u; 164 | } 165 | else 166 | { 167 | // Toggle the heart-beat PWM counter 168 | gSoftPwmDutyCycle = (SOFT_PWM_LED_DARK == gSoftPwmDutyCycle) ? SOFT_PWM_LED_BRIGHT : SOFT_PWM_LED_DARK;4 169 | gHeartBeatCounter = HEARTBEAT_RELOAD - 1u; 170 | gRemainingHeartBeats -= 1u; 171 | } 172 | } 173 | else 174 | { 175 | // Flatline 176 | 177 | gSoftPwmDutyCycle = 0u; 178 | 179 | SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; 180 | 181 | LPC_GPIO3->FIOSET = GPIO3_BLUE_LED_Msk; 182 | } 183 | } 184 | 185 | //------------------------------------------------------------------------------------------------- 186 | void DMA_IRQHandler(void) 187 | { 188 | const uint32_t int_stat = LPC_GPDMA->DMACIntStat; 189 | 190 | // Clear terminal count interrupts 191 | if (0u != (int_stat & (1u << DMACU_DMA_CHANNEL))) 192 | { 193 | // Channel 0 is done (terminal count or error) 194 | gHal_DmaTransferDone = 1u; 195 | __SEV(); 196 | } 197 | 198 | // Clear error and terminal count IRQs 199 | LPC_GPDMA->DMACIntErrClr = int_stat; 200 | LPC_GPDMA->DMACIntTCClear = int_stat; 201 | } 202 | 203 | //------------------------------------------------------------------------------------------------- 204 | void Hal_DmaTransfer(const Dma_Descriptor_t *desc) 205 | { 206 | // Ensure that the DMA controller is enabled 207 | LPC_GPDMA->DMACConfig |= GPDMA_CONFIG_E; 208 | 209 | // Halt channel #0 (initial status is unknown) 210 | LPC_GPDMACH0->DMACCConfig |= GPDMA_CH_CONFIG_H; 211 | 212 | while (0u != (LPC_GPDMACH0->DMACCConfig & GPDMA_CH_CONFIG_A)) 213 | { 214 | __NOP(); 215 | } 216 | 217 | // Disable the channel (and clear the halt + IRQ flags) 218 | LPC_GPDMACH0->DMACCConfig = 0u; 219 | 220 | // Load the initial descriptor 221 | LPC_GPDMACH0->DMACCSrcAddr = desc->src; 222 | LPC_GPDMACH0->DMACCDestAddr = desc->dst; 223 | LPC_GPDMACH0->DMACCLLI = desc->lli; 224 | LPC_GPDMACH0->DMACCControl = desc->ctrl; 225 | 226 | // Set the GPIO pin 227 | LPC_GPIO0->FIOSET = (1u << 22); 228 | 229 | // Enable the DMA controller interrupt (transfer not yet done) 230 | LPC_GPDMA->DMACIntTCClear = (1u << DMACU_DMA_CHANNEL); 231 | LPC_GPDMA->DMACIntErrClr = (1u << DMACU_DMA_CHANNEL); 232 | 233 | gHal_DmaTransferDone = 0u; 234 | 235 | // Ensure that the DMA IRQ is enabled 236 | NVIC_EnableIRQ(DMA_IRQn); 237 | 238 | // Enable the channel 239 | LPC_GPDMACH0->DMACCConfig |= (GPDMA_CH_CONFIG_E | GPDMA_CH_CONFIG_ITC); 240 | 241 | // Wait until the channel becomes idle 242 | while (!gHal_DmaTransferDone) 243 | { 244 | __WFE(); 245 | } 246 | 247 | // Disable the RED LED, enable the green LED 248 | LPC_GPIO0->FIODIR &= ~GPIO0_RED_LED_Msk; 249 | } 250 | -------------------------------------------------------------------------------- /src/c/ports/lpc176x/keil/lpc176x.sct: -------------------------------------------------------------------------------- 1 | #!armclang --target=arm-arm-none-eabi -march=armv7-m -E -x c 2 | ; 3 | ; Scatter-loading descriptor for the LPC176x C 4 | ; 5 | ; Adapted from uVision generated scatter-loading description file 6 | ; to accomodate for compact placement of DMACU content. 7 | 8 | LR_IROM1 0x00000000 0x000080000 9 | { 10 | ER_IROM1 0x00000000 0x80000 11 | { 12 | *.o (RESET, +First) 13 | *(InRoot$$Sections) 14 | .ANY (+RO) 15 | .ANY (+XO) 16 | } 17 | 18 | RW_IRAM1 0x10000000 0x00008000 19 | { 20 | ; Normal (ARM-side) content 21 | .ANY (+RW +ZI) 22 | } 23 | 24 | RW_IRAM2 0x2007C000 0x00004000 25 | { 26 | ; DMACU descriptors (we let the scatter-loader load all 27 | ; patchable and read-only descriptors to this segment to 28 | ; minimize interference with the ARM CPU and the flash). 29 | ; 30 | ; NOTE: Placement of our DMA descriptors in the AHB SRAM allows 31 | ; the PL080 controller to resume operating while the CPU is in WFE. 32 | ; (cf. [UM10360; "4.8.1 Sleep Mode"]) 33 | ; 34 | *(.rodata.Dmacu*) 35 | *(.data.Dmacu*) 36 | *(.bss.Dmacu*) 37 | 38 | ; Lookup tables 39 | *(.rodata.Lut_*) 40 | 41 | ; Test program (flash is not accessible in sleep mode - i.e. during WFE) 42 | *(.rodata.gTestProgram) 43 | 44 | #if (DMACU_VIRTUAL_PL080 != 0) 45 | ; Slave CPU (for virtual PL080 operation) 46 | *(.rodata.SlaveCpu*) 47 | *(.data.SlaveCpu*) 48 | *(.bss.SlaveCpu*) 49 | 50 | ; Microcode for the virtual PL080 51 | *(.rodata.gVirtualPL080Code) 52 | #endif 53 | } 54 | 55 | RW_IRAM3 0x20080000 0x00004000 56 | { 57 | ; RAM segment for the DMACU is placed at a 64k boundary 58 | *(.bss.gTestRam +FIRST) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/c/ports/qemu/versatile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Minimal CPU Emulator Powered by the ARM PL080 DMA Controller (dmacu) 3 | * 4 | * Copyright (c) 2019-2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the prohect for the license text. 8 | */ 9 | 10 | /** 11 | * @file 12 | * @brief Minimal host application for the DMACU emulator 13 | * 14 | * This host application can be used on QEMU's versatilepb board model (ARM926EJ-S CPU). 15 | * 16 | * Typical QEMU invocation: 17 | * qemu-system-arm.exe -machine versatilepb -semihosting -nographic -kernel dmacu_qemu.elf 18 | * 19 | */ 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | // Base address of the PL080 DMAC 26 | #define PL080_DMA_BASE_ADDR UINT32_C(0x10130000) 27 | 28 | // Register of the PL080 DMAC (offset gives offset relative to controller base address) 29 | #define PL080_DMA_REG(offset) (* (volatile uint32_t *) (PL080_DMA_BASE_ADDR + (offset))) 30 | 31 | //------------------------------------------------------------------------------------------------- 32 | // Dummy HAL configuration 33 | // 34 | 35 | // RealView System Control Block (and its LEDs register) 36 | #define ARM_SYSCTL_BASE_ADDR UINT32_C(0x10000000) 37 | #define ARM_SYSCTL_REG(offset) (*(volatile uint32_t *) (ARM_SYSCTL_BASE_ADDR + (offset))) 38 | 39 | #define GPIO_LED_MASK (1u) 40 | 41 | const Hal_Config_t gHalConfig = 42 | { 43 | .platform_id = HAL_PLATFORM_QEMU 44 | }; 45 | 46 | //----------------------------------------------------------------------------------------- 47 | void Hal_Init(void) 48 | { 49 | // Disable all virtual LEDs 50 | ARM_SYSCTL_REG(0x008) = 0u; 51 | } 52 | 53 | //----------------------------------------------------------------------------------------- 54 | void Hal_DmaTransfer(const Dma_Descriptor_t *entry) 55 | { 56 | // Enable the DMA controller 57 | PL080_DMA_REG(0x030) |= UINT32_C(0x00000001); 58 | 59 | // Setup DMA channel #0 (using the first descriptor) 60 | PL080_DMA_REG(0x100) = entry->src; 61 | PL080_DMA_REG(0x104) = entry->dst; 62 | PL080_DMA_REG(0x108) = entry->lli; 63 | PL080_DMA_REG(0x10C) = entry->ctrl; 64 | 65 | // Set the channel configuration for channel 0 (and enable) 66 | PL080_DMA_REG(0x110) = UINT32_C(0x0000000001); 67 | 68 | while (UINT32_C(0) != (PL080_DMA_REG(0x01C) & UINT32_C(0x00000008))) 69 | { 70 | // Wait for the DMA controller 71 | } 72 | 73 | // Clear configuration for DMA channel #0 and stop. 74 | PL080_DMA_REG(0x110) = UINT32_C(0x0000000000); 75 | } 76 | -------------------------------------------------------------------------------- /src/c/vcpu/dmacu.h: -------------------------------------------------------------------------------- 1 | /** 2 | * PoC virtual CPU implementation for the ARM PL080 DMA Controller. 3 | * 4 | * Copyright (c) 2019-2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the project for the license text. 8 | */ 9 | 10 | /** 11 | * @file dmacu.h 12 | * @brief Virtual CPU emulator core (PL080 backend; common data) 13 | */ 14 | #ifndef DMACU_H_ 15 | #define DMACU_H_ 1 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | // Quiet mode 22 | #if !defined(DMACU_QUIET) 23 | # define DMACU_QUIET (0) 24 | #endif 25 | 26 | #ifndef DMACU_ALIGNED 27 | # define DMACU_ALIGNED(x) __attribute__((__aligned__((x)))) 28 | #endif 29 | 30 | #ifndef DMACU_PRIVATE 31 | # define DMACU_PRIVATE 32 | #endif 33 | 34 | #ifndef DMACU_PRIVATE_DECL 35 | # define DMACU_PRIVATE_DECL extern 36 | #endif 37 | 38 | 39 | #ifndef DMACU_CONST 40 | # define DMACU_CONST const 41 | #endif 42 | 43 | #ifndef DMACU_READONLY 44 | # define DMACU_READONLY const 45 | #endif 46 | 47 | #ifndef DMACU_READWRITE 48 | # define DMACU_READWRITE 49 | #endif 50 | 51 | /// \brief 32-bit pointer type for the virtual CPU emulator. 52 | /// 53 | typedef uint32_t Dma_UIntPtr_t; 54 | 55 | /// \brief PL080 DMA descriptor 56 | /// 57 | /// \note See the PL080 DMA controller datasheet for details on the fields of the 58 | /// structure. 59 | /// 60 | typedef struct Dma_Descriptor 61 | { 62 | Dma_UIntPtr_t src; ///!< Source address of the transfer 63 | Dma_UIntPtr_t dst; ///!< Destination address of the transfer 64 | Dma_UIntPtr_t lli; ///!< Address of the next transfer in the chain 65 | uint32_t ctrl; ///!< Control bits and transfer size 66 | } Dma_Descriptor_t; 67 | 68 | /// \brief Converts a C pointer to a 32-bit DMA address. 69 | /// 70 | /// \param p is the pointer-typed C expresion to be converted. 71 | /// \return The raw address as (unsigned) 32-bit integer of type @ref Dma_UIntPtr_t. 72 | /// 73 | #define Dma_PtrToAddr(p) ((Dma_UIntPtr_t) (p)) 74 | 75 | /// \brief Gets the offset of field @p _field in type @p _type. 76 | /// 77 | /// \param _type is a compound type (struct). 78 | /// 79 | /// \param _field is the 80 | #define Dma_OffsetOf(_type,_field) ((uint32_t) offsetof(_type, _field)) 81 | 82 | /// \brief Canonical invalid (NULL) pointer 83 | /// 84 | #define DMA_INVALID_ADDR Dma_PtrToAddr(NULL) 85 | 86 | //------------------------------------------------------------------------------------------------- 87 | /// \brief Execution state of the DMACU virtual CPU 88 | /// 89 | /// \note The DMACU virtual CPU requires the CPU structure to be aligned on an even 256-byte boundary 90 | /// to ensure correct operation of the register file. (Register file accesses patch the lowest 91 | /// byte of DMA source/destination addresses) 92 | /// 93 | typedef struct Dmacu_Cpu 94 | { 95 | /// \brief Register file (256 registers) 96 | uint8_t RegFile[256u]; 97 | 98 | /// \brief Guard zone (catches off-by-one/two/three access for regfile corner-cases) 99 | uint32_t GuardZone; 100 | 101 | /// \brief Current program counter 102 | uint32_t PC; 103 | 104 | /// \brief Next program counter 105 | uint32_t NextPC; 106 | 107 | /// \brief Program base address (initial PC) 108 | uint32_t ProgramBase; 109 | 110 | /// \brief State tracker for the debug state 111 | /// 112 | /// \todo Back-port from assembler implementation (and integrate in the CPU pipeline) 113 | uint32_t DbgState; 114 | 115 | /// \brief Current instruction word 116 | union 117 | { 118 | /// \brief Byte-wise via (for simpler descriptor construction) 119 | uint8_t Bytes[4u]; 120 | 121 | /// \brief Word value 122 | uint32_t Value; 123 | } CurrentOPC; 124 | 125 | /// \brief Operand values 126 | struct 127 | { 128 | /// \brief Current A operand value 129 | uint32_t A; 130 | 131 | /// \brief Current B operand value 132 | uint32_t B; 133 | 134 | /// \brief Current Z result value 135 | uint32_t Z; 136 | } Operands; 137 | 138 | /// \brief Scratchpad for temporary values 139 | uint8_t Scratchpad[4u]; 140 | 141 | /// \brief Active SBOX (for shared logic pipeline) 142 | uint32_t ActiveLogicSbox; 143 | } Dmacu_Cpu_t; 144 | 145 | //------------------------------------------------------------------------------------------------- 146 | // Helper functions to interact with the virtual CPU 147 | // 148 | 149 | /// \brief Boots the virtual CPU and executes the built-in test program (see utils.c). 150 | /// 151 | extern void Dmacu_RunTestProgram(void); 152 | 153 | /// \brief Configures a DMACU virtual CPU for executing a small test program. 154 | /// 155 | /// \param[out] cpu points to the CPU state object to be configuzed. 156 | /// 157 | extern void Dmacu_SetupTestProgram(Dmacu_Cpu_t *cpu); 158 | 159 | /// \brief Proof of the simulation hypothesis in the PL080 universe :) 160 | /// 161 | /// This function is a drop-in replacmeent for @ref Dmacu_SetupTestProgram. It configures a 162 | /// second DMACU instrance to execute simulate a (simplified) PL080 DMA controller, which in 163 | /// turn executes the main test program (aka @ref Dmacu_SetupTestProgram). 164 | /// 165 | /// \param[out] cpu points to the (primary) CPU state object to be configuzed. 166 | extern void Dmacu_SetupVirtualPL080(Dmacu_Cpu_t *cpu); 167 | 168 | /// \brief Dumps the current CPU execution state of the virtual CPU to the standard output. 169 | /// 170 | /// \param[in] prefix specifies the prefix string to be prepended to each output line. 171 | /// 172 | /// \param[in] cpu points to the CPU state object to be dumped. 173 | /// 174 | extern void Dmacu_DumpCpuState(const char *prefix, const Dmacu_Cpu_t *cpu); 175 | 176 | //------------------------------------------------------------------------------------------------- 177 | // Hardware abstraction layer 178 | // 179 | 180 | /// \brief Static configuration of the hardware abstraction layer. 181 | typedef struct Hal_Config 182 | { 183 | /// \brief HAL platform ID 184 | /// 185 | /// We pass this value in r247 to allow the microcode to adapt to the host platform. 186 | /// Currently the following platform IDs are in use: 187 | /// 188 | /// - 0x00 ('\0') Host-based simulation 189 | /// - 0x41 ('A') LPCxpresso LPC1769 (or compatible) board. 190 | /// - 0x51 ('Q') QEMU simulating a versatilepb board. 191 | uint8_t platform_id; 192 | } Hal_Config_t; 193 | 194 | /// \brief Virtual "host" simulation platform. 195 | #define HAL_PLATFORM_HOST UINT8_C(0x00) 196 | 197 | /// \brief LPCxpress LPC1769 (or compatible) board. 198 | #define HAL_PLATFORM_LPCXPRESSO_1769 UINT8_C(0x41) 199 | 200 | /// \brief QEMU simulating a versatilepb board. 201 | #define HAL_PLATFORM_QEMU UINT8_C(0x51) 202 | 203 | /// \brief Static HAL configuration (provided by the platform layer) 204 | extern const Hal_Config_t gHalConfig; 205 | 206 | /// \brief Initializes the hardware abstraction layer. 207 | /// 208 | /// \note This function must be provided by the platform specific port to initalize platform specific 209 | /// hardware features for the DMACU environment. 210 | /// 211 | extern void Hal_Init(void); 212 | 213 | /// \brief Executes a DMA transfer (via the PL080 DMA controller). 214 | /// 215 | /// \param[in] desc is the first DMA descriptor in the transfer chain. 216 | extern void Hal_DmaTransfer(const Dma_Descriptor_t *desc); 217 | 218 | #endif // DMACU_H_ 219 | -------------------------------------------------------------------------------- /src/c/vcpu/dmacu_instance.h: -------------------------------------------------------------------------------- 1 | /** 2 | * PoC virtual CPU implementation for the ARM PL080 DMA Controller. 3 | * 4 | * Copyright (c) 2019-2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the project for the license text. 8 | */ 9 | 10 | /** 11 | * @file dmacu_instance.h 12 | * @brief Virtual CPU emulator core (PL080 backend; instance specific data) 13 | */ 14 | #ifndef DMACU_INSTANCE_H_ 15 | #define DMACU_INSTANCE_H_ 1 16 | 17 | // Common types and entrypoint for the main instance. 18 | #include "dmacu.h" 19 | 20 | // DMA instance prefix 21 | // 22 | // The instance prefix can be defined (e.g. when building a library) to enable coexistence of 23 | // multiple DMACU instances in the same executable image. 24 | // 25 | #if !defined(DMA_INSTANCE_PREFIX) 26 | # define DMA_INSTANCE_PREFIX Dmacu 27 | #endif 28 | 29 | // Alignment of the RAM segment 30 | #if !defined(DMACU_RAM_ALIGNMENT) 31 | # define DMACU_RAM_ALIGNMENT (0x10000) 32 | #endif 33 | 34 | // Alignment of the ROM segment 35 | #if !defined(DMACU_ROM_ALIGNMENT) 36 | # define DMACU_ROM_ALIGNMENT (0x10000) 37 | #endif 38 | 39 | //------------------------------------------------------------------------------------------------- 40 | // Basic DMA descriptors (PL080) 41 | // 42 | 43 | /// \brief Concatenates a name with arguments @p a and @p b expanded. 44 | #define Dma_Concat_Name(a,b) \ 45 | Dma_Concat_Name_Inner(a,b) 46 | 47 | /// \brief Macro expansion helper for @ref Dma_Concat_Name (implementation detail) 48 | /// \internal 49 | #define Dma_Concat_Name_Inner(a,b) \ 50 | a ## _ ## b 51 | 52 | /// \brief Constructs the name of a global descriptor or object 53 | #define Dma_Global_Name(_self) \ 54 | Dma_Concat_Name(DMA_INSTANCE_PREFIX, _self) 55 | 56 | /// \brief Defines an externally visible DMA descriptor 57 | #define Dma_Define_Descriptor(_self,...) \ 58 | DMACU_ALIGNED(16u) \ 59 | DMACU_PRIVATE Dma_Descriptor_t Dma_Global_Name(_self) = { __VA_ARGS__ }; 60 | 61 | /// \brief Constructs the name of a local descriptor or object. 62 | #define Dma_Local_Name(_self,_suffix) \ 63 | Dma_Concat_Name(_self,_suffix) 64 | 65 | /// \brief (Re-)declares an externally visible DMA descriptor 66 | #define Dma_Declare_Descriptor(_self) \ 67 | DMACU_PRIVATE_DECL Dma_Descriptor_t Dma_Global_Name(_self); 68 | 69 | /// \brief (Re-)declares a local DMA descriptor 70 | #define Dma_Declare_Local_Descriptor(_self,_suffix) \ 71 | DMACU_PRIVATE_DECL Dma_Descriptor_t Dma_Local_Name(Dma_Global_Name(_self),_suffix); 72 | 73 | /// \brief References a declared global descriptor 74 | #define Dma_Global_Reference(_self) \ 75 | (&Dma_Global_Name(_self)) 76 | 77 | /// \brief References a declared local descriptor 78 | #define Dma_Local_Reference(_self,_suffix) \ 79 | (&Dma_Local_Name(Dma_Global_Name(_self), _suffix)) 80 | 81 | /// \brief Common DMA copy core operation 82 | /// 83 | /// Copies "size" bytes from "src" to "dst". Then links to the next descriptor at "lli". 84 | /// 85 | /// width indicates the source/destination transfer width in PL080's log-2 encoding: 86 | /// - width=0 generates a byte copy 87 | /// - width=1 generates a half-word (16-bit) copy 88 | /// - width=2 generates a word (32-bit) copy 89 | /// 90 | #define Dma_Copy_Core(_qual,_self,_dst,_src,_size,_lli,_width) \ 91 | _qual Dma_Define_Descriptor(_self, \ 92 | .src = (Dma_UIntPtr_t) (_src), \ 93 | .dst = (Dma_UIntPtr_t) (_dst), \ 94 | .lli = (Dma_UIntPtr_t) (_lli), \ 95 | .ctrl = UINT32_C(0x0C000000) + (((_width) & 0x3u) << 21u) + (((_width) & 0x3u) << 18u) + (uint32_t) (_size) \ 96 | ) 97 | 98 | /// \brief Basic byte (8-bit) wise DMA copy operation 99 | /// 100 | /// Copies "size" bytes from "src" to "dst". Then links to the next descriptor at "lli". 101 | /// 102 | #define Dma_ByteCopy_Core(_qual,_self,_dst,_src,_size,_lli) \ 103 | Dma_Copy_Core(_qual,_self,_dst,_src,_size,_lli,0u) 104 | 105 | // Patchable version of Dma_ByteCopy 106 | #define Dma_ByteCopy(_self,_dst,_src,_size,_lli) \ 107 | Dma_ByteCopy_Core(DMACU_READWRITE,_self,_dst,_src,_size,_lli) 108 | 109 | // Fixed (non-patchable) version of Dma_ByteCopy 110 | #define Dma_FixedByteCopy(_self,_dst,_src,_size,_lli) \ 111 | Dma_ByteCopy_Core(DMACU_READONLY,_self,_dst,_src,_size,_lli) 112 | 113 | /// \brief Basic half-word (16-bit) wise DMA copy operation 114 | /// 115 | /// Copies "size" bytes from "src" to "dst". Then links to the next descriptor at "lli". 116 | /// Size give the number of 16-bit half-words to copy 117 | /// 118 | #define Dma_HalfWordCopy_Core(_qual,_self,_dst,_src,_size,_lli) \ 119 | Dma_Copy_Core(_qual,_self,_dst,_src,_size,_lli,1u) 120 | 121 | // Patchable version of Dma_HalfWordCopy 122 | #define Dma_HalfWordCopy(_self,_dst,_src,_size,_lli) \ 123 | Dma_HalfWordCopy_Core(DMACU_READWRITE,_self,_dst,_src,_size,_lli) 124 | 125 | // Fixed (non-patchable) version of DmaHalfWordCopy 126 | #define Dma_FixedHalfWordCopy(_self,_dst,_src,_size,_lli) \ 127 | Dma_HalfWordCopy_Core(DMACU_READONLY,_self,_dst,_src,_size,_lli) 128 | 129 | /// \brief Basic word (32-bit) wise DMA copy operation 130 | /// 131 | /// Copies "size" bytes from "src" to "dst". Then links to the next descriptor at "lli". 132 | /// Size give the number of 32-bit words to copy 133 | /// 134 | #define Dma_WordCopy_Core(_qual,_self,_dst,_src,_size,_lli) \ 135 | Dma_Copy_Core(_qual,_self,_dst,_src,_size,_lli,2u) 136 | 137 | // Patchable version of Dma_WordCopy 138 | #define Dma_WordCopy(_self,_dst,_src,_size,_lli) \ 139 | Dma_WordCopy_Core(DMACU_READWRITE,_self,_dst,_src,_size,_lli) 140 | 141 | // Fixed (non-patchable) version of Dma_WordCopy 142 | #define Dma_FixedWordCopy(_self,_dst,_src,_size,_lli) \ 143 | Dma_WordCopy_Core(DMACU_READONLY,_self,_dst,_src,_size,_lli) 144 | 145 | /// \brief Basic byte-wise DMA fill operation. 146 | /// 147 | /// Fills a block of "size" bytes at "dst" with the byte found at "src". Then links to the 148 | /// next descriptor at "lli". 149 | /// 150 | #define Dma_ByteFill_Core(_qual,_self,_dst,_src,_size,_lli) \ 151 | _qual Dma_Define_Descriptor(_self, \ 152 | .src = (Dma_UIntPtr_t) (_src), \ 153 | .dst = (Dma_UIntPtr_t) (_dst), \ 154 | .lli = (Dma_UIntPtr_t) (_lli), \ 155 | .ctrl = UINT32_C(0x08000000) + (uint32_t) (_size) \ 156 | ) 157 | 158 | // Fixed (non-patchable) version of Dma_ByteFill 159 | #define Dma_ByteFill(_self,_dst,_src,_size,_lli) \ 160 | Dma_ByteFill_Core(DMACU_READWRITE,_self,_dst,_src,_size,_lli) 161 | 162 | // Fixed (non-patchable) version of Dma_ByteFill 163 | #define Dma_FixedByteFill(_self,_dst,_src,_size,_lli) \ 164 | Dma_ByteFill_Core(DMACU_READONLY,_self,_dst,_src,_size,_lli) 165 | 166 | 167 | /// \brief Common DMA copy core operation (with terminal count interrupt) 168 | /// 169 | /// Copies "size" bytes from "src" to "dst". Then links to the next descriptor at "lli". 170 | /// 171 | /// width indicates the source/destination transfer width in PL080's log-2 encoding: 172 | /// - width=0 generates a byte copy 173 | /// - width=1 generates a half-word (16-bit) copy 174 | /// - width=2 generates a word (32-bit) copy 175 | /// 176 | /// This version of the copy operation triggers a terminal count interrupt (if enabled). 177 | /// 178 | #define Dma_TerminalCopy_Core(_qual,_self,_dst,_src,_size,_lli,_width) \ 179 | _qual Dma_Define_Descriptor(_self, \ 180 | .src = (Dma_UIntPtr_t) (_src), \ 181 | .dst = (Dma_UIntPtr_t) (_dst), \ 182 | .lli = (Dma_UIntPtr_t) (_lli), \ 183 | .ctrl = UINT32_C(0x8C000000) + (((_width) & 0x3u) << 21u) + (((_width) & 0x3u) << 18u) + (uint32_t) (_size) \ 184 | ) 185 | 186 | /// \brief Basic word (32-bit) wise DMA copy operation (with terminal count interrupt) 187 | /// 188 | /// Copies "size" bytes from "src" to "dst". Then links to the next descriptor at "lli". 189 | /// Size give the number of 32-bit words to copy 190 | /// 191 | #define Dma_TerminalWordCopy_Core(_qual,_self,_dst,_src,_size,_lli) \ 192 | Dma_TerminalCopy_Core(_qual,_self,_dst,_src,_size,_lli,2u) 193 | 194 | // Patchable version of Dma_TerminalWordCopy (with terminal count interrupt) 195 | #define Dma_TerminalWordCopy(_self,_dst,_src,_size,_lli) \ 196 | Dma_WordCopy_Core(DMACU_READWRITE,_self,_dst,_src,_size,_lli) 197 | 198 | // Fixed (non-patchable) version of Dma_TerminalWordCopy (with terminal count interrupt) 199 | #define Dma_FixedTerminalWordCopy(_self,_dst,_src,_size,_lli) \ 200 | Dma_TerminalWordCopy_Core(DMACU_READONLY,_self,_dst,_src,_size,_lli) 201 | 202 | /// \brief Gets the virtual CPU's global execution state. 203 | /// 204 | extern Dmacu_Cpu_t* Dma_Global_Name(GetCpu)(void); 205 | 206 | /// \brief Gets the DMA descriptor for booting and running the virtual CPU. 207 | /// 208 | extern const Dma_Descriptor_t* Dma_Global_Name(CpuBootDescriptor)(void); 209 | 210 | #endif // DMACU_INSTANCE_H_ 211 | -------------------------------------------------------------------------------- /src/c/vcpu/dmacu_shared.c: -------------------------------------------------------------------------------- 1 | /** 2 | * PoC virtual CPU implementation for the ARM PL080 DMA Controller. 3 | * 4 | * Copyright (c) 2019-2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the project for the license text. 8 | */ 9 | 10 | /** 11 | * @file dmacu.c 12 | * @brief Virtual CPU emulator core (PL080 backend; shared lookup tables) 13 | */ 14 | #include "dmacu.h" 15 | 16 | //------------------------------------------------------------------------------------------------- 17 | // Lookup-Tables (common helpers and support macros) 18 | // 19 | 20 | // Helper macros to populate the entries of a LUT (with a power-of-two number of elements) 21 | #define LUT_MAKE_1(_gen,_base) [(_base)] = _gen((_base)) 22 | #define LUT_MAKE_2(_gen,_base) LUT_MAKE_1 (_gen, (_base)), LUT_MAKE_1 (_gen, ((_base) + 1u)) 23 | #define LUT_MAKE_4(_gen,_base) LUT_MAKE_2 (_gen, (_base)), LUT_MAKE_2 (_gen, ((_base) + 2u)) 24 | #define LUT_MAKE_8(_gen,_base) LUT_MAKE_4 (_gen, (_base)), LUT_MAKE_4 (_gen, ((_base) + 4u)) 25 | #define LUT_MAKE_16(_gen,_base) LUT_MAKE_8 (_gen, (_base)), LUT_MAKE_8 (_gen, ((_base) + 8u)) 26 | #define LUT_MAKE_32(_gen,_base) LUT_MAKE_16 (_gen, (_base)), LUT_MAKE_16 (_gen, ((_base) + 16u)) 27 | #define LUT_MAKE_64(_gen,_base) LUT_MAKE_32 (_gen, (_base)), LUT_MAKE_32 (_gen, ((_base) + 32u)) 28 | #define LUT_MAKE_128(_gen,_base) LUT_MAKE_64 (_gen, (_base)), LUT_MAKE_64 (_gen, ((_base) + 64u)) 29 | #define LUT_MAKE_256(_gen,_base) LUT_MAKE_128 (_gen, (_base)), LUT_MAKE_128(_gen, ((_base) + 128u)) 30 | #define LUT_MAKE_512(_gen,_base) LUT_MAKE_256 (_gen, (_base)), LUT_MAKE_256(_gen, ((_base) + 256u)) 31 | 32 | //------------------------------------------------------------------------------------------------- 33 | // Lookup tables for Unary Functions (uint8_t -> uint8_t) 34 | // 35 | 36 | /// \brief Bitwise Complement (1's complement) 37 | /// 38 | /// C model: 39 | /// \code 40 | /// uint8_t BitNot(const uint8_t a) 41 | /// { 42 | /// return ~a & 0xFFu; 43 | /// } 44 | /// \endcode 45 | DMACU_ALIGNED(256u) 46 | DMACU_READONLY uint8_t Lut_BitNot[256u] = 47 | { 48 | #define Lut_BitNot_Generator(_a) ((uint8_t) (~(_a) & 0xFFu)) 49 | 50 | LUT_MAKE_256(Lut_BitNot_Generator, 0u) 51 | }; 52 | 53 | /// \brief Two's Complement / Negation 54 | /// 55 | /// C model: 56 | /// \code 57 | /// uint8_t BitNeg(const uint8_t a) 58 | /// { 59 | /// return -a & 0xFFu; 60 | /// } 61 | /// \endcode 62 | /// 63 | DMACU_ALIGNED(256u) 64 | DMACU_READONLY uint8_t Lut_Neg[256u] = 65 | { 66 | #define Lut_Neg_Generator(_a) ((uint8_t) (-(_a) & 0xFFu)) 67 | 68 | LUT_MAKE_256(Lut_Neg_Generator, 0u) 69 | }; 70 | 71 | /// \brief Logic Rotate-Right by 1 72 | /// 73 | /// C model: 74 | /// \code 75 | /// uint8_t RotateRight(const uint8_t a) 76 | /// { 77 | /// return ((a >> 1u) & 0x7Fu) | ((a & 0x1) << 7u); 78 | /// } 79 | /// \endcode 80 | /// 81 | DMACU_ALIGNED(256u) 82 | DMACU_READONLY uint8_t Lut_RotateRight[256u] = 83 | { 84 | #define Lut_RotateRight_Generator(_a) \ 85 | ((uint8_t) ((((_a) >> 1u) & 0x7Fu) | (((_a) & 0x1u) << 7u))) 86 | 87 | LUT_MAKE_256(Lut_RotateRight_Generator, 0u) 88 | }; 89 | 90 | /// \brief Logic Rotate-Left by 1 91 | /// 92 | /// C model: 93 | /// \code 94 | /// uint8_t RotateLeft(const uint8_t a) 95 | /// { 96 | /// return ((a & 0x7Fu) << 1u) | ((a >> 7u) & 0x1u); 97 | /// } 98 | /// \endcode 99 | /// 100 | DMACU_ALIGNED(256u) 101 | DMACU_READONLY uint8_t Lut_RotateLeft[256u] = 102 | { 103 | #define Lut_RotateLeft_Generator(_a) \ 104 | ((uint8_t) ((((_a) & 0x7Fu) << 1u) | (((_a) >> 7u) & 0x1u))) 105 | 106 | LUT_MAKE_256(Lut_RotateLeft_Generator, 0u) 107 | }; 108 | 109 | /// \brief Extract Lower Nibble / Mask with 0x0F 110 | /// 111 | /// C model: 112 | /// \code 113 | /// uint8_t Lo4(const uint8_t a) 114 | /// { 115 | /// return a & 0x0Fu; 116 | /// } 117 | /// \endcode 118 | /// 119 | DMACU_ALIGNED(256u) 120 | DMACU_READONLY uint8_t Lut_Lo4[256u] = 121 | { 122 | #define Lut_Lo4_Generator(_a) \ 123 | ((uint8_t) ((_a) & 0x0Fu)) 124 | 125 | LUT_MAKE_256(Lut_Lo4_Generator, 0u) 126 | }; 127 | 128 | /// \brief Divide by 16 / Logic-Shift Right by 4 / Extract Upper Nibble 129 | /// 130 | /// C model: 131 | /// \code 132 | /// uint8_t Hi4(const uint8_t a) 133 | /// { 134 | /// return (a >> 4u) & 0x0Fu; 135 | /// } 136 | /// \endcode 137 | /// 138 | DMACU_ALIGNED(256u) 139 | DMACU_READONLY uint8_t Lut_Hi4[256u] = 140 | { 141 | #define Lut_Hi4_Generator(_a) \ 142 | ((uint8_t) (((_a) >> 4u) & 0x0Fu)) 143 | 144 | LUT_MAKE_256(Lut_Hi4_Generator, 0u) 145 | }; 146 | 147 | /// \brief Multiply by 4 / Logic Shift-Left by 2 148 | /// 149 | /// C model: 150 | /// \code 151 | /// uint8_t Mul4(const uint8_t a) 152 | /// { 153 | /// return (a & 0x3Fu) << 2u; 154 | /// } 155 | /// \endcode 156 | /// 157 | DMACU_ALIGNED(256u) 158 | DMACU_READONLY uint8_t Lut_Mul4[256u] = 159 | { 160 | #define Lut_Mul4_Generator(_a) \ 161 | ((uint8_t) (((_a) & 0x3Fu) << 2u)) 162 | 163 | LUT_MAKE_256(Lut_Mul4_Generator, 0u) 164 | }; 165 | 166 | /// \brief Multiply by 16 / Logic Shift-Left by 4 167 | /// 168 | /// C model: 169 | /// \code 170 | /// uint8_t Mul16(const uint8_t a) 171 | /// { 172 | /// return (a & 0x0Fu) << 4u; 173 | /// } 174 | /// \endcode 175 | /// 176 | DMACU_ALIGNED(256u) 177 | DMACU_READONLY uint8_t Lut_Mul16[256u] = 178 | { 179 | #define Lut_Mul16_Generator(_a) \ 180 | ((uint8_t) (((_a) & 0x0Fu) << 4u)) 181 | 182 | LUT_MAKE_256(Lut_Mul16_Generator, 0u) 183 | }; 184 | 185 | //----------------------------------------------------------------------------------------- 186 | // Lookup tables for binary functions (Lower Nibble) 187 | // 188 | // Logic functions: 189 | // Full lookup tables for 8-bit x 8-bit lookups would occupy 64k for each table. To conserve 190 | // ROM/flash space we store 4-bit x 4-bit lookup tables and use construct the 8-bit result 191 | // from from two lookups on the upper/lower nibble of the operand bytes. 192 | // 193 | //----------------------------------------------------------------------------------------- 194 | 195 | /// \brief Bitwise AND (Lower Nibble) 196 | /// 197 | /// C model: 198 | /// \code 199 | /// uint8_t BitAnd(uint8_t x) 200 | /// { 201 | /// uint8_t a = x & 0x0Fu; 202 | /// uint8_t b = (x >> 4u) & 0x0Fu; 203 | /// return (a & b) & 0x0Fu; 204 | /// } 205 | /// \endcode 206 | /// 207 | DMACU_ALIGNED(256u) 208 | DMACU_READONLY uint8_t Lut_BitAnd[256u] = 209 | { 210 | #define Lut_BitAnd_Generator(_x) \ 211 | ((uint8_t) ((((_x) & 0x0Fu) & (((_x) >> 4u) & 0x0Fu)) & 0x0Fu)) 212 | 213 | LUT_MAKE_256(Lut_BitAnd_Generator, 0u) 214 | }; 215 | 216 | /// \brief Bitwise OR (Lower Nibble) 217 | /// 218 | /// C model: 219 | /// \code 220 | /// uint8_t BitAnd(uint8_t x) 221 | /// { 222 | /// uint8_t a = x & 0x0Fu; 223 | /// uint8_t b = (x >> 4u) & 0x0Fu; 224 | /// return (a | b) & 0x0Fu; 225 | /// } 226 | /// \endcode 227 | /// 228 | DMACU_ALIGNED(256u) 229 | DMACU_READONLY uint8_t Lut_BitOr[256u] = 230 | { 231 | #define Lut_BitOr_Generator(_x) \ 232 | ((uint8_t) ((((_x) & 0x0Fu) | (((_x) >> 4u) & 0x0Fu)) & 0x0Fu)) 233 | 234 | LUT_MAKE_256(Lut_BitOr_Generator, 0u) 235 | }; 236 | 237 | /// \brief Bitwise Exclusive-OR (Lower Nibble) 238 | /// 239 | /// C model: 240 | /// \code 241 | /// uint8_t BitAnd(uint8_t x) 242 | /// { 243 | /// uint8_t a = x & 0x0Fu; 244 | /// uint8_t b = (x >> 4u) & 0x0Fu; 245 | /// return (a | b) & 0x0Fu; 246 | /// } 247 | /// \endcode 248 | /// 249 | DMACU_ALIGNED(256u) 250 | DMACU_READONLY uint8_t Lut_BitEor[256u] = 251 | { 252 | #define Lut_BitEor_Generator(_x) \ 253 | ((uint8_t) ((((_x) & 0x0Fu) ^ (((_x) >> 4u) & 0x0Fu)) & 0x0Fu)) 254 | 255 | LUT_MAKE_256(Lut_BitEor_Generator, 0u) 256 | }; 257 | 258 | /// \brief Identity lookup table. 259 | /// 260 | /// The identity lookup table is used to add two 8-bit integers. Approximate C model: 261 | /// \code 262 | /// static uint8_t Add8(uint8_t a, uint8_t b) 263 | /// { 264 | /// uint8_t temp[256u]; 265 | /// 266 | /// // Implemented as Dma_ByteCopy with patch on bits [7:0] of the source address 267 | /// memcpy(&temp[0u], &Lut_Identity[a], 256u); 268 | /// 269 | /// // Implemented as Dma_ByteCopy with patch on bits [7:0] of the source address 270 | /// return temp[b]; 271 | /// } 272 | /// \endcode 273 | /// 274 | /// \note A "direct" approach to addition would be to use a 64k lookup table and to 275 | /// patch bits [7:0] and [15:9] of the source address of a Dma_ByteCopy. The temporary 276 | /// copy used here favors reduced memory usage and relaxed alignment requirements over 277 | /// the speed advantage of the "direct" approach. 278 | /// 279 | /// \note We force alignment of our LUT to an even 512 bytes boundary. This trivially 280 | /// ensures that we do not violate the PL080's hardware limitations w.r.t. to crossing 281 | /// 1K boundaries in DMA transfers. 282 | /// 283 | DMACU_ALIGNED(512u) 284 | DMACU_READONLY uint8_t Lut_Identity[512u] = 285 | { 286 | #define Lut_Identity_Generator(_x) \ 287 | ((uint8_t) ((_x) & 0xFFu)) 288 | 289 | LUT_MAKE_512(Lut_Identity_Generator, 0u) 290 | }; 291 | 292 | /// \brief Carry generator table 293 | /// 294 | /// The identity lookup table is used to add two 8-bit integers. Approximate C model: 295 | /// \code 296 | /// static uint8_t Add8(uint8_t a, uint8_t b) 297 | /// { 298 | /// uint8_t temp[256u]; 299 | /// 300 | /// // Implemented as Dma_ByteCopy with patch on bits [7:0] of the source address 301 | /// memcpy(&temp[0u], &Lut_Carry[a], 256u); 302 | /// 303 | /// // Implemented as Dma_ByteCopy with patch on bits [7:0] of the source address 304 | /// return temp[b]; 305 | /// } 306 | /// \endcode 307 | /// 308 | /// \note We force alignment of our LUT to an even 512 bytes boundary. This trivially 309 | /// ensures that we do not violate the PL080's hardware limitations w.r.t. to crossing 310 | /// 1K boundaries in DMA transfers. 311 | /// 312 | /// \see Lut_Identity for remarks on the "temporary copy" approach used here. 313 | /// 314 | /// 315 | DMACU_ALIGNED(512u) 316 | DMACU_READONLY uint8_t Lut_Carry[512u] = 317 | { 318 | #define Lut_Carry_Generator(_x) \ 319 | ((uint8_t) (((_x) >> 8u) & 0x01u)) 320 | 321 | LUT_MAKE_512(Lut_Carry_Generator, 0u) 322 | }; 323 | 324 | -------------------------------------------------------------------------------- /src/c/vcpu/mc/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore intermediate microcode build outputs 2 | # (we keep the source files and the final include files with the program/data blobs) 3 | *.bin 4 | *.o 5 | -------------------------------------------------------------------------------- /src/c/vcpu/mc/demo.code.inc: -------------------------------------------------------------------------------- 1 | 0x10, 0x00, 0xf7, 0x0d, 0x24, 0x51, 0xf7, 0x0d, 0x34, 0x41, 0xf7, 0x0d, 2 | 0xee, 0xee, 0x00, 0x1f, 0xfc, 0x00, 0xe4, 0x01, 0xe4, 0xfd, 0xe4, 0x03, 3 | 0xfe, 0xff, 0xe6, 0x03, 0x01, 0x00, 0xe8, 0x02, 0x00, 0x00, 0xea, 0x02, 4 | 0x50, 0x00, 0x00, 0x08, 0x08, 0x00, 0xe4, 0x02, 0x00, 0x10, 0xe6, 0x02, 5 | 0x01, 0x00, 0xe8, 0x02, 0x00, 0x00, 0xea, 0x02, 0x50, 0x00, 0x00, 0x08, 6 | 0x14, 0xc0, 0xe4, 0x02, 0x09, 0x20, 0xe6, 0x02, 0x00, 0x00, 0xe8, 0x02, 7 | 0x40, 0x00, 0xea, 0x02, 0x50, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x01, 8 | 0x00, 0x00, 0x01, 0x01, 0x10, 0x00, 0x00, 0x0d, 0xff, 0x00, 0x00, 0x04, 9 | 0x01, 0x01, 0x01, 0x04, 0x58, 0x00, 0x00, 0x08, 0x08, 0x04, 0x01, 0x0c, 10 | 0x84, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x04, 0xff, 0x01, 0x01, 0x04, 11 | 0x00, 0x00, 0x02, 0x0e, 0x01, 0x02, 0x03, 0x11, 0x68, 0x00, 0x00, 0x08, 12 | 0x10, 0xde, 0xe0, 0x0c, 0x0c, 0xad, 0xe1, 0x0c, 0x08, 0xc0, 0xe2, 0x0c, 13 | 0x08, 0xde, 0xe3, 0x0d, 0x01, 0xe0, 0x00, 0x1f, 0xfd, 0xfc, 0x10, 0x03, 14 | 0x01, 0x00, 0x01, 0x01, 0xc3, 0x00, 0x02, 0x01, 0x10, 0xfe, 0x03, 0x19, 15 | 0x02, 0x03, 0x03, 0x11, 0x00, 0x03, 0x03, 0x13, 0x03, 0x23, 0x22, 0x03, 16 | 0x38, 0x01, 0x20, 0x17, 0x03, 0x23, 0x22, 0x03, 0xdc, 0x00, 0x20, 0x17, 17 | 0x10, 0xfe, 0x03, 0x1a, 0x14, 0x00, 0x03, 0x0d, 0x01, 0x10, 0x04, 0x07, 18 | 0x01, 0x10, 0x10, 0x06, 0x04, 0x11, 0x11, 0x06, 0xa4, 0x00, 0x00, 0x08, 19 | 0x64, 0x6e, 0x65, 0x1f, 0x01, 0x00, 0x23, 0x01, 0x00, 0xe8, 0x25, 0x0e, 20 | 0x00, 0xe9, 0x26, 0x0e, 0x00, 0xea, 0x27, 0x0e, 0x00, 0xeb, 0x28, 0x0e, 21 | 0x23, 0x22, 0x24, 0x0f, 0xe4, 0xe6, 0x29, 0x1d, 0x18, 0x00, 0x24, 0x0d, 22 | 0xe8, 0x29, 0x29, 0x10, 0xe9, 0x2a, 0x2a, 0x10, 0xea, 0x2b, 0x2b, 0x10, 23 | 0xeb, 0x2c, 0x2c, 0x10, 0x24, 0x01, 0x00, 0x08, 0x25, 0x29, 0x29, 0x0f, 24 | 0x26, 0x2a, 0x2a, 0x0f, 0x27, 0x2b, 0x2b, 0x0f, 0x28, 0x2c, 0x2c, 0x0f, 25 | 0x24, 0x01, 0x00, 0x08, 0xe4, 0xe6, 0x29, 0x1e, 0x0c, 0x80, 0x23, 0x0d, 26 | 0x00, 0x23, 0x23, 0x13, 0xf0, 0x00, 0x00, 0x08, 0x20, 0x21, 0x00, 0x09, 27 | 0x08, 0x51, 0xf7, 0x0d, 0x20, 0x21, 0x00, 0x09, 0x1f, 0x10, 0x23, 0x02, 28 | 0x00, 0x10, 0x25, 0x02, 0x18, 0x10, 0x27, 0x02, 0x80, 0x00, 0x2d, 0x01, 29 | 0x27, 0x23, 0x29, 0x1d, 0x2d, 0x29, 0x29, 0x0f, 0xf8, 0x00, 0x29, 0x0d, 30 | 0x25, 0x23, 0x22, 0x1a, 0x20, 0x21, 0x00, 0x09 31 | -------------------------------------------------------------------------------- /src/c/vcpu/mc/demo.data.inc: -------------------------------------------------------------------------------- 1 | 0xe7, 0x71, 0xf5, 0xf5, 0x74, 0xd3, 0xf2, 0xfa, 0x73, 0xf8, 0x71, 0xd3, 2 | 0xf4, 0x71, 0x78, 0xd3, 0xeb, 0xe5, 0xdb, 0xdf, 0xdb, 0xd3, 0xe1, 0x65, 3 | 0x63, 0xd3, 0x78, 0x74, 0xfa, 0xf5, 0xf1, 0x53, 0xc6, 0xc3 4 | -------------------------------------------------------------------------------- /src/c/vcpu/mc/demo.mc: -------------------------------------------------------------------------------- 1 | /** 2 | * Demo program for the DMACU virtual CPU 3 | * 4 | * Copyright (c) 2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the project for the license text. 8 | */ 9 | 10 | .include "dmacu.inc" 11 | 12 | #define LABEL_AT(x) 13 | #define UINT32_C(x) .long (x) 14 | 15 | // Interbit delay (extra) 16 | #if !defined(DMACU_DEMO_INTERBIT_DELAY) 17 | # define DMACU_DEMO_INTERBIT_DELAY (0) 18 | #endif 19 | 20 | // UART output 21 | #if !defined(DMACU_DEMO_UART) 22 | # define DMACU_DEMO_UART (1) 23 | #endif 24 | 25 | // LED output 26 | #if !defined(DMACU_DEMO_LED) 27 | # define DMACU_DEMO_LED (1) 28 | #endif 29 | 30 | // Obfuscates a byte on the host (for our test-ram message) 31 | // 32 | // We obfuscate be rotating right by 1 bit and XOR-ing with 0x5A 33 | .macro obf_byte x 34 | .byte ((((\x) >> 1) | ((\x) << 7u)) ^ 0xC3) & 0xFF 35 | .endm 36 | 37 | // 38 | // Data segment for the demo program 39 | // 40 | DMACU.DATA.BEGIN demo 41 | // Reference test message (obfuscated) 42 | .irp c,'H','e','l','l','o',' ','b','r','a','v','e',' ','n','e','w', \ 43 | ' ','P','L','0','8','0',' ','D','M','A',' ','w','o','r','l', \ 44 | 'd','!', 0x0A,0x00 45 | obf_byte \c 46 | .endr 47 | DMACU.DATA.END demo 48 | 49 | // 50 | // Code segment for the demo program 51 | // 52 | DMACU.PROGRAM.BEGIN demo 53 | // Alias for the host marker registers 54 | .equ rMagic0, r224 55 | .equ rMagic1, r225 56 | .equ rMagic2, r226 57 | .equ rMagic3, r227 58 | 59 | .equ kExpectedMagic0, 0xDE 60 | .equ kExpectedMagic1, 0xAD 61 | .equ kExpectedMagic2, 0xC0 62 | .equ kExpectedMagic3, 0xDE 63 | 64 | // Global register used for the LED blink output 65 | .equ gLedGpioPin0, r228 66 | .equ gLedGpioPin1, r229 67 | .equ gLedGpioPin2, r230 68 | .equ gLedGpioPin3, r231 69 | .equ gLedGpioMask0, r232 70 | .equ gLedGpioMask1, r233 71 | .equ gLedGpioMask2, r234 72 | .equ gLedGpioMask3, r235 73 | 74 | // Platform ID register (r247) 75 | .equ rPlatformId, r247 76 | .set kHostPlatform, 0x00 77 | .set kLpcXpresso1769Platform, 0x41 78 | .set kQemuPlatform, 0x51 79 | 80 | // Code base address 81 | .equ gCodeBase0, r248 82 | .equ gCodeBase0, r249 83 | .equ gCodeBase0, r250 84 | .equ gCodeBase0, r251 85 | 86 | // Ram base address 87 | .equ gRamBase0, r252 88 | .equ gRamBase1, r253 89 | .equ gRamBase2, r254 90 | .equ gRamBase3, r255 91 | 92 | //------------------------------------------------------------------------------------- 93 | // Part 0: Platform setup 94 | // 95 | 96 | // Platform check: Blink is currently supported on all platforms6 97 | DMACU.BEQ .Lsetup_host, rPlatformId, kHostPlatform 98 | DMACU.BEQ .Lsetup_qemu, rPlatformId, kQemuPlatform 99 | DMACU.BEQ .Lsetup_lpcxpresso1769, rPlatformId, kLpcXpresso1769Platform 100 | DMACU.UND 0xEEEE 101 | 102 | // Host platform (or other platform that does not support the blink) 103 | // 104 | // We let the blink logic run against the the word at offset 0xFC in 105 | // the RAM. (We assume a 256 byte aligned RAM) 106 | .Lsetup_host: 107 | DMACU.MOV.IMM8 gLedGpioPin0, 0xFC 108 | DMACU.MOV2 gLedGpioPin0, gRamBase1, gLedGpioPin0 109 | DMACU.MOV2 gLedGpioPin2, gRamBase3, gRamBase2 110 | DMACU.MOV.IMM16 gLedGpioMask0, 0x0001 111 | DMACU.MOV.IMM16 gLedGpioMask2, 0x0000 112 | DMACU.JMP 0f 113 | 114 | .Lsetup_qemu: 115 | // RealView System Control Block (and its LEDs register) 116 | DMACU.MOV.IMM16 gLedGpioPin0, 0x0008 // PIN register @ 0x10000008 117 | DMACU.MOV.IMM16 gLedGpioPin2, 0x1000 // -"- 118 | DMACU.MOV.IMM16 gLedGpioMask0, 0x0001 // PIN mask is 0x00000001 119 | DMACU.MOV.IMM16 gLedGpioMask2, 0x0000 // -"- 120 | DMACU.JMP 0f 121 | 122 | .Lsetup_lpcxpresso1769: 123 | DMACU.MOV.IMM16 gLedGpioPin0, 0xC014 // PIN register (LPC_GPIO0->FIOPIN) @ 0x2009C014 124 | DMACU.MOV.IMM16 gLedGpioPin2, 0x2009 // -"- 125 | DMACU.MOV.IMM16 gLedGpioMask0, 0x0000 // PIN mask is 0x0000040 126 | DMACU.MOV.IMM16 gLedGpioMask2, 0x0040 // -"- 127 | DMACU.JMP 0f 128 | 129 | //------------------------------------------------------------------------------------- 130 | // Part 1: Loop around a bit 131 | // 132 | 0: DMACU.MOV.IMM8 r0, 0x08 133 | DMACU.MOV.IMM8 r1, 0x00 134 | 135 | 1: DMACU.BEQ 2f, r0, 0x00 136 | DMACU.ADD.IMM8 r0, r0, 0xFF 137 | DMACU.ADD.IMM8 r1, r1, 0x01 138 | DMACU.JMP 1b 139 | 140 | 2: DMACU.BNE 3f, r1, 0x04 141 | DMACU.JMP 4f 142 | 143 | 3: DMACU.ADD.IMM8 r0, r0, 0x01 144 | DMACU.ADD.IMM8 r1, r1, 0xFF 145 | DMACU.NOT r2, r0 146 | DMACU.EOR r3, r2, r1 147 | DMACU.JMP 2b 148 | 149 | //------------------------------------------------------------------------------------- 150 | // Part 2: Check for the 0xDE 0xAD 0xC60 0xDE pattern in r224-r227 151 | // 152 | 4: DMACU.BNE 5f, rMagic0, kExpectedMagic0 153 | DMACU.BNE 5f, rMagic1, kExpectedMagic1 154 | DMACU.BNE 5f, rMagic2, kExpectedMagic2 155 | DMACU.BEQ 6f, rMagic3, kExpectedMagic3 156 | 5: DMACU.UND 0xE001 157 | 158 | // ------------------------------------------------------------------------------------ 159 | // Part 3: 'Decrypt' the test message in host RAM 160 | // 161 | 162 | // - Copy the lower 16-bit of the RAM base pointer r255:r254:r253:r252 to r17:r16 163 | // We assume that our data-RAM lies within a single 64k segment and that we can 164 | // use r255:r254:r17:r16 as source/destination pointer. 165 | // 166 | 6: DMACU.MOV2 r16, gRamBase0, gRamBase1 167 | 168 | // - Load the XOR "key" (0xC3) in r2, load our loop increment (1) in r1 169 | DMACU.MOV.IMM8 r1, 0x01 170 | DMACU.MOV.IMM8 r2, 0xC3 171 | 172 | // - Load the current byte into r3 173 | 7: DMACU.LDB r3, gRamBase2, r16 174 | 175 | // - Deobfuscate (step 1) be XOR'ing with 0x5A, followed by a rotate left by 1 176 | DMACU.EOR r3, r3, r2 177 | DMACU.ROL1 r3, r3 178 | 179 | // - Send a byte to the PL011 UART (currently only supported on QEMU) 180 | #if (DMACU_DEMO_UART != 0) 181 | DMACU.MOV r34, r3 // --> Parameter for our subroutine 182 | DMACU.JAL r32, uart_putchar 183 | #endif 184 | 185 | // - Blink-out the byte via our LED (on all platforms) 186 | #if (DMACU_DEMO_LED != 0) 187 | DMACU.MOV r34, r3 // --> Parameter for our subroutine 188 | DMACU.JAL r32, blink_led // --> Call the blink subroutine 189 | #endif 190 | 191 | // - Store the deobfuscated byte 192 | DMACU.STB r3, gRamBase2, r16 193 | 194 | // - Stop if we have a NUL byte 195 | DMACU.BEQ 8f, r3, 0 196 | 197 | // Increment our 16-bit offset in r17:r16 and resume 198 | DMACU.ACY r4, r16, r1 199 | DMACU.ADD r16, r16, r1 200 | DMACU.ADD r17, r17, r4 201 | DMACU.JMP 7b 202 | 203 | //------------------------------------------------------------------------------------ 204 | // End of line :) 205 | // 206 | 207 | // And we are done 208 | 8: DMACU.UND 0x656E64 209 | 210 | //------------------------------------------------------------------------------------ 211 | // Subroutine to "blink"-out the value in r34 212 | // 213 | // Input: 214 | // r34 - The value to be "blinked out" 215 | // r33:r32 - Link register 216 | // 217 | // Temporary: 218 | // r35 - Output bit position (clobbered) 219 | // r36 - Tempory register (clobbered) 220 | // 221 | // r231:r230:r229:r228 - GPIO output pin register (clobbered) 222 | // r235:r234:r233:r232 - GPIO output pin mask (clobbered) 223 | // 224 | // r40:r39:r38:r37 - Used to construct the led mask 225 | // r44:r43:r42:r41 - Used to construct the led mask 226 | // 227 | 228 | blink_led: 229 | // - Start clocking at the LSB 230 | DMACU.MOV.IMM8 r35, 0x01 231 | 232 | // - Prepare the inverse LED mask in r40:r39:r38:r37 233 | DMACU.NOT r37, gLedGpioMask0 234 | DMACU.NOT r38, gLedGpioMask1 235 | DMACU.NOT r39, gLedGpioMask2 236 | DMACU.NOT r40, gLedGpioMask3 237 | 238 | // - Extract the current bit into r36 239 | 9: DMACU.AND r36, r34, r35 240 | 241 | // - Load the led status into r44:r43:r42:r41 242 | DMACU.LDW r41, gLedGpioPin2, gLedGpioPin0 243 | 244 | // - Set the led (if the current bit is 1) 245 | DMACU.BEQ 10f, r36, 0x00 246 | DMACU.OR r41, r41, gLedGpioMask0 247 | DMACU.OR r42, r42, gLedGpioMask1 248 | DMACU.OR r43, r43, gLedGpioMask2 249 | DMACU.OR r44, r44, gLedGpioMask3 250 | DMACU.JMP 11f 251 | 252 | // - Clear the led (if the current bit is 0) 253 | 10: DMACU.AND r41, r41, r37 254 | DMACU.AND r42, r42, r38 255 | DMACU.AND r43, r43, r39 256 | DMACU.AND r44, r44, r40 257 | DMACU.JMP 11f 258 | 259 | // - Write the new led status 260 | 11: DMACU.STW r41, gLedGpioPin2, gLedGpioPin0 261 | 262 | 263 | #if (DMACU_DEMO_INTERBIT_DELAY > 0) 264 | // Inter-bit delay (for illustration) 265 | DMACU.MOV.IMM8 r36, DMACU_DEMO_INTERBIT_DELAY 266 | 267 | 12: DMACU.BEQ 13f, r36, 0x00 268 | DMACU.ADD.IMM8 r36, r36, 0xFF 269 | DMACU.JMP 12b 270 | #endif 271 | 272 | // - Advance r35 to the next bit and loop 273 | 13: DMACU.BEQ 14f, r35, 0x80 274 | DMACU.ROL1 r35, r35 275 | DMACU.JMP 9b 276 | 277 | // - Byte done, return to main 278 | 14: DMACU.RET r32 279 | 280 | //------------------------------------------------------------------------------------ 281 | // Subroutine to print a single character (in r34) to QEMU's PL011 UART 282 | // 283 | // Input: 284 | // r34 - The byte to be sent (preserved) 285 | // r33:r32 - Link register 286 | // 287 | // Temporary: 288 | // r36:r35 - Peripheral base for the UART (0x101F____) 289 | // r38:r37 - Offset of the PL011 data register (0x____1000) 290 | // r40:r39 - Offset of the PL011 flag register (0x____1018) 291 | // r44:r43:r42:r41 - Scratchpad for PL011 register reads/writes 292 | // r45 - Mask for the UART ready flag 293 | // 294 | .equ kPeriphBase, r35 295 | .equ kUartDataReg, r37 296 | .equ kUartFlagReg, r39 297 | .equ rUartTemp, r41 298 | .equ kUartTxReadyFlag, r45 299 | 300 | #if (DMACU_DEMO_UART != 0) 301 | uart_putchar: 302 | // Platform check: Use the PL011 UART on QEMU 303 | DMACU.BEQ uart_putchar_qemu, rPlatformId, kQemuPlatform 304 | 305 | // All other platforms: Ignore 306 | DMACU.RET r32 307 | 308 | // Setup 309 | uart_putchar_qemu: 310 | DMACU.MOV.IMM16 kPeriphBase, 0x101F 311 | DMACU.MOV.IMM16 kUartDataReg, 0x1000 312 | DMACU.MOV.IMM16 kUartFlagReg, 0x1018 313 | DMACU.MOV.IMM8 kUartTxReadyFlag, 0x80 314 | 315 | // Wait until the UART is ready to transmit 316 | uart_putchar_qemu_wait_for_tx_ready: 317 | DMACU.LDW rUartTemp, kPeriphBase, kUartFlagReg 318 | DMACU.AND rUartTemp, rUartTemp, kUartTxReadyFlag 319 | DMACU.BEQ uart_putchar_qemu_wait_for_tx_ready, rUartTemp, 0x00 320 | 321 | // Send one byte and return 322 | DMACU.STB r34, kPeriphBase, kUartDataReg 323 | DMACU.RET r32 324 | #endif 325 | 326 | DMACU.PROGRAM.END demo 327 | -------------------------------------------------------------------------------- /src/c/vcpu/mc/dmacu.inc: -------------------------------------------------------------------------------- 1 | /** 2 | * Assembler macro bindings for DMACU microcode 3 | * 4 | * Copyright (c) 2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the project for the license text. 8 | */ 9 | 10 | /* Enable .altmacro mode (needed for e.g. dmacu_declare_regs) */ 11 | .altmacro 12 | 13 | /*------------------------------------------------------------------------------------------------- 14 | * Encoding helpers for generic DMACU instructions (and programs) 15 | *-----------------------------------------------------------------------------------------------*/ 16 | 17 | /* Starts the definition of a DMACU program */ 18 | .macro DMACU.PROGRAM.BEGIN progname 19 | .pushsection ".microcode.program", "a", "progbits" 20 | .p2align 16 21 | .global __dmacu_program_\progname 22 | __dmacu_program_\progname: 23 | .LDMACU_Code: 24 | .endm 25 | 26 | /* Ends the definition of a DMACU program */ 27 | .macro DMACU.PROGRAM.END progname 28 | .type __dmacu_program_\progname, "object" 29 | .size __dmacu_program_\progname, . - __dmacu_program_\progname 30 | .popsection 31 | .endm 32 | 33 | /* Starts the definition of a DMACU data memory */ 34 | .macro DMACU.DATA.BEGIN progname 35 | .pushsection ".microcode.data", "aw", "progbits" 36 | .p2align 16 37 | .global __dmacu_data_\progname 38 | __dmacu_data_\progname: 39 | .LDMACU_Data: 40 | .endm 41 | 42 | /* Ends the definition of a DMACU data memory */ 43 | .macro DMACU.DATA.END progname 44 | .type __dmacu_data_\progname, "object" 45 | .size __dmacu_data_\progname, . - __dmacu_data_\progname 46 | .popsection 47 | .endm 48 | 49 | /* Emits a generic DMACU instruction */ 50 | .macro DMACU.INST op, rz, rb, ra 51 | .byte (\ra), (\rb), (\rz), (\op) 52 | .endm 53 | 54 | /* Emits a DMACU instruction with 16 bit immediate */ 55 | .macro DMACU.OP1.IMM16 op, rz, imm16 56 | DMACU.INST (\op), (\rz), ((\imm16) >> 8) & 0xFF, (\imm16) & 0xFF 57 | .endm 58 | 59 | /* Emit an absolute (program base relative) branch instrcution */ 60 | .macro DMACU.INST.JMP.ABS op, rz, tgt 61 | DMACU.OP1.IMM16 (\op), (\rz), ((\tgt) - .LDMACU_Code) 62 | .endm 63 | 64 | /* Emit a relative branch instrcution */ 65 | .macro DMACU.INST.BRANCH.REL op, rz, rb, tgt 66 | .LDMACU_JmpRel_Anchor\@: 67 | DMACU.INST (\op), (\rz), (\rb), ((\tgt) - .LDMACU_JmpRel_Anchor\@) 68 | .endm 69 | 70 | /*------------------------------------------------------------------------------------------------- 71 | * Define standard register aliases 72 | *-----------------------------------------------------------------------------------------------*/ 73 | 74 | .macro dmacu_declare_one_reg val 75 | .set r\val, \val 76 | .endm 77 | 78 | .macro dmacu_declare_regs 79 | i=0 80 | .rept 256 81 | dmacu_declare_one_reg %(i) 82 | i=i+1 83 | .endr 84 | .endm 85 | 86 | dmacu_declare_regs 87 | 88 | 89 | /*------------------------------------------------------------------------------------------------- 90 | * Natively implemented DMACU instructions 91 | *-----------------------------------------------------------------------------------------------*/ 92 | /* 93 | * NOP - No Operation 94 | * 95 | * 31 24 16 8 0 96 | * +------+------+------+------+ 97 | * | 0x00 | (0) | (0) | (0) | 98 | * +------+------+------+------+ 99 | */ 100 | .macro DMACU.NOP 101 | DMACU.INST 0x00, 0, 0, 0 102 | .endm 103 | 104 | /* 105 | * MOV rZ, #imm8 - Move to register from 8-bit immediate 106 | * 107 | * 31 24 16 8 0 108 | * +------+------+------+------+ 109 | * | 0x01 | rZ | (0) | imm8 | 110 | * +------+------+------+------+ 111 | */ 112 | .macro DMACU.MOV.IMM8 rZ, imm8 113 | DMACU.INST 0x01, (\rZ), 0, (\imm8) 114 | .endm 115 | 116 | /* 117 | * MOV rZ+1:rZ, #imm16 - Move to register pair from 16-bit immediate 118 | * 119 | * 31 24 16 0 120 | * +------+------+-------------+ 121 | * | 0x02 | rZ | imm16 | 122 | * +------+------+-------------+ 123 | */ 124 | .macro DMACU.MOV.IMM16 rZ, imm16 125 | DMACU.OP1.IMM16 0x02, (\rZ), (\imm16) 126 | .endm 127 | 128 | /* 129 | * MOV2 rZ+1:rZ, rB:rA - Move from register pair to register pair 130 | * MOV rZ, rA - (Pseudo-Instruction) Move from register to register (if rB=rZ+1) 131 | * 132 | * 31 24 16 8 0 133 | * +------+------+------+------+ 134 | * | 0x03 | rZ | rB | rA | 135 | * +------+------+------+------+ 136 | */ 137 | .macro DMACU.MOV2 rZ, rB, rA 138 | DMACU.INST 0x03, (\rZ), (\rB), (\rA) 139 | .endm 140 | 141 | .macro DMACU.MOV rZ, rA 142 | DMACU.MOV2 (\rZ), ((\rZ)+1), (\rA) 143 | .endm 144 | 145 | /* 146 | * ADD rZ, rB, #imm8 - Add register and 8-bit immediate 147 | * 148 | * 31 24 16 8 0 149 | * +------+------+------+------+ 150 | * | 0x04 | rZ | rB | imm8 | 151 | * +------+------+------+------+ 152 | */ 153 | .macro DMACU.ADD.IMM8 rZ, rB, imm8 154 | DMACU.INST 0x04, (\rZ), (\rB), (\imm8) 155 | .endm 156 | 157 | /* 158 | * ACY rZ, rB, #imm8 - Generate carry from add with 8-bit immediate 159 | * 160 | * 31 24 16 8 0 161 | * +------+------+------+------+ 162 | * | 0x05 | rZ | rB | imm8 | 163 | * +------+------+------+------+ 164 | */ 165 | .macro DMACU.ACY.IMM8 rZ, rB, imm8 166 | DMACU.INST 0x05, (\rZ), (\rB), (\imm8) 167 | .endm 168 | 169 | /* 170 | * ADD rZ, rB, rA - Add two registers 171 | * 172 | * 31 24 16 8 0 173 | * +------+------+------+------+ 174 | * | 0x06 | rZ | rB | rA | 175 | * +------+------+------+------+ 176 | */ 177 | .macro DMACU.ADD rZ, rB, rA 178 | DMACU.INST 0x06, (\rZ), (\rB), (\rA) 179 | .endm 180 | 181 | /* 182 | * ACY rZ, rB, rA - Generate carry from add with 8-bit registers 183 | * 184 | * 31 24 16 8 0 185 | * +------+------+------+------+ 186 | * | 0x07 | rZ | rB | rA | 187 | * +------+------+------+------+ 188 | */ 189 | .macro DMACU.ACY rZ, rB, rA 190 | DMACU.INST 0x07, (\rZ), (\rB), (\rA) 191 | .endm 192 | 193 | /* 194 | * JMP #imm16 - Jump absolute 195 | * 196 | * 31 24 23 0 197 | * +------+------+-------------+ 198 | * | 0x08 | (0) | imm16 | 199 | * +------+------+-------------+ 200 | */ 201 | .macro DMACU.JMP tgt 202 | DMACU.INST.JMP.ABS 0x08, 0x00, (\tgt) 203 | .endm 204 | 205 | /* 206 | * JMP rB:rA - Jump register indirect 207 | * RET rA - (Pseudo-Instruction) Return from Subroutine (if rB=rZ+1) 208 | * 209 | * +------+------+------+------+ 210 | * | 0x09 | (0) | rB | rA | 211 | * +------+------+------+------+ 212 | */ 213 | .macro DMACU.JMP.REG rB, rA 214 | DMACU.INST 0x09, 0x00, (\rB), (\rA) 215 | .endm 216 | 217 | .macro DMACU.RET rA 218 | DMACU.INST 0x09, 0x00, ((\rA) + 1), (\rA) 219 | .endm 220 | 221 | /* 222 | * BNE (+off8) rZ, rB - Branch if not equal 223 | * 224 | * +------+------+------+------+ 225 | * | 0x0A | rZ | rB | off8 | 226 | * +------+------+------+------+ 227 | */ 228 | .macro DMACU.BNE.REG tgt, rZ, rB 229 | DMACU.INST.BRANCH.REL 0x0A, (\rZ), (\rB), (\tgt) 230 | .endm 231 | 232 | /* 233 | * BEQ (+off8) rZ, rB - Branch if equal 234 | * 235 | * +------+------+------+------+ 236 | * | 0x0B | rZ | rB | off8 | 237 | * +------+------+------+------+ 238 | */ 239 | .macro DMACU.BEQ.REG tgt, rZ, rB 240 | DMACU.INST.BRANCH.REL 0x0B, (\rZ), (\rB), (\tgt) 241 | .endm 242 | 243 | /* 244 | * BNE (+off8) rZ, #imm8 - Branch if not equal 245 | * 246 | * +------+------+------+------+ 247 | * | 0x0C | rZ | imm8 | off8 | 248 | * +------+------+------+------+ 249 | */ 250 | .macro DMACU.BNE tgt, rZ, imm8 251 | DMACU.INST.BRANCH.REL 0x0C, (\rZ), (\imm8), (\tgt) 252 | .endm 253 | 254 | /* 255 | * BEQ (+off8) rZ, #imm8 - Branch if equal 256 | * 257 | * +------+------+------+------+ 258 | * | 0x0D | rZ | imm8 | off8 | 259 | * +------+------+------+------+ 260 | */ 261 | .macro DMACU.BEQ tgt, rZ, imm8 262 | DMACU.INST.BRANCH.REL 0x0D, (\rZ), (\imm8), (\tgt) 263 | .endm 264 | 265 | /* 266 | * NOT rZ, rB - Bitwise NOT 267 | * 268 | * 31 24 16 8 0 269 | * +------+------+------+------+ 270 | * | 0x0E | rZ | rB | (0) | 271 | * +------+------+------+------+ 272 | */ 273 | .macro DMACU.NOT rZ, rB 274 | DMACU.INST 0x0E, (\rZ), (\rB), 0 275 | .endm 276 | 277 | /* 278 | * AND rZ, rB, rA - Bitwise AND 279 | * 280 | * 31 24 16 8 0 281 | * +------+------+------+------+ 282 | * | 0x0F | rZ | rB | rA | 283 | * +------+------+------+------+ 284 | */ 285 | .macro DMACU.AND rZ, rB, rA 286 | DMACU.INST 0x0F, (\rZ), (\rB), (\rA) 287 | .endm 288 | 289 | /* 290 | * OR rZ, rB, rA - Bitwise OR 291 | * 292 | * 31 24 16 8 0 293 | * +------+------+------+------+ 294 | * | 0x10 | rZ | rB | rA | 295 | * +------+------+------+------+ 296 | */ 297 | .macro DMACU.OR rZ, rB, rA 298 | DMACU.INST 0x10, (\rZ), (\rB), (\rA) 299 | .endm 300 | 301 | /* 302 | * EOR rZ, rB, rA - Bitwise XOR 303 | * 304 | * 31 24 16 8 0 305 | * +------+------+------+------+ 306 | * | 0x11 | rZ | rB | rA | 307 | * +------+------+------+------+ 308 | */ 309 | .macro DMACU.EOR rZ, rB, rA 310 | DMACU.INST 0x11, (\rZ), (\rB), (\rA) 311 | .endm 312 | 313 | /* 314 | * ROR rZ, rB, #1 - Rotate-Right by 1 315 | * 316 | * 31 24 16 8 0 317 | * +------+------+------+------+ 318 | * | 0x12 | rZ | rB | (0) | 319 | * +------+------+------+------+ 320 | */ 321 | .macro DMACU.ROR1 rZ, rB 322 | DMACU.INST 0x12, (\rZ), (\rB), 0 323 | .endm 324 | 325 | /* 326 | * ROL rZ, rB, #1 - Rotate-Left by 1 327 | * 328 | * 31 24 16 8 0 329 | * +------+------+------+------+ 330 | * | 0x13 | rZ | rB | (0) | 331 | * +------+------+------+------+ 332 | */ 333 | .macro DMACU.ROL1 rZ, rB 334 | DMACU.INST 0x13, (\rZ), (\rB), 0 335 | .endm 336 | 337 | /* 338 | * LO4 rZ, rB - Extract lower 4 bits 339 | * 340 | * 31 24 16 8 0 341 | * +------+------+------+------+ 342 | * | 0x14 | rZ | rB | (0) | 343 | * +------+------+------+------+ 344 | */ 345 | .macro DMACU.LO4 rZ, rB 346 | DMACU.INST 0x14, (\rZ), (\rB), 0 347 | .endm 348 | 349 | /* 350 | * HI4 rZ, rB - Extract upper 4 bits 351 | * 352 | * 31 24 16 8 0 353 | * +------+------+------+------+ 354 | * | 0x15 | rZ | rB | (0) | 355 | * +------+------+------+------+ 356 | */ 357 | .macro DMACU.HI4 rZ, rB 358 | DMACU.INST 0x15, (\rZ), (\rB), 0 359 | .endm 360 | 361 | /* 362 | * SHL4 rZ, rB - Shift left by 4 bits 363 | * 364 | * 31 24 16 8 0 365 | * +------+------+------+------+ 366 | * | 0x16 | rZ | rB | (0) | 367 | * +------+------+------+------+ 368 | */ 369 | .macro DMACU.SHL4 rZ, rB 370 | DMACU.INST 0x16, (\rZ), (\rB), 0 371 | .endm 372 | 373 | /* 374 | * JAL rZ+1:rZ, #imm16 - Jump and Link 375 | * 376 | * 31 24 16 8 0 377 | * +------+------+-------------+ 378 | * | 0x17 | rZ | imm16 | 379 | * +------+------+-------------+ 380 | */ 381 | .macro DMACU.JAL rZ, tgt 382 | DMACU.INST.JMP.ABS 0x17, (\rZ), (\tgt) 383 | .endm 384 | 385 | /* 386 | * LIT32 rZ+3:rZ+2:rZ+1:rZ, (off16) - Load a 32-bit literal 387 | * 388 | * 31 24 16 8 0 389 | * +------+------+-------------+ 390 | * | 0x18 | rZ | (off16) | 391 | * +------+------+-------------+ 392 | */ 393 | .macro DMACU.LIT32 rZ, tgt 394 | DMACU.OP1.IMM16 0x18, (\rZ), ((\tgt) - .LDMACU_Code) 395 | .endm 396 | 397 | /* 398 | * LDB rZ, [rB+1:rB:rA+1:rA] - Load byte indirect 399 | * 400 | * 31 24 16 8 0 401 | * +------+------+------+------+ 402 | * | 0x19 | rZ | rB | rA | 403 | * +------+------+------+------+ 404 | */ 405 | .macro DMACU.LDB rZ, rB, rA 406 | DMACU.INST 0x19, (\rZ), (\rB), (\rA) 407 | .endm 408 | 409 | /* 410 | * LDH rZ+1:rZ, [rB+1:rB:rA+1:rA] - Load half-word indirect 411 | * 412 | * 31 24 16 8 0 413 | * +------+------+------+------+ 414 | * | 0x1B | rZ | rB | rA | 415 | * +------+------+------+------+ 416 | */ 417 | .macro DMACU.LDH rZ, rB, rA 418 | DMACU.INST 0x1B, (\rZ), (\rB), (\rA) 419 | .endm 420 | 421 | /* 422 | * LDW rZ+3:rZ+2:rZ+1:rZ, [rB+1:rB:rA+1:rA] - Load word indirect 423 | * 424 | * 31 24 16 8 0 425 | * +------+------+------+------+ 426 | * | 0x1D | rZ | rB | rA | 427 | * +------+------+------+------+ 428 | */ 429 | .macro DMACU.LDW rZ, rB, rA 430 | DMACU.INST 0x1D, (\rZ), (\rB), (\rA) 431 | .endm 432 | 433 | /* 434 | * STB rZ, [rB+1:rB:rA+1:rA] - Store byte indirect 435 | * 436 | * 31 24 16 8 0 437 | * +------+------+------+------+ 438 | * | 0x1A | rZ | rB | rA | 439 | * +------+------+------+------+ 440 | */ 441 | .macro DMACU.STB rZ, rB, rA 442 | DMACU.INST 0x1A, (\rZ), (\rB), (\rA) 443 | .endm 444 | 445 | /* 446 | * STH rZ+1:rZ, [rB+1:rB:rA+1:rA] - Store half-word indirect 447 | * 448 | * 31 24 16 8 0 449 | * +------+------+------+------+ 450 | * | 0x1C | rZ | rB | rA | 451 | * +------+------+------+------+ 452 | */ 453 | .macro DMACU.STH rZ, rB, rA 454 | DMACU.INST 0x1C, (\rZ), (\rB), (\rA) 455 | .endm 456 | 457 | /* 458 | * STW rZ+3:rZ+2:rZ+1:rZ, [rB+1:rB:rA+1:rA] - Store word indirect 459 | * 460 | * 31 24 16 8 0 461 | * +------+------+------+------+ 462 | * | 0x1E | rZ | rB | rA | 463 | * +------+------+------+------+ 464 | */ 465 | .macro DMACU.STW rZ, rB, rA 466 | DMACU.INST 0x1E, (\rZ), (\rB), (\rA) 467 | .endm 468 | 469 | /* 470 | * UND #imm24 - Undefined Instruction 471 | * 472 | * 31 24 16 8 0 473 | * +---------+------+------+------+ 474 | * | 0x1F(*) | (0) | (0) | (0) | 475 | * +---------+------+------+------+ 476 | * 477 | * (*) Canonical encoding of the undefined instruction 478 | * 479 | * The UND instruction (or any other undefined instruction encoding) writes the special 480 | * value 0xDEADC0DE to the Cpu_NextPC descriptor and terminates further DMA processing 481 | * (by linking to the NULL descriptor). The instruction itself (and its 24-bit immediate 482 | * operand) are retained in the Cpu_CurrentOPC register and can be used for debugging 483 | * purposes (from the host system). 484 | */ 485 | .macro DMACU.UND imm24=0 486 | DMACU.INST 0x1F, (((\imm24)>>16)&0xFF), (((\imm24)>>8)&0xFF), (((\imm24)>>0)&0xFF) 487 | .endm 488 | 489 | /* 0x20 - DMACPY rZ+3:rZ+2:rZ+1:rZ, rB+3:rB+2:rB+1:rB, rA+3:rA+2:rA+1:rA - PL080 DMA Copy 490 | * 491 | * 31 24 16 8 0 492 | * +---------+------+------+------+ 493 | * | 0x20 | rZ | rB | rA | 494 | * +---------+------+------+------+ 495 | * 496 | * The DMACPY instruction enables the guest program to dynamically configure PL080 DMA transfers that are 497 | * executed on the underlying DMA controller. The linked list item (LLI) of the transfer is fixed (and provided 498 | * by the DMACU core itself). 499 | * 500 | * rZ+3:rZ+2:rZ+1:rZ - Mapped to the Channel Destination Address (DMACCxDstAddr) 501 | * rB+3:rB+2:rB+1:rB - Mapped to the Channel Source Address (DMACCxSrcAddr) 502 | * rA+3:rA+2:rA+1:rA - Mapped to the Channel Control Register (DMACCxControl) 503 | */ 504 | .macro DMACU.DMACPY rZ, rB, rA 505 | DMACU.INST 0x20, (\rZ), (\rB), (\rA) 506 | .endm 507 | -------------------------------------------------------------------------------- /src/c/vcpu/mc/pl080.code.inc: -------------------------------------------------------------------------------- 1 | 0x00, 0x00, 0x72, 0x01, 0x01, 0x00, 0x73, 0x01, 0x02, 0x00, 0x74, 0x01, 2 | 0x04, 0x00, 0x75, 0x01, 0x08, 0x00, 0x76, 0x01, 0x0e, 0x00, 0x77, 0x01, 3 | 0xf0, 0x00, 0x78, 0x01, 0xff, 0x00, 0x79, 0x01, 0xf3, 0xf4, 0x08, 0x03, 4 | 0xf5, 0xf6, 0x0a, 0x03, 0x01, 0x00, 0x10, 0x01, 0x80, 0x00, 0x7a, 0x17, 5 | 0x34, 0x00, 0x00, 0x08, 0x00, 0x00, 0x66, 0x01, 0x4c, 0x00, 0x7a, 0x17, 6 | 0x20, 0x66, 0x66, 0x10, 0x08, 0x00, 0x66, 0x0d, 0x34, 0x00, 0x00, 0x08, 7 | 0x00, 0x00, 0x00, 0x1f, 0x73, 0x10, 0x40, 0x0f, 0x08, 0x01, 0x40, 0x0d, 8 | 0xc4, 0x00, 0x00, 0x08, 0x0c, 0x00, 0x04, 0x20, 0x80, 0x00, 0x00, 0x08, 9 | 0x24, 0x20, 0x40, 0x07, 0x24, 0x20, 0x20, 0x06, 0x40, 0x21, 0x41, 0x07, 10 | 0x40, 0x21, 0x21, 0x06, 0x41, 0x22, 0x42, 0x07, 0x41, 0x22, 0x22, 0x06, 11 | 0x42, 0x23, 0x23, 0x06, 0x7c, 0x7d, 0x00, 0x09, 0x14, 0x00, 0x08, 0x0c, 12 | 0x10, 0x00, 0x09, 0x0c, 0x0c, 0x00, 0x0a, 0x0c, 0x08, 0x00, 0x0b, 0x0c, 13 | 0xc4, 0x00, 0x00, 0x08, 0x08, 0x09, 0x20, 0x03, 0x0a, 0x0b, 0x22, 0x03, 14 | 0x04, 0x00, 0x24, 0x01, 0x20, 0x22, 0x00, 0x1d, 0x60, 0x00, 0x7c, 0x17, 15 | 0x20, 0x22, 0x04, 0x1d, 0x60, 0x00, 0x7c, 0x17, 0x20, 0x22, 0x08, 0x1d, 16 | 0x60, 0x00, 0x7c, 0x17, 0x20, 0x22, 0x0c, 0x1d, 0xff, 0x00, 0x20, 0x01, 17 | 0x7a, 0x7b, 0x00, 0x09, 0x00, 0x00, 0x0c, 0x01, 0x78, 0x0d, 0x0d, 0x0f, 18 | 0x77, 0x10, 0x10, 0x0f, 0x00, 0x00, 0x20, 0x01, 0x7a, 0x7b, 0x00, 0x09 19 | -------------------------------------------------------------------------------- /src/c/vcpu/mc/pl080.data.inc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jowinter/dmacu/31f662dcd39f8a9d1ab34ed3380ecc086c37f205/src/c/vcpu/mc/pl080.data.inc -------------------------------------------------------------------------------- /src/c/vcpu/mc/pl080.mc: -------------------------------------------------------------------------------- 1 | /** 2 | * Microcoded PL080 channel emulator 3 | * 4 | * Copyright (c) 2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the project for the license text. 8 | */ 9 | 10 | .include "dmacu.inc" 11 | 12 | //------------------------------------------------------------------------------------- 13 | // We simulate a largely simplified 14 | // 15 | DMACU.PROGRAM.BEGIN pl080 16 | //------------------------------------------------------------------------------------- 17 | // Virtual DMA Channel #0 18 | // 19 | 20 | // Channel #x - Source Address Register 21 | .equ DMACCxSrcAddr_0, r0 22 | .equ DMACCxSrcAddr_1, r1 23 | .equ DMACCxSrcAddr_2, r2 24 | .equ DMACCxSrcAddr_3, r3 25 | 26 | // Channel #x - Destination Address Register 27 | .equ DMACCxDstAddr_0, r4 28 | .equ DMACCxDstAddr_1, r5 29 | .equ DMACCxDstAddr_2, r6 30 | .equ DMACCxDstAddr_3, r7 31 | 32 | // Channel #x - Linked List Item register 33 | .equ DMACCxLLI_0, r8 34 | .equ DMACCxLLI_1, r9 35 | .equ DMACCxLLI_2, r10 36 | .equ DMACCxLLI_3, r11 37 | 38 | // Channel #x - Channel Control Register 39 | .equ DMACCxControl_0, r12 40 | .equ DMACCxControl_1, r13 41 | .equ DMACCxControl_2, r14 42 | .equ DMACCxControl_3, r15 43 | 44 | // Channel #x - Channel Config Register 45 | .equ DMACCxConfig_0, r16 46 | .equ DMACCxConfig_1, r17 47 | .equ DMACCxConfig_2, r18 48 | .equ DMACCxConfig_3, r19 49 | 50 | // Parameter registers (4x 8-bit) 51 | .equ rParam0, r32 52 | .equ rParam1, r33 53 | .equ rParam2, r34 54 | .equ rParam3, r35 55 | .equ rParam4, r36 56 | 57 | // Scratchpad registers (4x 8-bit) 58 | .equ rTmp0, r64 59 | .equ rTmp1, r65 60 | .equ rTmp2, r66 61 | .equ rTmp3, r67 62 | 63 | // Data transfer register (4x 8-bit) 64 | .equ rDat0, r68 65 | .equ rDat1, r69 66 | .equ rDat2, r70 67 | .equ rDat3, r71 68 | 69 | // Transfer size 70 | .equ rSizeLo, r100 71 | .equ rSizeHi, r101 72 | 73 | // All channels done 74 | .equ rHasMoreWork, r102 75 | 76 | // Temporary registers used to copy 77 | 78 | // Constants 79 | .equ kLit_0x00, r114 // Literal value 0x00 80 | .equ kLit_0x01, r115 // Literal value 0x01 81 | .equ kLit_0x02, r116 // Literal value 0x02 82 | .equ kLit_0x04, r117 // Literal value 0x04 83 | .equ kLit_0x08, r118 // Literal value 0x08 84 | .equ kLit_0x0E, r119 // Literal value 0x0E 85 | .equ kLit_0xF0, r120 // Literal value 0xF0 86 | .equ kLit_0xFF, r121 // Literal value 0xFF 87 | 88 | 89 | // Link register(s) for up to 3-levels of call hierarchy (static) 90 | .equ rLinkA, r122 // Link register pair A (r123:r122) 91 | .equ rLinkB, r124 // Link register pair B (r125:r124) 92 | .equ rLinkC, r126 // Link register pair C (r127:r126) 93 | 94 | 95 | // Bootstrap descriptor (configured by the host) 96 | .equ gBootstrapDescriptorPtr0, r243 97 | .equ gBootstrapDescriptorPtr1, r244 98 | .equ gBootstrapDescriptorPtr2, r245 99 | .equ gBootstrapDescriptorPtr3, r246 100 | 101 | //------------------------------------------------------------------------------------- 102 | // Virtual PL080 "power-on reset" 103 | // 104 | Virtual_PL080_Reset: 105 | DMACU.MOV.IMM8 kLit_0x00, 0x00 106 | DMACU.MOV.IMM8 kLit_0x01, 0x01 107 | DMACU.MOV.IMM8 kLit_0x02, 0x02 108 | DMACU.MOV.IMM8 kLit_0x04, 0x04 109 | DMACU.MOV.IMM8 kLit_0x08, 0x08 110 | DMACU.MOV.IMM8 kLit_0x0E, 0x0E 111 | DMACU.MOV.IMM8 kLit_0xF0, 0xF0 112 | DMACU.MOV.IMM8 kLit_0xFF, 0xFF 113 | 114 | // Setup the initial descriptor (via LLI) and channel (for testing) 115 | DMACU.MOV2 DMACCxLLI_0, gBootstrapDescriptorPtr1, gBootstrapDescriptorPtr0 116 | DMACU.MOV2 DMACCxLLI_2, gBootstrapDescriptorPtr3, gBootstrapDescriptorPtr2 117 | DMACU.MOV.IMM8 DMACCxConfig_0, 0x1 118 | 119 | DMACU.JAL rLinkA, Virtual_PL080_LinkNextDescriptor 120 | 121 | // Branch into the main loop 122 | DMACU.JMP Virtual_PL080_MainLoop 123 | 124 | //------------------------------------------------------------------------------------- 125 | // Main simulation loop of the virtual PL080 126 | // 127 | Virtual_PL080_MainLoop: 128 | // Assume no work has been done so far 129 | DMACU.MOV.IMM8 rHasMoreWork, 0x00 130 | 131 | // Process Channel #0 132 | DMACU.JAL rLinkA, Virtual_PL080_RunChannel 133 | DMACU.OR rHasMoreWork, rHasMoreWork, rParam0 134 | 135 | // Check if we made process (stop otherwise) 136 | DMACU.BEQ .LNoMoreWork, rHasMoreWork, 0x00 137 | DMACU.JMP Virtual_PL080_MainLoop 138 | 139 | .LNoMoreWork: 140 | DMACU.UND 0x000000 141 | 142 | //------------------------------------------------------------------------------------- 143 | // Executes a single transfer on the active DMA channel 144 | // 145 | // rParam0 indicates (on exit) whether the channel has more work to be done. 146 | // 147 | // Link register: rLinkA 148 | // 149 | Virtual_PL080_RunChannel: 150 | // Is the channel enabled? 151 | // 152 | // NOTE: We blatantly ignore DMACCxConfiguration.{H,A,...} 153 | // 154 | DMACU.AND rTmp0, DMACCxConfig_0, kLit_0x01 155 | DMACU.BEQ .LSetup, rTmp0, 0x01 156 | 157 | // No more work 158 | DMACU.JMP Virtual_PL080_StopChannel 159 | 160 | // Channel has some work 161 | .LSetup: 162 | // Execute the DMA transfer on our underlying controller and link 163 | // 164 | // NOTE: There is currently no need to sync back status changes (i.e. TransferSize going 165 | // to zero or similar). 166 | // 167 | DMACU.DMACPY DMACCxDstAddr_0, DMACCxSrcAddr_0, DMACCxControl_0 168 | 169 | // Link the next descriptor 170 | DMACU.JMP Virtual_PL080_LinkNextDescriptor 171 | 172 | //------------------------------------------------------------------------------------- 173 | // Helper to add an 8-bit value to a 32-bit value 174 | // 175 | // rParam3:rParam2:rParam1:rParam0 hold the 32-bit operand (and result) 176 | // rParam4 holds the 8-bit value to be added (preserved accrsoss the call) 177 | // rTmp2:rTmp1:rTmp0 are clobbered (for carry propagation) 178 | // 179 | // Link register: rLinkB 180 | // 181 | Virtual_PL080_Add8To32: 182 | DMACU.ACY rTmp0, rParam0, rParam4 // rTmp0 <= CarryFrom(A[ 7: 0] + B[ 7: 0]) 183 | DMACU.ADD rParam0, rParam0, rParam4 // Z[ 7: 0] <= A[ 7: 0] + B[ 7: 0] 184 | 185 | DMACU.ACY rTmp1, rParam1, rTmp0 // rTmp1 <= CarryFrom(A[15: 8] + rTmp0) 186 | DMACU.ADD rParam1, rParam1, rTmp0 // Z[15: 8] <= A[15: 8] + rTmp0 187 | 188 | DMACU.ACY rTmp2, rParam2, rTmp1 // rTmp2 <= CarryFrom(A[23:16] + rTmp1) 189 | DMACU.ADD rParam2, rParam2, rTmp1 // Z[23:16] <= A[23:16] + rTmp1 190 | 191 | DMACU.ADD rParam3, rParam3, rTmp2 // Z[31:24] <= A[31:24] + rTmp2 192 | DMACU.RET rLinkB 193 | 194 | 195 | //------------------------------------------------------------------------------------- 196 | // Links the next DMA descriptor 197 | // 198 | // rParam0 indicates (on exit) whether the channel has more work to be done. 199 | // 200 | // Link register: rLinkA 201 | // 202 | 203 | // Fetch the next descriptor and return 204 | Virtual_PL080_LinkNextDescriptor: 205 | // Check for presence of another descriptor 206 | DMACU.BNE .LChannelHasMoreWork, DMACCxLLI_0, 0x00 207 | DMACU.BNE .LChannelHasMoreWork, DMACCxLLI_1, 0x00 208 | DMACU.BNE .LChannelHasMoreWork, DMACCxLLI_2, 0x00 209 | DMACU.BNE .LChannelHasMoreWork, DMACCxLLI_3, 0x00 210 | DMACU.JMP Virtual_PL080_StopChannel 211 | 212 | // Channel has more descriptors pending 213 | .LChannelHasMoreWork: 214 | DMACU.MOV2 rParam0, DMACCxLLI_1, DMACCxLLI_0 215 | DMACU.MOV2 rParam2, DMACCxLLI_3, DMACCxLLI_2 216 | DMACU.MOV.IMM8 rParam4, 0x04 217 | 218 | DMACU.LDW DMACCxSrcAddr_0, rParam2, rParam0 219 | 220 | DMACU.JAL rLinkB, Virtual_PL080_Add8To32 221 | 222 | DMACU.LDW DMACCxDstAddr_0, rParam2, rParam0 223 | DMACU.JAL rLinkB, Virtual_PL080_Add8To32 224 | 225 | DMACU.LDW DMACCxLLI_0, rParam2, rParam0 226 | DMACU.JAL rLinkB, Virtual_PL080_Add8To32 227 | 228 | DMACU.LDW DMACCxControl_0, rParam2, rParam0 229 | 230 | DMACU.MOV.IMM8 rParam0, 0xFF 231 | DMACU.RET rLinkA 232 | 233 | //------------------------------------------------------------------------------------- 234 | // Terminate activities of the current channel 235 | // 236 | // rParam0 indicates (on exit) whether the channel has more work to be done. 237 | // 238 | // Link register: rLinkA 239 | // 240 | Virtual_PL080_StopChannel: 241 | // Channel is done (last transfer completed; no more descriptors to link) 242 | // we stop the channel (DMACCxConfig.E=0, DMACCxControl.TransferSize=0) 243 | DMACU.MOV.IMM8 DMACCxControl_0, 0x00 244 | DMACU.AND DMACCxControl_1, DMACCxControl_1, kLit_0xF0 245 | DMACU.AND DMACCxConfig_0, DMACCxConfig_0, kLit_0x0E 246 | 247 | DMACU.MOV.IMM8 rParam0, 0x00 248 | DMACU.RET rLinkA 249 | 250 | DMACU.PROGRAM.END pl080 251 | -------------------------------------------------------------------------------- /src/c/vcpu/rt.c: -------------------------------------------------------------------------------- 1 | /** 2 | * PoC virtual CPU implementation for the ARM PL080 DMA Controller. 3 | * 4 | * Copyright (c) 2019-2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the project for the license text. 8 | */ 9 | 10 | /** 11 | * @file rt.c 12 | * @brief Runtime-Environment (and startup code) 13 | */ 14 | #include "dmacu.h" 15 | 16 | #include 17 | 18 | //------------------------------------------------------------------------------------------------- 19 | int main(void) 20 | { 21 | // HAL-level initialization 22 | Hal_Init(); 23 | 24 | // And run our test-program 25 | Dmacu_RunTestProgram(); 26 | 27 | return EXIT_SUCCESS; 28 | } 29 | -------------------------------------------------------------------------------- /src/c/vcpu/utils.c: -------------------------------------------------------------------------------- 1 | /** 2 | * PoC virtual CPU implementation for the ARM PL080 DMA Controller. 3 | * 4 | * Copyright (c) 2019-2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the project for the license text. 8 | */ 9 | 10 | /** 11 | * @file utils.c 12 | * @brief Utilities for working with the DMACU virtual CPU 13 | */ 14 | #include "dmacu_instance.h" // Primary instance 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #if (DMACU_VIRTUAL_PL080 != 0) 21 | // Slave CPU (running the actual program) 22 | extern Dmacu_Cpu_t *SlaveCpu_GetCpu(void); 23 | #endif 24 | 25 | // Enable dumping of the ROM on Dmacu_DumpCpuState 26 | #if !defined(DMACU_DUMP_ROM) 27 | # define DMACU_DUMP_ROM (0) 28 | #endif 29 | 30 | // Virtual PL080 mode (work in progress) 31 | #if !defined(DMACU_VIRTUAL_PL080) 32 | # define DMACU_VIRTUAL_PL080 (0) 33 | #endif 34 | 35 | //----------------------------------------------------------------------------------------- 36 | /// \brief Host scratch area (for read/write tests to host memory) 37 | /// 38 | 39 | // Obfuscates a byte on the host (for our test-ram message) 40 | // 41 | // We obfuscate be rotating right by 1 bit and XOR-ing with 0x5A 42 | #define OBF_ROR1(x) ((((unsigned) (x) >> 1u) | ((unsigned) (x) << 7u)) & 0xFFu) 43 | #define OBF_BYTE(x) (OBF_ROR1(x) ^ 0xC3u) 44 | 45 | //----------------------------------------------------------------------------------------- 46 | // Reference test message (obfuscated) 47 | // 48 | static const uint8_t gkTestMessage[] = 49 | { 50 | // Source the generated microcode data for the demo 51 | # include "mc/demo.data.inc" 52 | }; 53 | 54 | //----------------------------------------------------------------------------------------- 55 | DMACU_ALIGNED(DMACU_RAM_ALIGNMENT) 56 | static volatile uint8_t gTestRam[256u]; 57 | 58 | //----------------------------------------------------------------------------------------- 59 | /// \brief Static test program 60 | /// 61 | DMACU_ALIGNED(DMACU_ROM_ALIGNMENT) 62 | static const uint8_t gTestProgram[] = 63 | { 64 | // Source the generated microcode program for the demo 65 | # include "mc/demo.code.inc" 66 | }; 67 | 68 | //----------------------------------------------------------------------------------------- 69 | void Dmacu_SetupTestProgram(Dmacu_Cpu_t *cpu) 70 | { 71 | // Clear the CPU structure 72 | memset(cpu, 0, sizeof(Dmacu_Cpu_t)); 73 | 74 | // Setup the initial program counter 75 | cpu->ProgramBase = (uint32_t) &gTestProgram[0u]; 76 | cpu->PC = cpu->ProgramBase; 77 | 78 | // Fill the register file with a test pattern 79 | // 80 | // The lower 224 registers (r0-r223) are cleared by the virtual CPU. The last 81 | // 32 register (r224-r255) are retained. We provide parameters through some of 82 | // those. 83 | // 84 | for (uint32_t i = 0u; i < 256u; ++i) 85 | { 86 | cpu->RegFile[i] = (i & 1u) ? 0xA5u : 0x5Au; 87 | } 88 | 89 | // Setup A, B and Z with dummy value (will be cleared by CPU) 90 | cpu->Operands.A = UINT16_C(0xBAD0); 91 | cpu->Operands.B = UINT16_C(0xBAD1); 92 | cpu->Operands.Z = UINT16_C(0xBAD2); 93 | 94 | // Pass a marker cookie in r224-r227 95 | cpu->RegFile[224u] = 0xDEu; 96 | cpu->RegFile[225u] = 0xADu; 97 | cpu->RegFile[226u] = 0xC0u; 98 | cpu->RegFile[227u] = 0xDEu; 99 | 100 | // Use r247 to pass a "platform-id" from the HAL layer 101 | // 102 | // This allows us to have some platform specific logic (e.g. PL011 UART output 103 | // on QEMU) in the microcode. 104 | cpu->RegFile[247u] = (uint8_t) gHalConfig.platform_id; 105 | 106 | // Pass the address of the code memory in registers r251:r248 107 | // 108 | // currently unused, but this opens up space for self-modifying code shenanigans ;) 109 | const Dma_UIntPtr_t rom_base = Dma_PtrToAddr(cpu->ProgramBase); 110 | cpu->RegFile[248u] = (uint8_t) (rom_base & 0xFFu); 111 | cpu->RegFile[249u] = (uint8_t) ((rom_base >> 8u) & 0xFFu); 112 | cpu->RegFile[250u] = (uint8_t) ((rom_base >> 16u) & 0xFFu); 113 | cpu->RegFile[251u] = (uint8_t) ((rom_base >> 24u) & 0xFFu); 114 | 115 | // Pass the address of the test RAM in registers r255:r252 116 | const Dma_UIntPtr_t ram_base = Dma_PtrToAddr(&gTestRam[0u]); 117 | cpu->RegFile[252u] = (uint8_t) (ram_base & 0xFFu); 118 | cpu->RegFile[253u] = (uint8_t) ((ram_base >> 8u) & 0xFFu); 119 | cpu->RegFile[254u] = (uint8_t) ((ram_base >> 16u) & 0xFFu); 120 | cpu->RegFile[255u] = (uint8_t) ((ram_base >> 24u) & 0xFFu); 121 | 122 | // Setup the test RAM 123 | for (uint32_t i = 0u; i < sizeof(gTestRam); ++i) 124 | { 125 | gTestRam[i] = (i < sizeof(gkTestMessage)) ? gkTestMessage[i] : 0u; 126 | } 127 | } 128 | 129 | //----------------------------------------------------------------------------------------- 130 | void Dmacu_RunTestProgram(void) 131 | { 132 | Dmacu_Cpu_t *const cpu = Dmacu_GetCpu(); 133 | 134 | // Setup the test program 135 | #if (DMACU_VIRTUAL_PL080 == 0) 136 | Dmacu_SetupTestProgram(cpu); 137 | #else 138 | Dmacu_SetupVirtualPL080(cpu); 139 | #endif 140 | 141 | // Dump the initial CPU state (after test program setup) 142 | #if !DMACU_QUIET 143 | Dmacu_DumpCpuState("vcpu[init]", cpu); 144 | 145 | #if (DMACU_VIRTUAL_PL080 != 0) 146 | Dmacu_DumpCpuState("vcpu[slave:init]", SlaveCpu_GetCpu()); 147 | #endif 148 | #endif 149 | 150 | // And run the DMA transfer for the test program 151 | Hal_DmaTransfer(Dmacu_CpuBootDescriptor()); 152 | 153 | #if !DMACU_QUIET 154 | // Dump the virtual CPU state on exit. 155 | printf("vcpu[run] dma transfers done (virtual cpu is stopped)\n"); 156 | Dmacu_DumpCpuState("vcpu[exit]", cpu); 157 | 158 | #if (DMACU_VIRTUAL_PL080 != 0) 159 | Dmacu_DumpCpuState("vcpu[slave:exit]", SlaveCpu_GetCpu()); 160 | #endif 161 | #endif 162 | 163 | // I am feeling lucky :) 164 | for (unsigned i = 0u; i < sizeof(gTestRam); ++i) 165 | { 166 | volatile const uint8_t c = gTestRam[i]; 167 | if (c == '\0') 168 | { 169 | break; 170 | } 171 | 172 | #if !DMACU_QUIET 173 | // Print the test character 174 | putchar(c); 175 | #endif 176 | 177 | // Check that the test message has been deobfuscated correctly 178 | if (i < sizeof(gkTestMessage)) 179 | { 180 | if (OBF_BYTE(c) != gkTestMessage[i]) 181 | { 182 | abort(); 183 | } 184 | } 185 | } 186 | 187 | 188 | } 189 | 190 | //----------------------------------------------------------------------------------------- 191 | void Dmacu_DumpCpuState(const char *prefix, const Dmacu_Cpu_t *cpu) 192 | { 193 | #if !DMACU_QUIET 194 | printf("%s PC: %08X NextPC: %08X Base: %08X\n" 195 | "%s OPC: %08X\n" 196 | "%s rA: %08X rB: %08X rZ: %08X\n", 197 | prefix, (unsigned) cpu->PC, (unsigned) cpu->NextPC, (unsigned) cpu->ProgramBase, 198 | prefix, (unsigned) cpu->CurrentOPC.Value, 199 | prefix, (unsigned) cpu->Operands.A, 200 | (unsigned) cpu->Operands.B, (unsigned) cpu->Operands.Z); 201 | 202 | printf("%s =========================================================\n", prefix); 203 | 204 | // Register file 205 | const unsigned num_regs = 256u; 206 | 207 | for (unsigned i = 0u; i < num_regs; i += 16u) 208 | { 209 | const unsigned line_len = (num_regs - i) > 16u ? 16u : (num_regs - i); 210 | 211 | printf("%s REGS[%02X]:", prefix, (unsigned) i); 212 | 213 | for (unsigned j = 0u; j < line_len; ++j) 214 | { 215 | printf(" %02X", (unsigned) cpu->RegFile[i + j]); 216 | } 217 | 218 | printf("\n"); 219 | } 220 | 221 | printf("%s =========================================================\n", prefix); 222 | 223 | // Test RAM 224 | for (unsigned i = 0u; i < sizeof(gTestRam); i += 16u) 225 | { 226 | const unsigned line_len = (sizeof(gTestRam) - i) > 16u ? 227 | 16u : (sizeof(gTestRam) - i); 228 | 229 | printf("%s RAM[%03X]:", prefix, (unsigned) i); 230 | 231 | // Hexdump 232 | for (unsigned j = 0u; j < line_len; ++j) 233 | { 234 | printf(" %02X", (unsigned) gTestRam[i + j]); 235 | } 236 | 237 | for (unsigned j = line_len; j < 16u; ++j) 238 | { 239 | printf(" "); 240 | } 241 | 242 | // ASCII dump 243 | printf(" "); 244 | 245 | for (unsigned j = 0u; j < line_len; ++j) 246 | { 247 | uint8_t c = gTestRam[i + j]; 248 | printf("%c", (c >= 0x20u && c <= 0x7Eu) ? c : '.'); 249 | } 250 | 251 | printf("\n"); 252 | } 253 | 254 | # if DMACU_DUMP_ROM 255 | printf("%s =========================================================\n", prefix); 256 | 257 | // Test ROM 258 | const uint32_t *const rom_data = (const uint32_t *) &gTestProgram[0u]; 259 | const size_t rom_size = sizeof(gTestProgram) / sizeof(uint32_t); 260 | 261 | for (unsigned i = 0u; i < rom_size; i += 4u) 262 | { 263 | const unsigned line_len = (rom_size - i) > 4u ? 4u : (rom_size - i); 264 | 265 | printf("%s ROM[%03X]:", prefix, (unsigned) i); 266 | 267 | // Hexdump 268 | for (unsigned j = 0u; j < line_len; ++j) 269 | { 270 | const uint32_t w = rom_data[i + j]; 271 | printf(" %02X_%06X", (unsigned) ((w >> 24u) & 0xFFu), 272 | (unsigned) (w & 0x00FFFFFFu)); 273 | } 274 | 275 | printf("\n"); 276 | } 277 | # endif 278 | #else 279 | // Quiet mode 280 | (void) prefix; 281 | (void) cpu; 282 | #endif 283 | } 284 | -------------------------------------------------------------------------------- /src/c/vcpu/vpl080.c: -------------------------------------------------------------------------------- 1 | /** 2 | * PoC virtual CPU implementation for the ARM PL080 DMA Controller. 3 | * 4 | * Copyright (c) 2019-2022 Johannes Winter 5 | * 6 | * This file is licensed under the MIT License. See LICENSE in the root directory 7 | * of the project for the license text. 8 | */ 9 | 10 | /** 11 | * @file vpl080.c 12 | * @brief Proof of the simulation hyptothesis in a small (virtual) PL080 universe ;) 13 | */ 14 | #include 15 | #include 16 | 17 | #define DMA_INSTANCE_PREFIX SlaveCpu 18 | #include "dmacu_instance.c" // Slave CPU (driven be the virtual PL080 running on the primary CPU) 19 | 20 | /// \brief Microcode of the virtual PL080 21 | DMACU_ALIGNED(DMACU_ROM_ALIGNMENT) 22 | static const uint8_t gVirtualPL080Code[] = 23 | { 24 | // Source the generated microcode program for the demo 25 | # include "mc/pl080.code.inc" 26 | }; 27 | 28 | //----------------------------------------------------------------------------------------- 29 | void Dmacu_SetupVirtualPL080(Dmacu_Cpu_t *cpu) 30 | { 31 | // Clear the CPU structure 32 | memset(cpu, 0, sizeof(Dmacu_Cpu_t)); 33 | 34 | // Setup the initial program counter (on the primary CPU) 35 | cpu->ProgramBase = (uint32_t) &gVirtualPL080Code[0u]; 36 | cpu->PC = cpu->ProgramBase; 37 | 38 | // Pass the inital DMA descriptor of the slave CPU to our primary CPU running the virtual PL080 39 | const Dma_UIntPtr_t slave_cpu_boot_descriptor = Dma_PtrToAddr(SlaveCpu_CpuBootDescriptor()); 40 | cpu->RegFile[243u] = (uint8_t) (slave_cpu_boot_descriptor & 0xFFu); 41 | cpu->RegFile[244u] = (uint8_t) ((slave_cpu_boot_descriptor >> 8u) & 0xFFu); 42 | cpu->RegFile[245u] = (uint8_t) ((slave_cpu_boot_descriptor >> 16u) & 0xFFu); 43 | cpu->RegFile[246u] = (uint8_t) ((slave_cpu_boot_descriptor >> 24u) & 0xFFu); 44 | 45 | // Finally initialize the slave CPU 46 | Dmacu_Cpu_t *const slave = SlaveCpu_GetCpu(); 47 | Dmacu_SetupTestProgram(slave); 48 | } 49 | --------------------------------------------------------------------------------