暑假前應該這篇文章會一直更新(?)
============================================
首先準備 tool chains
到這裡去找 arm-none-eabi 的工具
http://www.mentor.com/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/request?id=e023fac2-e611-476b-a702-90eabb2aeca8&returnURL=https%3A%2F%2Fsourcery%2Ementor%2Ecom%2FGNUToolchain%2Frelease830%3Flite%3Darm%26cmpid%3D7108%26downloadlite%3Dscblite2012&downloadlite=scblite2012&fmpath=/embedded-software/sourcery-tools/sourcery-codebench/editions/lite-edition/form
很該死的註冊完後應該可以抓到 arm-2012.03-56-arm-none-eabi-i686-pc-linux-gnu.tar.bz2
解壓後放在一個跟 project 相關的資料夾之後把路徑加到現在的 bash shell 上
export PATH=$PATH:/home/xatierlike/stlink/arm-2012.03/bin
然後到 github.com 上面去把 texane/stlink clone 下來
git clone https://github.com/texane/stlink.git
然後想辦法去找個可以玩耍的 demo code 下來...
昨天跟 jserv 找可以用的 code 找到快哭了QQ 幾乎沒一個能用的 OTZ
最後找到這邊去把他的 blinky.zip 弄下來
http://gostm32.blogspot.tw/2010/09/blinky-ii.html
這裡還需要用 vim 改一下 Makefile,%s/elf/none-eabi/g
原本的 blinky 是用 arm-elf-* tools 工作的,而我用的是 arm-none-eabi-* tools
會後把 make 出來的 blinky.bin 燒進去 STM32 的 flash 就可以囉
./st-flash write ../blinky/blinky.bin 0x8000000
./st-util 搭配 gdb target remote 可以拿來 debug ,不過我還沒玩熟
============================================
又研究了一下下,成功用 gdb 跟小板子玩耍了 XD
vim Makefile
CFLAGS = -I./ -c -fno-common -Os -mcpu=cortex-m3 -mthumb -g
打開 compiler 的 debug flag
make clean; make
重新燒進去
./st-flash write ../blinky/blinky.bin 0x8000000
聽一下 :4242 port
./st-util
arm-none-eabi-gdb blinky.none-eabi
可以開始想辦法看懂 code 惹QQ
============================================又研究了一下下,成功用 gdb 跟小板子玩耍了 XD
vim Makefile
CFLAGS = -I./ -c -fno-common -Os -mcpu=cortex-m3 -mthumb -g
打開 compiler 的 debug flag
make clean; make
重新燒進去
./st-flash write ../blinky/blinky.bin 0x8000000
聽一下 :4242 port
./st-util
arm-none-eabi-gdb blinky.none-eabi
(gdb) target remote :4242 Remote debugging using :4242 main () at blinky.c:37 37 RCC->APB2ENR |= 0x10 | 0x04; /* Enable the GPIOA (bit 2) and GPIOC (bit 8) */ (gdb) n 33 int main(void){ (gdb) n 37 RCC->APB2ENR |= 0x10 | 0x04; /* Enable the GPIOA (bit 2) and GPIOC (bit 8) */ (gdb) list 32 33 int main(void){ 34 int n = 0; 35 int button; 36 37 RCC->APB2ENR |= 0x10 | 0x04; /* Enable the GPIOA (bit 2) and GPIOC (bit 8) */ 38 GPIOC->CRH = 0x11; /* Set GPIOC Pin 8 and Pin 9 to outputs */ 39 GPIOA->CRL = 0x04; /* Set GPIOA Pin 0 to input floating */ 40 41 while(1) (gdb)
可以開始想辦法看懂 code 惹QQ
今天晚上跟 jserv 研究他那邊弄過來的 qemu code
不知道為什麼我這邊就是跑不起來 ><
於是先去吃宵夜了XD
吃完宵夜後回來改 code 把中間改掉... 神奇的可以動了
serversocket.bind((socket.gethostname(), port)) serversocket.bind(("localhost", port))
但是當下我不知道為什麼,明明 socket.gethostname 得到的也是我機器的 hostname ...
根據 http://docs.python.org/library/socket.html#socket.gethostname
Return a string containing the hostname of the machine where the Python interpreter is currently executing.
我在我本機工作, gethostname 要到的理論上是跟在 shell 上打 hostname 一樣的結果
後來 方括號拉拉學長 提出了令我念頭一轉的問題點
問題是你hostname如果和我一樣在/etc/hosts查不到,你就不能直接用"localhost"去bind, 要用127.0.0.1
我馬上 ...
cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 xatierlike-NB
幹~~~~~~ 單純我 /etc/hosts 不知道哪時候被我腦殘動到 OTZ
============================================
原本聽 jserv 的去找 github 上面的 Qemu git
不斷的 make 失敗...
結果後來才發現東西是太舊的..囧
真。Qemu git
http://git.qemu.org/qemu.git
arm instruction
it instruction, condition (cbz / cnbz)
============================================
basic computer organization
http://goo.gl/jW6A0
Intro to Git for the Perl Hacker
http://marklodato.github.com/visual-git-guide/index-en.html
git labs
http://gitimmersion-apputu.rhcloud.com/
http://gitimmersion-apputu.rhcloud.com/lab_42.html
arn instructions
http://simplemachines.it/doc/arm_inst.pdf
arm-none-eabi-gcc -static -fno-common -Os -mcpu=cortex-a9 -mthumb test.c
arm-none-eabi-objdump -d a.out
git rebase => http://codepad.org/hehastWp
2252 git diff 2253 cd .. 2254 ls 2255 git diff 2256 git diff > p.diff 2257 git reset --hard HEAD 2258 git log 2259 git branch 2260 git branch summer-work 2261 git checkout summer-work 2262 tig 2263 sudo apt-get install tig 2264 tig 2265 git apply p.diff 2266 git diff 2267 git commit -a 2268 export EDITOR=vim 2269 git commit -a 2270 git commit --amend 2271 vi README 2272 git add README 2273 git commit --amend 2274 tig 2275 git format-patch -1 2276 vi 0001-Attempt-to-build-STM32-related-files.patch 2277 git rebase --help 2278 git branch -r 2279 git fetch origin 2280 tig 2281 git log 2282 git log origin/master 2283 git rebase origin/master 2284 tig 2285 git checkout master 2286 git pull
Harvard vs Von Nuemann Architecture
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka11516.html
http://www.pictutorials.com/Harvard_vs_Von_Nuemann_Architecture.htm
http://embeddedbasics.wordpress.com/2009/12/18/von_neumann_architecture_vs_harvard_architecture/
http://89c51.blogspot.tw/2007/11/von-neumann-architecture-and-harvard.html
Harvard architecture impossible to self-modified code (data:RW, code:RO)
ijsung: 不過現在的harvard architecture只是說指令跟資料有各自的L1 cache,出了L1之後還是共用的。要self-modified code是可行的,只是要flush L1 caches
好比說ARM7是Princeton arch, 到了ARM9是Harvard arch, 但是仍然可以self-modify只是多了一步flush L1 I/D cache
way Harvard arch 適合 DSP =>資料大小的關係
ijsung:
因為同一個clock cycle內可以同時從instruction cache跟data cache各抓出指令跟資料
DSP的working set通常遠大於register file能裝的大小,所以能夠每個clock cycle都能從data memory抓東西進來的harvard arch樂勝。
大部分的DSP都有玄妙的指令集可以在同一個cycle內1)抓下個指令所需的資料 2)用上個週期抓進來的資料計算
若是Princeton arch的話這是不可能的。要抓data的話instruction fetch就得暫停。
http://sestevenson.wordpress.com/2009/10/01/implementation-of-fir-filtering-in-c-part-1/
qemu-devel mailling list archive
http://lists.gnu.org/archive/html/qemu-devel/
大概猜出 make 失敗的原因,cpu_register_* 這組 API 好像有被換過了
docs/memory 裏面有寫
MMIO Operations
---------------
MMIO regions are provided with ->read() and ->write() callbacks; in addition
various constraints can be supplied to control how these callbacks are called:
- .valid.min_access_size, .valid.max_access_size define the access sizes
(in bytes) which the device accepts; accesses outside this range will
have device and bus specific behaviour (ignored, or machine check)
- .valid.aligned specifies that the device only accepts naturally aligned
accesses. Unaligned accesses invoke device and bus specific behaviour.
- .impl.min_access_size, .impl.max_access_size define the access sizes
(in bytes) supported by the *implementation*; other access sizes will be
emulated using the ones available. For example a 4-byte write will be
emulated using four 1-byte writes, if .impl.max_access_size = 1.
- .impl.valid specifies that the *implementation* only supports unaligned
accesses; unaligned accesses will be emulated by two aligned accesses.
- .old_portio and .old_mmio can be used to ease porting from code using
cpu_register_io_memory() and register_ioport(). They should not be used
in new code.
git blame -L 160,170 docs/memory.txt 看一下,應該是這個 commit 有動到(? 明天研究
9d3a4736 (Avi Kivity
2011-07-26 14:26:00 +0300 170 差不多是去年這個時候 lol
7/26 早上跟 jserv 整理了一下大概有動到的東西
SysBusDevieceInfo
memory regi
cpu_register_io_memory
qdev_init_chardev
macro
目前 led / button 好像修好了,來嘗試 GPIO 的 porting
qemu/docs/tracing.txts
http://www.pcmech.com/forum/computer-hardware/153070-guide-dual-core-smp.html
L2 cache, SMP dual core
Symmetric Multi-Processing (SMP)
mmio
interrupt VS trap system call
I2C / I2S
============================================
8/7 update
gdb
run <參數> # run the program
bt # backtrace
c # continue
list
# read a elf file
readelf -a main_qemu.elf | less
# dynamic link program needs a interpreter
/lib/ld-linux.so.2 # interpreter
# 飛上天的方法 (平行化處理 make)
make -j2
# 思考
can dynamic linker run alone?
# 蹦床,很多關於 stack 的操過跟這個有關
http://en.wikipedia.org/wiki/Trampoline_(computing)
.eh_frame_hdr
# 本周要完成的進度
修好 UI
refactoring
產生 format-patch
# 相關的 git commands
git git format-patch -1
git am 0001-try-to-fix-core-dump.patch -s
git stash
git rebase
git blame
git apply
============================================
8/8 update
今日主要修改,猜出(?) momory region 需要的大小
hw/stm32.c 最上面
#define GPIO_A 0 //0x4002 0000 - 0x4002 03FF
#define GPIO_B 1 //0x4002 0400 - 0x4002 07FF
#define GPIO_C 2 //0x4002 0800 - 0x4002 0BFF
#define GPIO_D 3 //0x4002 0C00 - 0x4002 0FFF
#define GPIO_E 4 //0x4002 1000 - 0x4002 13FF
#define GPIO_H 5 //0x4002 1400 - 0x4002 17FF
就猜他應該會用 0x17FF 這麼多,於是把 hw/stm32_gpio.c 裏面上次卡關的 size 換掉
memory_region_init_io(&s->iomem, &gpio_ops, s, "gpio", 0x17FF);
另外 LED 也找出來應該是用錯 API 了
- s->chr = qemu_char_get_next_serial();
+ s->chr = qemu_chr_find(id);
換掉後就成功跟 UI 連結了,看到燈在閃的那瞬間感動的快哭出來了 QQ
順手重購了一下,法國人寫的 code 有點亂 :3
至於 assert 造成 core dump 的原因還要再找找
============================================
8/10 update
實在是太開心了
這兩天自己研究了很久還是沒想出解法,gdb 挖了半天沒有想法
去找了一些相關於 stellaris 的 mailing list,也是很多人有遇到相關的議題
http://lists.gnu.org/archive/html/qemu-devel/2012-07/msg03040.html
https://bugs.launchpad.net/qemu/+bug/1028260
最後找到這個 patch
http://patchwork.ozlabs.org/patch/172820/
apply 後好像就能動了,耶~
============================================
8/15 update
整理完 code,fetch 一下 master
順便 fetch 一下 qemu 的 master 打算來製作 format patch
上次那個找到的 fix coredump 的 patch 在昨天下午有被到 master
感謝 Anthony Liguori <aliguori@us.ibm.com> !
我嘗試 rebase 後就 Makefile 噴衝突了,感覺像是有人把架構又切開了
(這部份還要追 log)
手動 merge (不知道有沒有出問題XD)
目前先另外開一個 branch 製作 patch
底下是我用 git format-patch -2 生出來的 patch
From 808d1135a501fe0c524c7572fd82ca904d1d5900 Mon Sep 17 00:00:00 2001 From: xatier <xatierlike@gmail.com> Date: Tue, 14 Aug 2012 14:37:46 +0800 Subject: [PATCH 1/2] try to support stm32l152rbt6 board --- hw/arm/Makefile.objs | 1 + hw/stm32.c | 189 ++++++++++++++++++++++++++++ hw/stm32_gpio.c | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 521 insertions(+) create mode 100644 hw/stm32.c create mode 100644 hw/stm32_gpio.c diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 2b39fb3..15aff03 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -9,6 +9,7 @@ obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o obj-y += exynos4210_rtc.o exynos4210_i2c.o obj-y += arm_mptimer.o a15mpcore.o obj-y += armv7m.o armv7m_nvic.o stellaris.o stellaris_enet.o +obj-y += stm32.o stm32_gpio.o obj-y += highbank.o obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o diff --git a/hw/stm32.c b/hw/stm32.c new file mode 100644 index 0000000..a57d384 --- /dev/null +++ b/hw/stm32.c @@ -0,0 +1,189 @@ + +#include "sysbus.h" +#include "exec-memory.h" +#include "arm-misc.h" +#include "boards.h" +#include "devices.h" + +#define NB_NVIC_IRQ 5 +#define NB_GPIO 6 + +#define GPIO_A 0 // 0x4002 0000 - 0x4002 03FF +#define GPIO_B 1 // 0x4002 0400 - 0x4002 07FF +#define GPIO_C 2 // 0x4002 0800 - 0x4002 0BFF +#define GPIO_D 3 // 0x4002 0C00 - 0x4002 0FFF +#define GPIO_E 4 // 0x4002 1000 - 0x4002 13FF +#define GPIO_H 5 // 0x4002 1400 - 0x4002 17FF + +typedef const struct { + const char *name; + uint16_t f_size; +} stm32_board_info; + + + +static stm32_board_info stm32_board = { + "stm32l152rbt6", + 0x0080, // 128kb flash +}; + + + +typedef struct { + uint32_t int_status; + uint32_t int_mask; + MemoryRegion iomem; + qemu_irq irq; + stm32_board_info* board; +} ssys_state; + + + +static void ssys_reset(void *opaque) { + // unimplemtmented +} + + + +static uint64_t ssys_read(void *opaque, target_phys_addr_t offset, + unsigned size) +{ + // nothing to do + return 0; +} + + + +static void ssys_write(void *opaque, target_phys_addr_t offset, uint64_t value, + unsigned size) +{ + // unimplemtmented +} + + + +static const MemoryRegionOps ssys_ops = { + .read = ssys_read, + .write = ssys_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + + + +static int stm32_sys_post_load(void *opaque, int version_id) +{ + //Nothing to do + return 0; +} + + + +static const VMStateDescription vmstate_stm32_sys = { + .name = "stm32_sys", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = stm32_sys_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT32(int_mask, ssys_state), + VMSTATE_UINT32(int_status, ssys_state), + VMSTATE_END_OF_LIST() + } +}; + + + +static int stm32l_sys_init(uint32_t base, qemu_irq irq, + stm32_board_info * board) +{ + ssys_state *s; + + s = (ssys_state *)g_malloc0(sizeof(ssys_state)); + s->irq = irq; + s->board = board; + + memory_region_init_io(&s->iomem, &ssys_ops, s, "ssys", 0x00010000); + memory_region_add_subregion(get_system_memory(), base, &s->iomem); + + ssys_reset(s); + vmstate_register(NULL, -1, &vmstate_stm32_sys, s); + + return 0; +} + + + +static void stm32l152rbt6_init(ram_addr_t ram_size, const char *boot_device, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + + // prepare the memory + MemoryRegion *address_space_mem = get_system_memory(); + uint16_t flash_size = stm32_board.f_size; // 128KBits + uint16_t sram_size = 0x0010; // 16 KBits + + + // initial the processor (+ memory) + qemu_irq* pic = armv7m_init(address_space_mem, flash_size, sram_size, + kernel_filename, cpu_model); + stm32l_sys_init(0x1FF00000, pic[28], &stm32_board); + + // structures GPIO + static const uint32_t gpio_addr[NB_GPIO] = { + 0x40020000, // GPIO_A + 0x40020400, // GPIO_B + 0x40020800, // GPIO_C + 0x40020C00, // GPIO_D + 0x40021000, // GPIO_E + 0x40021400 // GPIO_H + }; + + DeviceState* gpio_dev[NB_GPIO]; + + //create the botton + DeviceState* button = sysbus_create_simple("stm32_button", -1, NULL); + + //create the LEDs + DeviceState* led_dev6 = sysbus_create_simple("stm32_led_blue" , -1, NULL); + DeviceState* led_dev7 = sysbus_create_simple("stm32_led_green", -1, NULL); + + + //initial GPIO_A + gpio_dev[GPIO_A] = sysbus_create_varargs("stm32_gpio_A", gpio_addr[GPIO_A], + NULL); + qemu_irq entreeBouton = qdev_get_gpio_in(gpio_dev[GPIO_A], 1); + + qdev_connect_gpio_out(button, 0, entreeBouton); + + //initial GPIO_B + gpio_dev[GPIO_B] = sysbus_create_varargs("stm32_gpio_B", gpio_addr[GPIO_B], + NULL); + + qemu_irq entreeLED6 = qdev_get_gpio_in(led_dev6, 0); + qdev_connect_gpio_out(gpio_dev[GPIO_B], 6, entreeLED6); + qemu_irq entreeLED7 = qdev_get_gpio_in(led_dev7, 0); + qdev_connect_gpio_out(gpio_dev[GPIO_B], 7, entreeLED7); + +} + +static QEMUMachine stm32l152rbt6_machine = { + .name = "stm32l152rbt6", + .desc = "STM32L Discovery", + .init = stm32l152rbt6_init, + // user manual page 105 + // STM32 = ARM-based 32-bit microcontroller + // L = Low power + // 152: Devices with LCD + // R = 64 pins + // B = 128 Kbytes of Flash memory + // T = LQFP + // 6 = Industrial temperature range, –40 to 85 °C +}; + +static void stm32l_machine_init(void) { + qemu_register_machine(&stm32l152rbt6_machine); +} + +machine_init(stm32l_machine_init); + diff --git a/hw/stm32_gpio.c b/hw/stm32_gpio.c new file mode 100644 index 0000000..0ac3535 --- /dev/null +++ b/hw/stm32_gpio.c @@ -0,0 +1,331 @@ +#include "sysbus.h" +#include "exec-memory.h" + +#define NB_PIN 64 + +typedef struct { + SysBusDevice busdev; + + /* Registres GPIO (Reference Manual p119 */ + uint32_t mode; /* Mode */ + uint16_t otype; /* Output type */ + uint32_t ospeed; /* Output speed */ + uint32_t pupd; /* Pull-up/Pull-down */ + uint16_t ind; /* Input data */ + uint16_t outd; /* Output data register */ + uint16_t outd_old; /* Output data register */ + uint32_t bsr; /* Bit set/reset */ + uint32_t lck; /* Lock */ + uint32_t afrl; /* Alternate function low */ + uint32_t afrh; /* Alternate function high */ + + qemu_irq irq_out[NB_PIN]; + unsigned char id; + MemoryRegion iomem; +} stm32_gpio_state; + + +static const VMStateDescription vmstate_stm32_gpio = { + .name = "stm32_gpio", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) + { + VMSTATE_UINT32(mode, stm32_gpio_state), + VMSTATE_UINT16(otype, stm32_gpio_state), + VMSTATE_UINT32(ospeed, stm32_gpio_state), + VMSTATE_UINT32(pupd, stm32_gpio_state), + VMSTATE_UINT16(ind, stm32_gpio_state), + VMSTATE_UINT16(outd, stm32_gpio_state), + VMSTATE_UINT16(outd_old, stm32_gpio_state), + VMSTATE_UINT32(bsr, stm32_gpio_state), + VMSTATE_UINT32(lck, stm32_gpio_state), + VMSTATE_UINT32(afrl, stm32_gpio_state), + VMSTATE_UINT32(afrh, stm32_gpio_state), + VMSTATE_END_OF_LIST() + } +}; + + +static void stm32_gpio_update(stm32_gpio_state *s) +{ + uint16_t changed; + uint16_t mask; + int i; + + changed = s->outd_old ^ s->outd; //XOR: Tous les bits à 1 seront les bits changés + if (!changed) + return; + + s->outd_old = s->outd; + for (i = 0; i < 8; i++) { + mask = 1 << i; + if (changed & mask) { + //Conditions de changement + //--Mode register != 00 + uint32_t modeMask = (1 << (i*2)) | (1 << ((i*2) + 1)); + if((s->mode & modeMask) != 0) { + // send an IRQ to the device connected to the GPIO pin + //FIXME: the transmition to the pin is direct when it should occur at the next tick of the RCC + qemu_set_irq(s->irq_out[i], (s->outd & mask) != 0); + } + } + } +} + + +static uint64_t stm32_gpio_read(void *opaque, target_phys_addr_t offset, unsigned size) +{ + stm32_gpio_state *s = (stm32_gpio_state *) opaque; + + switch (offset) { + case 0x00: /* Mode */ + return s->mode; + case 0x04: /* oType */ + return s->otype; + case 0x08: /* oSpeed */ + return s->ospeed; + case 0x0C: /* Pull-up / Pull-down */ + return s->pupd; + case 0x10: /* Input data register */ + return s->ind; + case 0x14: /* Output data */ + return s->outd; + case 0x18: /* BSR */ + return 0x0; //Write only + case 0x1C: /* lock */ + return 0x0; //Non implémenté + case 0x20: /* AFRL */ + return s->afrl; + case 0x24: /* AFRH */ + return s->afrh; + default: + hw_error("stm32_gpio_read: Bad offset %x\n", (int) offset); + return 0; + } +} + + +static void stm32_gpio_write(void *opaque, target_phys_addr_t offset, + uint64_t value, unsigned size) +{ + stm32_gpio_state *s = (stm32_gpio_state *) opaque; + int i; + uint16_t low = (uint16_t)value; + uint16_t high = (uint16_t)value >> 16; + + switch (offset) { + case 0x00: /* Mode */ + s->mode = value; + break; + case 0x04: /* oType */ + s->otype = value; + break; + case 0x08: /* oSpeed */ + s->ospeed = value; + break; + case 0x0C: /* Pull-up / Pull-down */ + s->pupd = value; + break; + case 0x10: /* Input data register */ + //Read only + break; + case 0x14: /* Output data */ + s->outd = value; + stm32_gpio_update(s); + break; + + case 0x18: /* BSR */ + //set = low + //reset = high + for(i=0; i<16; i++) { + int mask = 1 << i; + if((high & mask) != 0) { //Si bit reset[i] + s->outd &= ~(1 << i); //Mise à 0 + } + if((low & mask) != 0) { //Si bit reset[i] + s->outd |= (1 << i); //Mise à 1 + } + } + stm32_gpio_update(s); + break; + + case 0x1C: /* lock */ + //FIXME: Non implémenté + break; + case 0x20: /* AFRL */ + s->afrl = value; + break; + case 0x24: /* AFRH */ + s->afrh = value; + break; + default: + hw_error("stm32_gpio_write: Bad offset %x\n", (int) offset); + } +} + + + +static void stm32_gpio_reset(stm32_gpio_state *s) +{ + switch (s->id) { + case 'A': + s->mode = 0xA8000000; + s->pupd = 0x64000000; + s->ospeed = 0x00000000; + break; + case 'B': + s->mode = 0x00000280; + s->pupd = 0x00000100; + s->ospeed = 0x000000C0; + break; + default: + s->mode = 0x00000000; + s->pupd = 0x00000000; + s->ospeed = 0x00000000; + } + + //Valeur commune + s->ind = 0x00000000; + s->otype = 0x00000000; + s->outd = 0x00000000; + s->outd_old = s->outd; + s->bsr = 0x00000000; + s->lck = 0x00000000; + s->afrh = 0x00000000; + s->afrl = 0x00000000; + +} + +/* + * Appelé quand une entrée de GPIO reçois une IT + * called when an input GPIO receive an IT + */ +static void stm32_gpio_in_recv(void * opaque, int numPin, int level) +{ + assert(numPin>=0 && numPin<NB_PIN); + stm32_gpio_state *s = (stm32_gpio_state *) opaque; + + + uint32_t mask = (1 << (numPin*2)) | (1 << ((numPin*2) + 1)); + //check if the pin is confihured as input + //--Pull-up Pull-Down -> must be different trom 00 + if((s->pupd & mask) == 0) {return;} + //--Mode register -> 00 + if((s->mode & mask) != 0) {return;} + + //Writing to the register input data register + printf("GPIO_in[%d]->%d\n", numPin, level); + if(level) { + s->ind |= (1 << numPin); // last => 1 + } else { + s->ind &= ~(1 << numPin); //Mise à 0 + } +} + + + +static const MemoryRegionOps gpio_ops = { + .read = stm32_gpio_read, + .write = stm32_gpio_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + + + +static int stm32_gpio_init(SysBusDevice *dev, const unsigned char id) +{ + stm32_gpio_state *s = FROM_SYSBUS(stm32_gpio_state, dev); + s->id = id; + + // initialisation of the memory range + memory_region_init_io(&s->iomem, &gpio_ops, s, "gpio", 0x17FF); + sysbus_init_mmio(dev, &s->iomem); + + // initial the pins + qdev_init_gpio_in(&dev->qdev, stm32_gpio_in_recv, NB_PIN); + qdev_init_gpio_out(&dev->qdev, s->irq_out, NB_PIN); + + stm32_gpio_reset(s); + vmstate_register(&dev->qdev, -1, &vmstate_stm32_gpio, s); + + return 0; +} + + + +static int stm32_gpio_init_A(SysBusDevice *dev) +{ + return stm32_gpio_init(dev, 'A'); +} + + + +static int stm32_gpio_init_B(SysBusDevice *dev) +{ + return stm32_gpio_init(dev, 'B'); +} + + + +static Property stm32_gpio_sysbus_properties[] = { + //XXX: DEFINE_PROP_CHR("chardev", NULL, chr), + DEFINE_PROP_END_OF_LIST(), +}; + + + +static void stm32_gpio_class_init_A (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = stm32_gpio_init_A; + dc->desc = "STM32 GPIO A"; + dc->vmsd = &vmstate_stm32_gpio; + dc->props = stm32_gpio_sysbus_properties; + +} + + + +static void stm32_gpio_class_init_B (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = stm32_gpio_init_B; + dc->desc = "STM32 GPIO B"; + dc->vmsd = &vmstate_stm32_gpio; + dc->props = stm32_gpio_sysbus_properties; + +} + + + +static TypeInfo stm32_gpioA_info = { + .name = "stm32_gpio_A", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof (stm32_gpio_state), + .class_init = stm32_gpio_class_init_A, +}; + + + +static TypeInfo stm32_gpioB_info = { + .name = "stm32_gpio_B", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof (stm32_gpio_state), + .class_init = stm32_gpio_class_init_B, +}; + + + +static void stm32_gpio_register_devices(void) { + type_register_static(&stm32_gpioA_info); + type_register_static(&stm32_gpioB_info); +} + + + +type_init(stm32_gpio_register_devices) -- 1.7.9.5
From 59ec269e532d85be4af08ab993ecf748513f4311 Mon Sep 17 00:00:00 2001 From: xatier <xatierlike@gmail.com> Date: Tue, 14 Aug 2012 14:53:20 +0800 Subject: [PATCH 2/2] add button and leds for stm32 --- hw/arm/Makefile.objs | 2 +- hw/stm32_button.c | 125 ++++++++++++++++++++++++++++++++++++++++++ hw/stm32_led.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 hw/stm32_button.c create mode 100644 hw/stm32_led.c diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index 15aff03..58f2894 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -9,7 +9,7 @@ obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o obj-y += exynos4210_rtc.o exynos4210_i2c.o obj-y += arm_mptimer.o a15mpcore.o obj-y += armv7m.o armv7m_nvic.o stellaris.o stellaris_enet.o -obj-y += stm32.o stm32_gpio.o +obj-y += stm32.o stm32_gpio.o stm32_button.o stm32_led.o obj-y += highbank.o obj-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o diff --git a/hw/stm32_button.c b/hw/stm32_button.c new file mode 100644 index 0000000..33df31b --- /dev/null +++ b/hw/stm32_button.c @@ -0,0 +1,125 @@ + +#include "sysbus.h" + +typedef struct { + SysBusDevice busdev; + uint8_t buttonState; + qemu_irq gpio_out; + CharDriverState* chr; + const char *id; +} stm32_button_state; + + + +static const VMStateDescription vmstate_stm32_button = { + .name = "stm32_button", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) + { + VMSTATE_UINT8(buttonState, stm32_button_state), + VMSTATE_END_OF_LIST() + } +}; + + + +static void stm32_button_reset(stm32_button_state *s) +{ + s->buttonState = 0; +} + + + +static int stm32_can_receive(void *opaque) { return 1; } // always return 1 + + + +static void stm32_receive(void *opaque, const uint8_t* buf, int size) +{ + + stm32_button_state *s = (stm32_button_state *) opaque; + + int i = 0; + for(i = 0; i < size; i++) { + //Leve une IRQ + uint8_t etat = buf[i]; + s->buttonState = etat; + printf("the BUTTON change state->%d\n", (int)etat); + qemu_set_irq(s->gpio_out, (int)etat); + } +} + + + +static void stm32_event(void *opaque, int event) { } // NOT USED + + + +static int stm32_button_init(SysBusDevice *dev, const char* id) +{ + stm32_button_state *s = FROM_SYSBUS(stm32_button_state, dev); + + // initial the output pins + qdev_init_gpio_out(&dev->qdev, &s->gpio_out, 1); + + // inital the char dev + s->chr = qemu_char_get_next_serial(); + s->id = id; + + if (s->chr) { + qemu_chr_add_handlers(s->chr, stm32_can_receive, stm32_receive, stm32_event, s); + } + + stm32_button_reset(s); + vmstate_register(&dev->qdev, -1, &vmstate_stm32_button, s); + + return 0; +} + + + +static int stm32_button_init_(SysBusDevice *dev) +{ + return stm32_button_init(dev, "user0"); +} + + + +static Property stm32_button_sysbus_properties[] = { + //XXX: DEFINE_PROP_CHR("chardev", NULL, chr), + DEFINE_PROP_END_OF_LIST(), +}; + + + +static void stm32_button_class_init (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = stm32_button_init_; + dc->desc = "STM32 Button"; + dc->vmsd = &vmstate_stm32_button; + dc->props = stm32_button_sysbus_properties; + +} + + + +static TypeInfo stm32_button_info = { + .name = "stm32_button", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof (stm32_button_state), + .class_init = stm32_button_class_init, +}; + + + +static void stm32_button_register_devices(void) { + type_register_static(&stm32_button_info); +} + + + +type_init(stm32_button_register_devices) diff --git a/hw/stm32_led.c b/hw/stm32_led.c new file mode 100644 index 0000000..51f87e7 --- /dev/null +++ b/hw/stm32_led.c @@ -0,0 +1,148 @@ + +#include "sysbus.h" + +typedef struct { + SysBusDevice busdev; + uint8_t ledState; + CharDriverState *chr; + const char *id; +} stm32_led_state; + + + +static const VMStateDescription vmstate_stm32_led = { + .name = "stm32_led", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) + { + VMSTATE_UINT8(ledState, stm32_led_state), + VMSTATE_END_OF_LIST() + } +}; + + + +static void stm32_led_reset(stm32_led_state *s) +{ + s->ledState = 0; +} + +/* + * Appelé quand une entrée de led reçoit une IT + */ +static void stm32_led_recvirq(void * opaque, int numPin, int level) +{ + // the LED change state + printf("The LED change state->%d\n", level); + stm32_led_state *s = (stm32_led_state *) opaque; + + if(s->chr) { + uint8_t buffer = (uint8_t)level; + qemu_chr_fe_write(s->chr, &buffer, 1); + } +} + + + +static int stm32_led_init(SysBusDevice *dev, const char* id) +{ + stm32_led_state *s = FROM_SYSBUS(stm32_led_state, dev); + + + // debug message + // printf("%p, %d\n", &dev->qdev, dev->qdev.num_gpio_out); + + // initial the output pins + qdev_init_gpio_in(&dev->qdev, stm32_led_recvirq, 1); + + // initial the char device + s->chr = qemu_chr_find(id); + s->id = id; + + stm32_led_reset(s); + vmstate_register(&dev->qdev, -1, &vmstate_stm32_led, s); + + return 0; +} + + + +static int stm32_led_init_Blue(SysBusDevice *dev) +{ + return stm32_led_init(dev, "led_blue"); +} + + + +static int stm32_led_init_Green(SysBusDevice *dev) +{ + return stm32_led_init(dev, "led_green"); +} + + + +static Property stm32_led_blue_sysbus_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + + + +static Property stm32_led_green_sysbus_properties[] = { + DEFINE_PROP_END_OF_LIST(), +}; + + + +static void stm32_led_blue_class_init (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = stm32_led_init_Blue; + dc->desc = "STM32 LED Blue"; + dc->vmsd = &vmstate_stm32_led, + dc->props = stm32_led_blue_sysbus_properties; +} + + + +static void stm32_led_green_class_init (ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = stm32_led_init_Green; + dc->desc = "STM32 LED Green"; + dc->vmsd = &vmstate_stm32_led, + dc->props = stm32_led_green_sysbus_properties; +} + + + +static TypeInfo stm32_led_info_blue = { + .name = "stm32_led_blue", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof (stm32_led_state), + .class_init = stm32_led_blue_class_init, +}; + + + +static TypeInfo stm32_led_info_green = { + .name = "stm32_led_green", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof (stm32_led_state), + .class_init = stm32_led_green_class_init, +}; + + + +static void stm32_led_register_devices(void) { + type_register_static(&stm32_led_info_blue); + type_register_static(&stm32_led_info_green); +} + + + +type_init(stm32_led_register_devices) -- 1.7.9.5
很開心的把生出來的 patch 寄給 jserv review,馬上被抓出以下有問題的地方QAQ
看來開發功力還要再練練!!慢慢養成經驗值
注意以下:
(1) 使用 C-style comment 風格
(2) 錯別字,如 "unimplemtmented"
(3) 文法,如 "initial the processor" 應該是 "initialize the processor"
(4) "create the button" 與 "create the LEDs" 應該獨立為其他 patch
(5) ssys_{write,read} 是否需要實做?
=======================================
8/20 update
把我的 code 放上 github: https://github.com/xatier/qemu
以後改完 code 要先XD
git push qemu-github summer-work
另外 rebase origin 要記得先 pull 下來... merge,不然會失敗XD
筆記一下流程
git checkout master
git fetch origin
git pull
git checkout summer-work
git rebase origin/master
git pull qemu-github summer-work
git merge
git push qemu-github summer-work
=======================================
目前的問題是卡在實作 RCC 的部份,參考了 pl031 / stellaris 等機器正在想辦法實作
想辦法加上 RCC tick 的行為,透過 qemu_new_timer_ns 去初始化 tick
另外有這台歪果人做的 STM32 模擬,好像跟我們的很像...
https://github.com/beckus/qemu_stm32/commits/stm32_v1.1.0/
https://github.com/beckus/stm32_p103_demos
不過 beckus 的 code 最近在大改就是 (應該是要 fit 新的 qemu 版本)
=======================================
9/23 update
git checkout master
git fetch origin
git pull
git checkout summer-work
git rebase origin/master
git pull qemu-github summer-work
git merge
git push qemu-github summer-work
=======================================
目前的問題是卡在實作 RCC 的部份,參考了 pl031 / stellaris 等機器正在想辦法實作
想辦法加上 RCC tick 的行為,透過 qemu_new_timer_ns 去初始化 tick
接上 qemu-timer.h 上面的 API
另外有這台歪果人做的 STM32 模擬,好像跟我們的很像...
https://github.com/beckus/qemu_stm32/commits/stm32_v1.1.0/
https://github.com/beckus/stm32_p103_demos
不過 beckus 的 code 最近在大改就是 (應該是要 fit 新的 qemu 版本)
=======================================
9/23 update
後來進開學比較忙,一方面 qemu 的進度比較少,令一方面也沒時間再把這些瑣碎的小進度放上來
接下來的工作是幫忙 jserv 測試 beckus 的作品,我這邊目前應該暫時停止開發了
前端的部份 WeiYao 會幫忙做網頁式的模擬器外觀,任務是要把原本的 Python-TKinter 的部份重新做過,用 HTML5
jserv 在成大的課程也陸續開始了,課程網頁:
作業(使用 gitcafe!):
雖然很可惜最後沒能在暑假前幫 jserv 完成完整的 qemu-STM32 的 modeling ,但是還是很開心,在這期間學到了非常非常多的東西,也感謝 jserv 能給我一個這麼棒的打工經驗!
希望接下來還有機會跟 jserv 一起合作其他相關有趣的專案 :)
開發暫且告一段落囉~
No comments:
Post a Comment