# HG changeset patch
# User Windel Bouwman
# Date 1424351452 -3600
# Node ID f381cea07fec3b8404d71ebc62ec31e9881aa3a6
# Parent a284749c5729ffb30f3c4637cf9688efede7977f# Parent 742588fb8cd699c48f1ab43c345b632a5ce81668
merge
diff -r 742588fb8cd6 -r f381cea07fec build.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/build.xml Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff -r 742588fb8cd6 -r f381cea07fec doc/compiler.rst
--- a/doc/compiler.rst Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-
-
-.. toctree::
-
- ir
-
-Compiler
-========
-
-This chapter describes the design of the compiler.
-The compiler consists a frontend, mid-end and back-end. The frontend deals with
-source file parsing and semantics checking. The mid-end performs optimizations.
-This is optional. The back-end generates machine code. The front-end produces
-intermediate code. This is a simple representation of the source. The back-end
-can accept this kind of representation.
-
-.. graphviz::
-
- digraph x {
- rankdir="LR"
- 1 [label="c3 source file"]
- 10 [label="c3 front end" ]
- 11 [label="language X front end" ]
- 20 [label="mid end" ]
- 30 [label="back end for X86" ]
- 31 [label="back end for ARM" ]
- 40 [label="object file"]
- 1 -> 10
- 10 -> 20 [label="IR-code"]
- 11 -> 20 [label="IR-code"]
- 20 -> 30 [label="IR-code"]
- 20 -> 31 [label="IR-code"]
- 30 -> 40
- }
-
-
-IR-code
--------
-
-The intermediate representation (IR) of a program de-couples the front end
-from the backend of the compiler.
-
-See :doc:`ir` for details about all the available instructions.
-
-
-C3 Front-end
-------------
-
-For the front-end a recursive descent parser is created for the c3 language.
-This is a subset of the C language with some additional features.
-
-.. graphviz::
-
- digraph c3 {
- rankdir="LR"
- 1 [label="source text"]
- 10 [label="lexer" ]
- 20 [label="parser" ]
- 40 [label="code generation"]
- 99 [label="IR-code object"]
- 1 -> 10
- 10 -> 20
- 20 -> 40
- 40 -> 99
- }
-
-.. autoclass:: ppci.c3.Lexer
-
-.. autoclass:: ppci.c3.Parser
-
-.. autoclass:: ppci.c3.CodeGenerator
-
-.. autoclass:: ppci.c3.Builder
-
-Back-end
---------
-
-The back-end is more complicated. There are several steps to be taken here.
-
-1. Instruction selection
-2. register allocation
-3. Peep hole optimization?
-4. real code generation
-
-.. automodule:: ppci.codegen
- :members:
-
-Instruction selection
-~~~~~~~~~~~~~~~~~~~~~
-
-The instruction selection phase takes care of scheduling and instruction
-selection. The output of this phase is a one frame per function with a flat
-list of abstract machine instructions.
-
-// .. autoclass:: ppci.irmach.Frame
-
-// .. autoclass:: ppci.irmach.AbstractInstruction
-
-
diff -r 742588fb8cd6 -r f381cea07fec doc/ir.rst
--- a/doc/ir.rst Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-
-
-IR-code
-=======
-
-Front ends generate this IR-code. Backends transform it into machine code.
-
-The IR-code is implemented in the ir package.
-
-.. autoclass:: ppci.ir.Module
-
-.. autoclass:: ppci.ir.Function
-
-.. autoclass:: ppci.ir.Block
-
-A block contains a sequence of statements.
-
-.. autoclass:: ppci.ir.Statement
-
-.. autoclass:: ppci.ir.Move
-
-Jump instructions:
-
-.. autoclass:: ppci.ir.Jump
-
-.. autoclass:: ppci.ir.CJump
-
-Statements can contain again expressions.
-
-.. autoclass:: ppci.ir.Expression
-
-.. autoclass:: ppci.ir.Const
-
-.. autoclass:: ppci.ir.Binop
-
-.. autoclass:: ppci.ir.Call
-
-.. autoclass:: ppci.ir.Eseq
-
diff -r 742588fb8cd6 -r f381cea07fec doc/utils.rst
--- a/doc/utils.rst Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-
-Utilities
-=========
-
-Hexfile manipulation
---------------------
-
-
-.. autoclass:: utils.HexFile
-
-
->>> from utils import HexFile
->>> h = HexFile()
->>> h.dump()
-Hexfile containing 0 bytes
->>> h.addRegion(0, bytes([1,2,3]))
->>> h
-Hexfile containing 3 bytes
-
-
-Yacc
-----
-
-.. automodule:: yacc
-
-
-Burg
-----
-
-.. automodule:: pyburg
-
diff -r 742588fb8cd6 -r f381cea07fec examples/c3/build.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/c3/build.xml Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -r 742588fb8cd6 -r f381cea07fec examples/c3/recipe.yaml
--- a/examples/c3/recipe.yaml Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-
-link:
- inputs:
- - assemble:
- source: startup_stm32f4.asm
- machine: thumb
- - compile:
- sources: [burn2.c3]
- includes: [stm32f4xx.c3]
- machine: thumb
- output: burn.elf2
- output: burn2.bin
- layout:
- code: 0x08000000
- data: 0x20000000
-
diff -r 742588fb8cd6 -r f381cea07fec examples/c3/stm32f4.mmap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/c3/stm32f4.mmap Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,9 @@
+
+
+MEMORY flash LOCATION=0x08000000 SIZE=0x10000 {
+ SECTION(code)
+}
+
+MEMORY ram LOCATION=0x20000000 SIZE=0x10000 {
+ SECTION(data)
+}
diff -r 742588fb8cd6 -r f381cea07fec examples/qemu_a9_hello/build.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/qemu_a9_hello/build.xml Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
diff -r 742588fb8cd6 -r f381cea07fec examples/qemu_a9_hello/make.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/qemu_a9_hello/make.sh Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,4 @@
+
+../../python/zcc.py recipe recipe.yaml
+
+
diff -r 742588fb8cd6 -r f381cea07fec examples/qemu_a9_hello/qemu.mmap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/qemu_a9_hello/qemu.mmap Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,9 @@
+
+MEMORY flash LOCATION=0x60010000 SIZE=0x10000 {
+ SECTION(code)
+}
+
+MEMORY ram LOCATION=0x60020000 SIZE=0x10000 {
+ SECTION(data)
+}
+
diff -r 742588fb8cd6 -r f381cea07fec examples/qemu_a9_hello/qemutst.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/qemu_a9_hello/qemutst.sh Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+echo "Trying to run versatilePB board"
+
+qemu-system-arm -M realview-pb-a8 -m 128M -kernel hello.bin -serial stdio
+
+
diff -r 742588fb8cd6 -r f381cea07fec examples/qemu_a9_hello/recipe.yaml
--- a/examples/qemu_a9_hello/recipe.yaml Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-
-
-link:
- inputs:
- - assemble:
- source: startup_a9.asm
- machine: arm
- - compile:
- sources: [hello.c3]
- includes: []
- machine: arm
- layout:
- code: 0x60010000
- data: 0x60020000
- output: hello.bin
-
diff -r 742588fb8cd6 -r f381cea07fec experiments/qemu_vexpress_a9/display.c
--- a/experiments/qemu_vexpress_a9/display.c Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-
-
-#define PL110_CR_EN 0x001
-#define PL110_CR_16BPP 0x008
-#define PL110_CR_MONO 0x010
-#define PL110_CR_TFT 0x020
-#define PL110_CR_MONO_8B 0x040
-#define PL110_CR_DUAL_LCD 0x080
-#define PL110_CR_BGR 0x100
-#define PL110_CR_BEBO 0x200
-#define PL110_CR_BEPO 0x400
-#define PL110_CR_PWR 0x800
-
-
-
-
-#define PL110_IOBASE 0x10020000
-#define FB_BASE 0x60050000
-
-
-typedef unsigned int uint32;
-typedef unsigned char uint8;
-typedef unsigned short uint16;
-
-typedef struct
-{
- uint32 volatile tim0; //0
- uint32 volatile tim1; //4
- uint32 volatile tim2; //8
- uint32 volatile tim3; //c
- uint32 volatile upbase; //10
- uint32 volatile lpbase; //14
- uint32 volatile control; //18
-} PL111MMIO;
-
-void print_uart0(const char *s);
-
-extern uint16* image_data;
-extern int image_width;
-extern int image_height;
-
-void do_display(void)
-{
- uint16 volatile *fb;
- PL111MMIO *plio;
- int x, y;
-
- plio = (PL111MMIO*)PL110_IOBASE;
-
- plio->tim0 = 0x3f1f3f9c;
- plio->tim1 = 0x080b61df;
- plio->upbase = FB_BASE;
-
- /* 16-bit color */
- plio->control = PL110_CR_EN | (0xC) | PL110_CR_TFT | PL110_CR_PWR;
-
- fb = (uint16*)FB_BASE;
-
- for (x = 0; x < (640 * 480) - 10; ++x)
- {
- fb[x] = 0x1f << (5 + 6) | 0xf << 5;
- }
-
- print_uart0("Cleared disp\n");
-
- for (x = 0; x < image_width; x++)
- {
- for (y = 0; y < image_height; y++)
- {
- fb[x + 640 * y] = image_data[x + image_width * y];
- }
- }
-
-}
-
diff -r 742588fb8cd6 -r f381cea07fec experiments/qemu_vexpress_a9/layout.ld
--- a/experiments/qemu_vexpress_a9/layout.ld Fri Mar 07 17:10:21 2014 +0100
+++ b/experiments/qemu_vexpress_a9/layout.ld Thu Feb 19 14:10:52 2015 +0100
@@ -3,10 +3,14 @@
SECTIONS
{
- . = 0x60010000;
- .startup . : { startup.o(.text) }
+ . = 0x010000;
+ .startup . : { startup.o(.init) }
.text : {*(.text)}
- .data : {*(.data)}
+ . = ALIGN(0x4000);
+ .data : {
+ *(.padata)
+ *(.data)
+ }
.bss : {*(.bss)}
. = . + 0x1000;
stack_top = .;
diff -r 742588fb8cd6 -r f381cea07fec experiments/qemu_vexpress_a9/main.c
--- a/experiments/qemu_vexpress_a9/main.c Fri Mar 07 17:10:21 2014 +0100
+++ b/experiments/qemu_vexpress_a9/main.c Thu Feb 19 14:10:52 2015 +0100
@@ -1,6 +1,6 @@
-volatile unsigned int * const UART0_DR = (unsigned int *)0x10009000;
+volatile unsigned int * const UART0_DR = (unsigned int *)0x109000;
void print_uart0(const char *s)
@@ -11,12 +11,10 @@
}
}
-void do_display(void);
void start(void)
{
print_uart0("Hello world\n");
- do_display();
for (;;);
}
diff -r 742588fb8cd6 -r f381cea07fec experiments/qemu_vexpress_a9/make.sh
--- a/experiments/qemu_vexpress_a9/make.sh Fri Mar 07 17:10:21 2014 +0100
+++ b/experiments/qemu_vexpress_a9/make.sh Thu Feb 19 14:10:52 2015 +0100
@@ -4,12 +4,11 @@
TARGET=arm-none-eabi
MCPU=arm926ej-s
-python make_image.py
$TARGET-as -mcpu=$MCPU -g startup.s -o startup.o
$TARGET-gcc -c -g -mcpu=$MCPU -marm main.c -nostdlib -o main.o
-$TARGET-gcc -c -g -mcpu=$MCPU -marm display.c -nostdlib -o disp.o
-$TARGET-gcc -c -g -mcpu=$MCPU -marm image.c -nostdlib -o img.o
-$TARGET-ld -g -T layout.ld main.o startup.o disp.o img.o -o test.elf
+$TARGET-ld -g -T layout.ld main.o startup.o -o test.elf
$TARGET-objcopy -O binary test.elf test.bin
+$TARGET-nm test.elf
+$TARGET-objdump -x test.elf
diff -r 742588fb8cd6 -r f381cea07fec experiments/qemu_vexpress_a9/make_image.py
--- a/experiments/qemu_vexpress_a9/make_image.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-
-from PyQt5.QtGui import QImage, QGuiApplication, qRed, qBlue, qGreen
-
-app = QGuiApplication([])
-img = QImage('../../python/ide/icons/hardware.png')
-#print(img)
-
-f = open('image.c', 'w')
-print('typedef unsigned short uint16;',file=f)
-print('uint16 image_width = {};'.format(img.width()), file=f)
-print('uint16 image_height = {};'.format(img.height()), file=f)
-print('uint16 image_data[{}] = {{'.format(img.width()*img.height()+1), file=f)
-for y in range(img.height()):
- for x in range(img.width()):
- pix = img.pixel(x, y)
- #print(qRed(pix))
- r = qRed(pix) >> 3
- g = qGreen(pix) >> 2
- b = qBlue(pix) >> 3
- u16 = (r << 11) | (g << 6) | b
- assert u16 in range(2**16)
- print(' {},'.format(hex(u16)),file=f)
-
-print('0x0};', file=f)
-f.close()
-
diff -r 742588fb8cd6 -r f381cea07fec experiments/qemu_vexpress_a9/run.sh
--- a/experiments/qemu_vexpress_a9/run.sh Fri Mar 07 17:10:21 2014 +0100
+++ b/experiments/qemu_vexpress_a9/run.sh Thu Feb 19 14:10:52 2015 +0100
@@ -1,5 +1,5 @@
#!/bin/bash
-qemu-system-arm -M vexpress-a9 -m 128M -kernel test.bin \
- -serial file:output.txt
+qemu-system-arm -M vexpress-a9 -m 128M -kernel test.bin \
+ -serial stdio # -nographic
diff -r 742588fb8cd6 -r f381cea07fec experiments/qemu_vexpress_a9/startup.s
--- a/experiments/qemu_vexpress_a9/startup.s Fri Mar 07 17:10:21 2014 +0100
+++ b/experiments/qemu_vexpress_a9/startup.s Thu Feb 19 14:10:52 2015 +0100
@@ -1,8 +1,55 @@
+.section .init
.global _Reset;
_Reset:
+
+_start:
LDR sp, =stack_top
+
+ ldr r2, =0x10009000
+
+ mov r1, #'1'
+ str r1, [r2]
+
+// Load TTBR0 and TTBR1
+ ldr r0, =kernel_table0
+ mcr p15, 0, r0, c2, c0, 1
+ mcr p15, 0, r0, c2, c0, 0
+
+ // Domain 0:
+mov r0, #3
+mcr p15, 0, r0, c3, c0, 0
+
+ # ; Enable paging:
+mrc p15, 0, r0, c1, c0, 0
+orr r0, r0, #1
+mcr p15, 0, r0, c1, c0, 0
+
+// Change uart DR pointer (now located at 0x109000:
+ ldr r2, =0x109000
+ mov r1, #'2'
+ str r1, [r2]
+
BL start
B .
+.section .padata
+
+/*
+ Maybe the kernel is loaded at 0x60000000, so we need to map that to first
+ megabyte also...
+*/
+
+kernel_table0:
+ .long 0x00000000 + 0x402 // 0x00000000 # ; Identity map first 1 MB
+ .long 0x10000000 + 0x402 // 0x00100000 # ; second mb mapping to peripherals
+
+ .rept 0x600 - 2
+ .long 0x0
+ .endr
+ .long 0x00000402 // 0x60000000 maps 1 MB to first MB
+ .rept 0x1000 - 0x601
+ .long 0x0
+ .endr
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/arch/qemu_m3/archmem.c3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/arch/qemu_m3/archmem.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,8 @@
+module archmem;
+import io;
+
+function void init()
+{
+}
+
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/arch/qemu_m3/startup_m3.asm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/arch/qemu_m3/startup_m3.asm Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,6 @@
+
+
+DCD 0x20000678 ; Setup stack pointer
+DCD 0x08000009 ; Reset vector, jump to address 8
+B kernel_start ; Branch to main (this is actually in the interrupt vector)
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/arch/qemu_vexpress/layout.mmap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/arch/qemu_vexpress/layout.mmap Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,14 @@
+
+MEMORY image LOCATION=0x10000 SIZE=0x10000 {
+ SECTION(reset)
+ SECTION(code)
+ ALIGN(0x4000)
+ SECTION(mem_tables)
+ ALIGN(0x4000)
+ SECTION(ramdisk)
+}
+
+MEMORY ram LOCATION=0x20000 SIZE=0x10000 {
+ SECTION(data)
+}
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/arch/qemu_vexpress/start.asm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/arch/qemu_vexpress/start.asm Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,94 @@
+
+; This file contains the low level assembly code required for interrupt
+; handling and virtual memory.
+
+section reset
+
+interrupt_vector_table:
+ivt_reset: B start ; 0x0 reset
+ivt_undef: B undef_handler ; 0x4 undefined instruction
+ivt_svc: B undef_handler ; 0x08 Supervisor call
+ivt_prefetch: B undef_handler ; 0x0C prefetch abort
+ivt_data: B undef_handler ; 0x10 data abort
+ivt_hyptrap: B undef_handler ; 0x14 not used
+ivt_irq: B undef_handler ; 0x18 IRQ
+ivt_fiq: B undef_handler ; 0x18 FIQ
+
+
+start:
+
+; Setup the memory manager and the stack before entering kernel
+
+; Setup TTBR1 (translation table base register)
+
+ldr r0, =kernel_table0 ; pseudo instruction which loads the value of the symbol
+; -KERNEL_BASE
+mcr p15, 0, r0, c2, c0, 1 ; TTBR1
+mcr p15, 0, r0, c2, c0, 0 ; TTBR0
+
+; Prepare the TTBCR (translation table base control register)
+mov r0, 0x1 ; TBD: why set this to 1?
+mcr p15, 0, r0, c2, c0, 2
+
+
+; Set domain 0 to manager:
+mov r0, 3
+mcr p15, 0, r0, c3, c0, 0
+
+
+; Enable the VMSA (Virtual memory system architecture):
+mrc p15, 0, r0, c1, c0, 0
+; TODO:
+mov r1, 0x1
+orr r0, r0, r1 ; TODO: implement orr r0, r0, 1
+mcr p15, 0, r0, c1, c0, 0
+
+; Setup stack:
+mov sp, 0x30000
+BL kernel_start ; Branch to main (this is actually in the interrupt vector)
+local_loop:
+B local_loop
+
+
+; Interrupt handlers:
+
+undef_handler:
+B undef_handler
+
+
+; Assembly language helpers:
+; Called to identify the proc:
+arch_pfr0:
+mrc p15, 0, r0, c0, c1, 0
+mov pc, lr
+
+arch_pfr1:
+mrc p15, 0, r0, c0, c1, 1
+mov pc, lr
+
+arch_mmfr0:
+mrc p15, 0, r0, c0, c1, 4
+mov pc, lr
+
+arch_mpuir:
+mrc p15, 0, r0, c0, c0, 4
+mov pc, lr
+
+
+; Memory map tables:
+
+section mem_tables
+
+kernel_table0:
+ dcd 0x00000402 ; Identity map first 1 MB
+ dcd 0x10000402 ; Map to peripheral space 1 MB
+ repeat 0x5FE
+ dcd 0
+ endrepeat
+
+ dcd 0x00000402 ; Alias to 0x0
+
+ repeat 0x9FF
+ dcd 0
+ endrepeat
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/arch/qemu_vexpress/vexpressA9.c3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/arch/qemu_vexpress/vexpressA9.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,34 @@
+module arch;
+import io;
+
+
+function void init()
+{
+ // putc(65)
+ io.print2("PFR0 = ", pfr0());
+ io.print2("PFR1 = ", pfr1());
+ io.print2("MMFR0 = ", mmfr0());
+
+ // This below is not compatible with all qemu versions:
+ // io.print2("MPUIR = ", arch.mpuir());
+}
+
+function void putc(int c)
+{
+ var int *UART0DR;
+ UART0DR = cast(0x109000); // UART0 DR register when remapped at 1MB
+ *UART0DR = c;
+}
+
+function void halt()
+{
+ while(true)
+ {
+ }
+}
+
+function int pfr0();
+function int pfr1();
+function int mmfr0();
+// function int mpuir();
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/arch_arm.c3
--- a/kernel/arch_arm.c3 Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-module arch;
-
-function void init()
-{
- var int *UART0DR;
- UART0DR = cast(0x10009000);
- *UART0DR = 0x65;
-}
-
-function void halt()
-{
-}
-
diff -r 742588fb8cd6 -r f381cea07fec kernel/build.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/build.xml Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/debug.c3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/debug.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,3 @@
+
+module debug;
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/interrupt.c3
--- a/kernel/interrupt.c3 Fri Mar 07 17:10:21 2014 +0100
+++ b/kernel/interrupt.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -1,7 +1,7 @@
module interrupt;
-func irq_handle()
+function void irq_handle()
{
}
diff -r 742588fb8cd6 -r f381cea07fec kernel/io.c3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/io.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,52 @@
+module io;
+import arch;
+
+function void println(string txt)
+{
+ print(txt);
+ arch.putc(10); // Newline!
+}
+
+function void print(string txt)
+{
+ var int i;
+ i = 0;
+
+ while (i < txt->len)
+ {
+ arch.putc(cast(txt->txt[i]));
+ i = i + 1;
+ }
+}
+
+// Print integer in hexadecimal notation:
+function void print_int(int i)
+{
+ print("0x");
+
+ // int txt[20];
+ var int b;
+ var int c;
+
+ for (b=28; b >= 0; b = b - 4)
+ {
+ c = (i >> b) & 0xF;
+ if (c < 10)
+ {
+ arch.putc( 48 + c );
+ }
+ else
+ {
+ arch.putc( 65 - 10 + c );
+ }
+ }
+
+ arch.putc(10); // Newline!
+}
+
+function void print2(string label, int value)
+{
+ print(label);
+ print_int(value);
+}
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/kernel.c3
--- a/kernel/kernel.c3 Fri Mar 07 17:10:21 2014 +0100
+++ b/kernel/kernel.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -4,25 +4,34 @@
import process;
import scheduler;
import arch;
+import io;
+import debug;
+
+// Globals:
+var process.process_t* init_proc;
+
// Main entry point of the kernel:
function void start()
{
- var int* UART0DR;
- UART0DR = cast(0x10009000); // UART0 Data register
- *UART0DR = 72;
+ io.println("Welcome to lcfos!");
+ arch.init();
process.init();
- //memory:init();
+ memory.init();
+
+ init_proc = process.create();
+ // TODO: copy content into process??
- //Process proc = new process:Process();
+ io.print2("init address ", cast(init_proc));
//scheduler:queue(proc);
- while(true) {}
+ io.println("Kernel finished");
+ panic();
}
-
+// Called in total stress:
function void panic()
{
arch.halt();
diff -r 742588fb8cd6 -r f381cea07fec kernel/make.sh
--- a/kernel/make.sh Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-../python/zcc.py recipe recipe.yaml
diff -r 742588fb8cd6 -r f381cea07fec kernel/memory.c3
--- a/kernel/memory.c3 Fri Mar 07 17:10:21 2014 +0100
+++ b/kernel/memory.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -1,13 +1,36 @@
module memory;
-import process;
+import arch;
+import io;
var int ptr;
-function u8* Alloc(int size)
+// Let the heap grow upwards..
+
+function void init()
{
- ptr = ptr + size;
- return cast(ptr);
+ ptr = 0x80000;
}
+function byte* alloc(int size)
+{
+ var int ptr2;
+ ptr2 = ptr;
+ io.print2("alloc size ", size);
+ io.print2("alloc address ", ptr);
+
+ // Increment new free point:
+ ptr = ptr + size;
+ return ptr2;
+}
+
+function void memcpy(byte* dst, byte* src, int size)
+{
+ var int i;
+ for (i = 0; i < size; i = i + 1)
+ {
+ *(dst + i) = *(src + i);
+ }
+}
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/monitor.sh
--- a/kernel/monitor.sh Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-socat stdio UNIX-CONNECT:vm.sock
diff -r 742588fb8cd6 -r f381cea07fec kernel/process.c3
--- a/kernel/process.c3 Fri Mar 07 17:10:21 2014 +0100
+++ b/kernel/process.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -7,30 +7,55 @@
type struct {
int id;
int status;
+ process_t* next; // For linked list..
} process_t;
// Or, use this list structure:
// List procs;
// init is the root of all processes:
-var process_t* init_pid;
+var process_t* root_process;
+
var int next_pid;
function void init()
{
next_pid = 0;
- init_pid = Create();
+ root_process = create();
}
/*
Create a new process.
*/
-function process_t* Create()
+function process_t* create()
{
var process_t* p;
- //= memory.Alloc(sizeof(process_t));
+
+ p = cast(memory.alloc(sizeof(process_t)));
p->id = next_pid;
+ p->status = 0; // Ready!
+ p->next = cast(0);
+
+ // Increment PID:
next_pid = next_pid + 1;
+
+ // Store it in the list:
+ if (root_process == cast(0))
+ {
+ root_process = p;
+ }
+ else
+ {
+ var process_t* parent;
+ parent = root_process;
+ while (parent->next != cast(0))
+ {
+ parent = parent->next;
+ }
+
+ parent->next = p;
+ }
+
return p;
}
diff -r 742588fb8cd6 -r f381cea07fec kernel/qemutst.sh
--- a/kernel/qemutst.sh Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-
-set -e
-
-echo "quit" | socat stdio stdio
-
-echo "Trying to run test on stellaris qemu machine"
-
-# -S means halt at start:
-qemu-system-arm -M vexpress-a9 -m 128M -kernel kernel.bin \
- -monitor unix:vm.sock,server -serial file:output.txt -S -s
-
-#sleep 1
-
-# Send quit to the monitor application
-#echo "quit" | socat stdio UNIX-CONNECT:vm.sock
-
-#echo "Output from terminal:"
-#cat output.txt
-#echo ""
-
diff -r 742588fb8cd6 -r f381cea07fec kernel/ramdisk.asm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/ramdisk.asm Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,5 @@
+
+section ramdisk
+
+ramdisk_begin:
+
diff -r 742588fb8cd6 -r f381cea07fec kernel/recipe.yaml
--- a/kernel/recipe.yaml Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-
-link:
- inputs:
- - assemble:
- source: startup_a9.asm
- machine: thumb
- - compile:
- sources: [memory.c3, kernel.c3, syscall.c3, process.c3, schedule.c3, arch_arm.c3]
- includes: []
- machine: thumb
- output: kernel.elf2
- layout:
- code: 0x10000
- data: 0x20000000
- output: kernel.bin
-
diff -r 742588fb8cd6 -r f381cea07fec kernel/schedule.c3
--- a/kernel/schedule.c3 Fri Mar 07 17:10:21 2014 +0100
+++ b/kernel/schedule.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -2,13 +2,16 @@
module scheduler;
import process;
+import arch;
var process.process_t *current;
-function void executeNext()
+function void execute_next()
{
var process.process_t *old;
+ old = 0;
+
if (old != current)
{
//execute(current);
diff -r 742588fb8cd6 -r f381cea07fec kernel/startup_a9.asm
--- a/kernel/startup_a9.asm Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-
-; DCD 0x20000678 ; Setup stack pointer
-DCD 0x06daa0e3 ; mov sp, #0x60 << 8
-DCD 0x60010009 ; Reset vector, jump to address 8
-B kernel_start ; Branch to main (this is actually in the interrupt vector)
-
diff -r 742588fb8cd6 -r f381cea07fec kernel/startup_m3.asm
--- a/kernel/startup_m3.asm Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-
-
-DCD 0x20000678 ; Setup stack pointer
-DCD 0x08000009 ; Reset vector, jump to address 8
-B kernel_start ; Branch to main (this is actually in the interrupt vector)
-
diff -r 742588fb8cd6 -r f381cea07fec kernel/syscall.c3
--- a/kernel/syscall.c3 Fri Mar 07 17:10:21 2014 +0100
+++ b/kernel/syscall.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -9,6 +9,8 @@
import process;
+/* System call numbers:
+*/
const int SendMsg = 1;
const int ReceiveMsg = 2;
const int Reboot = 3;
@@ -18,7 +20,7 @@
function void handle_system_call(int callId, int a, int b)
{
// Main entry, check what to do here
- if (callId == 1)
+ if (callId == SendMsg)
{
handle_send_msg();
var process.process_t* proc;
diff -r 742588fb8cd6 -r f381cea07fec make.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/make.sh Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+export PYTHONPATH=../ppci
+../ppci/bin/ppci-build.py --log debug build
+
diff -r 742588fb8cd6 -r f381cea07fec python/asm.py
--- a/python/asm.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-#!/usr/bin/env python3
-
-import argparse
-from ppci.assembler import Assembler
-
-if __name__ == '__main__':
- # When run as main file, try to grab command line arguments:
- parser = argparse.ArgumentParser(description="Assembler")
- parser.add_argument('sourcefile', type=argparse.FileType('r'),
- help='the source file to assemble')
- args = parser.parse_args()
- a = Assembler()
- obj = a.assemble(args.sourcefile.read())
diff -r 742588fb8cd6 -r f381cea07fec python/baselex.py
--- a/python/baselex.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-
-import re
-from ppci import Token
-
-def tokenize(tok_spec, txt):
- tok_re = '|'.join('(?P<{}>{})'.format(pair[0], pair[1]) for pair in tok_spec)
- gettok = re.compile(tok_re).match
- func_map = {pair[0]: pair[2] for pair in tok_spec}
-
- # Parse line:
- line = txt
- mo = gettok(line)
- pos = 0
- while mo:
- typ = mo.lastgroup
- val = mo.group(typ)
- func = func_map[typ]
- if func:
- typ, val = func(typ, val)
- yield Token(typ, val)
- pos = mo.end()
- mo = gettok(line, pos)
- if len(line) != pos:
- raise ParserException('Lex fault at {}'.format(line[pos:]))
diff -r 742588fb8cd6 -r f381cea07fec python/burg.x
--- a/python/burg.x Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-
-%tokens ':' ';' '(' ')' ',' template id number '%%' '%terminal' header
-
-%%
-
-burgdef: header '%%' directives '%%' rules { self.system.header_lines = $1.val };
-
-directives:
- | directives directive;
-
-directive: termdef;
-
-termdef: '%terminal' termids;
-
-termids:
- | termids termid;
-
-termid: id { self.system.add_terminal($1.val) };
-
-rules:
- | rules rule;
-
-rule: id ':' tree cost template { self.system.add_rule($1.val, $3, $4, $5.val) };
-
-cost: number { return $1.val };
-
-tree: id { return self.system.tree($1.val) }
- | id '(' tree ')' { return self.system.tree($1.val, $3) }
- | id '(' tree ',' tree ')' { return self.system.tree($1.val, $3, $5) };
-
diff -r 742588fb8cd6 -r f381cea07fec python/hexutil.py
--- a/python/hexutil.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-#!/usr/bin/python
-
-import sys
-import argparse
-from utils import HexFile
-
-def hex2int(s):
- if s.startswith('0x'):
- s = s[2:]
- return int(s, 16)
- raise ValueError('Hexadecimal value must begin with 0x')
-
-parser = argparse.ArgumentParser(
- description='hexfile manipulation tool by Windel Bouwman')
-subparsers = parser.add_subparsers(title='commands',
- description='possible commands', dest='command')
-
-p = subparsers.add_parser('info', help='dump info about hexfile')
-p.add_argument('hexfile', type=argparse.FileType('r'))
-
-p = subparsers.add_parser('new', help='create a hexfile')
-p.add_argument('hexfile', type=argparse.FileType('w'))
-p.add_argument('address', type=hex2int, help="hex address of the data")
-p.add_argument('datafile', type=argparse.FileType('rb'), help='binary file to add')
-
-p = subparsers.add_parser('merge', help='merge two hexfiles into a third')
-p.add_argument('hexfile1', type=argparse.FileType('r'), help="hexfile 1")
-p.add_argument('hexfile2', type=argparse.FileType('r'), help="hexfile 2")
-p.add_argument('rhexfile', type=argparse.FileType('w'), help="resulting hexfile")
-
-
-def main(args):
- if args.command == 'info':
- hexfile = HexFile()
- hexfile.load(args.hexfile)
- print(hexfile)
- for region in hexfile.regions:
- print(region)
- elif args.command == 'new':
- hf = HexFile()
- data = args.datafile.read()
- hf.addRegion(args.address, data)
- hf.save(args.hexfile)
- elif args.command == 'merge':
- hf = HexFile()
- hf.load(args.hexfile1)
- hf2 = HexFile()
- hf2.load(args.hexfile2)
- hf.merge(hf2)
- hf.save(args.rhexfile)
- else:
- raise NotImplementedError()
-
-if __name__ == '__main__':
- args = parser.parse_args()
- if not args.command:
- parser.print_usage()
- sys.exit(1)
- main(args)
diff -r 742588fb8cd6 -r f381cea07fec python/other/diagrameditor.py
--- a/python/other/diagrameditor.py Fri Mar 07 17:10:21 2014 +0100
+++ b/python/other/diagrameditor.py Thu Feb 19 14:10:52 2015 +0100
@@ -1,11 +1,16 @@
#!/usr/bin/python
-from PyQt4.QtGui import *
-from PyQt4.QtCore import *
-import sys, json, base64
+import sys
+import json
+import base64
+import os
+
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'ide'))
+
+from qtwrapper import QtGui, QtCore, QtWidgets, pyqtSignal, get_icon
+from qtwrapper import abspath, Qt
from diagramitems import Connection, ResizeSelectionHandle, Block, DiagramScene, CodeBlock
-from icons import newicon, saveicon, loadicon
import diagramitems
"""
@@ -15,11 +20,14 @@
run with python 3.x as:
$ python [thisfile.py]
"""
-def indent(lines):
- return [' ' + line for line in lines]
+
-class ParameterDialog(QDialog):
- def __init__(self, block, parent = None):
+def indent(lines):
+ return [' ' + line for line in lines]
+
+
+class ParameterDialog(QtWidgets.QDialog):
+ def __init__(self, block, parent = None):
super(ParameterDialog, self).__init__(parent)
self.block = block
self.button = QPushButton('Ok', self)
@@ -31,29 +39,35 @@
l.addRow('Code:', self.codeEdit)
l.addWidget(self.button)
self.button.clicked.connect(self.OK)
- def OK(self):
+ def OK(self):
self.block.name = self.nameEdit.text()
self.block.code = self.codeEdit.toPlainText()
self.close()
-class EditorGraphicsView(QGraphicsView):
+
+class EditorGraphicsView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
- QGraphicsView.__init__(self, parent)
- self.setDragMode(QGraphicsView.RubberBandDrag)
- self.delShort = QShortcut(QKeySequence.Delete, self)
+ super().__init__(parent)
+ self.setObjectName('Editor')
+ self.setDragMode(QtWidgets.QGraphicsView.RubberBandDrag)
+ self.delShort = QtWidgets.QShortcut(QtGui.QKeySequence.Delete, self)
self._model = None
- self.treeView = QTreeView()
+ self.treeView = QtWidgets.QTreeView()
self.treeView.clicked.connect(self.itemActivated)
+
def itemActivated(self, idx):
b = idx.internalPointer()
s = b.scene()
s.clearSelection()
b.setSelected(True)
+
def setDiagram(self, d):
self.setScene(d)
self.delShort.activated.connect(d.deleteItems)
+
def getModel(self):
return self._model
+
def setModel(self, m):
self._model = m
if m:
@@ -70,15 +84,19 @@
with open(self.model.filename, 'w') as f:
f.write(json.dumps(self.model.Dict, indent=2))
def load(self):
- filename = QFileDialog.getOpenFileName(self)
- if filename:
- self.model = loadModel(filename)
+ filename = QtWidgets.QFileDialog.getOpenFileName(self)
+ if filename:
+ self.model = loadModel(filename)
+
def newModel(self):
- self.model = ModelHierarchyModel()
+ print('NEW')
+ self.model = ModelHierarchyModel()
+
def goUp(self):
if hasattr(self.diagram, 'containingBlock'):
self.diagram = self.diagram.containingBlock.scene()
self.zoomAll()
+
def showCode(self):
if self.model:
c = self.model.gencode()
@@ -101,22 +119,28 @@
exec(codeview.toPlainText(), globs)
runButton.clicked.connect(runIt)
d.exec_()
+
def zoomAll(self):
""" zoom to fit all items """
rect = self.diagram.itemsBoundingRect()
self.fitInView(rect, Qt.KeepAspectRatio)
+
def wheelEvent(self, event):
pos = event.pos()
posbefore = self.mapToScene(pos)
- degrees = event.delta() / 8.0
+ degrees = event.angleDelta().y() / 8.0
sx = (100.0 + degrees) / 100.0
self.scale(sx, sx)
event.accept()
+
def dragEnterEvent(self, event):
- if event.mimeData().hasFormat('component/name'):
- event.accept()
+ if event.mimeData().hasFormat('component/name'):
+ event.accept()
+
def dragMoveEvent(self, event):
- if event.mimeData().hasFormat('component/name'): event.accept()
+ if event.mimeData().hasFormat('component/name'):
+ event.accept()
+
def dropEvent(self, event):
if event.mimeData().hasFormat('component/name'):
name = bytes(event.mimeData().data('component/name')).decode()
@@ -132,29 +156,39 @@
b.setPos(pos)
s.addItem(b)
-class LibraryModel(QStandardItemModel):
- mimeTypes = lambda self: ['component/name']
- def mimeData(self, idxs):
- mimedata = QMimeData()
- for idx in idxs:
- if idx.isValid():
- txt = self.data(idx, Qt.DisplayRole)
- mimedata.setData('component/name', txt)
- return mimedata
+
+class LibraryModel(QtGui.QStandardItemModel):
+ def __init__(self, parent):
+ super().__init__(parent)
+ self.setObjectName('Library')
-class ModelHierarchyModel(QAbstractItemModel):
+ mimeTypes = lambda self: ['component/name']
+ def mimeData(self, idxs):
+ mimedata = QtCore.QMimeData()
+ for idx in idxs:
+ if idx.isValid():
+ txt = self.data(idx, Qt.DisplayRole)
+ mimedata.setData('component/name', txt)
+ return mimedata
+
+
+class ModelHierarchyModel(QtCore.QAbstractItemModel):
def __init__(self):
super(ModelHierarchyModel, self).__init__()
self.rootDiagram = DiagramScene()
self.rootDiagram.structureChanged.connect(self.handlechange)
self.filename = None
+
def handlechange(self):
self.modelReset.emit()
+
def setDict(self, d):
self.rootDiagram.Dict = d
self.modelReset.emit()
+
def getDict(self):
return self.rootDiagram.Dict
+
Dict = property(getDict, setDict)
def gencode(self):
c = ['def topLevel():']
@@ -163,6 +197,7 @@
c.append('topLevel()')
c.append('print("Done")')
return c
+
def index(self, row, column, parent=None):
if parent.isValid():
parent = parent.internalPointer().subModel
@@ -174,16 +209,18 @@
# TODO: solve this in a better way.
block.index = self.createIndex(row, column, block)
return block.index
+
def parent(self, index):
if index.isValid():
block = index.internalPointer()
if block.scene() == self.rootDiagram:
- return QModelIndex()
+ return QtCore.QModelIndex()
else:
print(block)
outerBlock = block.scene().containingBlock
return outerBlock.index
print('parent: No valid index')
+
def data(self, index, role):
if index.isValid() and role == Qt.DisplayRole:
b = index.internalPointer()
@@ -191,6 +228,7 @@
return b.name
elif index.column() == 1:
return str(type(b))
+
def headerData(self, section, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
if section == 0:
@@ -199,6 +237,7 @@
return "Type"
else:
return "x"
+
def rowCount(self, parent):
if parent.column() > 0:
return 0
@@ -210,32 +249,37 @@
return 0
else:
return len(self.rootDiagram.blocks)
+
def columnCount(self, parent):
return 2
-class LibraryWidget(QListView):
- def __init__(self):
- super(LibraryWidget, self).__init__(None)
+
+class LibraryWidget(QtWidgets.QListView):
+ def __init__(self):
+ super().__init__()
+ self.setObjectName('LibraryWidget')
self.libraryModel = LibraryModel(self)
self.libraryModel.setColumnCount(1)
# Create an icon with an icon:
- pixmap = QPixmap(60, 60)
+ pixmap = QtGui.QPixmap(60, 60)
pixmap.fill()
- painter = QPainter(pixmap)
+ painter = QtGui.QPainter(pixmap)
painter.fillRect(10, 10, 40, 40, Qt.blue)
painter.setBrush(Qt.yellow)
painter.drawEllipse(20, 20, 20, 20)
painter.end()
# Fill library:
for name in ['CodeBlock:codeBlock', 'DiagramBlock:submod', 'Block:blk']:
- self.libraryModel.appendRow(QStandardItem(QIcon(pixmap), name))
+ self.libraryModel.appendRow(QtGui.QStandardItem(QtGui.QIcon(pixmap), name))
self.setModel(self.libraryModel)
self.setViewMode(self.IconMode)
self.setDragDropMode(self.DragOnly)
+
def warning(txt):
QMessageBox.warning(None, "Warning", txt)
+
def loadModel(filename):
try:
m = ModelHierarchyModel()
@@ -250,8 +294,9 @@
except FileNotFoundError:
warning('File [{0}] not found'.format(filename))
-class Main(QMainWindow):
- def __init__(self):
+
+class Main(QtWidgets.QMainWindow):
+ def __init__(self):
super(Main, self).__init__(None)
self.editor = EditorGraphicsView()
self.setCentralWidget(self.editor)
@@ -264,30 +309,32 @@
toolbar = self.addToolBar('Tools')
toolbar.setObjectName('Tools')
def act(name, shortcut, callback, icon=None):
- a = QAction(icon, name, self) if icon else QAction(name, self)
+ a = QtWidgets.QAction(icon, name, self) if icon else QtWidgets.QAction(name, self)
a.setShortcuts(shortcut)
a.triggered.connect(callback)
toolbar.addAction(a)
- act('New', QKeySequence.New, self.editor.newModel, buildIcon(newicon))
- act('Save', QKeySequence.Save, self.editor.save, buildIcon(saveicon))
- act('Load', QKeySequence.Open, self.editor.load, buildIcon(loadicon))
- act('Full screen', QKeySequence("F11"), self.toggleFullScreen)
- act('Fit in view', QKeySequence("F8"), self.editor.zoomAll)
- act('Go up', QKeySequence(Qt.Key_Up), self.editor.goUp)
- act('Model code', QKeySequence("F7"), self.editor.showCode)
+ act('New', QtGui.QKeySequence.New, self.editor.newModel)
+ act('Save', QtGui.QKeySequence.Save, self.editor.save)
+ act('Load', QtGui.QKeySequence.Open, self.editor.load)
+ act('Full screen', QtGui.QKeySequence("F11"), self.toggleFullScreen)
+ act('Fit in view', QtGui.QKeySequence("F8"), self.editor.zoomAll)
+ act('Go up', QtGui.QKeySequence(Qt.Key_Up), self.editor.goUp)
+ act('Model code', QtGui.QKeySequence("F7"), self.editor.showCode)
def addDock(name, widget):
- dock = QDockWidget(name, self)
+ dock = QtWidgets.QDockWidget(name, self)
dock.setObjectName(name)
dock.setWidget(widget)
self.addDockWidget(Qt.LeftDockWidgetArea, dock)
addDock('Library', LibraryWidget())
addDock('Model tree', self.editor.treeView)
- self.settings = QSettings('windelsoft', 'diagrameditor')
+ self.settings = QtCore.QSettings('windelsoft', 'diagrameditor')
self.loadSettings()
- def toggleFullScreen(self):
- self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
- self.editor.zoomAll()
- def loadSettings(self):
+
+ def toggleFullScreen(self):
+ self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
+ self.editor.zoomAll()
+
+ def loadSettings(self):
if self.settings.contains('mainwindowstate'):
self.restoreState(self.settings.value('mainwindowstate'))
if self.settings.contains('mainwindowgeometry'):
@@ -295,7 +342,8 @@
if self.settings.contains('openedmodel'):
modelfile = self.settings.value('openedmodel')
self.editor.model = loadModel(modelfile)
- def closeEvent(self, ev):
+
+ def closeEvent(self, ev):
self.settings.setValue('mainwindowstate', self.saveState())
self.settings.setValue('mainwindowgeometry', self.saveGeometry())
if self.editor.model and self.editor.model.filename:
@@ -306,11 +354,10 @@
ev.accept()
if __name__ == '__main__':
- if sys.version_info.major != 3:
- print('Please use python 3.x')
- sys.exit(1)
- app = QApplication(sys.argv)
- main = Main()
- main.show()
- app.exec_()
-
+ if sys.version_info.major != 3:
+ print('Please use python 3.x')
+ sys.exit(1)
+ app = QtWidgets.QApplication(sys.argv)
+ main = Main()
+ main.show()
+ app.exec_()
diff -r 742588fb8cd6 -r f381cea07fec python/other/diagramitems.py
--- a/python/other/diagramitems.py Fri Mar 07 17:10:21 2014 +0100
+++ b/python/other/diagramitems.py Thu Feb 19 14:10:52 2015 +0100
@@ -2,46 +2,62 @@
Contains all blocks that can be used to build models.
"""
-from PyQt4.QtGui import *
-from PyQt4.QtCore import *
+import sys
+import json
+import base64
+import os
+
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'ide'))
+
+from qtwrapper import QtGui, QtCore, QtWidgets, pyqtSignal, get_icon
+from qtwrapper import abspath, Qt
+
def uniqify(name, names):
- newname, i = name, 1
- while newname in names: newname, i = name + str(i), i + 1
- return newname
+ newname, i = name, 1
+ while newname in names: newname, i = name + str(i), i + 1
+ return newname
+
def enum(**enums):
- return type('Enum', (), enums)
+ return type('Enum', (), enums)
+
Position = enum(TOP=0, TOP_RIGHT=1, RIGHT=2, BOTTOM_RIGHT=3, BOTTOM=4, BOTTOM_LEFT=5, LEFT=6, TOP_LEFT=7)
+
def buildPath(pts):
- path = QPainterPath(pts[0])
- for pt in pts[1:]: path.lineTo(pt)
- return path
+ path = QtGui.QPainterPath(pts[0])
+ for pt in pts[1:]: path.lineTo(pt)
+ return path
def equalSpace(n, l, offset=15):
- if n == 1:
- return [l / 2]
- elif n > 1:
- return [offset + (l - offset*2)/(n - 1)*i for i in range(n)]
- return []
+ if n == 1:
+ return [l / 2]
+ elif n > 1:
+ return [offset + (l - offset*2)/(n - 1)*i for i in range(n)]
+ return []
-class Connection(QGraphicsPathItem):
+
+class Connection(QtWidgets.QGraphicsPathItem):
""" A connection between blocks """
def __init__(self, fromPort=None, toPort=None):
- super(Connection, self).__init__()
- self.pos2 = self.fromPort = self.toPort = None
- self.setFlags(self.ItemIsSelectable | self.ItemClipsToShape)
- pen = QPen(Qt.blue, 2, cap=Qt.RoundCap)
- self.setPen(pen)
- self.arrowhead = QGraphicsPathItem(self)
- self.arrowhead.setPath(buildPath([QPointF(0.0, 0.0), QPointF(-6.0, 10.0), QPointF(6.0, 10.0), QPointF(0.0, 0.0)]))
- self.arrowhead.setPen(pen)
- self.arrowhead.setBrush(QBrush(pen.color()))
- self.vias = []
- self.setFromPort(fromPort)
- self.setToPort(toPort)
+ super(Connection, self).__init__()
+ self.pos2 = self.fromPort = self.toPort = None
+ self.setFlags(self.ItemIsSelectable | self.ItemClipsToShape)
+ pen = QtGui.QPen(Qt.blue, 2, cap=Qt.RoundCap)
+ self.setPen(pen)
+ self.arrowhead = QtWidgets.QGraphicsPathItem(self)
+ self.arrowhead.setPath(buildPath([QtCore.QPointF(0.0, 0.0),
+ QtCore.QPointF(-6.0, 10.0),
+ QtCore.QPointF(6.0, 10.0),
+ QtCore.QPointF(0.0, 0.0)]))
+ self.arrowhead.setPen(pen)
+ self.arrowhead.setBrush(QtGui.QBrush(pen.color()))
+ self.vias = []
+ self.setFromPort(fromPort)
+ self.setToPort(toPort)
+
def getDict(self):
d = {}
d['fromBlock'] = self.fromPort.block.name
@@ -79,14 +95,17 @@
return self.fromPort.scenePos()
def setBeginPos(self, pos1): self.updateLineStukken()
def setEndPos(self, endpos):
- self.pos2 = endpos
- self.updateLineStukken()
+ self.pos2 = endpos
+ self.updateLineStukken()
def itemChange(self, change, value):
- if change == self.ItemSelectedHasChanged:
- for via in self.vias:
- via.setVisible(value)
- return super(Connection, self).itemChange(change, value)
- def shape(self): return self.myshape
+ if change == self.ItemSelectedHasChanged:
+ for via in self.vias:
+ via.setVisible(value)
+ return super(Connection, self).itemChange(change, value)
+
+ def shape(self):
+ return self.myshape
+
def updateLineStukken(self):
"""
This algorithm determines the optimal routing of all signals.
@@ -97,13 +116,13 @@
if pos1 is None or pos2 is None:
return
scene = self.scene()
- vias = [pos1 + QPointF(20, 0)] + self.vias + [pos2 + QPointF(-20, 0)]
+ vias = [pos1 + QtCore.QPointF(20, 0)] + self.vias + [pos2 + QtCore.QPointF(-20, 0)]
if scene:
- litem = QGraphicsLineItem()
+ litem = QtWidgets.QGraphicsLineItem()
litem.setFlags(self.ItemIsSelectable)
scene.addItem(litem)
for p1, p2 in zip(vias[:-1], vias[1:]):
- line = QLineF(p1, p2)
+ line = QtCore.QLineF(p1, p2)
litem.setLine(line)
citems = scene.collidingItems(litem)
citems = [i for i in citems if type(i) is Block]
@@ -115,19 +134,19 @@
self.setPath(p)
""" Create a shape outline using the path stroker """
s = super(Connection, self).shape()
- pps = QPainterPathStroker()
+ pps = QtGui.QPainterPathStroker()
pps.setWidth(10)
self.myshape = pps.createStroke(s).simplified()
-class PortItem(QGraphicsPathItem):
+class PortItem(QtWidgets.QGraphicsPathItem):
""" Represents a port to a subsystem """
def __init__(self, name, block):
super(PortItem, self).__init__(block)
- self.textItem = QGraphicsTextItem(self)
+ self.textItem = QtWidgets.QGraphicsTextItem(self)
self.connection = None
self.block = block
- self.setCursor(QCursor(Qt.CrossCursor))
- self.setPen(QPen(Qt.blue, 2, cap=Qt.RoundCap))
+ self.setCursor(QtGui.QCursor(Qt.CrossCursor))
+ self.setPen(QtGui.QPen(Qt.blue, 2, cap=Qt.RoundCap))
self.name = name
self.posCallbacks = []
self.setFlag(self.ItemSendsScenePositionChanges, True)
@@ -148,87 +167,101 @@
return value
return super(PortItem, self).itemChange(change, value)
+
class OutputPort(PortItem):
- def __init__(self, name, block, d=10.0):
- super(OutputPort, self).__init__(name, block)
- self.setPath(buildPath([QPointF(0.0, -d), QPointF(d, 0), QPointF(0.0, d)]))
- def mousePressEvent(self, event):
- self.scene().startConnection(self)
+ def __init__(self, name, block, d=10.0):
+ super().__init__(name, block)
+ self.setPath(buildPath([QtCore.QPointF(0.0, -d), QtCore.QPointF(d, 0),
+ QtCore.QPointF(0.0, d)]))
+
+ def mousePressEvent(self, event):
+ self.scene().startConnection(self)
+
class InputPort(PortItem):
- def __init__(self, name, block, d=10.0):
- super(InputPort, self).__init__(name, block)
- self.setPath(buildPath([QPointF(-d, -d), QPointF(0, 0), QPointF(-d, d)]))
+ def __init__(self, name, block, d=10.0):
+ super().__init__(name, block)
+ self.setPath(buildPath([QtCore.QPointF(-d, -d), QtCore.QPointF(0, 0),
+ QtCore.QPointF(-d, d)]))
-class Handle(QGraphicsEllipseItem):
+class Handle(QtWidgets.QGraphicsEllipseItem):
""" A handle that can be moved by the mouse """
def __init__(self, dx=10.0, parent=None):
- super(Handle, self).__init__(QRectF(-0.5*dx,-0.5*dx,dx,dx), parent)
- self.setBrush(QBrush(Qt.white))
+ super(Handle, self).__init__(QtCore.QRectF(-0.5*dx,-0.5*dx,dx,dx), parent)
+ self.setBrush(QtGui.QBrush(Qt.white))
self.setFlags(self.ItemIsMovable)
self.setZValue(1)
self.setVisible(False)
- self.setCursor(QCursor(Qt.SizeFDiagCursor))
+ self.setCursor(QtGui.QCursor(Qt.SizeFDiagCursor))
def mouseMoveEvent(self, event):
""" Move function without moving the other selected elements """
p = self.mapToParent(event.pos())
self.setPos(p)
+
class ResizeSelectionHandle(Handle):
- def __init__(self, position, block):
- super(ResizeSelectionHandle, self).__init__(dx=12, parent=block)
- self.position = position
- self.block = block
- if position in [Position.TOP_LEFT, Position.BOTTOM_RIGHT]:
- self.setCursor(QCursor(Qt.SizeFDiagCursor))
- elif position in [Position.TOP_RIGHT, Position.BOTTOM_LEFT]:
- self.setCursor(QCursor(Qt.SizeBDiagCursor))
- elif position in [Position.TOP, Position.BOTTOM]:
- self.setCursor(QCursor(Qt.SizeVerCursor))
- elif position in [Position.LEFT, Position.RIGHT]:
- self.setCursor(QCursor(Qt.SizeHorCursor))
- def mouseMoveEvent(self, event):
- self.block.sizerMoveEvent(self, event.scenePos())
+ def __init__(self, position, block):
+ super(ResizeSelectionHandle, self).__init__(dx=12, parent=block)
+ self.position = position
+ self.block = block
+ if position in [Position.TOP_LEFT, Position.BOTTOM_RIGHT]:
+ self.setCursor(QtGui.QCursor(Qt.SizeFDiagCursor))
+ elif position in [Position.TOP_RIGHT, Position.BOTTOM_LEFT]:
+ self.setCursor(QtGui.QCursor(Qt.SizeBDiagCursor))
+ elif position in [Position.TOP, Position.BOTTOM]:
+ self.setCursor(QtGui.QCursor(Qt.SizeVerCursor))
+ elif position in [Position.LEFT, Position.RIGHT]:
+ self.setCursor(QtGui.QCursor(Qt.SizeHorCursor))
-class Block(QGraphicsRectItem):
+ def mouseMoveEvent(self, event):
+ self.block.sizerMoveEvent(self, event.scenePos())
+
+
+class Block(QtWidgets.QGraphicsRectItem):
""" Represents a block in the diagram. """
def __init__(self, name='Untitled', parent=None):
super(Block, self).__init__(parent)
self.selectionHandles = [ResizeSelectionHandle(i, self) for i in range(8)]
# Properties of the rectangle:
- self.setPen(QPen(Qt.blue, 2))
- self.setBrush(QBrush(Qt.lightGray))
+ self.setPen(QtGui.QPen(Qt.blue, 2))
+ self.setBrush(QtGui.QBrush(Qt.lightGray))
self.setFlags(self.ItemIsSelectable | self.ItemIsMovable | self.ItemSendsScenePositionChanges)
- self.setCursor(QCursor(Qt.PointingHandCursor))
+ self.setCursor(QtGui.QCursor(Qt.PointingHandCursor))
self.setAcceptHoverEvents(True)
- self.label = QGraphicsTextItem(name, self)
+ self.label = QtWidgets.QGraphicsTextItem(name, self)
self.name = name
# Create corner for resize:
- button = QPushButton('+in')
+ button = QtWidgets.QPushButton('+in')
button.clicked.connect(self.newInputPort)
- self.buttonItemAddInput = QGraphicsProxyWidget(self)
+ self.buttonItemAddInput = QtWidgets.QGraphicsProxyWidget(self)
self.buttonItemAddInput.setWidget(button)
self.buttonItemAddInput.setVisible(False)
- button = QPushButton('+out')
+ button = QtWidgets.QPushButton('+out')
button.clicked.connect(self.newOutputPort)
- self.buttonItemAddOutput = QGraphicsProxyWidget(self)
+ self.buttonItemAddOutput = QtWidgets.QGraphicsProxyWidget(self)
self.buttonItemAddOutput.setWidget(button)
self.buttonItemAddOutput.setVisible(False)
# Inputs and outputs of the block:
self.inputs = []
self.outputs = []
self.changeSize(2,2)
+
def editParameters(self):
- pd = ParameterDialog(self, self.window())
- pd.exec_()
+ pd = ParameterDialog(self, self.window())
+ pd.exec_()
+
def newInputPort(self):
- names = [i.name for i in self.inputs + self.outputs]
- self.addInput(InputPort(uniqify('in', names), self))
+ names = [i.name for i in self.inputs + self.outputs]
+ self.addInput(InputPort(uniqify('in', names), self))
+
def newOutputPort(self):
- names = [i.name for i in self.inputs + self.outputs]
- self.addOutput(OutputPort(uniqify('out', names), self))
+ names = [i.name for i in self.inputs + self.outputs]
+ self.addOutput(OutputPort(uniqify('out', names), self))
+
def setName(self, name): self.label.setPlainText(name)
+
def getName(self): return self.label.toPlainText()
+
name = property(getName, setName)
def getDict(self):
d = {'x': self.scenePos().x(), 'y': self.scenePos().y()}
@@ -247,14 +280,17 @@
for outp in d['outputs']:
self.addOutput(OutputPort(outp['name'], self))
Dict = property(getDict, setDict)
+
def addInput(self, i):
- self.inputs.append(i)
- self.updateSize()
+ self.inputs.append(i)
+ self.updateSize()
+
def addOutput(self, o):
- self.outputs.append(o)
- self.updateSize()
+ self.outputs.append(o)
+ self.updateSize()
+
def contextMenuEvent(self, event):
- menu = QMenu()
+ menu = QtWidgets.QMenu()
pa = menu.addAction('Parameters')
pa.triggered.connect(self.editParameters)
menu.exec_(event.screenPos())
@@ -269,13 +305,13 @@
return super(Block, self).itemChange(change, value)
def hoverEnterEvent(self, event):
- if not self.isSelected():
- self.repositionAndShowHandles()
- super(Block, self).hoverEnterEvent(event)
+ if not self.isSelected():
+ self.repositionAndShowHandles()
+ super().hoverEnterEvent(event)
def hoverLeaveEvent(self, event):
- if not self.isSelected():
- [h.setVisible(False) for h in self.selectionHandles]
- super(Block, self).hoverLeaveEvent(event)
+ if not self.isSelected():
+ [h.setVisible(False) for h in self.selectionHandles]
+ super().hoverLeaveEvent(event)
def myDelete(self):
for p in self.inputs + self.outputs:
if p.connection: p.connection.myDelete()
@@ -316,31 +352,35 @@
for outp, y in zip(self.outputs, equalSpace(len(self.outputs), h)):
outp.setPos(w, y)
def setCenterAndSize(self, center, size):
- self.changeSize(size.width(), size.height())
- p = QPointF(size.width(), size.height())
- self.setPos(center - p / 2)
+ self.changeSize(size.width(), size.height())
+ p = QtCore.QPointF(size.width(), size.height())
+ self.setPos(center - p / 2)
def changeSize(self, w, h):
- minw = 150
- minh = 50
- h = minh if h < minh else h
- w = minw if w < minw else w
- self.setRect(0.0, 0.0, w, h)
- rect = self.label.boundingRect()
- self.label.setPos((w - rect.width()) / 2, (h - rect.height()) / 2)
- self.updateSize()
+ minw = 150
+ minh = 50
+ h = minh if h < minh else h
+ w = minw if w < minw else w
+ self.setRect(0.0, 0.0, w, h)
+ rect = self.label.boundingRect()
+ self.label.setPos((w - rect.width()) / 2, (h - rect.height()) / 2)
+ self.updateSize()
+
class CodeBlock(Block):
- def __init__(self, name='Untitled', parent=None):
- super(CodeBlock, self).__init__(name, parent)
- self.code = ''
- def setDict(self, d):
- super(CodeBlock, self).setDict(d)
- self.code = d['code']
- def getDict(self):
- d = super(CodeBlock, self).getDict()
- d['code'] = self.code
- return d
- def gencode(self):
+ def __init__(self, name='Untitled', parent=None):
+ super(CodeBlock, self).__init__(name, parent)
+ self.code = ''
+
+ def setDict(self, d):
+ super(CodeBlock, self).setDict(d)
+ self.code = d['code']
+
+ def getDict(self):
+ d = super(CodeBlock, self).getDict()
+ d['code'] = self.code
+ return d
+
+ def gencode(self):
c = ['def {0}():'.format(self.name)]
if self.code:
c += indent(self.code.split('\n'))
@@ -348,24 +388,28 @@
c += indent(['pass'])
return c
+
class DiagramBlock(Block):
- def __init__(self, name='Untitled', parent=None):
- super(DiagramBlock, self).__init__(name, parent)
- self.subModel = DiagramScene()
- self.subModel.containingBlock = self
- def setDict(self, d):
- self.subModel.Dict = d['submodel']
- def mouseDoubleClickEvent(self, event):
- # descent into child diagram
- #self.editParameters()
- print('descent')
- scene = self.scene()
- if scene:
- for view in scene.views():
- view.diagram = self.subModel
- view.zoomAll()
+ def __init__(self, name='Untitled', parent=None):
+ super(DiagramBlock, self).__init__(name, parent)
+ self.subModel = DiagramScene()
+ self.subModel.containingBlock = self
+
+ def setDict(self, d):
+ self.subModel.Dict = d['submodel']
-class DiagramScene(QGraphicsScene):
+ def mouseDoubleClickEvent(self, event):
+ # descent into child diagram
+ #self.editParameters()
+ print('descent')
+ scene = self.scene()
+ if scene:
+ for view in scene.views():
+ view.diagram = self.subModel
+ view.zoomAll()
+
+
+class DiagramScene(QtWidgets.QGraphicsScene):
""" A diagram scene consisting of blocks and connections """
structureChanged = pyqtSignal()
def __init__(self):
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/__init__.py
--- a/python/ppci/__init__.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-# File to make this directory a package.
-
-import sys
-import os
-
-version = '0.0.1'
-
-# Assert python version:
-if sys.version_info.major != 3:
- print("Needs to be run in python version 3.x")
- sys.exit(1)
-
-from .common import SourceLocation, SourceRange, Token
-from .common import CompilerError, DiagnosticsManager
-
-logformat='%(asctime)s|%(levelname)s|%(name)s|%(message)s'
-
-def same_dir(full_path, filename):
- return os.path.join(os.path.dirname(os.path.abspath(full_path)), filename)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/assembler.py
--- a/python/ppci/assembler.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,204 +0,0 @@
-
-import re
-import pyyacc
-from . import Token, CompilerError, SourceLocation
-from .target import Target, Label
-
-
-def bit_type(value):
- assert value < (2**32)
- assert value >= 0
- t = 'val32'
- for n in [16, 12, 8, 5, 3]:
- if value < (2**n):
- t = 'val{}'.format(n)
- return t
-
-def tokenize(s, kws):
- """
- Tokenizer, generates an iterator that
- returns tokens!
-
- This GREAT example was taken from python re doc page!
- """
- tok_spec = [
- ('REAL', r'\d+\.\d+'),
- ('HEXNUMBER', r'0x[\da-fA-F]+'),
- ('NUMBER', r'\d+'),
- ('ID', r'[A-Za-z][A-Za-z\d_]*'),
- ('SKIP', r'[ \t]'),
- ('LEESTEKEN', r':=|[\.,=:\-+*\[\]/\(\)]|>=|<=|<>|>|<|}|{'),
- ('STRING', r"'.*?'"),
- ('COMMENT', r";.*")
- ]
- tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec)
- gettok = re.compile(tok_re).match
- line = 1
- pos = line_start = 0
- mo = gettok(s)
- while mo is not None:
- typ = mo.lastgroup
- val = mo.group(typ)
- if typ == 'NEWLINE':
- line_start = pos
- line += 1
- elif typ != 'SKIP':
- if typ == 'LEESTEKEN':
- typ = val
- elif typ == 'NUMBER':
- val = int(val)
- elif typ == 'HEXNUMBER':
- val = int(val[2:], 16)
- typ = 'NUMBER'
- elif typ == 'REAL':
- val = float(val)
- elif typ == 'STRING':
- val = val[1:-1]
- elif typ == 'ID':
- if val.lower() in kws: # ['r3', 'sp', 'add', 'yield', 'r4', 'r0', 'r1', 'sub', 'r5', 'r6', 'r2']:
- typ = val.lower()
- col = mo.start() - line_start
- loc = SourceLocation('', line, col, 0) # TODO retrieve length?
- if typ == 'NUMBER':
- typ = bit_type(val)
- yield Token(typ, val, loc)
- pos = mo.end()
- mo = gettok(s, pos)
- if pos != len(s):
- col = pos - line_start
- loc = SourceLocation('', line, col, 0)
- raise CompilerError('Unexpected character {0}'.format(s[pos]), loc)
- yield Token('EOF', pyyacc.EOF)
-
-
-class Lexer:
- def __init__(self, src, kws):
- self.tokens = tokenize(src, kws)
- self.curTok = self.tokens.__next__()
-
- def next_token(self):
- t = self.curTok
- if t.typ != 'EOF':
- self.curTok = self.tokens.__next__()
- return t
-
-
-class Parser:
- def add_rule(self, prod, rhs, f):
- """ Helper function to add a rule, why this is required? """
- if prod == 'instruction':
- def f_wrap(*args):
- i = f(args)
- self.emit(i)
- else:
- def f_wrap(*rhs):
- return f(rhs)
- self.g.add_production(prod, rhs, f_wrap)
-
- def __init__(self, kws, instruction_rules, emit):
- # Construct a parser given a grammar:
- tokens2 = ['ID', 'NUMBER', ',', '[', ']', ':', '+', '-', '*',
- pyyacc.EPS, 'COMMENT', '{', '}',
- pyyacc.EOF, 'val32', 'val16', 'val12', 'val8', 'val5', 'val3']
- tokens2.extend(kws)
- self.kws = kws
- g = pyyacc.Grammar(tokens2)
- self.g = g
- # Global structure of assembly line:
- g.add_production('asmline', ['asmline2'])
- g.add_production('asmline', ['asmline2', 'COMMENT'])
- g.add_production('asmline2', ['label', 'instruction'])
- g.add_production('asmline2', ['instruction'])
- g.add_production('asmline2', ['label'])
- g.add_production('asmline2', [])
- g.add_production('label', ['ID', ':'], self.p_label)
- #g.add_production('label', [])
-
- # Add instruction rules for the target in question:
- for prod, rhs, f in instruction_rules:
- self.add_rule(prod, rhs, f)
-
- #g.add_production('instruction', [])
- g.add_production('expression', ['term'], lambda x: x)
- g.add_production('expression', ['expression', 'addop', 'term'], self.p_binop)
- g.add_production('addop', ['-'], lambda x: x.val)
- g.add_production('addop', ['+'], lambda x: x.val)
- g.add_production('mulop', ['*'], lambda x: x.val)
- g.add_production('term', ['factor'], lambda x: x)
- g.add_production('term', ['term', 'mulop', 'factor'], self.p_binop)
- g.add_production('factor', ['ID'], lambda name: ASymbol(name.val))
- g.add_production('factor', ['NUMBER'], lambda num: ANumber(int(num.val)))
- g.start_symbol = 'asmline'
- self.emit = emit
- self.p = g.generate_parser()
- # print('length of table:', len(self.p.action_table))
-
- # Parser handlers:
- def p_ins_1(self, opc, ops):
- ins = AInstruction(opc, ops)
- self.emit(ins)
-
- def p_ins_2(self, opc):
- self.p_ins_1(opc, [])
-
- def p_operands_1(self, op1):
- return [op1]
-
- def p_operands_2(self, ops, comma, op2):
- assert type(ops) is list
- ops.append(op2)
- return ops
-
- def p_listitems_1(self, li1):
- return [li1]
-
- def p_listitems_2(self, lis, comma, li2):
- assert type(lis) is list
- lis.append(li2)
- return lis
-
- def p_list_op(self, brace_open, lst, brace_close):
- return AUnop('{}', lst)
-
- def p_mem_op(self, brace_open, exp, brace_close):
- return AUnop('[]', exp)
-
- def p_label(self, lname, cn):
- lab = Label(lname.val)
- self.emit(lab)
-
- def p_binop(self, exp1, op, exp2):
- return ABinop(op, exp1, exp2)
-
- def parse(self, lexer):
- self.p.parse(lexer)
-
-
-class Assembler:
- def __init__(self, target):
- self.target = target
- assert isinstance(target, Target)
- self.parser = Parser(target.asm_keywords, target.assembler_rules, self.emit)
-
- def emit(self, *args):
- self.stream.emit(*args)
-
- # Top level interface:
- def parse_line(self, line):
- """ Parse line into assembly instructions """
- tokens = Lexer(line, self.target.asm_keywords)
- self.parser.parse(tokens)
-
- def assemble(self, asmsrc, stream):
- """ Assemble this source snippet """
- if hasattr(asmsrc, 'read'):
- asmsrc2 = asmsrc.read()
- asmsrc.close()
- asmsrc = asmsrc2
- # TODO: use generic newline??
- # TODO: the bothersome newline ...
- self.stream = stream
- for line in asmsrc.split('\n'):
- self.parse_line(line)
- self.stream = None
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/bitfun.py
--- a/python/ppci/bitfun.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-
-
-def rotate_right(v, n):
- """ bit-wise Rotate right n times """
- mask = (2**n) - 1
- mask_bits = v & mask
- return (v >> n) | (mask_bits << (32 - n))
-
-def rotate_left(v, n):
- assert n >= 0
- assert n < 32
- return rotate_right(v, 32 - n)
-
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/buildtasks.py
--- a/python/ppci/buildtasks.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-
-"""
-Defines task classes that can compile, link etc..
-Task can depend upon one another.
-"""
-
-import logging
-
-from .c3 import Builder
-from .irutils import Verifier
-from .codegen import CodeGenerator
-from .transform import CleanPass, RemoveAddZero
-from .tasks import Task, TaskError
-from . import DiagnosticsManager, CompilerError
-from .assembler import Assembler
-from .objectfile import ObjectFile
-from .linker import Linker
-from .outstream import BinaryOutputStream
-
-
-class BuildTask(Task):
- """ Base task for all kind of weird build tasks """
- def __init__(self, name):
- super().__init__(name)
- self.logger = logging.getLogger('buildtask')
-
-
-class Assemble(BuildTask):
- """ Task that can runs the assembler over the source and enters the
- output into an object file """
- def __init__(self, source, target, output_object):
- super().__init__('Assemble')
- self.source = source
- self.output = output_object
- self.ostream = BinaryOutputStream(self.output)
- self.assembler = Assembler(target)
-
- def run(self):
- self.ostream.selectSection('code')
- self.assembler.assemble(self.source, self.ostream)
-
-
-class Compile(BuildTask):
- """ Task that compiles C3 source for some target into an object file """
- def __init__(self, sources, includes, target, output_object):
- super().__init__('Compile')
- self.sources = sources
- self.includes = includes
- self.target = target
- self.output = output_object
-
- def run(self):
- self.logger.debug('Compile started')
- diag = DiagnosticsManager()
- c3b = Builder(diag, self.target)
- cg = CodeGenerator(self.target)
-
- for ircode in c3b.build(self.sources, self.includes):
- if not ircode:
- return
-
- d = {'ircode':ircode}
- self.logger.debug('Verifying code {}'.format(ircode), extra=d)
- Verifier().verify(ircode)
-
- # Optimization passes:
- CleanPass().run(ircode)
- Verifier().verify(ircode)
- RemoveAddZero().run(ircode)
- Verifier().verify(ircode)
- CleanPass().run(ircode)
- Verifier().verify(ircode)
-
- # Code generation:
- d = {'ircode':ircode}
- self.logger.debug('Starting code generation for {}'.format(ircode), extra=d)
- o = BinaryOutputStream(self.output)
- cg.generate(ircode, o)
-
- if not c3b.ok:
- diag.printErrors()
- raise TaskError('Compile errors')
-
-
-class Link(BuildTask):
- """ Link together a collection of object files """
- def __init__(self, objects, layout, output_file):
- super().__init__('Link')
- self.objects = objects
- self.linker = Linker()
- self.duration = 0.1337
- self.layout = layout
- self.output_file = output_file
-
- def run(self):
- try:
- output_obj = self.linker.link(self.objects, self.layout)
- except CompilerError as e:
- raise TaskError(e.msg)
- code = output_obj.get_section('code').data
- with open(self.output_file, 'wb') as f:
- f.write(code)
-
-
-class ObjCopy(BuildTask):
- def __init__(self, objects, output_file):
- super().__init__('ObjCopy')
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/c3/__init__.py
--- a/python/ppci/c3/__init__.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-""" This is the C3 language front end. """
-
-from .parser import Parser
-from .lexer import Lexer
-from .codegenerator import CodeGenerator
-from .visitor import Visitor
-from .visitor import AstPrinter
-from .builder import Builder
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/c3/astnodes.py
--- a/python/ppci/c3/astnodes.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,376 +0,0 @@
-"""
-AST (abstract syntax tree) nodes for the c3 language.
-The tree is build by the parser.
-Then it is checked
-Finally code is generated from it.
-"""
-
-from ppci import SourceLocation
-
-
-class Node:
- """ Base class of all nodes in a AST """
- pass
-
-
-# Variables, parameters, local variables, constants and named types:
-class Symbol(Node):
- """ Symbol is the base class for all named things like variables,
- functions, constants and types and modules """
- def __init__(self, name):
- self.name = name
- self.refs = []
-
- def addRef(self, r):
- self.refs.append(r)
-
- @property
- def References(self):
- return self.refs
-
-
-# Modules
-class Package(Symbol):
- def __init__(self, name, loc):
- super().__init__(name)
- self.loc = loc
- self.declarations = []
- self.imports = []
-
- def add_declaration(self, decl):
- self.declarations.append(decl)
- if isinstance(decl, Function):
- decl.package = self
-
- def __repr__(self):
- return 'MODULE {}'.format(self.name)
-
-
-class Type(Node):
- """ Base class of all types """
- pass
-
-
-class NamedType(Type, Symbol):
- """ Some types are named, for example a user defined type (typedef)
- and built in types. That is why this class derives from both Type
- and Symbol. """
- def __init__(self, name):
- Symbol.__init__(self, name)
-
-
-class BaseType(NamedType):
- """ Built in type """
- def __init__(self, name):
- super().__init__(name)
-
- def __repr__(self):
- return '{}'.format(self.name)
-
-
-class FunctionType(Type):
- """ Function blueprint, defines argument types and return type """
- def __init__(self, parametertypes, returntype):
- self.parametertypes = parametertypes
- self.returntype = returntype
-
- def __repr__(self):
- params = ', '.join([str(v) for v in self.parametertypes])
- return '{1} f({0})'.format(params, self.returntype)
-
-
-class PointerType(Type):
- """ A type that points to data of some other type """
- def __init__(self, ptype):
- assert isinstance(ptype, Type) or isinstance(ptype, Expression)
- self.ptype = ptype
-
- def __repr__(self):
- return '({}*)'.format(self.ptype)
-
-
-class StructField:
- """ Field of a struct type """
- def __init__(self, name, typ):
- assert type(name) is str
- self.name = name
- self.typ = typ
-
-
-class StructureType(Type):
- """ Struct type consisting of several named members """
- def __init__(self, mems):
- self.mems = mems
- assert all(type(mem) is StructField for mem in mems)
-
- def hasField(self, name):
- for mem in self.mems:
- if name == mem.name:
- return True
- return False
-
- def fieldType(self, name):
- return self.findField(name).typ
-
- def fieldOffset(self, name):
- return self.findField(name).offset
-
- def findField(self, name):
- for mem in self.mems:
- if name == mem.name:
- return mem
- raise KeyError(name)
-
- def __repr__(self):
- return 'STRUCT'
-
-
-class DefinedType(NamedType):
- """ A named type indicating another type """
- def __init__(self, name, typ, loc):
- assert isinstance(name, str)
- super().__init__(name)
- self.typ = typ
- self.loc = loc
-
- def __repr__(self):
- return 'Named type {0} of type {1}'.format(self.name, self.typ)
-
-
-class Constant(Symbol):
- """ Constant definition """
- def __init__(self, name, typ, value):
- super().__init__(name)
- self.typ = typ
- self.value = value
-
- def __repr__(self):
- return 'CONSTANT {0} = {1}'.format(self.name, self.value)
-
-
-class Variable(Symbol):
- def __init__(self, name, typ):
- super().__init__(name)
- self.typ = typ
- self.isLocal = False
- self.isParameter = False
-
- def __repr__(self):
- return 'Var {} [{}]'.format(self.name, self.typ)
-
-
-class LocalVariable(Variable):
- def __init__(self, name, typ):
- super().__init__(name, typ)
- self.isLocal = True
-
-
-class FormalParameter(Variable):
- def __init__(self, name, typ):
- super().__init__(name, typ)
- self.isParameter = True
-
-
-# Procedure types
-class Function(Symbol):
- """ Actual implementation of a function """
- def __init__(self, name, loc):
- super().__init__(name)
- self.loc = loc
- self.declarations = []
-
- def add_declaration(self, decl):
- self.declarations.append(decl)
-
- def __repr__(self):
- return 'Func {}'.format(self.name)
-
-
-# Operations / Expressions:
-class Expression(Node):
- def __init__(self, loc):
- self.loc = loc
-
-
-class Deref(Expression):
- def __init__(self, ptr, loc):
- super().__init__(loc)
- assert isinstance(ptr, Expression)
- self.ptr = ptr
-
- def __repr__(self):
- return 'DEREF {}'.format(self.ptr)
-
-
-class TypeCast(Expression):
- def __init__(self, to_type, x, loc):
- super().__init__(loc)
- self.to_type = to_type
- self.a = x
-
- def __repr__(self):
- return 'TYPECAST {}'.format(self.to_type)
-
-
-class Member(Expression):
- """ Field reference of some object, can also be package selection """
- def __init__(self, base, field, loc):
- super().__init__(loc)
- assert isinstance(base, Expression)
- assert isinstance(field, str)
- self.base = base
- self.field = field
-
- def __repr__(self):
- return 'MEMBER {}.{}'.format(self.base, self.field)
-
-
-class Unop(Expression):
- """ Operation on one operand """
- def __init__(self, op, a, loc):
- super().__init__(loc)
- assert isinstance(a, Expression)
- assert isinstance(op, str)
- self.a = a
- self.op = op
-
- def __repr__(self):
- return 'UNOP {}'.format(self.op)
-
-
-class Binop(Expression):
- """ Expression taking two operands and one operator """
- def __init__(self, a, op, b, loc):
- super().__init__(loc)
- assert isinstance(a, Expression), type(a)
- assert isinstance(b, Expression)
- assert isinstance(op, str)
- self.a = a
- self.b = b
- self.op = op # Operation: '+', '-', '*', '/', 'mod'
-
- def __repr__(self):
- return 'BINOP {}'.format(self.op)
-
-
-class Identifier(Expression):
- """ Reference to some identifier, can be anything from package, variable
- function or type, any named thing! """
- def __init__(self, target, loc):
- super().__init__(loc)
- self.target = target
-
- def __repr__(self):
- return 'ID {}'.format(self.target)
-
-
-class Literal(Expression):
- """ Constant value or string """
- def __init__(self, val, loc):
- super().__init__(loc)
- self.val = val
-
- def __repr__(self):
- return 'LITERAL {}'.format(self.val)
-
-
-class FunctionCall(Expression):
- """ Call to a some function """
- def __init__(self, proc, args, loc):
- super().__init__(loc)
- self.proc = proc
- self.args = args
-
- def __repr__(self):
- return 'CALL {0} '.format(self.proc)
-
-
-# Statements
-class Statement(Node):
- """ Base class of all statements """
- def __init__(self, loc):
- self.loc = loc
-
-
-class Empty(Statement):
- """ Empty statement which does nothing! """
- def __init__(self):
- super().__init__(None)
-
- def __repr__(self):
- return 'NOP'
-
-
-class Compound(Statement):
- """ Statement consisting of a sequence of other statements """
- def __init__(self, statements):
- super().__init__(None)
- self.statements = statements
- for s in self.statements:
- assert isinstance(s, Statement)
-
- def __repr__(self):
- return 'COMPOUND STATEMENT'
-
-
-class Return(Statement):
- def __init__(self, expr, loc):
- super().__init__(loc)
- self.expr = expr
-
- def __repr__(self):
- return 'RETURN STATEMENT'
-
-
-class Assignment(Statement):
- def __init__(self, lval, rval, loc):
- super().__init__(loc)
- assert isinstance(lval, Expression)
- assert isinstance(rval, Expression)
- self.lval = lval
- self.rval = rval
-
- def __repr__(self):
- return 'ASSIGNMENT'
-
-
-class ExpressionStatement(Statement):
- def __init__(self, ex, loc):
- super().__init__(loc)
- self.ex = ex
-
- def __repr__(self):
- return 'Epression'
-
-
-class If(Statement):
- def __init__(self, condition, truestatement, falsestatement, loc):
- super().__init__(loc)
- self.condition = condition
- self.truestatement = truestatement
- self.falsestatement = falsestatement
-
- def __repr__(self):
- return 'IF-statement'
-
-
-class While(Statement):
- def __init__(self, condition, statement, loc):
- super().__init__(loc)
- self.condition = condition
- self.statement = statement
-
- def __repr__(self):
- return 'WHILE-statement'
-
-
-class For(Statement):
- def __init__(self, init, condition, final, statement, loc):
- super().__init__(loc)
- self.init = init
- self.condition = condition
- self.final = final
- self.statement = statement
-
- def __repr__(self):
- return 'FOR-statement'
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/c3/builder.py
--- a/python/ppci/c3/builder.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-import logging
-from .lexer import Lexer
-from .parser import Parser
-from .codegenerator import CodeGenerator
-from .scope import createTopScope, Scope
-from .visitor import AstPrinter, Visitor
-from .astnodes import Package, Function, Identifier, Symbol
-
-
-class C3Pass:
- def __init__(self, diag):
- self.diag = diag
- self.logger = logging.getLogger('c3')
- self.visitor = Visitor()
-
- def error(self, msg, loc=None):
- self.pkg.ok = False
- self.diag.error(msg, loc)
-
- def visit(self, pkg, pre, post):
- self.visitor.visit(pkg, pre, post)
-
-
-class ScopeFiller(C3Pass):
- scoped_types = [Package, Function]
-
- def __init__(self, diag, topScope, packages):
- super().__init__(diag)
- self.topScope = topScope
- self.packages = packages
-
- """ Scope is attached to the correct modules. """
- def addScope(self, pkg):
- self.logger.debug('Adding scoping to package {}'.format(pkg.name))
- self.pkg = pkg
- # Prepare top level scope and set scope to all objects:
- self.scopeStack = [self.topScope]
- modScope = Scope(self.CurrentScope)
- self.scopeStack.append(modScope)
- self.visit(pkg, self.enterScope, self.quitScope)
- assert len(self.scopeStack) == 2
-
- self.logger.debug('Resolving imports for package {}'.format(pkg.name))
- # Handle imports:
- for i in pkg.imports:
- if i not in self.packages:
- self.error('Cannot import {}'.format(i))
- continue
- pkg.scope.addSymbol(self.packages[i])
-
- @property
- def CurrentScope(self):
- return self.scopeStack[-1]
-
- def addSymbol(self, sym):
- if self.CurrentScope.hasSymbol(sym.name):
- self.error('Redefinition of {0}'.format(sym.name), sym.loc)
- else:
- self.CurrentScope.addSymbol(sym)
-
- def enterScope(self, sym):
- # Attach scope to references:
- if type(sym) is Identifier:
- sym.scope = self.CurrentScope
-
- # Add symbols to current scope:
- if isinstance(sym, Symbol):
- self.addSymbol(sym)
- sym.scope = self.CurrentScope
-
- # Create subscope for items creating a scope:
- if type(sym) in self.scoped_types:
- newScope = Scope(self.CurrentScope)
- self.scopeStack.append(newScope)
- sym.innerScope = self.CurrentScope
-
- def quitScope(self, sym):
- # Pop out of scope:
- if type(sym) in self.scoped_types:
- self.scopeStack.pop(-1)
-
-
-class Builder:
- """
- Generates IR-code from c3 source.
- Reports errors to the diagnostics system.
- """
- def __init__(self, diag, target):
- self.logger = logging.getLogger('c3')
- self.diag = diag
- self.lexer = Lexer(diag)
- self.parser = Parser(diag)
- self.cg = CodeGenerator(diag)
- self.topScope = createTopScope(target) # Scope with built in types
-
- def build(self, srcs, imps=[]):
- """ Create IR-code from sources """
- self.logger.debug('Building {} source files'.format(len(srcs)))
- iter(srcs) # Check if srcs are iterable
- iter(imps)
- self.ok = True
- self.pkgs = {}
-
- # Parsing stage (phase 1)
- def doParse(src):
- tokens = self.lexer.lex(src)
- return self.parser.parseSource(tokens)
- s_pkgs = set(map(doParse, srcs))
- i_pkgs = set(map(doParse, imps))
- all_pkgs = s_pkgs | i_pkgs
- if not all(all_pkgs):
- self.ok = False
- return
-
- # Fix scopes and package refs (phase 1.5)
- packages = {pkg.name: pkg for pkg in all_pkgs}
- self.pkgs = packages
-
- scopeFiller = ScopeFiller(self.diag, self.topScope, packages)
- # Fix scopes:
- for pkg in all_pkgs:
- scopeFiller.addScope(pkg)
- if not all(pkg.ok for pkg in all_pkgs):
- self.ok = False
- return
-
- # Generate intermediate code (phase 2)
- # Only return ircode when everything is OK
- for pkg in all_pkgs & s_pkgs:
- yield self.cg.gencode(pkg)
- if not all(pkg.ok for pkg in all_pkgs):
- self.ok = False
- return
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/c3/codegenerator.py
--- a/python/ppci/c3/codegenerator.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,400 +0,0 @@
-import logging
-from .. import ir
-from .. import irutils
-from . import astnodes as ast
-
-
-class SemanticError(Exception):
- """ Error thrown when a semantic issue is observed """
- def __init__(self, msg, loc):
- super().__init__()
- self.msg = msg
- self.loc = loc
-
-
-class CodeGenerator(irutils.Builder):
- """
- Generates intermediate (IR) code from a package. The entry function is
- 'genModule'. The main task of this part is to rewrite complex control
- structures, such as while and for loops into simple conditional
- jump statements. Also complex conditional statements are simplified.
- Such as 'and' and 'or' statements are rewritten in conditional jumps.
- And structured datatypes are rewritten.
-
- Type checking is done in one run with code generation.
- """
- def __init__(self, diag):
- self.logger = logging.getLogger('c3cgen')
- self.diag = diag
-
- def gencode(self, pkg):
- """ Generate code for a single module """
- self.prepare()
- assert type(pkg) is ast.Package
- self.pkg = pkg
- self.intType = pkg.scope['int']
- self.boolType = pkg.scope['bool']
- self.logger.debug('Generating ir-code for {}'.format(pkg.name), extra={'c3_ast':pkg})
- self.varMap = {} # Maps variables to storage locations.
- self.funcMap = {}
- self.m = ir.Module(pkg.name)
- try:
- for s in pkg.innerScope.Functions:
- f = self.newFunction(s.name)
- self.funcMap[s] = f
- for v in pkg.innerScope.Variables:
- self.varMap[v] = self.newTemp()
- for s in pkg.innerScope.Functions:
- self.gen_function(s)
- except SemanticError as e:
- self.error(e.msg, e.loc)
- if self.pkg.ok:
- return self.m
-
- def error(self, msg, loc=None):
- self.pkg.ok = False
- self.diag.error(msg, loc)
-
- def gen_function(self, fn):
- # TODO: handle arguments
- f = self.funcMap[fn]
- f.return_value = self.newTemp()
- self.setFunction(f)
- l2 = self.newBlock()
- self.emit(ir.Jump(l2))
- self.setBlock(l2)
- # generate room for locals:
-
- for sym in fn.innerScope:
- self.the_type(sym.typ)
- if sym.isParameter:
- p = ir.Parameter(sym.name)
- variable = ir.LocalVariable(sym.name + '_copy')
- f.addParameter(p)
- f.addLocal(variable)
- # Move parameter into local copy:
- self.emit(ir.Move(ir.Mem(variable), p))
- elif sym.isLocal:
- variable = ir.LocalVariable(sym.name)
- f.addLocal(variable)
- elif isinstance(sym, ast.Variable):
- variable = ir.LocalVariable(sym.name)
- f.addLocal(variable)
- else:
- raise NotImplementedError('{}'.format(sym))
- self.varMap[sym] = variable
-
- self.genCode(fn.body)
- self.emit(ir.Move(f.return_value, ir.Const(0)))
- self.emit(ir.Jump(f.epiloog))
- self.setFunction(None)
-
- def genCode(self, code):
- """ Wrapper around gen_stmt to catch errors """
- try:
- self.gen_stmt(code)
- except SemanticError as e:
- self.error(e.msg, e.loc)
-
- def gen_stmt(self, code):
- """ Generate code for a statement """
- assert isinstance(code, ast.Statement)
- self.setLoc(code.loc)
- if type(code) is ast.Compound:
- for s in code.statements:
- self.genCode(s)
- elif type(code) is ast.Empty:
- pass
- elif type(code) is ast.Assignment:
- lval = self.genExprCode(code.lval)
- rval = self.genExprCode(code.rval)
- if not self.equalTypes(code.lval.typ, code.rval.typ):
- msg = 'Cannot assign {} to {}'.format(code.rval.typ, code.lval.typ)
- raise SemanticError(msg, code.loc)
- if not code.lval.lvalue:
- raise SemanticError('No valid lvalue {}'.format(code.lval), code.lval.loc)
- self.emit(ir.Move(lval, rval))
- elif type(code) is ast.ExpressionStatement:
- self.emit(ir.Exp(self.genExprCode(code.ex)))
- elif type(code) is ast.If:
- bbtrue = self.newBlock()
- bbfalse = self.newBlock()
- te = self.newBlock()
- self.gen_cond_code(code.condition, bbtrue, bbfalse)
- self.setBlock(bbtrue)
- self.genCode(code.truestatement)
- self.emit(ir.Jump(te))
- self.setBlock(bbfalse)
- self.genCode(code.falsestatement)
- self.emit(ir.Jump(te))
- self.setBlock(te)
- elif type(code) is ast.Return:
- re = self.genExprCode(code.expr)
- self.emit(ir.Move(self.fn.return_value, re))
- self.emit(ir.Jump(self.fn.epiloog))
- b = self.newBlock()
- self.setBlock(b)
- elif type(code) is ast.While:
- bbdo = self.newBlock()
- bbtest = self.newBlock()
- te = self.newBlock()
- self.emit(ir.Jump(bbtest))
- self.setBlock(bbtest)
- self.gen_cond_code(code.condition, bbdo, te)
- self.setBlock(bbdo)
- self.genCode(code.statement)
- self.emit(ir.Jump(bbtest))
- self.setBlock(te)
- elif type(code) is ast.For:
- bbdo = self.newBlock()
- bbtest = self.newBlock()
- te = self.newBlock()
- self.genCode(code.init)
- self.emit(ir.Jump(bbtest))
- self.setBlock(bbtest)
- self.gen_cond_code(code.condition, bbdo, te)
- self.setBlock(bbdo)
- self.genCode(code.statement)
- self.emit(ir.Jump(bbtest))
- self.setBlock(te)
- else:
- raise NotImplementedError('Unknown stmt {}'.format(code))
-
- def gen_cond_code(self, expr, bbtrue, bbfalse):
- """ Generate conditional logic.
- Implement sequential logical operators. """
- if type(expr) is ast.Binop:
- if expr.op == 'or':
- l2 = self.newBlock()
- self.gen_cond_code(expr.a, bbtrue, l2)
- if not self.equalTypes(expr.a.typ, self.boolType):
- raise SemanticError('Must be boolean', expr.a.loc)
- self.setBlock(l2)
- self.gen_cond_code(expr.b, bbtrue, bbfalse)
- if not self.equalTypes(expr.b.typ, self.boolType):
- raise SemanticError('Must be boolean', expr.b.loc)
- elif expr.op == 'and':
- l2 = self.newBlock()
- self.gen_cond_code(expr.a, l2, bbfalse)
- if not self.equalTypes(expr.a.typ, self.boolType):
- self.error('Must be boolean', expr.a.loc)
- self.setBlock(l2)
- self.gen_cond_code(expr.b, bbtrue, bbfalse)
- if not self.equalTypes(expr.b.typ, self.boolType):
- raise SemanticError('Must be boolean', expr.b.loc)
- elif expr.op in ['==', '>', '<', '!=', '<=', '>=']:
- ta = self.genExprCode(expr.a)
- tb = self.genExprCode(expr.b)
- if not self.equalTypes(expr.a.typ, expr.b.typ):
- raise SemanticError('Types unequal {} != {}'
- .format(expr.a.typ, expr.b.typ), expr.loc)
- self.emit(ir.CJump(ta, expr.op, tb, bbtrue, bbfalse))
- else:
- raise SemanticError('non-bool: {}'.format(expr.op), expr.loc)
- expr.typ = self.boolType
- elif type(expr) is ast.Literal:
- self.genExprCode(expr)
- if expr.val:
- self.emit(ir.Jump(bbtrue))
- else:
- self.emit(ir.Jump(bbfalse))
- else:
- raise NotImplementedError('Unknown cond {}'.format(expr))
- if not self.equalTypes(expr.typ, self.boolType):
- self.error('Condition must be boolean', expr.loc)
-
- def genExprCode(self, expr):
- """ Generate code for an expression. Return the generated ir-value """
- assert isinstance(expr, ast.Expression)
- if type(expr) is ast.Binop:
- expr.lvalue = False
- if expr.op in ['+', '-', '*', '/', '<<', '>>', '|', '&']:
- ra = self.genExprCode(expr.a)
- rb = self.genExprCode(expr.b)
- if self.equalTypes(expr.a.typ, self.intType) and \
- self.equalTypes(expr.b.typ, self.intType):
- expr.typ = expr.a.typ
- else:
- raise SemanticError('Can only add integers', expr.loc)
- else:
- raise NotImplementedError("Cannot use equality as expressions")
- return ir.Binop(ra, expr.op, rb)
- elif type(expr) is ast.Unop:
- if expr.op == '&':
- ra = self.genExprCode(expr.a)
- expr.typ = ast.PointerType(expr.a.typ)
- if not expr.a.lvalue:
- raise SemanticError('No valid lvalue', expr.a.loc)
- expr.lvalue = False
- assert type(ra) is ir.Mem
- return ra.e
- else:
- raise NotImplementedError('Unknown unop {0}'.format(expr.op))
- elif type(expr) is ast.Identifier:
- # Generate code for this identifier.
- tg = self.resolveSymbol(expr)
- expr.kind = type(tg)
- expr.typ = tg.typ
- # This returns the dereferenced variable.
- if isinstance(tg, ast.Variable):
- expr.lvalue = True
- return ir.Mem(self.varMap[tg])
- elif isinstance(tg, ast.Constant):
- c_val = self.genExprCode(tg.value)
- return self.evalConst(c_val)
- else:
- raise NotImplementedError(str(tg))
- elif type(expr) is ast.Deref:
- # dereference pointer type:
- addr = self.genExprCode(expr.ptr)
- ptr_typ = self.the_type(expr.ptr.typ)
- expr.lvalue = True
- if type(ptr_typ) is ast.PointerType:
- expr.typ = ptr_typ.ptype
- return ir.Mem(addr)
- else:
- raise SemanticError('Cannot deref non-pointer', expr.loc)
- elif type(expr) is ast.Member:
- base = self.genExprCode(expr.base)
- expr.lvalue = expr.base.lvalue
- basetype = self.the_type(expr.base.typ)
- if type(basetype) is ast.StructureType:
- if basetype.hasField(expr.field):
- expr.typ = basetype.fieldType(expr.field)
- else:
- raise SemanticError('{} does not contain field {}'
- .format(basetype, expr.field), expr.loc)
- else:
- raise SemanticError('Cannot select {} of non-structure type {}'
- .format(expr.field, basetype), expr.loc)
-
- assert type(base) is ir.Mem, type(base)
- bt = self.the_type(expr.base.typ)
- offset = ir.Const(bt.fieldOffset(expr.field))
- return ir.Mem(ir.Add(base.e, offset))
- elif type(expr) is ast.Literal:
- expr.lvalue = False
- typemap = {int: 'int', float: 'double', bool: 'bool', str:'string'}
- if type(expr.val) in typemap:
- expr.typ = self.pkg.scope[typemap[type(expr.val)]]
- else:
- raise SemanticError('Unknown literal type {}'.format(expr.val), expr.loc)
- return ir.Const(expr.val)
- elif type(expr) is ast.TypeCast:
- return self.gen_type_cast(expr)
- elif type(expr) is ast.FunctionCall:
- return self.gen_function_call(expr)
- else:
- raise NotImplementedError('Unknown expr {}'.format(expr))
-
- def gen_type_cast(self, expr):
- """ Generate code for type casting """
- ar = self.genExprCode(expr.a)
- from_type = self.the_type(expr.a.typ)
- to_type = self.the_type(expr.to_type)
- if isinstance(from_type, ast.PointerType) and isinstance(to_type, ast.PointerType):
- expr.typ = expr.to_type
- return ar
- elif type(from_type) is ast.BaseType and from_type.name == 'int' and \
- isinstance(to_type, ast.PointerType):
- expr.typ = expr.to_type
- return ar
- else:
- raise SemanticError('Cannot cast {} to {}'
- .format(from_type, to_type), expr.loc)
-
- def gen_function_call(self, expr):
- """ Generate code for a function call """
- # Evaluate the arguments:
- args = [self.genExprCode(e) for e in expr.args]
- # Check arguments:
- tg = self.resolveSymbol(expr.proc)
- if type(tg) is not ast.Function:
- raise SemanticError('cannot call {}'.format(tg))
- ftyp = tg.typ
- fname = tg.package.name + '_' + tg.name
- ptypes = ftyp.parametertypes
- if len(expr.args) != len(ptypes):
- raise SemanticError('{} requires {} arguments, {} given'
- .format(fname, len(ptypes), len(expr.args)), expr.loc)
- for arg, at in zip(expr.args, ptypes):
- if not self.equalTypes(arg.typ, at):
- raise SemanticError('Got {}, expected {}'
- .format(arg.typ, at), arg.loc)
- # determine return type:
- expr.typ = ftyp.returntype
- return ir.Call(fname, args)
-
- def evalConst(self, c):
- if isinstance(c, ir.Const):
- return c
- else:
- raise SemanticError('Cannot evaluate constant {}'.format(c))
-
- def resolveSymbol(self, sym):
- if type(sym) is ast.Member:
- base = self.resolveSymbol(sym.base)
- if type(base) is not ast.Package:
- raise SemanticError('Base is not a package', sym.loc)
- scope = base.innerScope
- name = sym.field
- elif type(sym) is ast.Identifier:
- scope = sym.scope
- name = sym.target
- else:
- raise NotImplementedError(str(sym))
- if name in scope:
- s = scope[name]
- else:
- raise SemanticError('{} undefined'.format(name), sym.loc)
- assert isinstance(s, ast.Symbol)
- return s
-
- def size_of(self, t):
- """ Determine the byte size of a type """
- t = self.the_type(t)
- if type(t) is ast.BaseType:
- return t.bytesize
- elif type(t) is ast.StructureType:
- return sum(self.size_of(mem.typ) for mem in t.mems)
- else:
- raise NotImplementedError(str(t))
-
- def the_type(self, t):
- """ Recurse until a 'real' type is found """
- if type(t) is ast.DefinedType:
- t = self.the_type(t.typ)
- elif type(t) in [ast.Identifier, ast.Member]:
- t = self.the_type(self.resolveSymbol(t))
- elif type(t) is ast.StructureType:
- # Setup offsets of fields. Is this the right place?:
- offset = 0
- for mem in t.mems:
- mem.offset = offset
- offset = offset + self.size_of(mem.typ)
- elif isinstance(t, ast.Type):
- pass
- else:
- raise NotImplementedError(str(t))
- assert isinstance(t, ast.Type)
- return t
-
- def equalTypes(self, a, b):
- """ Compare types a and b for structural equavalence. """
- # Recurse into named types:
- a = self.the_type(a)
- b = self.the_type(b)
-
- if type(a) is type(b):
- if type(a) is ast.BaseType:
- return a.name == b.name
- elif type(a) is ast.PointerType:
- return self.equalTypes(a.ptype, b.ptype)
- elif type(a) is ast.StructureType:
- if len(a.mems) != len(b.mems):
- return False
- return all(self.equalTypes(am.typ, bm.typ) for am, bm in
- zip(a.mems, b.mems))
- else:
- raise NotImplementedError('{} not implemented'.format(type(a)))
- return False
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/c3/lexer.py
--- a/python/ppci/c3/lexer.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-import re
-from ppci import CompilerError, SourceLocation, Token
-import baselex
-
-"""
- Lexical analyzer part. Splits the input character stream into tokens.
-"""
-
-keywords = ['and', 'or', 'not', 'true', 'false',
- 'else', 'if', 'while', 'for', 'return',
- 'function', 'var', 'type', 'const',
- 'struct', 'cast',
- 'import', 'module']
-
-
-class Lexer:
- """ Generates a sequence of token from an input stream """
- def __init__(self, diag):
- self.diag = diag
-
- def lex(self, source):
- return self.tokenize(source)
-
- def tokenize(self, input_file):
- """
- Tokenizer, generates an iterator that
- returns tokens!
-
- Input is a file like object.
-
- This GREAT example was taken from python re doc page!
- """
- filename = input_file.name if hasattr(input_file, 'name') else ''
- s = input_file.read()
- input_file.close()
- self.diag.addSource(filename, s)
- tok_spec = [
- ('REAL', r'\d+\.\d+'),
- ('HEXNUMBER', r'0x[\da-fA-F]+'),
- ('NUMBER', r'\d+'),
- ('ID', r'[A-Za-z][A-Za-z\d_]*'),
- ('NEWLINE', r'\n'),
- ('SKIP', r'[ \t]'),
- ('COMMENTS', r'//.*'),
- ('LONGCOMMENTBEGIN', r'\/\*'),
- ('LONGCOMMENTEND', r'\*\/'),
- ('LEESTEKEN', r'==|->|<<|>>|!=|\+\+|[\.,=:;\-+*\[\]/\(\)]|>=|<=|<>|>|<|{|}|&|\^|\|'),
- ('STRING', r"'.*?'")
- ]
- tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec)
- gettok = re.compile(tok_re).match
- line = 1
- pos = line_start = 0
- mo = gettok(s)
- incomment = False
- while mo is not None:
- typ = mo.lastgroup
- val = mo.group(typ)
- if typ == 'NEWLINE':
- line_start = pos
- line += 1
- elif typ == 'COMMENTS':
- pass
- elif typ == 'LONGCOMMENTBEGIN':
- incomment = True
- elif typ == 'LONGCOMMENTEND':
- incomment = False
- elif typ == 'SKIP':
- pass
- elif incomment:
- pass # Wait until we are not in a comment section
- else:
- if typ == 'ID':
- if val in keywords:
- typ = val
- elif typ == 'LEESTEKEN':
- typ = val
- elif typ == 'NUMBER':
- val = int(val)
- elif typ == 'HEXNUMBER':
- val = int(val[2:], 16)
- typ = 'NUMBER'
- elif typ == 'REAL':
- val = float(val)
- elif typ == 'STRING':
- val = val[1:-1]
- loc = SourceLocation(filename, line, mo.start() - line_start,
- mo.end() - mo.start())
- yield Token(typ, val, loc)
- pos = mo.end()
- mo = gettok(s, pos)
- if pos != len(s):
- col = pos - line_start
- loc = SourceLocation(filename, line, col, 1)
- raise CompilerError('Unexpected: "{0}"'.format(s[pos]), loc)
- loc = SourceLocation(filename, line, 0, 0)
- yield Token('END', '', loc)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/c3/parser.py
--- a/python/ppci/c3/parser.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,412 +0,0 @@
-import logging
-from ppci import CompilerError
-from .astnodes import Member, Literal, TypeCast, Unop, Binop
-from .astnodes import Assignment, ExpressionStatement, Compound
-from .astnodes import Return, While, If, Empty, For
-from .astnodes import FunctionType, Function, FormalParameter
-from .astnodes import StructureType, DefinedType, PointerType
-from .astnodes import Constant, Variable
-from .astnodes import StructField, Deref
-from .astnodes import Package
-from .astnodes import Identifier
-from .astnodes import FunctionCall
-
-
-class Parser:
- """ Parses sourcecode into an abstract syntax tree (AST) """
- def __init__(self, diag):
- self.logger = logging.getLogger('c3')
- self.diag = diag
-
- def parseSource(self, tokens):
- self.logger.debug('Parsing source')
- self.tokens = tokens
- self.token = self.tokens.__next__()
- try:
- self.parsePackage()
- self.mod.ok = True # Valid until proven wrong :)
- return self.mod
- except CompilerError as e:
- self.diag.addDiag(e)
-
- def Error(self, msg):
- raise CompilerError(msg, self.token.loc)
-
- # Lexer helpers:
- def Consume(self, typ):
- if self.Peak == typ:
- return self.NextToken()
- else:
- self.Error('Excected: "{0}", got "{1}"'.format(typ, self.Peak))
-
- @property
- def Peak(self):
- return self.token.typ
-
- @property
- def CurLoc(self):
- return self.token.loc
-
- def hasConsumed(self, typ):
- if self.Peak == typ:
- self.Consume(typ)
- return True
- return False
-
- def NextToken(self):
- t = self.token
- if t.typ != 'END':
- self.token = self.tokens.__next__()
- return t
-
- def addDeclaration(self, decl):
- self.currentPart.add_declaration(decl)
-
- def parseImport(self):
- self.Consume('import')
- name = self.Consume('ID').val
- self.mod.imports.append(name)
- self.Consume(';')
-
- def parsePackage(self):
- self.Consume('module')
- name = self.Consume('ID')
- self.Consume(';')
- self.mod = Package(name.val, name.loc)
- self.currentPart = self.mod
- while self.Peak != 'END':
- self.parseTopLevel()
- self.Consume('END')
-
- def parseTopLevel(self):
- if self.Peak == 'function':
- self.parseFunctionDef()
- elif self.Peak == 'var':
- self.parseVarDef()
- # TODO handle variable initialization
- elif self.Peak == 'const':
- self.parseConstDef()
- elif self.Peak == 'type':
- self.parseTypeDef()
- elif self.Peak == 'import':
- self.parseImport()
- else:
- self.Error('Expected function, var, const or type')
-
- def parseDesignator(self):
- """ A designator designates an object with a name. """
- name = self.Consume('ID')
- return Identifier(name.val, name.loc)
-
- def parseIdSequence(self):
- ids = [self.Consume('ID')]
- while self.hasConsumed(','):
- ids.append(self.Consume('ID'))
- return ids
-
- # Type system
- def parseTypeSpec(self):
- # For now, do simple type spec, just parse an ID:
- if self.Peak == 'struct':
- self.Consume('struct')
- self.Consume('{')
- mems = []
- while self.Peak != '}':
- mem_t = self.parseTypeSpec()
- for i in self.parseIdSequence():
- mems.append(StructField(i.val, mem_t))
- self.Consume(';')
- self.Consume('}')
- theT = StructureType(mems)
- elif self.Peak == 'enum':
- # TODO)
- raise NotImplementedError()
- else:
- theT = self.PostFixExpression()
- # Check for pointer suffix:
- while self.hasConsumed('*'):
- theT = PointerType(theT)
- return theT
-
- def parseTypeDef(self):
- self.Consume('type')
- newtype = self.parseTypeSpec()
- typename = self.Consume('ID')
- self.Consume(';')
- df = DefinedType(typename.val, newtype, typename.loc)
- self.addDeclaration(df)
-
- # Variable declarations:
- def parseVarDef(self):
- self.Consume('var')
- t = self.parseTypeSpec()
- for name in self.parseIdSequence():
- v = Variable(name.val, t)
- v.loc = name.loc
- self.addDeclaration(v)
- self.Consume(';')
- return Empty()
-
- def parseConstDef(self):
- self.Consume('const')
- t = self.parseTypeSpec()
- while True:
- name = self.Consume('ID')
- self.Consume('=')
- val = self.Expression()
- c = Constant(name.val, t, val)
- self.addDeclaration(c)
- c.loc = name.loc
- if not self.hasConsumed(','):
- break
- self.Consume(';')
-
- def parseFunctionDef(self):
- loc = self.Consume('function').loc
- returntype = self.parseTypeSpec()
- fname = self.Consume('ID').val
- f = Function(fname, loc)
- self.addDeclaration(f)
- savePart = self.currentPart
- self.currentPart = f
- self.Consume('(')
- parameters = []
- if not self.hasConsumed(')'):
- while True:
- typ = self.parseTypeSpec()
- name = self.Consume('ID')
- param = FormalParameter(name.val, typ)
- param.loc = name.loc
- self.addDeclaration(param)
- parameters.append(param)
- if not self.hasConsumed(','):
- break
- self.Consume(')')
- paramtypes = [p.typ for p in parameters]
- f.typ = FunctionType(paramtypes, returntype)
- f.body = self.parseCompound()
- self.currentPart = savePart
-
- def parseIf(self):
- loc = self.Consume('if').loc
- self.Consume('(')
- condition = self.Expression()
- self.Consume(')')
- yes = self.Statement()
- no = self.Statement() if self.hasConsumed('else') else Empty()
- return If(condition, yes, no, loc)
-
- def parseWhile(self):
- loc = self.Consume('while').loc
- self.Consume('(')
- condition = self.Expression()
- self.Consume(')')
- statements = self.Statement()
- return While(condition, statements, loc)
-
- def parseFor(self):
- loc = self.Consume('for').loc
- self.Consume('(')
- init = self.Statement()
- self.Consume(';')
- condition = self.Expression()
- self.Consume(';')
- final = self.Statement()
- self.Consume(')')
- statements = self.Statement()
- return For(init, condition, final, statements, loc)
-
- def parseReturn(self):
- loc = self.Consume('return').loc
- if self.Peak == ';':
- expr = Literal(0, loc)
- else:
- expr = self.Expression()
- self.Consume(';')
- return Return(expr, loc)
-
- def parseCompound(self):
- self.Consume('{')
- statements = []
- while not self.hasConsumed('}'):
- statements.append(self.Statement())
- return Compound(statements)
-
- def Statement(self):
- # Determine statement type based on the pending token:
- if self.Peak == 'if':
- return self.parseIf()
- elif self.Peak == 'while':
- return self.parseWhile()
- elif self.Peak == 'for':
- return self.parseFor()
- elif self.Peak == '{':
- return self.parseCompound()
- elif self.hasConsumed(';'):
- return Empty()
- elif self.Peak == 'var':
- return self.parseVarDef()
- elif self.Peak == 'return':
- return self.parseReturn()
- else:
- x = self.UnaryExpression()
- if self.Peak == '=':
- # We enter assignment mode here.
- loc = self.Consume('=').loc
- rhs = self.Expression()
- return Assignment(x, rhs, loc)
- else:
- return ExpressionStatement(x, x.loc)
-
- # Expression section:
- # We not implement these C constructs:
- # a(2), f = 2
- # and this:
- # a = 2 < x : 4 ? 1;
-
- def Expression(self):
- exp = self.LogicalAndExpression()
- while self.Peak == 'or':
- loc = self.Consume('or').loc
- e2 = self.LogicalAndExpression()
- exp = Binop(exp, 'or', e2, loc)
- return exp
-
- def LogicalAndExpression(self):
- o = self.EqualityExpression()
- while self.Peak == 'and':
- loc = self.Consume('and').loc
- o2 = self.EqualityExpression()
- o = Binop(o, 'and', o2, loc)
- return o
-
- def EqualityExpression(self):
- ee = self.SimpleExpression()
- while self.Peak in ['<', '==', '>', '>=', '<=', '!=']:
- op = self.Consume(self.Peak)
- ee2 = self.SimpleExpression()
- ee = Binop(ee, op.typ, ee2, op.loc)
- return ee
-
- def SimpleExpression(self):
- """ Shift operations before + and - ? """
- e = self.AddExpression()
- while self.Peak in ['>>', '<<']:
- op = self.Consume(self.Peak)
- e2 = self.AddExpression()
- e = Binop(e, op.typ, e2, op.loc)
- return e
-
- def AddExpression(self):
- e = self.Term()
- while self.Peak in ['+', '-']:
- op = self.Consume(self.Peak)
- e2 = self.Term()
- e = Binop(e, op.typ, e2, op.loc)
- return e
-
- def Term(self):
- t = self.BitwiseOr()
- while self.Peak in ['*', '/']:
- op = self.Consume(self.Peak)
- t2 = self.BitwiseOr()
- t = Binop(t, op.typ, t2, op.loc)
- return t
-
- def BitwiseOr(self):
- a = self.BitwiseAnd()
- while self.Peak == '|':
- op = self.Consume(self.Peak)
- b = self.BitwiseAnd()
- a = Binop(a, op.typ, b, op.loc)
- return a
-
- def BitwiseAnd(self):
- a = self.CastExpression()
- while self.Peak == '&':
- op = self.Consume(self.Peak)
- b = self.CastExpression()
- a = Binop(a, op.typ, b, op.loc)
- return a
-
- # Domain of unary expressions:
-
- def CastExpression(self):
- """
- the C-style type cast conflicts with '(' expr ')'
- so introduce extra keyword 'cast'
- """
- if self.Peak == 'cast':
- loc = self.Consume('cast').loc
- self.Consume('<')
- t = self.parseTypeSpec()
- self.Consume('>')
- self.Consume('(')
- ce = self.Expression()
- self.Consume(')')
- return TypeCast(t, ce, loc)
- else:
- return self.UnaryExpression()
-
- def UnaryExpression(self):
- if self.Peak in ['&', '*']:
- op = self.Consume(self.Peak)
- ce = self.CastExpression()
- if op.val == '*':
- return Deref(ce, op.loc)
- else:
- return Unop(op.typ, ce, op.loc)
- else:
- return self.PostFixExpression()
-
- def PostFixExpression(self):
- pfe = self.PrimaryExpression()
- while self.Peak in ['[', '.', '->', '(', '++']:
- if self.hasConsumed('['):
- raise NotImplementedError('Array not yet implemented')
- elif self.hasConsumed('->'):
- field = self.Consume('ID')
- pfe = Deref(pfe, pfe.loc)
- pfe = Member(pfe, field.val, field.loc)
- elif self.hasConsumed('.'):
- field = self.Consume('ID')
- pfe = Member(pfe, field.val, field.loc)
- elif self.Peak == '++':
- loc = self.Consume('++').loc
- pfe = Unop('++', pfe, loc)
- elif self.hasConsumed('('):
- # Function call
- args = []
- if not self.hasConsumed(')'):
- args.append(self.Expression())
- while self.hasConsumed(','):
- args.append(self.Expression())
- self.Consume(')')
- pfe = FunctionCall(pfe, args, pfe.loc)
- else:
- raise Exception()
- return pfe
-
- def PrimaryExpression(self):
- if self.hasConsumed('('):
- e = self.Expression()
- self.Consume(')')
- return e
- elif self.Peak == 'NUMBER':
- val = self.Consume('NUMBER')
- return Literal(val.val, val.loc)
- elif self.Peak == 'REAL':
- val = self.Consume('REAL')
- return Literal(val.val, val.loc)
- elif self.Peak == 'true':
- val = self.Consume('true')
- return Literal(True, val.loc)
- elif self.Peak == 'false':
- val = self.Consume('false')
- return Literal(False, val.loc)
- elif self.Peak == 'STRING':
- val = self.Consume('STRING')
- return Literal(val.val, val.loc)
- elif self.Peak == 'ID':
- return self.parseDesignator()
- self.Error('Expected NUM, ID or (expr), got {0}'.format(self.Peak))
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/c3/scope.py
--- a/python/ppci/c3/scope.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-from .astnodes import Constant, Variable, Function, BaseType, Symbol
-
-
-class Scope:
- """ A scope contains all symbols in a scope. It also has a parent scope,
- when looking for a symbol, also the parent scopes are checked. """
- def __init__(self, parent=None):
- self.symbols = {}
- self.parent = parent
-
- def __iter__(self):
- # Iterate in a deterministic manner:
- return iter(self.Constants + self.Variables + self.Functions)
-
- @property
- def Syms(self):
- syms = self.symbols.values()
- return sorted(syms, key=lambda v: v.name)
-
- @property
- def Constants(self):
- return [s for s in self.Syms if type(s) is Constant]
-
- @property
- def Variables(self):
- return [s for s in self.Syms if isinstance(s, Variable)]
-
- @property
- def Functions(self):
- return [s for s in self.Syms if type(s) is Function]
-
- def getSymbol(self, name):
- if name in self.symbols:
- return self.symbols[name]
- # Look for symbol:
- elif self.parent:
- return self.parent.getSymbol(name)
- else:
- raise KeyError(name)
-
- def __getitem__(self, key):
- return self.getSymbol(key)
-
- def hasSymbol(self, name):
- if name in self.symbols:
- return True
- elif self.parent:
- return self.parent.hasSymbol(name)
- else:
- return False
-
- def __contains__(self, name):
- return self.hasSymbol(name)
-
- def addSymbol(self, sym):
- assert sym.name not in self.symbols
- assert isinstance(sym, Symbol)
- self.symbols[sym.name] = sym
-
- def __repr__(self):
- return 'Scope with {} symbols'.format(len(self.symbols))
-
-
-def createTopScope(target):
- scope = Scope()
- for tn in ['u64', 'u32', 'u16', 'u8']:
- scope.addSymbol(BaseType(tn))
- # buildin types:
- intType = BaseType('int')
- intType.bytesize = target.byte_sizes['int']
- scope.addSymbol(intType)
- scope.addSymbol(BaseType('double'))
- scope.addSymbol(BaseType('void'))
- scope.addSymbol(BaseType('bool'))
- scope.addSymbol(BaseType('string'))
- scope.addSymbol(BaseType('byte'))
- return scope
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/c3/visitor.py
--- a/python/ppci/c3/visitor.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-from .astnodes import *
-
-
-class Visitor:
- """
- Visitor that can visit all nodes in the AST
- and run pre and post functions.
- """
- def visit(self, node, f_pre=None, f_post=None):
- self.f_pre = f_pre
- self.f_post = f_post
- self.do(node)
-
- def do(self, node):
- # Run pre function:
- if self.f_pre:
- self.f_pre(node)
-
- # Descent into subnodes:
- if type(node) is Package:
- for decl in node.declarations:
- self.do(decl)
- elif type(node) is Function:
- for s in node.declarations:
- self.do(s)
- self.do(node.typ)
- self.do(node.body)
- elif type(node) is Compound:
- for s in node.statements:
- self.do(s)
- elif type(node) is If:
- self.do(node.condition)
- self.do(node.truestatement)
- self.do(node.falsestatement)
- elif type(node) is While:
- self.do(node.condition)
- self.do(node.statement)
- elif type(node) is For:
- self.do(node.init)
- self.do(node.condition)
- self.do(node.final)
- self.do(node.statement)
- elif type(node) is Assignment:
- self.do(node.lval)
- self.do(node.rval)
- elif type(node) is FunctionCall:
- for arg in node.args:
- self.do(arg)
- self.do(node.proc)
- elif type(node) is Return:
- self.do(node.expr)
- elif type(node) is Binop:
- self.do(node.a)
- self.do(node.b)
- elif type(node) is Unop:
- self.do(node.a)
- elif type(node) is ExpressionStatement:
- self.do(node.ex)
- elif type(node) is TypeCast:
- self.do(node.a)
- self.do(node.to_type)
- elif type(node) is Member:
- self.do(node.base)
- elif type(node) is Deref:
- self.do(node.ptr)
- elif type(node) is Constant:
- self.do(node.typ)
- self.do(node.value)
- elif type(node) is DefinedType:
- self.do(node.typ)
- elif isinstance(node, Variable):
- self.do(node.typ)
- elif type(node) is PointerType:
- self.do(node.ptype)
- elif type(node) is StructureType:
- for m in node.mems:
- self.do(m.typ)
- elif type(node) is FunctionType:
- for pt in node.parametertypes:
- self.do(pt)
- self.do(node.returntype)
- elif type(node) in [Identifier, Literal, Empty]:
- # Those nodes do not have child nodes.
- pass
- else:
- raise Exception('Could not visit "{0}"'.format(node))
-
- # run post function
- if self.f_post:
- self.f_post(node)
-
-
-class AstPrinter:
- """ Prints an AST as text """
- def printAst(self, pkg, f):
- self.indent = 2
- self.f = f
- visitor = Visitor()
- visitor.visit(pkg, self.print1, self.print2)
-
- def print1(self, node):
- print(' ' * self.indent + str(node), file=self.f)
- self.indent += 2
-
- def print2(self, node):
- self.indent -= 2
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/codegen/__init__.py
--- a/python/ppci/codegen/__init__.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-from .codegen import CodeGenerator
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/codegen/canon.py
--- a/python/ppci/codegen/canon.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-from .. import ir
-from .. import irutils
-from itertools import chain
-
-def make(function, frame):
- """
- Create canonicalized version of the IR-code. This means:
- - Calls out of expressions.
- - Other things?
- """
- # Change the tree. This modifies the IR-tree!
- # Move all parameters into registers
- parmoves = []
- for p in function.arguments:
- pt = newTemp()
- frame.parMap[p] = pt
- parmoves.append(ir.Move(pt, frame.argLoc(p.num)))
- function.entry.instructions = parmoves + function.entry.instructions
-
- for block in function.Blocks:
- for stmt in block.instructions:
- rewriteStmt(stmt, frame)
- linearize(block)
- # TODO: schedule here?
-
-# Visit all nodes with some function:
-# TODO: rewrite into visitor.
-
-# Rewrite rewrites call instructions into Eseq instructions.
-
-
-def rewriteStmt(stmt, frame):
- if isinstance(stmt, ir.Jump):
- pass
- elif isinstance(stmt, ir.CJump):
- stmt.a = rewriteExp(stmt.a, frame)
- stmt.b = rewriteExp(stmt.b, frame)
- elif isinstance(stmt, ir.Move):
- stmt.src = rewriteExp(stmt.src, frame)
- stmt.dst = rewriteExp(stmt.dst, frame)
- elif isinstance(stmt, ir.Terminator):
- pass
- elif isinstance(stmt, ir.Exp):
- stmt.e = rewriteExp(stmt.e, frame)
- else:
- raise NotImplementedError('STMT NI: {}'.format(stmt))
-
-newTemp = irutils.NamedClassGenerator('canon_reg', ir.Temp).gen
-
-def rewriteExp(exp, frame):
- if isinstance(exp, ir.Binop):
- exp.a = rewriteExp(exp.a, frame)
- exp.b = rewriteExp(exp.b, frame)
- return exp
- elif isinstance(exp, ir.Const):
- return exp
- elif isinstance(exp, ir.Temp):
- return exp
- elif isinstance(exp, ir.Parameter):
- return frame.parMap[exp]
- elif isinstance(exp, ir.LocalVariable):
- offset = frame.allocVar(exp)
- return ir.Add(frame.fp, ir.Const(offset))
- elif isinstance(exp, ir.Mem):
- exp.e = rewriteExp(exp.e, frame)
- return exp
- elif isinstance(exp, ir.Call):
- exp.arguments = [rewriteExp(p, frame) for p in exp.arguments]
- # Rewrite call into eseq:
- t = newTemp()
- return ir.Eseq(ir.Move(t, exp), t)
- else:
- raise NotImplementedError('NI: {}'.format(exp))
-
-# The flatten functions pull out seq instructions to the sequence list.
-
-def flattenExp(exp):
- if isinstance(exp, ir.Binop):
- exp.a, sa = flattenExp(exp.a)
- exp.b, sb = flattenExp(exp.b)
- return exp, sa + sb
- elif isinstance(exp, ir.Temp):
- return exp, []
- elif isinstance(exp, ir.Const):
- return exp, []
- elif isinstance(exp, ir.Mem):
- exp.e, s = flattenExp(exp.e)
- return exp, s
- elif isinstance(exp, ir.Eseq):
- s = flattenStmt(exp.stmt)
- exp.e, se = flattenExp(exp.e)
- return exp.e, s + se
- elif isinstance(exp, ir.Call):
- sp = []
- p = []
- for p_, sp_ in (flattenExp(p) for p in exp.arguments):
- p.append(p_)
- sp.extend(sp_)
- exp.arguments = p
- return exp, sp
- else:
- raise NotImplementedError('NI: {}'.format(exp))
-
-
-def flattenStmt(stmt):
- if isinstance(stmt, ir.Jump):
- return [stmt]
- elif isinstance(stmt, ir.CJump):
- stmt.a, sa = flattenExp(stmt.a)
- stmt.b, sb = flattenExp(stmt.b)
- return sa + sb + [stmt]
- elif isinstance(stmt, ir.Move):
- stmt.dst, sd = flattenExp(stmt.dst)
- stmt.src, ss = flattenExp(stmt.src)
- return sd + ss + [stmt]
- elif isinstance(stmt, ir.Terminator):
- return [stmt]
- elif isinstance(stmt, ir.Exp):
- stmt.e, se = flattenExp(stmt.e)
- return se + [stmt]
- else:
- raise NotImplementedError('STMT NI: {}'.format(stmt))
-
-
-def linearize(block):
- """
- Move seq instructions to top and flatten these in an instruction list
- """
- i = list(flattenStmt(s) for s in block.instructions)
- block.instructions = list(chain.from_iterable(i))
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/codegen/codegen.py
--- a/python/ppci/codegen/codegen.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-from .. import ir
-from ..irutils import Verifier
-from ..target import Target
-from .. import CompilerError
-from .canon import make as canonicalize
-from .registerallocator import RegisterAllocator
-import logging
-
-
-class CodeGenerator:
- """ Generic code generator """
- def __init__(self, target):
- # TODO: schedule traces in better order.
- # This is optional!
- assert isinstance(target, Target), target
- self.logger = logging.getLogger('codegen')
- self.target = target
- self.ins_sel = target.ins_sel
- self.ra = RegisterAllocator()
- self.verifier = Verifier()
-
- def generateFunc(self, irfunc, outs):
- """ Generate code for one function into a frame """
- self.logger.debug('Generating code for {}'.format(irfunc.name))
- # Create a frame for this function:
- frame = self.target.FrameClass(ir.label_name(irfunc))
-
- # Canonicalize the intermediate language:
- canonicalize(irfunc, frame)
- self.logger.debug('after canonicalize', extra={'irfunc': irfunc})
- self.verifier.verify_function(irfunc)
- self.ins_sel.munchFunction(irfunc, frame)
- self.logger.debug('Selected instructions', extra={'ppci_frame': frame})
-
- # Do register allocation:
- self.ra.allocFrame(frame)
- self.logger.debug('Registers allocated, now adding final glue')
- # TODO: Peep-hole here?
-
- # Add label and return and stack adjustment:
- frame.EntryExitGlue3()
-
- # Materialize the register allocated instructions into a stream of
- # real instructions.
- self.target.lower_frame_to_stream(frame, outs)
- self.logger.debug('Instructions materialized')
- return frame
-
- def generate(self, ircode, outs):
- """ Generate code into output stream """
- assert isinstance(ircode, ir.Module)
- outs.selectSection('code')
-
- # Munch program into a bunch of frames. One frame per function.
- # Each frame has a flat list of abstract instructions.
- # Generate code for all functions:
- self.frames = [self.generateFunc(f, outs) for f in ircode.Functions]
- return self.frames
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/codegen/dag.py
--- a/python/ppci/codegen/dag.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-
-# Instruction selection with DAG (Directed Acyclic Graph)
-class DagLeaf:
- def __init__(self, v):
- self.v = v
-
-class DagNode:
- def __init__(self, name):
- self.name = name
- self.children = []
- def __repr__(self):
- return str(self.name)
-
-class Dag:
- def __init__(self, bb):
- self.mapping = {}
- self.buildFromBB(bb)
-
- def buildFromBB(self, bb):
- for ins in bb.Instructions:
- if type(ins) is ir.BinaryOperator:
- if not ins.value1 in self.mapping:
- self.mapping[ins.value1] = DagNode(ins.value1)
- if not ins.value2 in self.mapping:
- self.mapping[ins.value2] = DagNode(ins.value2)
- # look for op with left and right operand the same:
- N = None
- lnode = self.mapping[ins.value1]
- rnode = self.mapping[ins.value2]
- for node in self.mapping.values():
- if node.name == ins.operation:
- if node.children[0] == lnode and node.children[1] == rnode:
- N = node
- break
- if not N:
- # Create a node.
- N = DagNode(ins.operation)
- N.children.append(lnode)
- N.children.append(rnode)
- self.mapping[ins.result] = N
- else:
- pass
-
- def dumpgv(self, outf):
- outf.write('subgraph {0} {{\n'.format(id(self)))
- for node in self.mapping.values():
- outf.write('{0} [label="{1}"];\n'.format(id(node), node.name))
- for c in node.children:
- outf.write('{0} -> {1};\n'.format(id(node), id(c)))
- outf.write('label="dag"}\n')
-
-def insSelect(mod):
- """ Create DAG from ir-code """
- for bb in mod.BasicBlocks:
- print(bb)
- dag = Dag(bb)
- print(dag.mapping)
- bb.dag = dag
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/codegen/flowgraph.py
--- a/python/ppci/codegen/flowgraph.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-from .graph import DiGraph, DiNode
-
-
-class FlowGraphNode(DiNode):
- """ A node in the flow graph """
- def __init__(self, g, ins):
- super().__init__(g)
- self.ins = ins
- self.uses = set(ins.src)
- self.defs = set(ins.dst)
- self.live_in = set()
- self.live_out = set()
-
- def __repr__(self):
- r = '{}'.format(self.ins)
- if self.uses:
- r += ' uses:' + ', '.join(str(u) for u in self.uses)
- if self.defs:
- r += ' defs:' + ', '.join(str(d) for d in self.defs)
- return r
-
-
-
-class FlowGraph(DiGraph):
- def __init__(self, instrs):
- """ Create a flowgraph from a list of abstract instructions """
- super().__init__()
- self._map = {}
- # Add nodes:
- for ins in instrs:
- n = FlowGraphNode(self, ins)
- self._map[ins] = n
- self.add_node(n)
-
- # Make edges:
- prev = None
- for ins in instrs:
- n = self._map[ins]
- if prev:
- self.addEdge(prev, n)
- if ins.jumps:
- prev = None
- for j in ins.jumps:
- to_n = self._map[j]
- self.addEdge(n, to_n)
- else:
- prev = n
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/codegen/graph.py
--- a/python/ppci/codegen/graph.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-
-class Graph:
- """
- Generic graph base class.
- Can dump to graphiz dot format for example!
- """
- def __init__(self):
- self.nodes = set()
- self.edges = set()
- self.adj_map = {}
-
- def add_node(self, n):
- self.nodes.add(n)
- if n not in self.adj_map:
- self.adj_map[n] = set()
-
- def delNode(self, n):
- self.nodes.remove(n)
-
- def addEdge(self, n, m):
- """ Add an edge from n to m """
- self.edges.add((n, m))
- self.edges.add((m, n))
- self.adj_map[n].add(m)
- self.adj_map[m].add(n)
-
- def hasEdge(self, n, m):
- return (n, m) in self.edges
-
- def delEdge(self, n, m):
- self.edges.remove((n, m))
- self.edges.remove((m, n))
-
- def adjecent(self, n):
- """ Return all nodes with edges to n """
- return self.adj_map[n] & self.nodes
-
- def to_dot(self, f):
- """ Generate graphviz dot representation """
- for n in self.nodes:
- print(' {} [label="{}" shape=box3d];'.format(id(n), n), file=f)
- for n, m in self.edges:
- print(' {} -> {};'.format(id(n), id(m)), file=f)
-
-
-class Node:
- """
- Node in a graph.
- """
- def __init__(self, g):
- self.g = g
- self.addDegree = 0 # Hack to increase degree
-
- @property
- def Adjecent(self):
- return self.g.adjecent(self)
-
- @property
- def Degree(self):
- return len(self.Adjecent) + self.addDegree
-
-
-class DiGraph(Graph):
- """ Directed graph. """
- def __init__(self):
- super().__init__()
- self.suc_map = {}
- self.pre_map = {}
-
- def addEdge(self, n, m):
- """ Add a directed edge from n to m """
- assert n in self.nodes
- assert m in self.nodes
- self.edges.add((n, m))
- self.suc_map[n].add(m)
- self.pre_map[m].add(n)
- self.adj_map[n].add(m)
- self.adj_map[m].add(n)
-
- def add_node(self, n):
- super().add_node(n)
- if n not in self.suc_map:
- self.suc_map[n] = set()
- if n not in self.pre_map:
- self.pre_map[n] = set()
-
- def hasEdge(self, n, m):
- return (n, m) in self.edges
-
- def successors(self, n):
- return self.suc_map[n] & self.nodes
-
- def predecessors(self, n):
- return self.pre_map[n] & self.nodes
-
-
-class DiNode(Node):
- @property
- def Succ(self):
- return self.g.successors(self)
-
- @property
- def Pred(self):
- return self.g.predecessors(self)
-
- def __gt__(self, other):
- return self in other.Succ
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/codegen/interferencegraph.py
--- a/python/ppci/codegen/interferencegraph.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-import logging
-from .graph import Graph, Node
-
-
-class InterferenceGraphNode(Node):
- def __init__(self, g, varname):
- super().__init__(g)
- self.temps = [varname]
- self.moves = set()
- self.color = None
-
- def __repr__(self):
- return '{}({})'.format(self.temps, self.color)
-
-
-class InterferenceGraph(Graph):
- """
- Interference graph.
- """
- def __init__(self, flowgraph):
- """ Create a new interference graph from a flowgraph """
- super().__init__()
- self.logger = logging.getLogger('interferencegraph')
- # Calculate liveness in CFG:
- ###
- # Liveness:
- # in[n] = use[n] UNION (out[n] - def[n])
- # out[n] = for s in n.succ in union in[s]
- ###
- for n in flowgraph.nodes:
- n.live_in = set()
- n.live_out = set()
-
- # Sort flowgraph nodes backwards:
- cfg_nodes = list(flowgraph.nodes)
- self.logger.debug('CFG nodes: {}'.format(cfg_nodes))
- cfg_nodes.sort(reverse=True)
-
- # Dataflow fixed point iteration:
- n_iterations = 0
- change = True
- while change:
- change = False
- for n in cfg_nodes:
- _in = n.live_in
- _out = n.live_out
- n.live_in = n.uses | (n.live_out - n.defs)
- if n.Succ:
- n.live_out = set.union(*(s.live_in for s in n.Succ))
- else:
- n.live_out = set()
- n.live_out = n.live_out | n.defs
- change = change or (_in != n.live_in) or (_out != n.live_out)
- n_iterations += 1
-
- self.logger.debug('Iterations: {} * {}'.format(n_iterations, len(cfg_nodes)))
- # Construct interference graph:
- for n in flowgraph.nodes:
- for tmp in n.live_out:
- n1 = self.getNode(tmp)
- for tmp2 in (n.live_out - {tmp}):
- n2 = self.getNode(tmp2)
- self.addEdge(n1, n2)
-
- def to_dot(self, f):
- """ Generate graphviz dot representation """
- for n in self.nodes:
- print(' {} [label="{}" shape=box3d];'.format(id(n), n), file=f)
- for n, m in self.edges:
- print(' {} -> {};'.format(id(n), id(m)), file=f)
-
- def to_txt(self):
- for node in self.nodes:
- print('{} interferes: {}'.format(node, node.Adjecent))
-
- def getNode(self, tmp):
- # Linear search
- # TODO: can be improved for speed!
- for n in self.nodes:
- if tmp in n.temps:
- return n
- n = InterferenceGraphNode(self, tmp)
- self.add_node(n)
- return n
-
- def Combine(self, n, m):
- """ Combine n and m into n """
- n.temps.extend(m.temps)
- n.moves.update(m.moves)
- # Reroute all edges:
- e1 = [e for e in self.edges if e[0] is m]
- e2 = [e for e in self.edges if e[1] is m]
- for e in e1:
- self.edges.remove(e)
- self.addEdge(n, e[1])
- for e in e2:
- self.edges.remove(e)
- self.addEdge(n, e[0])
- # Remove node m:
- self.delNode(m)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/codegen/registerallocator.py
--- a/python/ppci/codegen/registerallocator.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-import logging
-from .flowgraph import FlowGraph
-from .interferencegraph import InterferenceGraph
-
-# Nifty first function:
-first = lambda x: next(iter(x))
-
-
-class RegisterAllocator:
- """
- Target independent register allocator.
-
- Algorithm is iterated register coalescing by Appel and George.
-
- Chaitin's algorithm: remove all nodes with less than K neighbours.
- These nodes can be colored when added back.
-
- The process consists of the following steps:
- - build interference graph from the instruction list
- - remove low degree non move related nodes.
- - (optional) coalesc registers to remove redundant moves
- - (optional) spill registers
- - select registers
- """
- def __init__(self):
- self.logger = logging.getLogger('registerallocator')
-
- def InitData(self, f):
- self.f = f
- # Register information:
- self.regs = set(f.regs)
- self.K = len(self.regs)
-
- # Move related sets:
- self.coalescedMoves = set()
- self.constrainedMoves = set()
- self.frozenMoves = set()
- self.activeMoves = set()
- self.worklistMoves = set()
-
- def Build(self):
- """ 1. Construct interference graph from instruction list """
- self.f.cfg = FlowGraph(self.f.instructions)
- self.logger.debug('Constructed flowgraph', extra={'ra_cfg':self.f.cfg})
- self.f.ig = InterferenceGraph(self.f.cfg)
- self.logger.debug('Constructed interferencegraph', extra={'ra_ig':self.f.ig})
-
- self.Node = self.f.ig.getNode
-
- # Divide nodes into pre-colored and initial:
- pre_tmp = list(self.f.tempMap.keys())
- self.precolored = set(self.Node(tmp) for tmp in pre_tmp)
- self.workSet = set(self.f.ig.nodes - self.precolored)
-
- for n in self.precolored:
- n.addDegree = 100 + len(self.f.ig.nodes) + self.K
-
- # Initialize color map:
- self.color = {}
- for tmp, c in self.f.tempMap.items():
- self.color[self.Node(tmp)] = c
-
- self.moves = [i for i in self.f.instructions if i.ismove]
- for mv in self.moves:
- self.Node(mv.src[0]).moves.add(mv)
- self.Node(mv.dst[0]).moves.add(mv)
-
- def NodeMoves(self, n):
- return n.moves & (self.activeMoves | self.worklistMoves)
-
- def MoveRelated(self, n):
- return bool(self.NodeMoves(n))
-
- @property
- def SpillWorkSet(self):
- c = lambda n: n.Degree >= self.K
- return set(filter(c, self.workSet))
-
- @property
- def FreezeWorkSet(self):
- c = lambda n: n.Degree < self.K and self.MoveRelated(n)
- return set(filter(c, self.workSet))
-
- @property
- def SimplifyWorkSet(self):
- c = lambda n: n.Degree < self.K and not self.MoveRelated(n)
- return set(filter(c, self.workSet))
-
- def makeWorkList(self):
- """ Divide initial nodes into worklists """
- self.selectStack = []
-
- # Fill initial move set:
- for m in self.moves:
- self.worklistMoves.add(m)
-
- def Simplify(self):
- """ 2. Remove nodes from the graph """
- n = first(self.SimplifyWorkSet)
- self.workSet.remove(n)
- self.selectStack.append(n)
- # Pop out of graph:
- self.f.ig.delNode(n)
-
- def EnableMoves(self, nodes):
- for n in nodes:
- for m in self.NodeMoves(n):
- if m in self.activeMoves:
- self.activeMoves.remove(m)
- self.worklistMoves.add(m)
-
- def Coalesc(self):
- """ Coalesc conservative. """
- m = first(self.worklistMoves)
- x = self.Node(m.dst[0])
- y = self.Node(m.src[0])
- u, v = (y, x) if y in self.precolored else (x, y)
- self.worklistMoves.remove(m)
- if u is v:
- self.coalescedMoves.add(m)
- elif v in self.precolored or self.f.ig.hasEdge(u, v):
- self.constrainedMoves.add(m)
- elif u not in self.precolored and self.Conservative(u, v):
- self.coalescedMoves.add(m)
- self.workSet.remove(v)
- self.f.ig.Combine(u, v)
- else:
- self.activeMoves.add(m)
-
- def Conservative(self, u, v):
- """ Briggs conservative criteria for coalesc """
- nodes = u.Adjecent | v.Adjecent
- c = lambda n: n.Degree >= self.K
- k = len(list(filter(c, nodes)))
- return k < self.K
-
- def Freeze(self):
- """ Give up coalescing on some node """
- u = first(self.FreezeWorkSet)
- self.freezeMoves(u)
-
- def freezeMoves(self, u):
- """ Freeze moves for node u """
- for m in self.NodeMoves(u):
- if m in self.activeMoves:
- self.activeMoves.remove(m)
- else:
- sekf.worklistMoves.remove(m)
- self.frozenMoves.add(m)
- # Check other part of the move for still being move related:
- v = m.src[0] if u is m.dst[0] else m.dst[0]
-
- def SelectSpill(self):
- raise NotImplementedError("Spill is not implemented")
-
- def AssignColors(self):
- """ Add nodes back to the graph to color it. """
- while self.selectStack:
- n = self.selectStack.pop(-1) # Start with the last added
- self.f.ig.add_node(n)
- takenregs = set(self.color[m] for m in n.Adjecent)
- okColors = self.regs - takenregs
- if okColors:
- self.color[n] = first(okColors)
- n.color = self.color[n]
- else:
- raise NotImplementedError('Spill required here!')
-
- def ApplyColors(self):
- # Remove coalesced moves:
- for mv in self.coalescedMoves:
- self.f.instructions.remove(mv)
-
- # Use allocated registers:
- lookup = lambda t: self.color[self.Node(t)]
- for i in self.f.instructions:
- i.src = tuple(map(lookup, i.src))
- i.dst = tuple(map(lookup, i.dst))
-
- def allocFrame(self, f):
- """ Do iterated register allocation for a single stack frame. """
- self.InitData(f)
- self.Build()
- self.makeWorkList()
- while True:
- if self.SimplifyWorkSet:
- self.Simplify()
- elif self.worklistMoves:
- self.Coalesc()
- elif self.FreezeWorkSet:
- self.Freeze()
- elif self.SpillWorkSet:
- raise NotImplementedError('Spill not implemented')
- else:
- break # Done!
- self.AssignColors()
- self.ApplyColors()
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/common.py
--- a/python/ppci/common.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-from collections import namedtuple
-import logging
-
-"""
- Error handling routines
- Diagnostic utils
- Source location structures
-"""
-
-# Token is used in the lexical analyzer:
-class Token:
- def __init__(self, typ, val, loc=None):
- self.typ = typ
- self.val = val
- if loc is None:
- loc = SourceLocation('', 0, 0, 0)
- assert type(loc) is SourceLocation
- self.loc = loc
-
- def __repr__(self):
- return 'Token({0}, {1})'.format(self.typ, self.val)
-
-
-class SourceLocation:
- def __init__(self, filename, row, col, ln):
- self.filename = filename
- self.row = row
- self.col = col
- self.length = ln
-
- def __repr__(self):
- return '{}, {}, {}'.format(self.filename, self.row, self.col)
-
-
-SourceRange = namedtuple('SourceRange', ['p1', 'p2'])
-
-
-class CompilerError(Exception):
- def __init__(self, msg, loc=None):
- self.msg = msg
- self.loc = loc
- if loc:
- assert type(loc) is SourceLocation, \
- '{0} must be SourceLocation'.format(type(loc))
- self.row = loc.row
- self.col = loc.col
- else:
- self.row = self.col = 0
-
- def __repr__(self):
- return '"{}"'.format(self.msg)
-
-
-class DiagnosticsManager:
- def __init__(self):
- self.diags = []
- self.sources = {}
- self.logger = logging.getLogger('diagnostics')
-
- def addSource(self, name, src):
- self.logger.debug('Adding source {}'.format(name))
- self.sources[name] = src
-
- def addDiag(self, d):
- #self.logger.warning(str(d.msg))
- self.diags.append(d)
-
- def error(self, msg, loc):
- self.addDiag(CompilerError(msg, loc))
-
- def clear(self):
- del self.diags[:]
- self.sources.clear()
-
- def printErrors(self):
- if len(self.diags) > 0:
- print('{0} Errors'.format(len(self.diags)))
- for d in self.diags:
- self.printError(d)
-
- def printError(self, e):
- def printLine(row, txt):
- print(str(row)+':'+txt)
- print('==============')
- if not e.loc:
- print('Error: {0}'.format(e))
- else:
- if e.loc.filename not in self.sources:
- print('Error: {0}'.format(e))
- return
- print("File: {}".format(e.loc.filename))
- source = self.sources[e.loc.filename]
- lines = source.split('\n')
- ro, co = e.row, e.col
- prerow = ro - 2
- if prerow < 1:
- prerow = 1
- afterrow = ro + 3
- if afterrow > len(lines):
- afterrow = len(lines)
-
- # print preceding source lines:
- for r in range(prerow, ro):
- printLine(r, lines[r-1])
- # print source line containing error:
- printLine(ro, lines[ro-1])
- print(' '*(len(str(ro)+':')+co-1) + '^ Error: {0}'.format(e.msg))
- # print trailing source line:
- for r in range(ro+1, afterrow+1):
- printLine(r, lines[r-1])
- print('==============')
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/ir.py
--- a/python/ppci/ir.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,383 +0,0 @@
-"""
-Intermediate representation (IR) code classes.
-"""
-
-
-def label_name(dut):
- """ Function that returns the assembly code label name """
- if isinstance(dut, Block):
- f = dut.function
- return label_name(f) + '_' + dut.name
- elif isinstance(dut, Function):
- return label_name(dut.module) + '_' + dut.name
- elif isinstance(dut, Module):
- return dut.name
- else:
- raise NotImplementedError(str(dut))
-
-
-class Module:
- """ Container unit for variables and functions. """
- def __init__(self, name):
- self.name = name
- self.functions = []
- self.variables = []
-
- def __repr__(self):
- return 'module {0}'.format(self.name)
-
- def add_function(self, f):
- """ Add a function to this module """
- self.functions.append(f)
- f.module = self
-
- def add_variable(self, v):
- self.variables.append(v)
-
- def getVariables(self):
- return self.variables
-
- Variables = property(getVariables)
-
- def getFunctions(self):
- return self.functions
-
- Functions = property(getFunctions)
-
- def findFunction(self, name):
- for f in self.funcs:
- if f.name == name:
- return f
- raise KeyError(name)
-
- getFunction = findFunction
-
-
-class Function:
- """ Represents a function. """
- def __init__(self, name, module=None):
- self.name = name
- self.entry = Block('entry')
- self.entry.function = self
- self.epiloog = Block('epilog')
- self.epiloog.function = self
- self.epiloog.addInstruction(Terminator())
- self.return_value = Temp('{}_retval'.format(name))
- self.arguments = []
- self.localvars = []
- if module:
- module.add_function(self)
-
- def __repr__(self):
- args = ','.join(str(a) for a in self.arguments)
- return 'function i32 {}({})'.format(self.name, args)
-
- def add_block(self, bb):
- #self.bbs.append(bb)
- bb.function = self
-
- def removeBlock(self, bb):
- #self.bbs.remove(bb)
- bb.function = None
-
- def getBlocks(self):
- bbs = [self.entry]
- worklist = [self.entry]
- while worklist:
- b = worklist.pop()
- for sb in b.Successors:
- if sb not in bbs:
- bbs.append(sb)
- worklist.append(sb)
- bbs.remove(self.entry)
- if self.epiloog in bbs:
- bbs.remove(self.epiloog)
- bbs.insert(0, self.entry)
- bbs.append(self.epiloog)
- return bbs
-
- def findBasicBlock(self, name):
- for bb in self.bbs:
- if bb.name == name:
- return bb
- raise KeyError(name)
-
- Blocks = property(getBlocks)
-
- @property
- def Entry(self):
- return self.entry
-
- def check(self):
- for b in self.Blocks:
- b.check()
-
- def addParameter(self, p):
- assert type(p) is Parameter
- p.num = len(self.arguments)
- self.arguments.append(p)
-
- def addLocal(self, l):
- assert type(l) is LocalVariable
- self.localvars.append(l)
-
-
-class Block:
- """
- Uninterrupted sequence of instructions with a label at the start.
- """
- def __init__(self, name, function=None):
- self.name = name
- self.function = function
- self.instructions = []
-
- parent = property(lambda s: s.function)
-
- def __repr__(self):
- return '{0}:'.format(self.name)
-
- def addInstruction(self, i):
- i.parent = self
- assert not isinstance(self.LastInstruction, LastStatement)
- self.instructions.append(i)
-
- def replaceInstruction(self, i1, i2):
- idx = self.instructions.index(i1)
- i1.parent = None
- i1.delete()
- i2.parent = self
- self.instructions[idx] = i2
-
- def removeInstruction(self, i):
- i.parent = None
- #i.delete()
- self.instructions.remove(i)
-
- @property
- def Instructions(self):
- return self.instructions
-
- @property
- def LastInstruction(self):
- if not self.Empty:
- return self.instructions[-1]
-
- @property
- def Empty(self):
- return len(self.instructions) == 0
-
- @property
- def FirstInstruction(self):
- return self.instructions[0]
-
- def getSuccessors(self):
- if not self.Empty:
- return self.LastInstruction.Targets
- return []
-
- Successors = property(getSuccessors)
-
- def getPredecessors(self):
- preds = []
- for bb in self.parent.Blocks:
- if self in bb.Successors:
- preds.append(bb)
- return preds
-
- Predecessors = property(getPredecessors)
-
- def precedes(self, other):
- raise NotImplementedError()
-
-
-# Instructions:
-
-class Expression:
- """ Base class for an expression """
- pass
-
-
-class Const(Expression):
- """ Represents a constant value """
- def __init__(self, value):
- self.value = value
-
- def __repr__(self):
- return 'Const {}'.format(self.value)
-
-
-class Call(Expression):
- """ Call a function with some arguments """
- def __init__(self, f, arguments):
- assert type(f) is str
- self.f = f
- self.arguments = arguments
-
- def __repr__(self):
- args = ', '.join([str(arg) for arg in self.arguments])
- return '{}({})'.format(self.f, args)
-
-
-# Data operations
-class Binop(Expression):
- """ Generic binary operation """
- ops = ['+', '-', '*', '/', '|', '&', '<<', '>>']
-
- def __init__(self, value1, operation, value2):
- assert operation in Binop.ops
- self.a = value1
- self.b = value2
- self.operation = operation
-
- def __repr__(self):
- a, b = self.a, self.b
- return '({} {} {})'.format(a, self.operation, b)
-
-
-def Add(a, b):
- """ Add a and b """
- return Binop(a, '+', b)
-
-
-def Sub(a, b):
- """ Substract b from a """
- return Binop(a, '-', b)
-
-
-def Mul(a, b):
- """ Multiply a by b """
- return Binop(a, '*', b)
-
-
-def Div(a, b):
- """ Divide a in b pieces """
- return Binop(a, '/', b)
-
-
-class Eseq(Expression):
- """ Sequence of instructions where the last is an expression """
- def __init__(self, stmt, e):
- self.stmt = stmt
- self.e = e
-
- def __repr__(self):
- return '({}, {})'.format(self.stmt, self.e)
-
-
-class Alloc(Expression):
- """ Allocates space on the stack """
- def __init__(self):
- super().__init__()
-
- def __repr__(self):
- return 'Alloc'
-
-
-class Variable(Expression):
- def __init__(self, name):
- self.name = name
-
- def __repr__(self):
- return 'Var {}'.format(self.name)
-
-
-class LocalVariable(Variable):
- def __repr__(self):
- return 'Local {}'.format(self.name)
-
-
-class Parameter(Variable):
- def __repr__(self):
- return 'Param {}'.format(self.name)
-
-
-class Temp(Expression):
- """ Temporary storage, same as register """
- def __init__(self, name):
- self.name = name
-
- def __repr__(self):
- return 'TMP_{}'.format(self.name)
-
-
-class Mem(Expression):
- """ Memory access """
- def __init__(self, e):
- self.e = e
-
- def __repr__(self):
- return '[{}]'.format(self.e)
-
-
-class Statement:
- """ Base class for all instructions. """
- @property
- def IsTerminator(self):
- return isinstance(self, LastStatement)
-
-
-class Move(Statement):
- """ Move source to destination """
- def __init__(self, dst, src):
- self.dst = dst
- self.src = src
-
- def __repr__(self):
- return '{} = {}'.format(self.dst, self.src)
-
-
-class Exp(Statement):
- def __init__(self, e):
- self.e = e
-
- def __repr__(self):
- return '{}'.format(self.e)
-
-
-# Branching:
-class LastStatement(Statement):
- def changeTarget(self, old, new):
- idx = self.Targets.index(old)
- self.Targets[idx] = new
-
-
-class Terminator(LastStatement):
- """ Instruction that terminates the terminal block """
- def __init__(self):
- self.Targets = []
-
- def __repr__(self):
- return 'Terminator'
-
-
-class Jump(LastStatement):
- """ Jump statement to some target location """
- def __init__(self, target):
- self.Targets = [target]
-
- def setTarget(self, t):
- self.Targets[0] = t
-
- target = property(lambda s: s.Targets[0], setTarget)
-
- def __repr__(self):
- return 'JUMP {}'.format(self.target.name)
-
-
-class CJump(LastStatement):
- """ Conditional jump to true or false labels. """
- conditions = ['==', '<', '>', '>=', '<=', '!=']
-
- def __init__(self, a, cond, b, lab_yes, lab_no):
- assert cond in CJump.conditions
- self.a = a
- self.cond = cond
- self.b = b
- self.Targets = [lab_yes, lab_no]
-
- lab_yes = property(lambda s: s.Targets[0])
- lab_no = property(lambda s: s.Targets[1])
-
- def __repr__(self):
- return 'IF {} {} {} THEN {} ELSE {}'\
- .format(self.a, self.cond, self.b, self.lab_yes, self.lab_no)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/ir2tree.py
--- a/python/ppci/ir2tree.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-from tree import Tree
-from . import ir
-
-""" Create a tree from ir code. """
-
-f_map = {} # Mapping from types to tree creation functions
-
-def register(tp):
- """ Register a function for type tp """
- def reg_f(f):
- f_map[tp] = f
- return f
- return reg_f
-
-@register(ir.Binop)
-def binop_to_tree(e):
- names = {'+':'ADDI32', '-':'SUBI32', '|':'ORI32', '<<':'SHLI32',
- '*':'MULI32'}
- op = names[e.operation]
- return Tree(op, makeTree(e.a), makeTree(e.b))
-
-@register(ir.Temp)
-def temp_to_tree(e):
- t = Tree('REGI32')
- t.value = e
- return t
-
-@register(ir.Const)
-def const_to_tree(e):
- t = Tree('CONSTI32')
- t.value = e.value
- return t
-
-@register(ir.Mem)
-def mem_to_tree(e):
- return Tree('MEMI32', makeTree(e.e))
-
-@register(ir.Call)
-def call_to_tree(e):
- t = Tree('CALL')
- t.value = e
- return t
-
-def makeTree(ir_node):
- """ Transform an ir node into a tree usable for matching """
- return f_map[type(ir_node)](ir_node)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/irmach.py
--- a/python/ppci/irmach.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-
-"""
- Abstract assembly language instructions.
-
- This is the second intermediate representation.
-
- Instructions are selected and scheduled at this stage.
-"""
-
-from .target import Instruction
-
-
-class Frame:
- """
- Activation record abstraction. This class contains a flattened
- function. Instructions are selected and scheduled at this stage.
- Frames differ per machine.
- """
- def __init__(self, name):
- self.name = name
- self.instructions = []
- self.stacksize = 0
-
- def __repr__(self):
- return 'Frame {}'.format(self.name)
-
-
-class AbstractInstruction:
- """
- Abstract machine instruction class. This is a very simple
- abstraction of machine instructions.
- """
- def __init__(self, cls, ops=(), src=(), dst=(), jumps=(), others=(), ismove=False):
- assert type(cls) is type or isinstance(cls, Instruction), str(cls)
- self.assem = cls
- self.ops = tuple(ops)
- self.src = tuple(src)
- self.dst = tuple(dst)
- self.jumps = tuple(jumps)
- self.others = tuple(others)
- self.ismove = ismove
-
- def __repr__(self):
- """ Substitutes source, dst and labels in the string """
- if isinstance(self.assem, Instruction):
- x = str(self.assem)
- else:
- cn = self.assem.__name__
- x = '{}, def={}, use={}, other={}'
- x = x.format(cn, self.dst, self.src, self.others)
- return x
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/irutils.py
--- a/python/ppci/irutils.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,268 +0,0 @@
-
-"""
- Some utilities for ir-code.
-"""
-import re
-from . import ir
-
-def dumpgv(m, outf):
- print('digraph G ', file=outf)
- print('{', file=outf)
- for f in m.Functions:
- print('{} [label="{}" shape=box3d]'.format(id(f), f), file=outf)
- for bb in f.Blocks:
- contents = str(bb) + '\n'
- contents += '\n'.join([str(i) for i in bb.Instructions])
- print('{0} [shape=note label="{1}"];'
- .format(id(bb), contents), file=outf)
- for successor in bb.Successors:
- print('"{}" -> "{}"'.format(id(bb), id(successor)), file=outf)
-
- print('"{}" -> "{}" [label="entry"]'
- .format(id(f), id(f.entry)), file=outf)
- print('}', file=outf)
-
-
-class Writer:
- def __init__(self, extra_indent=''):
- self.extra_indent = extra_indent
-
- def write(self, ir, f):
- """ Write ir-code to file f """
- print('{}{}'.format(self.extra_indent, ir), file=f)
- for v in ir.Variables:
- print('{}{}'.format(self.extra_indent, v), file=f)
- for function in ir.Functions:
- self.write_function(function, f)
-
- def write_function(self, fn, f):
- args = ','.join('i32 ' + str(a) for a in fn.arguments)
- print('{}function i32 {}({})'.format(self.extra_indent, fn.name, args), file=f)
- for bb in fn.Blocks:
- print('{} {}'.format(self.extra_indent, bb), file=f)
- for ins in bb.Instructions:
- print('{} {}'.format(self.extra_indent, ins), file=f)
-
-
-class IrParseException(Exception):
- pass
-
-
-class Reader:
- def read(self, f):
- """ Read ir code from file f """
- # Read lines from the file:
- lines = [line.rstrip() for line in f]
-
- # Create a regular expression for the lexing part:
- tok_spec = [
- ('NUMBER', r'\d+'),
- ('ID', r'[A-Za-z][A-Za-z\d_]*'),
- ('SKIP2', r' '),
- ('SKIP1', r' '),
- ('OTHER', r'[\.,=:;\-+*\[\]/\(\)]|>|<|{|}|&|\^|\|')
- ]
- tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec)
- gettok = re.compile(tok_re).match
-
- def tokenize():
- for line in lines:
- if not line:
- continue # Skip empty lines
- mo = gettok(line)
- first = True
- while mo:
- typ = mo.lastgroup
- val = mo.group(typ)
- if typ == 'ID':
- if val in ['function', 'module']:
- typ = val
- yield (typ, val)
- elif typ == 'OTHER':
- typ = val
- yield (typ, val)
- elif typ in ['SKIP1', 'SKIP2']:
- if first:
- yield (typ, val)
- elif typ == 'NUMBER':
- yield (typ, int(val))
- else:
- raise NotImplementedError(str(typ))
- first = False
- pos = mo.end()
- mo = gettok(line, pos)
- if len(line) != pos:
- raise IrParseException('Lex fault')
- yield ('eol', 'eol')
- yield ('eof', 'eof')
- self.tokens = tokenize()
- self.token = self.tokens.__next__()
-
- try:
- module = self.parse_module()
- return module
- except IrParseException as e:
- print(e)
-
- def next_token(self):
- t = self.token
- if t[0] != 'eof':
- self.token = self.tokens.__next__()
- return t
-
- @property
- def Peak(self):
- return self.token[0]
-
- def Consume(self, typ):
- if self.Peak == typ:
- return self.next_token()
- else:
- raise IrParseException('Expected "{}" got "{}"'.format(typ, self.Peak))
-
- def parse_module(self):
- """ Entry for recursive descent parser """
- self.Consume('module')
- name = self.Consume('ID')[1]
- module = ir.Module(name)
- self.Consume('eol')
- while self.Peak != 'eof':
- if self.Peak == 'function':
- module.add_function(self.parse_function())
- else:
- raise IrParseException('Expected function got {}'.format(self.Peak))
- return module
-
- def parse_function(self):
- self.Consume('function')
- self.parse_type()
- name = self.Consume('ID')[1]
- function = ir.Function(name)
- self.Consume('(')
- while self.Peak != ')':
- self.parse_type()
- self.Consume('ID')
- if self.Peak != ',':
- break
- else:
- self.Consume(',')
- self.Consume(')')
- self.Consume('eol')
- while self.Peak == 'SKIP1':
- function.add_block(self.parse_block())
- return function
-
- def parse_type(self):
- self.Consume('ID')
-
- def parse_block(self):
- self.Consume('SKIP1')
- name = self.Consume('ID')[1]
- block = ir.Block(name)
- self.Consume(':')
- self.Consume('eol')
- while self.Peak == 'SKIP2':
- self.parse_statement()
- return block
-
- def parse_statement(self):
- self.Consume('SKIP2')
- while self.Peak != 'eol':
- # raise NotImplementedError()
- self.next_token()
- self.Consume('eol')
-
-
-# Constructing IR:
-
-class NamedClassGenerator:
- def __init__(self, prefix, cls):
- self.prefix = prefix
- self.cls = cls
-
- def NumGen():
- a = 0
- while True:
- yield a
- a = a + 1
- self.nums = NumGen()
-
- def gen(self, prefix=None):
- if not prefix:
- prefix = self.prefix
- return self.cls('{0}{1}'.format(prefix, self.nums.__next__()))
-
-
-class Builder:
- """ Base class for ir code generators """
- def __init__(self):
- self.prepare()
-
- def prepare(self):
- self.newTemp = NamedClassGenerator('reg', ir.Temp).gen
- self.newBlock2 = NamedClassGenerator('block', ir.Block).gen
- self.bb = None
- self.m = None
- self.fn = None
- self.loc = None
-
- # Helpers:
- def setModule(self, m):
- self.m = m
-
- def newFunction(self, name):
- f = ir.Function(name)
- self.m.add_function(f)
- return f
-
- def newBlock(self):
- assert self.fn
- b = self.newBlock2()
- b.function = self.fn
- return b
-
- def setFunction(self, f):
- self.fn = f
- self.bb = f.entry if f else None
-
- def setBlock(self, b):
- self.bb = b
-
- def setLoc(self, l):
- self.loc = l
-
- def emit(self, i):
- assert isinstance(i, ir.Statement)
- i.debugLoc = self.loc
- if not self.bb:
- raise Exception('No basic block')
- self.bb.addInstruction(i)
-
-
-class Verifier:
- def verify(self, module):
- """ Verifies a module for some sanity """
- assert isinstance(module, ir.Module)
- for f in module.Functions:
- self.verify_function(f)
-
- def verify_function(self, function):
- for b in function.Blocks:
- self.verify_block_termination(b)
-
- # Now we can build a dominator tree
- for b in function.Blocks:
- self.verify_block(b)
-
- def verify_block_termination(self, block):
- assert not block.Empty
- assert block.LastInstruction.IsTerminator
- for i in block.Instructions[:-1]:
- assert not isinstance(i, ir.LastStatement)
-
- def verify_block(self, block):
- for instruction in block.Instructions:
- self.verify_instruction(instruction)
-
- def verify_instruction(self, instruction):
- pass
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/linker.py
--- a/python/ppci/linker.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,147 +0,0 @@
-
-import struct
-from .objectfile import ObjectFile
-from . import CompilerError
-
-def align(x, m):
- while ((x % m) != 0):
- x = x + 1
- return x
-
-def wrap_negative(x, bits):
- b = struct.unpack('> 2
- section.data[reloc.offset] = rel8
-
-
-@reloc('wrap_new11')
-def apply_wrap_new11(reloc, sym, section, reloc_value):
- offset = sym.value - (align(reloc_value, 2) + 4)
- assert offset in range(-2048, 2046, 2)
- imm11 = wrap_negative(offset >> 1, 11)
- section.data[reloc.offset] = (imm11 & 0xff)
- section.data[reloc.offset + 1] |= (imm11 >> 8) & 0x7
-
-
-@reloc('rel8')
-def apply_rel8(reloc, sym, section, reloc_value):
- assert sym.value % 2 == 0
- offset = sym.value - (align(reloc_value, 2) + 4)
- assert offset in range(-256, 254, 2), str(offset) + str(reloc)
- imm8 = wrap_negative(offset >> 1, 8)
- section.data[reloc.offset] = imm8
-
-
-@reloc('bl_imm11_imm10')
-def apply_bl_imm11(reloc, sym, section, reloc_value):
- assert sym.value % 2 == 0
- offset = sym.value - (align(reloc_value, 2) + 4)
- assert offset in range(-16777216, 16777214, 2), str(offset)
- imm32 = wrap_negative(offset >> 1, 32)
- imm11 = imm32 & 0x7FF
- imm10 = (imm32 >> 11) & 0x3FF
- s = (imm32 >> 24) & 0x1
- section.data[reloc.offset + 2] = imm11 & 0xFF
- section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
- section.data[reloc.offset] = imm10 & 0xff
- section.data[reloc.offset + 1] |= ((imm10 >> 8) & 0x3) | (s << 2)
-
-@reloc('b_imm11_imm6')
-def apply_b_imm11_imm6(reloc, sym, section, reloc_value):
- assert sym.value % 2 == 0
- offset = sym.value - (align(reloc_value, 2) + 4)
- assert offset in range(-1048576, 1048574, 2), str(offset)
- imm32 = wrap_negative(offset >> 1, 32)
- imm11 = imm32 & 0x7FF
- imm6 = (imm32 >> 11) & 0x3F
- s = (imm32 >> 24) & 0x1
- section.data[reloc.offset + 2] = imm11 & 0xFF
- section.data[reloc.offset + 3] |= (imm11 >> 8) & 0x7
- section.data[reloc.offset] |= imm6
- section.data[reloc.offset + 1] |= (s << 2)
-
-# ARM reloc!!
-# TODO: move to target classes???
-@reloc('b_imm24')
-def apply_b_imm24(reloc, sym, section, reloc_value):
- assert sym.value % 4 == 0
- assert reloc_value % 4 == 0
- offset = (sym.value - (reloc_value + 8))
- rel24 = wrap_negative(offset >> 2, 24)
- section.data[reloc.offset+2] = (rel24 >> 16) & 0xFF
- section.data[reloc.offset+1] = (rel24 >> 8) & 0xFF
- section.data[reloc.offset+0] = rel24 & 0xFF
-
-
-class Linker:
- """ Merges the sections of several object files and
- performs relocation """
- def link(self, objs, layout={}):
- # Create new object file to store output:
- self.dst = ObjectFile()
-
- # Create sections with address:
- for section_name, address in layout.items():
- self.dst.get_section(section_name).address = address
-
- # First copy all sections into output sections:
- for iobj in objs:
- offsets = {}
- # Merge sections:
- for in_s in iobj.sections.values():
- out_s = self.dst.get_section(in_s.name)
- # TODO: align section in other way:
- while out_s.Size % 4 != 0:
- out_s.add_data(bytes([0]))
-
- # Add new section:
- offsets[in_s.name] = out_s.Size
- out_s.add_data(in_s.data)
-
-
- # Merge symbols:
- for sym in iobj.symbols.values():
- out_s = self.dst.get_section(sym.section)
- value = offsets[sym.section] + out_s.address + sym.value
- self.dst.add_symbol(sym.name, value, sym.section)
-
- # Merge relocations:
- for reloc in iobj.relocations:
- offset = offsets[reloc.section] + reloc.offset
- self.dst.add_relocation(reloc.sym, offset, reloc.typ, reloc.section)
-
- # Perform relocations:
- for reloc in self.dst.relocations:
- # Lookup symbol:
- if reloc.sym not in self.dst.symbols:
- raise CompilerError('Undefined reference "{}"'.format(reloc.sym))
- sym = self.dst.symbols[reloc.sym]
- # patch up:
- section = self.dst.get_section(reloc.section)
-
- # Determine location in memory of reloc patchup position:
- reloc_value = section.address + reloc.offset
-
- if reloc.typ in reloc_map:
- f = reloc_map[reloc.typ]
- f(reloc, sym, section, reloc_value)
- else:
- raise NotImplementedError('Unknown relocation type {}'.format(reloc.typ))
-
- return self.dst
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/mem2reg.py
--- a/python/ppci/mem2reg.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-import logging
-from transform import FunctionPass
-from ir import *
-
-def isAllocPromotable(allocinst):
- # Check if alloc value is only used by load and store operations.
- assert type(allocinst) is Alloc
- return all(type(use) in [Load, Store] for use in allocinst.value.used_by)
-
-
-class Mem2RegPromotor(FunctionPass):
- def promoteSingleBlock(self, ai):
- v = ai.value
- bb = ai.Block
-
- # Replace all loads with the value:
- loads = [i for i in v.used_by if isinstance(i, Load)]
- stores = [i for i in v.used_by if isinstance(i, Store)]
- stores.sort(key=lambda s: s.Position)
- stores.reverse()
-
- for load in loads:
- idx = load.Position
- # Search upwards:
- for store in stores:
- if store.Position < load.Position:
- break
- load.value.replaceby(store.value)
- logging.debug('replaced {} with {}'.format(load, store.value))
- bb.removeInstruction(load)
-
- # Remove store instructions:
- for store in stores:
- sv = store.value
- logging.debug('removing {}'.format(store))
- bb.removeInstruction(store)
- #assert sv.Used
-
- # Remove alloca instruction:
- assert not ai.value.Used, ai.value.used_by
- bb.removeInstruction(ai)
-
- def promote(self, ai):
- # Find load operations and replace them with assignments
- v = ai.value
- if len(ai.value.UsedInBlocks) == 1:
- self.promoteSingleBlock(ai)
- return
-
- loads = [i for i in v.used_by if isinstance(i, Load)]
- stores = [i for i in v.used_by if isinstance(i, Store)]
-
- # Each store instruction can be removed (later).
- # Instead of storing the value, we use it
- # where the load would have been!
- replMap = {}
- for store in stores:
- replMap[store] = store.value
-
- # for each load, track back what the defining store
- # was.
- for load in loads:
- pass
-
- def onFunction(self, f):
- for bb in f.BasicBlocks:
- allocs = [i for i in bb.Instructions if isinstance(i, Alloc)]
- for i in allocs:
- if isAllocPromotable(i):
- self.promote(i)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/objectfile.py
--- a/python/ppci/objectfile.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-
-"""
-Object files are used to store assembled code. Information contained
-is code, symbol table and relocation information.
-"""
-
-from . import CompilerError
-
-class Symbol:
- def __init__(self, name, value, section):
- self.name = name
- self.value = value
- self.section = section
-
- def __repr__(self):
- return 'SYM {}, val={} sec={}'.format(self.name, self.value, self.section)
-
-
-class Relocation:
- """ Represents a relocation entry. A relocation always has a symbol to refer to
- and a relocation type """
- def __init__(self, sym, offset, typ, section):
- self.sym = sym
- self.offset = offset
- self.typ = typ
- self.section = section
-
- def __repr__(self):
- return 'RELOC {} off={} t={} sec={}'.format(self.sym, self.offset, self.typ, self.section)
-
-
-class Section:
- def __init__(self, name):
- self.name = name
- self.address = 0
- self.data = bytearray()
-
- def add_data(self, data):
- self.data += data
-
- @property
- def Size(self):
- return len(self.data)
-
- def __repr__(self):
- return 'SECTION {}'.format(self.name)
-
-
-class ObjectFile:
- """ Container for sections with compiled code or data.
- Also contains symbols and relocation entries """
- def __init__(self):
- self.symbols = {}
- self.sections = {}
- self.relocations = []
-
- def find_symbol(self, name):
- return self.symbols[name]
-
- def add_symbol(self, name, value, section):
- if name in self.symbols:
- raise CompilerError('{} already defined'.format(name))
- assert section in self.sections
- sym = Symbol(name, value, section)
- self.symbols[name] = sym
- return sym
-
- def add_relocation(self, sym_name, offset, typ, section):
- assert type(sym_name) is str, str(sym_name)
- assert section in self.sections
- reloc = Relocation(sym_name, offset, typ, section)
- self.relocations.append(reloc)
- return reloc
-
- def get_section(self, name):
- if not name in self.sections:
- self.sections[name] = Section(name)
- return self.sections[name]
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/optimize.py
--- a/python/ppci/optimize.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-from mem2reg import Mem2RegPromotor
-from transform import CommonSubexpressionElimination, CleanPass
-from transform import DeadCodeDeleter, ConstantFolder
-
-def optimize(ir):
- return
- cf = ConstantFolder()
- cf.run(ir)
- return
- dcd = DeadCodeDeleter()
- m2r = Mem2RegPromotor()
- clr = CleanPass()
- cse = CommonSubexpressionElimination()
- dcd.run(ir)
- clr.run(ir)
- m2r.run(ir)
- cse.run(ir)
- cf.run(ir)
- dcd.run(ir)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/outstream.py
--- a/python/ppci/outstream.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-import binascii
-from ppci.target import Instruction, Alignment
-from ppci.objectfile import ObjectFile
-
-"""
- The output stream is a stream of instructions that can be output
- to a file or binary or hexfile.
-"""
-
-
-class OutputStream:
- def emit(self, item):
- raise NotImplementedError('Abstract base class')
-
- def selectSection(self, sname):
- raise NotImplementedError('Abstract base class')
-
-
-class OutputStreamWriter:
- def __init__(self, extra_indent=''):
- self.extra_indent = extra_indent
-
- def dump(self, stream, f):
- for s in sorted(stream.sections.keys()):
- # print('.section '+ s)
- self.dumpSection(stream.sections[s], f)
-
- def dumpSection(self, s, f):
- for i in s.instructions:
- addr = i.address
- insword = i.encode()
- assert type(insword) is bytes
- insword = binascii.hexlify(bytes(reversed(insword))).decode('ascii')
- asm = str(i)
- if len(insword) == 0:
- print(' {}'.format(asm), file=f)
- else:
- print(' 0x{0:08x} 0x{1} {2}'.format(addr, insword, asm), file=f)
-
-
-class BinaryOutputStream(OutputStream):
- """ Output stream that writes to object file """
- def __init__(self, obj_file):
- super().__init__()
- self.obj_file = obj_file
-
- def emit(self, item):
- """ Encode instruction and add symbol and relocation information """
- assert isinstance(item, Instruction), str(item) + str(type(item))
- assert self.currentSection
- section = self.currentSection
- address = self.currentSection.Size
- b = item.encode()
- syms = item.symbols()
- relocs = item.relocations()
- section.add_data(b)
- for sym in syms:
- self.obj_file.add_symbol(sym, address, section.name)
- for sym, typ in relocs:
- self.obj_file.add_relocation(sym, address, typ, section.name)
- # Special case for align, TODO do this different?
- if type(item) is Alignment:
- while section.Size % item.align != 0:
- section.add_data(bytes([0]))
-
- def selectSection(self, sname):
- self.currentSection = self.obj_file.get_section(sname)
-
-
-class DummyOutputStream(OutputStream):
- def emit(self, item):
- pass
-
- def selectSection(self, sname):
- pass
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/recipe.py
--- a/python/ppci/recipe.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-import os
-import yaml
-
-from .buildtasks import Compile, Assemble, Link
-from .objectfile import ObjectFile
-from .target.target_list import target_list
-
-
-targets = {t.name: t for t in target_list}
-targetnames = list(targets.keys())
-
-class RecipeLoader:
- """ Loads a recipe into a runner from a dictionary or file """
- def __init__(self):
- self.directive_handlers = {}
- for a in dir(self):
- if a.startswith('handle_'):
- f = getattr(self, a)
- self.directive_handlers[a[7:]] = f
-
- def load_file(self, recipe_file, runner):
- """ Loads a recipe dictionary into a task runner """
- self.recipe_dir = os.path.abspath(os.path.dirname(recipe_file))
- with open(recipe_file, 'r') as f:
- recipe = yaml.load(f)
- self.runner = runner
- self.load_dict(recipe)
-
- def relpath(self, filename):
- return os.path.join(self.recipe_dir, filename)
-
- def openfile(self, filename):
- return open(self.relpath(filename), 'r')
-
- def handle_compile(self, value):
- sources = [self.openfile(s) for s in value['sources']]
- includes = [self.openfile(i) for i in value['includes']]
- target = targets[value['machine']]
- output = ObjectFile()
- task = Compile(sources, includes, target, output)
- self.runner.add_task(task)
- return task
-
- def handle_assemble(self, value):
- asm_src = self.openfile(value['source'])
- target = targets[value['machine']]
- output = ObjectFile()
- task = Assemble(asm_src, target, output)
- self.runner.add_task(task)
- return task
-
- def handle_link(self, value):
- inputs = value['inputs']
- objs = []
- for i in inputs:
- task = self.load_dict(i)
- objs.append(task.output)
- layout = value['layout']
- output = self.relpath(value['output'])
- self.runner.add_task(Link(objs, layout, output))
-
- def handle_apps(self, value):
- for a in value:
- self.load_dict(a)
-
- def load_dict(self, recipe):
- for command, value in recipe.items():
- return self.directive_handlers[command](value)
-
-
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/report.py
--- a/python/ppci/report.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-
-import logging
-import io
-
-from . import outstream
-from .c3 import AstPrinter
-from . import logformat
-from .irutils import Writer
-
-class RstFormatter(logging.Formatter):
- """ Formatter that tries to create an rst document """
- def __init__(self):
- super().__init__(fmt=logformat)
-
- def format(self, record):
- s = super().format(record)
- s += '\n'
- if hasattr(record, 'c3_ast'):
- f = io.StringIO()
- print('', file=f)
- print('', file=f)
- print('.. code::', file=f)
- print('', file=f)
- AstPrinter().printAst(record.c3_ast, f)
- print('', file=f)
- s += '\n' + f.getvalue()
- if hasattr(record, 'ircode'):
- f = io.StringIO()
- print('', file=f)
- print('', file=f)
- print('.. code::', file=f)
- print('', file=f)
- Writer(' ').write(record.ircode, f)
- print('', file=f)
- s += '\n' + f.getvalue()
- if hasattr(record, 'irfunc'):
- f = io.StringIO()
- print('', file=f)
- print('', file=f)
- print('.. code::', file=f)
- print('', file=f)
- Writer(' ').write_function(record.irfunc, f)
- print('', file=f)
- s += '\n' + f.getvalue()
- if hasattr(record, 'ppci_frame'):
- f = io.StringIO()
- frame = record.ppci_frame
- print('', file=f)
- print('.. code::', file=f)
- print('', file=f)
- print(' {}'.format(frame.name), file=f)
- for i in frame.instructions:
- print(' {}'.format(i),file=f)
- print('', file=f)
- s += '\n' + f.getvalue()
- if hasattr(record, 'ra_cfg'):
- f = io.StringIO()
- print('', file=f)
- print('', file=f)
- print('.. graphviz::', file=f)
- print('', file=f)
- print(' digraph G {', file=f)
- print(' size="8,80";', file=f)
- cfg = record.ra_cfg
- cfg.to_dot(f)
- print(' }', file=f)
- print('', file=f)
- s += '\n' + f.getvalue()
- if hasattr(record, 'ra_ig'):
- f = io.StringIO()
- print('', file=f)
- print('', file=f)
- print('.. graphviz::', file=f)
- print('', file=f)
- print(' digraph G {', file=f)
- print(' ratio="compress";', file=f)
- print(' size="8,80";', file=f)
- ig = record.ra_ig
- ig.to_dot(f)
- print(' }', file=f)
- print('', file=f)
- s += '\n' + f.getvalue()
- if hasattr(record, 'zcc_outs'):
- f = io.StringIO()
- print('', file=f)
- print('', file=f)
- print('.. code::', file=f)
- print('', file=f)
- outstream.OutputStreamWriter(' ').dump(record.zcc_outs, f)
- print('', file=f)
- s += '\n' + f.getvalue()
- return s
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/__init__.py
--- a/python/ppci/target/__init__.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-#!/usr/bin/env python
-
-from .basetarget import Nop, Instruction, Label, Target, Comment, Alignment
-
-
-class SimpleTarget(Target):
- def __init__(self):
- super().__init__('SimpleTarget')
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/arm/__init__.py
--- a/python/ppci/target/arm/__init__.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-
-from ..basetarget import Target
-from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7
-from ..arm.registers import R8, R9, R10, R11, R12, SP, LR, PC
-from ..arm.registers import register_range
-
-from .instructions import Dcd, Mov, Add, Sub, Orr1, Mul, Mov2
-from .instructions import B, Bl, Ble, Bgt, Beq, Blt
-from .instructions import Push, Pop, Str, Ldr, Ldr3, Str1, Ldr1
-from .selector import ArmInstructionSelector
-from .frame import ArmFrame
-
-class ArmTarget(Target):
- def __init__(self):
- super().__init__('arm')
- self.make_parser()
- self.ins_sel = ArmInstructionSelector()
- self.FrameClass = ArmFrame
-
- self.add_lowering(Ldr3, lambda im: Ldr3(im.dst[0], im.others[0]))
- self.add_lowering(Str1, lambda im: Str1(im.src[1], im.src[0], im.others[0]))
- self.add_lowering(Ldr1, lambda im: Ldr1(im.dst[0], im.src[0], im.others[0]))
- self.add_lowering(Mov2, lambda im: Mov2(im.dst[0], im.src[0]))
-
- def make_parser(self):
- # Assembly grammar:
- self.add_keyword('r0')
- self.add_keyword('r1')
- self.add_keyword('r2')
- self.add_keyword('r3')
- self.add_keyword('r4')
- self.add_keyword('r5')
- self.add_keyword('r6')
- self.add_keyword('r7')
- self.add_keyword('r8')
- self.add_keyword('r9')
- self.add_keyword('r10')
- self.add_keyword('r11')
- self.add_keyword('r12')
- self.add_keyword('sp')
- self.add_keyword('lr')
- self.add_keyword('pc')
-
- self.add_rule('reg', ['r0'], lambda rhs: R0)
- self.add_rule('reg', ['r1'], lambda rhs: R1)
- self.add_rule('reg', ['r2'], lambda rhs: R2)
- self.add_rule('reg', ['r3'], lambda rhs: R3)
- self.add_rule('reg', ['r4'], lambda rhs: R4)
- self.add_rule('reg', ['r5'], lambda rhs: R5)
- self.add_rule('reg', ['r6'], lambda rhs: R6)
- self.add_rule('reg', ['r7'], lambda rhs: R7)
- self.add_rule('reg', ['r8'], lambda rhs: R8)
- self.add_rule('reg', ['r9'], lambda rhs: R9)
- self.add_rule('reg', ['r10'], lambda rhs: R10)
- self.add_rule('reg', ['r11'], lambda rhs: R11)
- self.add_rule('reg', ['r12'], lambda rhs: R12)
- self.add_rule('reg', ['sp'], lambda rhs: SP)
- self.add_rule('reg', ['lr'], lambda rhs: LR)
- self.add_rule('reg', ['pc'], lambda rhs: PC)
-
- self.add_keyword('dcd')
- self.add_instruction(['dcd', 'imm32'],
- lambda rhs: Dcd(rhs[1]))
-
- self.add_keyword('mov')
- self.add_instruction(['mov', 'reg', ',', 'imm32'],
- lambda rhs: Mov(rhs[1], rhs[3]))
-
- self.add_keyword('add')
- self.add_instruction(['add', 'reg', ',', 'reg', ',', 'imm32'],
- lambda rhs: Add(rhs[1], rhs[3], rhs[5]))
-
- self.add_instruction(['add', 'reg', ',', 'reg', ',', 'reg'],
- lambda rhs: Add(rhs[1], rhs[3], rhs[5]))
-
- self.add_keyword('sub')
- self.add_instruction(['sub', 'reg', ',', 'reg', ',', 'imm32'],
- lambda rhs: Sub(rhs[1], rhs[3], rhs[5]))
-
- self.add_instruction(['sub', 'reg', ',', 'reg', ',', 'reg'],
- lambda rhs: Sub(rhs[1], rhs[3], rhs[5]))
-
- self.add_keyword('mul')
- self.add_instruction(['mul', 'reg', ',', 'reg', ',', 'reg'],
- lambda rhs: Mul(rhs[1], rhs[3], rhs[5]))
-
- self.add_keyword('orr')
- self.add_instruction(['orr', 'reg', ',', 'reg', ',', 'reg'],
- lambda rhs: Orr1(rhs[1], rhs[3], rhs[5]))
-
-
- # Jumping:
- self.add_keyword('b')
- self.add_instruction(['b', 'ID'], lambda rhs: B(rhs[1].val))
- self.add_keyword('ble')
- self.add_instruction(['ble', 'ID'], lambda rhs: Ble(rhs[1].val))
- self.add_keyword('bgt')
- self.add_instruction(['bgt', 'ID'], lambda rhs: Bgt(rhs[1].val))
- self.add_keyword('beq')
- self.add_instruction(['beq', 'ID'], lambda rhs: Beq(rhs[1].val))
- self.add_keyword('blt')
- self.add_instruction(['blt', 'ID'], lambda rhs: Blt(rhs[1].val))
-
- self.add_keyword('bl')
- self.add_instruction(['bl', 'ID'], lambda rhs: Bl(rhs[1].val))
-
- # memory:
- self.add_keyword('pop')
- self.add_instruction(['pop', 'reg_list'], lambda rhs: Pop(rhs[1]))
-
- self.add_keyword('push')
- self.add_instruction(['push', 'reg_list'], lambda rhs: Push(rhs[1]))
-
- self.add_keyword('ldr')
- self.add_instruction(['ldr', 'reg', ',', '[', 'reg', ',', 'imm8', ']'],
- lambda rhs: Ldr(rhs[1], rhs[4], rhs[6]))
-
- self.add_keyword('str')
- self.add_instruction(['str', 'reg', ',', '[', 'reg', ',', 'imm8', ']'],
- lambda rhs: Str(rhs[1], rhs[4], rhs[6]))
-
- self.add_instruction(['str', 'reg', ',', '[', 'reg', ',', 'reg', ']'],
- lambda rhs: Str(rhs[1], rhs[4], rhs[6]))
-
- # Register list grammar:
- self.add_rule('reg_list', ['{', 'reg_list_inner', '}'],
- lambda rhs: rhs[1])
- self.add_rule('reg_list_inner', ['reg_or_range'],
- lambda rhs: rhs[0])
- self.add_rule('reg_list_inner', ['reg_or_range', ',', 'reg_list_inner'],
- lambda rhs: rhs[0] | rhs[2])
- self.add_rule('reg_or_range', ['reg'], lambda rhs: {rhs[0]})
-
- self.add_rule('reg_or_range', ['reg', '-', 'reg'],
- lambda rhs: register_range(rhs[0], rhs[2]))
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/arm/arm.brg
--- a/python/ppci/target/arm/arm.brg Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-
-from ppci.target.arm.instructions import Add1, Sub1, Ldr1, Ldr3
-
-%%
-
-%terminal ADDI32 SUBI32 MULI32
-%terminal ORI32 SHLI32
-%terminal CONSTI32 MEMI32 REGI32 CALL
-%terminal MOVI32
-
-%%
-
-reg: ADDI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Add1, dst=[d], src=[$1, $2]); return d .)
-reg: SUBI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Sub1, dst=[d], src=[$1, $2]); return d .)
-reg: SUBI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Sub1, dst=[d], src=[$1, $2]); return d .)
-reg: MEMI32(ADDI32(reg, cn)) 2 (. d = self.newTmp(); self.emit(Ldr1, dst=[d], src=[$1], others=[$2]); return d .)
-
-
-cn: CONSTI32 0 (. return $$.value .)
-
-reg: CONSTI32 3 (. d = self.newTmp(); ln = self.selector.frame.addConstant($$.value); self.emit(Ldr3, dst=[d], others=[ln]); return d .)
-reg: REGI32 1 (. return $$.value .)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/arm/armv7.lidl
--- a/python/ppci/target/arm/armv7.lidl Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-
-# This file specifies the encoding of the arm instruction set.
-
-fields {
- word16 16 {
- opcode 15:12
- top2 15:14
- top6 15:10
- data_opcode 9..6
- opB 11:9
- Rm 8:6
- Rn 5:3
- Rt 2:0
- }
-}
-
-patterns {
- add = 0
- sub, mul = 1..2
- [r1, r2, r3, r4, r5] is todo = 1..5
- [STR, STRH, STRB, LDRSB, LDR, LDRH, LDRB, LDRSH] is opcode = 0b0101 & opB = {0 to 7}
-
- EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL = 0..14
- [AND, EOR, LSL, LSR, ASR, ADC, SBC, ROR, TST, RSB, CMP, CMN, ORR, MUL, BIC, MVN] is 0..15
-
- memop is STR | STRH | STRB | LDRSB | LDR | LDR | LDRH | LDRB | LDRSH
-}
-
-
-constructors
-{
- alu rs1, reg_or_imm, rd
- memop Rt, [Rn, Rm] is memop & Rt & Rn & Rm
-}
-
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/arm/frame.py
--- a/python/ppci/target/arm/frame.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-from ... import ir
-from ..basetarget import Label, Alignment
-from ...irmach import AbstractInstruction, Frame
-from .instructions import Dcd, Add, Sub, Push, Pop, Mov
-from .registers import R0, R1, R2, R3, R4, R5, R6, R7, R8, R11, LR, PC, SP
-
-
-class ArmFrame(Frame):
- """ Arm specific frame for functions. """
- def __init__(self, name):
- # We use r7 as frame pointer.
- super().__init__(name)
- self.regs = [R0, R1, R2, R3, R4, R5, R6, R7, R8]
- self.rv = ir.Temp('special_RV')
- self.p1 = ir.Temp('special_P1')
- self.p2 = ir.Temp('special_P2')
- self.p3 = ir.Temp('special_P3')
- self.p4 = ir.Temp('special_P4')
- self.fp = ir.Temp('special_FP')
- # Pre-colored registers:
- self.tempMap = {}
- self.tempMap[self.rv] = R0
- self.tempMap[self.p1] = R1
- self.tempMap[self.p2] = R2
- self.tempMap[self.p3] = R3
- self.tempMap[self.p4] = R4
- self.tempMap[self.fp] = R11
- self.locVars = {}
- self.parMap = {}
- # Literal pool:
- self.constants = []
-
- def argLoc(self, pos):
- """
- Gets the function parameter location in IR-code format.
- """
- if pos == 0:
- return self.p1
- elif pos == 1:
- return self.p2
- elif pos == 2:
- return self.p3
- elif pos == 3:
- return self.p4
- else:
- raise NotImplementedError('No more than 4 parameters implemented')
-
- def allocVar(self, lvar):
- if lvar not in self.locVars:
- self.locVars[lvar] = self.stacksize
- self.stacksize = self.stacksize + 4
- return self.locVars[lvar]
-
- def addConstant(self, value):
- lab_name = '{}_literal_{}'.format(self.name, len(self.constants))
- self.constants.append((lab_name, value))
- return lab_name
-
- def prologue(self):
- """ Returns prologue instruction sequence """
- pre = [
- Label(self.name), # Label indication function
- Push({LR, R11})
- ]
- if self.stacksize > 0:
- pre.append(Sub(SP, SP, self.stacksize)) # Reserve stack space
- pre += [
- Mov(R11, SP) # Setup frame pointer
- ]
- return pre
-
- def epilogue(self):
- """ Return epilogue sequence for a frame. Adjust frame pointer and add constant pool """
- post = []
- if self.stacksize > 0:
- post.append(Add(SP, SP, self.stacksize))
- post += [
- Pop({PC, R11}),
- Alignment(4) # Align at 4 bytes
- ]
- # Add constant literals:
- for ln, v in self.constants:
- post.extend([Label(ln), Dcd(v)])
- return post
-
- def EntryExitGlue3(self):
- """
- Add code for the prologue and the epilogue. Add a label, the
- return instruction and the stack pointer adjustment for the frame.
- """
- for index, ins in enumerate(self.prologue()):
- self.instructions.insert(index, AbstractInstruction(ins))
-
- # Postfix code:
- for ins in self.epilogue():
- self.instructions.append(AbstractInstruction(ins))
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/arm/instructions.py
--- a/python/ppci/target/arm/instructions.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,323 +0,0 @@
-
-from ..basetarget import Instruction
-from ...bitfun import rotate_left
-
-from .token import ArmToken
-from .registers import R0, SP, ArmRegister
-
-
-def encode_imm32(v):
- """ Bundle 32 bit value into 4 bits rotation and 8 bits value
- """
- for i in range(0, 16):
- v2 = rotate_left(v, i*2)
- if (v2 & 0xFFFFFF00) == 0:
- rotation = i
- val = v2 & 0xFF
- x = (rotation << 8) | val
- return x
- raise Exception("Invalid value {}".format(v))
-
-# Instructions:
-
-class ArmInstruction(Instruction):
- def __init__(self):
- self.token = ArmToken()
-
-
-class Dcd(ArmInstruction):
- def __init__(self, v):
- super().__init__()
- self.v = v
-
- def encode(self):
- self.token[0:32] = self.v
- return self.token.encode()
-
-
-def Mov(*args):
- if len(args) == 2:
- if isinstance(args[1], int):
- return Mov1(*args)
- elif isinstance(args[1], ArmRegister):
- return Mov2(*args)
- raise Exception()
-
-
-class Mov1(ArmInstruction):
- """ Mov Rd, imm16 """
- def __init__(self, reg, imm):
- super().__init__()
- assert type(imm) is int
- self.reg = reg
- self.imm = imm
-
- def encode(self):
- self.token[0:12] = encode_imm32(self.imm)
- self.token.Rd = self.reg.num
- self.token[16:20] = 0
- self.token[20] = 0 # Set flags
- self.token[21:28] = 0b0011101
- self.token.cond = AL
- return self.token.encode()
-
- def relocations(self):
- return []
-
- def __repr__(self):
- return 'Mov {}, {}'.format(self.reg, self.imm)
-
-
-class Mov2(ArmInstruction):
- def __init__(self, rd, rm):
- super().__init__()
- self.rd = rd
- self.rm = rm
-
- def encode(self):
- self.token[0:4] = self.rm.num
- self.token[4:12] = 0
- self.token[12:16] = self.rd.num
- self.token[16:20] = 0
- self.token.S = 0
- self.token[21:28] = 0xD
- self.token.cond = AL
- return self.token.encode()
-
-
-def Add(*args):
- if len(args) == 3 and isinstance(args[0], ArmRegister) and \
- isinstance(args[1], ArmRegister):
- if isinstance(args[2], ArmRegister):
- return Add1(args[0], args[1], args[2])
- elif isinstance(args[2], int):
- return Add2(args[0], args[1], args[2])
- raise Exception()
-
-def Sub(*args):
- if len(args) == 3 and isinstance(args[0], ArmRegister) and \
- isinstance(args[1], ArmRegister):
- if isinstance(args[2], ArmRegister):
- return Sub1(args[0], args[1], args[2])
- elif isinstance(args[2], int):
- return Sub2(args[0], args[1], args[2])
- raise Exception()
-
-def Mul(*args):
- return Mul1(args[0], args[1], args[2])
-
-
-class Mul(ArmInstruction):
- def __init__(self, rd, rn, rm):
- super().__init__()
- self.rd = rd
- self.rn = rn
- self.rm = rm
-
- def encode(self):
- self.token[0:4] = self.rn.num
- self.token[4:8] = 0b1001
- self.token[8:12] = self.rm.num
- self.token[16:20] = self.rd.num
- self.token.S = 0
- self.token.cond = AL
- return self.token.encode()
-
-
-class OpRegRegReg(ArmInstruction):
- """ add rd, rn, rm """
- def __init__(self, rd, rn, rm, shift=0):
- super().__init__()
- self.rd = rd
- self.rn = rn
- self.rm = rm
-
- def encode(self):
- self.token[0:4] = self.rm.num
- self.token[4] = 0
- self.token[5:7] = 0
- self.token[7:12] = 0 # Shift
- self.token.Rd = self.rd.num
- self.token.Rn = self.rn.num
- self.token.S = 0 # Set flags
- self.token[21:28] = self.opcode
- self.token.cond = 0xE # Always!
- return self.token.encode()
-
- def __repr__(self):
- return 'add {}, {}, {}'.format(self.rd, self.rn, self.rm)
-
-
-class Add1(OpRegRegReg):
- opcode = 0b0000100
-
-
-class Sub1(OpRegRegReg):
- opcode = 0b0000010
-
-
-class Orr1(OpRegRegReg):
- opcode = 0b0001100
-
-
-class OpRegRegImm(ArmInstruction):
- """ add rd, rn, imm12 """
- def __init__(self, rd, rn, imm):
- super().__init__()
- self.rd = rd
- self.rn = rn
- self.imm2 = encode_imm32(imm)
- self.imm = imm
-
- def encode(self):
- self.token[0:12] = self.imm2
- self.token.Rd = self.rd.num
- self.token.Rn = self.rn.num
- self.token.S = 0 # Set flags
- self.token[21:28] = self.opcode
- self.token.cond = 0xE # Always!
- return self.token.encode()
-
- def __repr__(self):
- return 'add {}, {}, {}'.format(self.rd, self.rn, self.imm)
-
-
-class Add2(OpRegRegImm):
- opcode = 0b0010100
-
-
-class Sub2(OpRegRegImm):
- opcode = 0b0010010
-
-
-
-# Branches:
-
-class BranchBaseRoot(ArmInstruction):
- def __init__(self, target):
- super().__init__()
- self.target = target
-
- def encode(self):
- self.token.cond = self.cond
- self.token[24:28] = self.opcode
- return self.token.encode()
-
- def relocations(self):
- return [(self.target, 'b_imm24')]
-
-
-EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL = range(15)
-
-class BranchBase(BranchBaseRoot):
- opcode = 0b1010
-
-class BranchLinkBase(BranchBaseRoot):
- opcode = 0b1011
-
-class Bl(BranchLinkBase):
- cond = AL
-
-class B(BranchBase):
- cond = AL
-
-class Beq(BranchBase):
- cond = EQ
-
-class Bgt(BranchBase):
- cond = GT
-
-class Ble(BranchBase):
- cond = LE
-
-class Blt(BranchBase):
- cond = LT
-
-
-# Memory:
-
-def reg_list_to_mask(reg_list):
- mask = 0
- for reg in reg_list:
- mask |= (1 << reg.num)
- return mask
-
-
-class Push(ArmInstruction):
- def __init__(self, register_set):
- super().__init__()
- self.reg_list = register_set
-
- def encode(self):
- self.token.cond = AL
- self.token[16:28] = 0b100100101101
- reg_list = 0
- self.token[0:16] = reg_list_to_mask(self.reg_list)
- return self.token.encode()
-
-class Pop(ArmInstruction):
- def __init__(self, register_set):
- super().__init__()
- self.reg_list = register_set
-
- def encode(self):
- self.token.cond = AL
- self.token[16:28] = 0b100010111101
- self.token[0:16] = reg_list_to_mask(self.reg_list)
- return self.token.encode()
-
-
-def Ldr(*args):
- if len(args) == 3 and isinstance(args[1], ArmRegister):
- return Ldr1(*args)
- elif len(args) == 2 and isinstance(args[1], ArmRegister):
- return Ldr1(args[0], args[1], 0)
- raise Exception()
-
-def Str(*args):
- if len(args) == 3 and isinstance(args[1], ArmRegister):
- return Str1(*args)
- elif len(args) == 2 and isinstance(args[1], ArmRegister):
- return Str1(args[0], args[1], 0)
- raise Exception()
-
-
-class LdrStrBase(ArmInstruction):
- def __init__(self, rt, rn, offset):
- super().__init__()
- self.rt = rt
- self.rn = rn
- self.offset = offset
-
- def encode(self):
- self.token.cond = AL
- self.token.Rn = self.rn.num
- self.token[25:28] = self.opcode
- self.token[20] = self.bit20
- self.token[12:16] = self.rt.num
- self.token[24] = 1 # Index
- if self.offset >= 0:
- self.token[23] = 1 # U == 1 'add'
- self.token[0:12] = self.offset
- else:
- self.token[23] = 0
- self.token[0:12] = -self.offset
- return self.token.encode()
-
-
-class Str1(LdrStrBase):
- opcode = 0b010
- bit20 = 0
-
-
-class Ldr1(LdrStrBase):
- opcode = 0b010
- bit20 = 1
-
-
-class Ldr3(ArmInstruction):
- """ Load PC relative constant value """
- def __init__(self, rt, label):
- self.rt = rt
- self.label = label
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/arm/registers.py
--- a/python/ppci/target/arm/registers.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-
-from ..basetarget import Register
-
-class ArmRegister(Register):
- def __init__(self, num, name):
- super().__init__(name)
- self.num = num
-
- def __repr__(self):
- return self.name
-
-
-class Reg8Op(ArmRegister):
- pass
-
-
-def get_register(n):
- for x in registers:
- if x.num == n:
- return x
- raise Exception('No register found with this number')
-
-def register_range(a, b):
- """ Return set of registers from a to b """
- assert a.num < b.num
- return {get_register(n) for n in range(a.num, b.num + 1)}
-
-
-R0 = Reg8Op(0, 'r0')
-R1 = Reg8Op(1, 'r1')
-R2 = Reg8Op(2, 'r2')
-R3 = Reg8Op(3, 'r3')
-R4 = Reg8Op(4, 'r4')
-R5 = Reg8Op(5, 'r5')
-R6 = Reg8Op(6, 'r6')
-R7 = Reg8Op(7, 'r7')
-R8 = ArmRegister(8, 'r8')
-R9 = ArmRegister(9, 'r9')
-R10 = ArmRegister(10, 'r10')
-R11 = ArmRegister(11, 'r11')
-R12 = ArmRegister(12, 'r12')
-
-# Other registers:
-# TODO
-SP = ArmRegister(13, 'sp')
-LR = ArmRegister(14, 'lr')
-PC = ArmRegister(15, 'pc')
-
-registers = [R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC]
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/arm/selector.py
--- a/python/ppci/target/arm/selector.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-from ... import ir, same_dir
-from ppci.irmach import AbstractInstruction as makeIns
-from ppci.ir2tree import makeTree
-from .instructions import Str1, Mov2
-from .instructions import B, Bl, Blt, Bgt, Beq
-import pyburg
-from ..basetarget import Nop
-from ..instructionselector import InstructionSelector
-
-# Import BURG spec for arm:
-spec_file = same_dir(__file__, 'arm.brg')
-arm_matcher = pyburg.load_as_module(spec_file)
-
-
-class ArmMatcher(arm_matcher.Matcher):
- """ Matcher that derives from a burg spec generated matcher """
- def __init__(self, selector):
- super().__init__()
- self.newTmp = selector.newTmp
- self.emit = selector.emit
- self.selector = selector
-
-
-class ArmInstructionSelector(InstructionSelector):
- """ Instruction selector for the arm architecture """
- def __init__(self):
- super().__init__()
- self.matcher = ArmMatcher(self)
-
- def munchExpr(self, e):
- # Use BURG system here:
- t = makeTree(e)
- return self.matcher.gen(t)
-
- def munchCall(self, e):
- """ Generate code for call sequence """
- # Move arguments into proper locations:
- reguses = []
- for i, a in enumerate(e.arguments):
- loc = self.frame.argLoc(i)
- m = ir.Move(loc, a)
- self.munchStm(m)
- if isinstance(loc, ir.Temp):
- reguses.append(loc)
- self.emit(Bl(e.f), src=reguses, dst=[self.frame.rv])
- d = self.newTmp()
- self.move(d, self.frame.rv)
- return d
-
- def munchStm(self, s):
- if isinstance(s, ir.Terminator):
- pass
- elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and \
- isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and \
- isinstance(s.dst.e.b, ir.Const):
- a = self.munchExpr(s.dst.e.a)
- val = self.munchExpr(s.src)
- c = s.dst.e.b.value
- self.emit(Str1, others=[c], src=[a, val])
- elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
- memloc = self.munchExpr(s.dst.e)
- val = self.munchExpr(s.src)
- self.emit(Str1, others=[0], src=[memloc, val])
- elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
- val = self.munchExpr(s.src)
- dreg = s.dst
- self.move(dreg, val)
- elif isinstance(s, ir.Exp):
- # Generate expression code and discard the result.
- x = self.munchExpr(s.e)
- self.emit(Nop(), src=[x])
- elif isinstance(s, ir.Jump):
- tgt = self.targets[s.target]
- self.emit(B(ir.label_name(s.target)), jumps=[tgt])
- elif isinstance(s, ir.CJump):
- a = self.munchExpr(s.a)
- b = self.munchExpr(s.b)
- self.emit(Cmp, src=[a, b])
- ntgt = self.targets[s.lab_no]
- ytgt = self.targets[s.lab_yes]
- jmp_ins = makeIns(B(ir.label_name(s.lab_no)), jumps=[ntgt])
- opnames = {'<': Blt, '>':Bgt, '==':Beq, '!=':Bne}
- op = opnames[s.cond](ir.label_name(s.lab_yes))
- self.emit(op, jumps=[ytgt, jmp_ins]) # Explicitely add fallthrough
- self.emit2(jmp_ins)
- else:
- raise NotImplementedError('Stmt --> {}'.format(s))
-
- def move(self, dst, src):
- self.emit(Mov2, src=[src], dst=[dst], ismove=True)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/arm/token.py
--- a/python/ppci/target/arm/token.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-
-from ..token import Token, u32, bit_range
-
-
-class ArmToken(Token):
- def __init__(self):
- super().__init__(32)
-
- cond = bit_range(28, 32)
- S = bit_range(20, 21)
- Rd = bit_range(12, 16)
- Rn = bit_range(16, 20)
-
- def encode(self):
- return u32(self.bit_value)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/basetarget.py
--- a/python/ppci/target/basetarget.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-from ppci import CompilerError
-
-"""
- Base classes for defining a target
-"""
-
-class Instruction:
- """ Base instruction class """
- def encode(self):
- return bytes()
-
- def relocations(self):
- return []
-
- def symbols(self):
- return []
-
-
-class Nop(Instruction):
- """ Instruction that does nothing and has zero size """
- def encode(self):
- return bytes()
-
-
-class PseudoInstruction(Instruction):
- pass
-
-
-class Label(PseudoInstruction):
- def __init__(self, name):
- self.name = name
-
- def __repr__(self):
- return '{}:'.format(self.name)
-
- def symbols(self):
- return [self.name]
-
-
-class Comment(PseudoInstruction):
- def __init__(self, txt):
- self.txt = txt
-
- def encode(self):
- return bytes()
-
- def __repr__(self):
- return '; {}'.format(self.txt)
-
-
-class Alignment(PseudoInstruction):
- def __init__(self, a):
- self.align = a
-
- def __repr__(self):
- return 'ALIGN({})'.format(self.align)
-
- def encode(self):
- pad = []
- # TODO
- address = 0
- while (address % self.align) != 0:
- address += 1
- pad.append(0)
- return bytes(pad)
-
-
-class DebugInfo(PseudoInstruction):
- def __init__(self, i):
- self.info = i
-
- def __repr__(self):
- return 'DebugInfo: {}'.format(self.info)
-
-
-class Register:
- def __init__(self, name):
- self.name = name
-
-
-class Target:
- def __init__(self, name, desc=''):
- self.name = name
- self.desc = desc
- self.registers = []
- self.byte_sizes = {'int' : 4} # For front end!
-
- # For lowering:
- self.lower_functions = {}
-
- # For assembler:
- self.assembler_rules = []
- self.asm_keywords = []
-
- self.generate_base_rules()
-
- def generate_base_rules(self):
- # Base rules for constants:
- self.add_rule('imm32', ['val32'], lambda x: x[0].val)
- self.add_rule('imm32', ['imm16'], lambda x: x[0])
-
- self.add_rule('imm16', ['val16'], lambda x: x[0].val)
- self.add_rule('imm16', ['imm12'], lambda x: x[0])
-
- self.add_rule('imm12', ['val12'], lambda x: x[0].val)
- self.add_rule('imm12', ['imm8'], lambda x: x[0])
-
- self.add_rule('imm8', ['val8'], lambda x: x[0].val)
- self.add_rule('imm8', ['imm5'], lambda x: x[0])
-
- self.add_rule('imm5', ['val5'], lambda x: x[0].val)
- self.add_rule('imm5', ['imm3'], lambda x: x[0])
-
- self.add_rule('imm3', ['val3'], lambda x: x[0].val)
-
- def add_keyword(self, kw):
- self.asm_keywords.append(kw)
-
- def add_instruction(self, rhs, f):
- self.add_rule('instruction', rhs, f)
-
- def add_rule(self, lhs, rhs, f):
- self.assembler_rules.append((lhs, rhs, f))
-
- def lower_frame_to_stream(self, frame, outs):
- """ Lower instructions from frame to output stream """
- for im in frame.instructions:
- if isinstance(im.assem, Instruction):
- outs.emit(im.assem)
- else:
- ins = self.lower_functions[im.assem](im)
- outs.emit(ins)
-
- def add_lowering(self, cls, f):
- """ Add a function to the table of lowering options for this target """
- self.lower_functions[cls] = f
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/instructionselector.py
--- a/python/ppci/target/instructionselector.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-from ppci import ir
-from ppci import irmach
-from ppci.irmach import AbstractInstruction as makeIns
-from .basetarget import Label
-
-def genTemps():
- n = 900
- while True:
- yield ir.Temp('t{}'.format(n))
- n = n + 1
-
-
-class InstructionSelector:
- """
- Base instruction selector. This class must be overridden by
- backends.
- """
- def __init__(self):
- self.temps = genTemps()
-
- def newTmp(self):
- return self.temps.__next__()
-
- def munchFunction(self, f, frame):
- # Entry point for instruction selection
- assert isinstance(f, ir.Function)
- self.targets = {}
- # Enter a frame per function:
- self.frame = frame
- # First define labels:
- for bb in f.Blocks:
- itgt = makeIns(Label(ir.label_name(bb)))
- self.targets[bb] = itgt
- # Generate code for all blocks:
- for bb in f.Blocks:
- self.emit2(self.targets[bb])
- for i in bb.Instructions:
- self.munchStm(i)
- self.munchStm(ir.Move(self.frame.rv, f.return_value))
-
- def move(self, dst, src):
- raise NotImplementedError('Not target implemented')
-
- def emit(self, *args, **kwargs):
- """ Abstract instruction emitter """
- i = makeIns(*args, **kwargs)
- return self.emit2(i)
-
- def emit2(self, i):
- self.frame.instructions.append(i)
- return i
-
- def munchStm(self, s):
- """ Implement this in the target specific back-end """
- raise NotImplementedError()
-
- def munchExpr(self, e):
- """ Implement this in the target specific back-end """
- raise NotImplementedError()
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/msp430/instructions.py
--- a/python/ppci/target/msp430/instructions.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,211 +0,0 @@
-
-from ..basetarget import Register, Instruction, Target
-from ..token import Token, u16, bit_range
-from .registers import Msp430Register
-
-
-class Msp430Token(Token):
- def __init__(self):
- super().__init__(16)
-
- condition = bit_range(10, 13)
- opcode = bit_range(12, 16)
- register = bit_range(0, 4)
- destination = bit_range(0, 4)
- source = bit_range(8, 12)
- bw = bit_range(6, 7) # TODO: actually a single bit!
- Ad = bit_range(7, 8) # TODO: actually a single bit!
- As = bit_range(4, 6)
-
- def encode(self):
- return u16(self.bit_value)
-
-REGISTER_MODE = 1
-SYMBOLIC_MODE = 3
-ABSOLUTE_MODE = 4
-#TODO: add more modes!
-IMMEDIATE_MODE = 7
-
-class Msp430Operand:
- pass
-
-class Msp430DestinationOperand(Msp430Operand):
- def __init__(self, param):
- if isinstance(param, Msp430Register):
- self.reg = param.num
- self.Ad = 0
- else:
- raise Exception()
-
-
-class Msp430SourceOperand(Msp430Operand):
- def __init__(self, param):
- if isinstance(param, Msp430Register):
- self.reg = param.num
- self.As = 0
- self.extra_bytes = bytes()
- elif isinstance(param, int):
- self.reg = 0
- self.As = 3
- self.extra_bytes = u16(param)
- else:
- raise Exception()
-
-
-class Msp430Instruction(Instruction):
- b = 0
- def __init__(self):
- self.token = Msp430Token()
-
-
-class Reti(Msp430Instruction):
- def encode(self):
- self.token[0:16] = 0x1300
- return self.token.encode()
-
-
-#########################
-# Jump instructions:
-#########################
-
-class JumpInstruction(Msp430Instruction):
- def __init__(self, target):
- super().__init__()
- self.target = target
-
- def encode(self):
- self.token.condition = self.condition
- self.token.offset = 0
- self.token[13] = 1
- return self.token.encode()
-
- def relocations(self):
- return [(self.target, 'msp_reloc')]
-
-
-class Jnz(JumpInstruction):
- condition = 0
-
-
-class Jz(JumpInstruction):
- condition = 1
-
-
-class Jnc(JumpInstruction):
- condition = 2
-
-
-class Jc(JumpInstruction):
- condition = 3
-
-
-class Jn(JumpInstruction):
- condition = 4
-
-
-class Jge(JumpInstruction):
- condition = 5
-
-
-class Jl(JumpInstruction):
- condition = 6
-
-
-class Jmp(JumpInstruction):
- condition = 7
-
-
-#########################
-# Single operand arithmatic:
-#########################
-
-
-class OneOpArith(Msp430Instruction):
- def __init__(self, op1):
- self.op1 = op1
-
- def encode(self):
- # TODO:
- bits[15:10] = '00100'
- h1 = (self.opcode << 4)
- return pack_ins(h1)
-
-
-def oneOpIns(mne, opc):
- """ Helper function to define a one operand arithmetic instruction """
- members = {'opcode': opc}
- ins_cls = type(mne + '_ins', (OneOpArith,), members)
-
-
-oneOpIns('rrc', 0)
-oneOpIns('swpb', 1)
-oneOpIns('rra', 2)
-oneOpIns('sxt', 3)
-oneOpIns('push', 4)
-oneOpIns('call', 5)
-
-
-#########################
-# Two operand arithmatic instructions:
-#########################
-
-
-class TwoOpArith(Msp430Instruction):
- def __init__(self, src, dst):
- super().__init__()
- self.src = Msp430SourceOperand(src)
- self.dst = Msp430DestinationOperand(dst)
-
- def encode(self):
- """
- Smart things have been done by MSP430 designers.
- As (2 bits) is the source addressing mode selector.
- Ad (1 bit) is the destination adressing mode selector.
- For the source there are 7 different addressing mode.
- For the destination there are 4.
- The trick is to use also the register to distuingish the
- different modes.
- """
- # TODO: Make memory also possible
- self.token.bw = self.b # When b=1, the operation is byte mode
- self.token.As = self.src.As
- self.token.Ad = self.dst.Ad
- self.token.destination = self.dst.reg
- self.token.source = self.src.reg
- self.token.opcode = self.opcode
- return self.token.encode() + self.src.extra_bytes
-
-
-def twoOpIns(mne, opc):
- """ Helper function to define a two operand arithmetic instruction """
- members = {'opcode': opc}
- ins_cls = type(mne + '_ins', (TwoOpArith,), members)
-
-
-class Mov(TwoOpArith):
- """ Moves the source to the destination """
- opcode = 4
-
-
-# This is equivalent to the helper function twoOpIns:
-class Add(TwoOpArith):
- """ Adds the source to the destination """
- mnemonic = 'add'
- opcode = 5
-
-
-twoOpIns('addc', 6)
-twoOpIns('subc', 7)
-twoOpIns('sub', 8)
-
-
-class Cmp(TwoOpArith):
- opcode = 9
-
-
-twoOpIns('dadd', 10)
-twoOpIns('bit', 11)
-twoOpIns('bic', 12)
-twoOpIns('bis', 13)
-twoOpIns('xor', 14)
-twoOpIns('and', 15)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/msp430/msp430.py
--- a/python/ppci/target/msp430/msp430.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-import struct
-import types
-from ..basetarget import Register, Instruction, Target
-from ppci import CompilerError
-from .registers import r10, r11, r12, r13, r14, r15
-from .instructions import Reti, Mov, Add
-
-# Create the target class (singleton):
-
-class Msp430Target(Target):
- def __init__(self):
- super().__init__('msp430')
-
- # Registers:
- self.add_keyword('r10')
- self.add_keyword('r11')
- self.add_keyword('r12')
- self.add_keyword('r13')
- self.add_keyword('r14')
- self.add_keyword('r15')
- self.add_rule('reg', ['r10'], lambda rhs: r10)
- self.add_rule('reg', ['r11'], lambda rhs: r11)
- self.add_rule('reg', ['r12'], lambda rhs: r12)
- self.add_rule('reg', ['r13'], lambda rhs: r13)
- self.add_rule('reg', ['r14'], lambda rhs: r14)
- self.add_rule('reg', ['r15'], lambda rhs: r15)
-
- # Instructions rules:
- self.add_keyword('mov')
- self.add_instruction(['mov', 'reg', ',', 'reg'],
- lambda rhs: Mov(rhs[1], rhs[3]))
- self.add_instruction(['mov', 'imm16', ',', 'reg'],
- lambda rhs: Mov(rhs[1], rhs[3]))
-
- self.add_keyword('add')
- self.add_instruction(['add', 'reg', ',', 'reg'],
- lambda rhs: Add(rhs[1], rhs[3]))
-
- self.add_keyword('reti')
- self.add_instruction(['reti'], lambda rhs: Reti())
-
-
-
-msp430target = Msp430Target()
-
-
-# Target description for the MSP430 processor
-
-
-msp430target.registers.append(r10)
-msp430target.registers.append(r11)
-msp430target.registers.append(r12)
-msp430target.registers.append(r13)
-msp430target.registers.append(r14)
-msp430target.registers.append(r15)
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/msp430/registers.py
--- a/python/ppci/target/msp430/registers.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-
-from ..basetarget import Register
-
-class Msp430Register(Register):
- def __init__(self, num, name):
- super().__init__(name)
- self.num = num
-
-# 8 bit registers:
-PCB = Msp430Register(0, 'r0')
-rpc = PCB
-r10 = Msp430Register(10, 'r10')
-r11 = Msp430Register(11, 'r11')
-r12 = Msp430Register(12, 'r12')
-r13 = Msp430Register(13, 'r13')
-r14 = Msp430Register(14, 'r14')
-r15 = Msp430Register(15, 'r15')
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/target_list.py
--- a/python/ppci/target/target_list.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-
-from .arm import ArmTarget
-from .thumb import ThumbTarget
-from .msp430.msp430 import msp430target
-
-# Instance:
-arm_target = ArmTarget()
-thumb_target = ThumbTarget()
-
-target_list = [arm_target, thumb_target]
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/thumb/__init__.py
--- a/python/ppci/target/thumb/__init__.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-
-
-from .armtarget import ThumbTarget
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/thumb/arm.brg
--- a/python/ppci/target/thumb/arm.brg Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-
-from ppci.target.thumb.instructions import Orr, Lsl, Str2, Ldr2, Ldr3
-from ppci.target.thumb.instructions import B, Bl, Bgt, Blt, Beq, Bne
-from ppci.target.thumb.instructions import Mov2, Mov3, Sub3
-from ppci.target.thumb.instructions import Add3, Sub, Cmp, Sub2, Add2, Mul
-
-%%
-
-%terminal ADDI32 SUBI32 MULI32
-%terminal ORI32 SHLI32
-%terminal CONSTI32 MEMI32 REGI32 CALL
-%terminal MOVI32
-
-%%
-
-
-reg: ADDI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Add3, dst=[d], src=[$1, $2]); return d .)
-reg: SUBI32(reg, reg) 2 (. d = self.newTmp(); self.emit(Sub3, dst=[d], src=[$1, $2]); return d .)
-reg: ORI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Orr, dst=[], src=[d, $2]); return d .)
-reg: SHLI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Lsl, dst=[], src=[d, $2]); return d .)
-reg: MULI32(reg, reg) 2 (. d = self.newTmp(); self.selector.move(d, $1); self.emit(Mul, dst=[d], src=[$2, d]); return d .)
-
-reg: CONSTI32 3 (. d = self.newTmp(); ln = self.selector.frame.addConstant($$.value); self.emit(Ldr3, dst=[d], others=[ln]); return d .)
-reg: MEMI32(reg) 4 (. d = self.newTmp(); self.emit(Ldr2, dst=[d], src=[$1], others=[0]); return d .)
-reg: REGI32 1 (. return $$.value .)
-reg: CALL 1 (. return self.selector.munchCall($$.value) .)
-
-
-stmt: MOVI32(MEMI32(addr), reg) 3 (. self.emit(Str2, src=[$1, $2]) .)
-
-addr: reg 2 (. .)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/thumb/arminstructionselector.py
--- a/python/ppci/target/thumb/arminstructionselector.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-from ... import ir, same_dir
-from ppci.irmach import AbstractInstruction as makeIns
-from ppci.ir2tree import makeTree
-import pyburg
-from ..basetarget import Nop
-from ..instructionselector import InstructionSelector
-from .instructions import Orr, Lsl, Str2, Ldr2, Ldr3
-from .instructions import B, Bl, Bgt, Blt, Beq, Bne
-from .instructions import Mov2, Mov3
-from .instructions import Cmp, Sub2, Mul
-
-# Import BURG spec for arm:
-spec_file = same_dir(__file__, 'arm.brg')
-arm_matcher = pyburg.load_as_module(spec_file)
-
-
-class ArmMatcher(arm_matcher.Matcher):
- """ Matcher that derives from a burg spec generated matcher """
- def __init__(self, selector):
- super().__init__()
- self.newTmp = selector.newTmp
- self.emit = selector.emit
- self.selector = selector
-
-
-class ArmInstructionSelector(InstructionSelector):
- """ Instruction selector for the arm architecture """
- def __init__(self):
- super().__init__()
- self.matcher = ArmMatcher(self)
-
- def munchExpr(self, e):
- # Use BURG system here:
- t = makeTree(e)
- return self.matcher.gen(t)
-
- def munchCall(self, e):
- """ Generate code for call sequence """
- # Move arguments into proper locations:
- reguses = []
- for i, a in enumerate(e.arguments):
- loc = self.frame.argLoc(i)
- m = ir.Move(loc, a)
- self.munchStm(m)
- if isinstance(loc, ir.Temp):
- reguses.append(loc)
- self.emit(Bl(e.f), src=reguses, dst=[self.frame.rv])
- d = self.newTmp()
- self.move(d, self.frame.rv)
- return d
-
- def munchStm(self, s):
- if isinstance(s, ir.Terminator):
- pass
- elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem) and \
- isinstance(s.dst.e, ir.Binop) and s.dst.e.operation == '+' and \
- isinstance(s.dst.e.b, ir.Const):
- a = self.munchExpr(s.dst.e.a)
- val = self.munchExpr(s.src)
- c = s.dst.e.b.value
- self.emit(Str2, others=[c], src=[a, val])
- elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Mem):
- memloc = self.munchExpr(s.dst.e)
- val = self.munchExpr(s.src)
- self.emit(Str2, others=[0], src=[memloc, val])
- elif isinstance(s, ir.Move) and isinstance(s.dst, ir.Temp):
- val = self.munchExpr(s.src)
- dreg = s.dst
- self.move(dreg, val)
- elif isinstance(s, ir.Exp):
- # Generate expression code and discard the result.
- x = self.munchExpr(s.e)
- self.emit(Nop(), src=[x])
- elif isinstance(s, ir.Jump):
- tgt = self.targets[s.target]
- self.emit(B(ir.label_name(s.target)), jumps=[tgt])
- elif isinstance(s, ir.CJump):
- a = self.munchExpr(s.a)
- b = self.munchExpr(s.b)
- self.emit(Cmp, src=[a, b])
- ntgt = self.targets[s.lab_no]
- ytgt = self.targets[s.lab_yes]
- jmp_ins = makeIns(B(ir.label_name(s.lab_no)), jumps=[ntgt])
- opnames = {'<': Blt, '>':Bgt, '==':Beq, '!=':Bne}
- op = opnames[s.cond](ir.label_name(s.lab_yes))
- self.emit(op, jumps=[ytgt, jmp_ins]) # Explicitely add fallthrough
- self.emit2(jmp_ins)
- else:
- raise NotImplementedError('Stmt --> {}'.format(s))
-
- def move(self, dst, src):
- self.emit(Mov2, src=[src], dst=[dst], ismove=True)
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/thumb/armtarget.py
--- a/python/ppci/target/thumb/armtarget.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-import struct
-from ..basetarget import Register, Instruction, Target, Label, Alignment
-from .instructions import Add2, Sub, Sub3, Add3, Cmp, Lsl, Orr, Add, Cmp2, Sub2, Add2, Mul, And
-from .instructions import Dcd, Pop, Push, Yield, Mov2, Mov3
-from .instructions import B, Bl, Bne, Beq, Blt, Bgt
-from .instructions import Ldr, Str2, Ldr2, Str1, Ldr1, Ldr3
-
-from .frame import ArmFrame
-from .arminstructionselector import ArmInstructionSelector
-from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7, SP, LR, PC
-from ..arm.registers import register_range
-
-
-""" ARM target description. """
-
-# TODO: encode this in DSL (domain specific language)
-# TBD: is this required?
-# TODO: make a difference between armv7 and armv5?
-
-thumb_assembly_rules = []
-def add_rule(rhs, f):
- thumb_assembly_rules.append(('instruction', rhs, f))
-
-
-class ThumbTarget(Target):
- def __init__(self):
- super().__init__('thumb')
- self.ins_sel = ArmInstructionSelector()
- self.FrameClass = ArmFrame
- self.add_rules()
-
- # Add lowering options:
- self.add_lowering(Str2, lambda im: Str2(im.src[1], im.src[0], im.others[0]))
- self.add_lowering(Ldr2, lambda im: Ldr2(im.dst[0], im.src[0], im.others[0]))
- self.add_lowering(Ldr3, lambda im: Ldr3(im.dst[0], im.others[0]))
- self.add_lowering(Mov3, lambda im: Mov3(im.dst[0], im.others[0]))
- self.add_lowering(Add2, lambda im: Add2(im.dst[0], im.src[0], im.others[0]))
- self.add_lowering(Sub2, lambda im: Sub2(im.dst[0], im.src[0], im.others[0]))
- self.add_lowering(Mov2, lambda im: Mov2(im.dst[0], im.src[0]))
- self.add_lowering(Add3, lambda im: Add3(im.dst[0], im.src[0], im.src[1]))
- self.add_lowering(Sub3, lambda im: Sub3(im.dst[0], im.src[0], im.src[1]))
- self.add_lowering(Mul, lambda im: Mul(im.src[0], im.dst[0]))
- self.add_lowering(And, lambda im: And(im.src[0], im.src[1]))
- self.add_lowering(Orr, lambda im: Orr(im.src[0], im.src[1]))
- self.add_lowering(Lsl, lambda im: Lsl(im.src[0], im.src[1]))
- self.add_lowering(Cmp, lambda im: Cmp(im.src[0], im.src[1]))
-
- def add_rules(self):
-
- # Add instructions:
- self.add_keyword('dcd')
- self.add_instruction(['dcd', 'imm32'], lambda rhs: Dcd(rhs[1]))
-
- self.add_keyword('mov')
- self.add_instruction(['mov', 'reg8', ',', 'reg8'],
- lambda rhs: Mov2(rhs[1], rhs[3]))
-
- self.add_instruction(['mov', 'reg8', ',', 'imm8'],
- lambda rhs: Mov3(rhs[1], rhs[3]))
-
- self.add_keyword('add')
- self.add_instruction(['add', 'reg8', ',', 'reg8', ',', 'imm3'],
- lambda rhs: Add2(rhs[1], rhs[3], rhs[5]))
-
- self.add_instruction(['add', 'reg8', ',', 'reg8', ',', 'reg8'],
- lambda rhs: Add3(rhs[1], rhs[3], rhs[5]))
-
- self.add_keyword('sub')
- self.add_instruction(['sub', 'reg8', ',', 'reg8', ',', 'imm3'],
- lambda rhs: Sub(rhs[1], rhs[3], rhs[5]))
-
- self.add_instruction(['sub', 'sp', ',', 'sp', ',', 'imm8'],
- lambda rhs: Sub(SP, SP, rhs[5]))
-
- self.add_instruction(['add', 'sp', ',', 'sp', ',', 'imm8'],
- lambda rhs: Add(SP, SP, rhs[5]))
-
- self.add_keyword('cmp')
- self.add_instruction(['cmp', 'reg8', ',', 'reg8'],
- lambda rhs: Cmp(rhs[1], rhs[3]))
- self.add_instruction(['cmp', 'reg8', ',', 'imm8'],
- lambda rhs: Cmp2(rhs[1], rhs[3]))
-
- self.add_keyword('lsl')
- self.add_instruction(['lsl', 'reg8', ',', 'reg8'],
- lambda rhs: Lsl(rhs[1], rhs[3]))
-
- self.add_keyword('str')
- self.add_instruction(['str', 'reg8', ',', '[', 'reg8', '+', 'imm5', ']'],
- lambda rhs: Str2(rhs[1], rhs[4], rhs[6]))
-
- self.add_keyword('ldr')
- self.add_instruction(['ldr', 'reg8', ',', '[', 'reg8', '+', 'imm5', ']'],
- lambda rhs: Ldr2(rhs[1], rhs[4], rhs[6]))
-
- self.add_instruction(['str', 'reg8', ',', '[', 'sp', '+', 'imm8', ']'],
- lambda rhs: Str1(rhs[1], rhs[6]))
-
- self.add_instruction(['ldr', 'reg8', ',', '[', 'sp', '+', 'imm8', ']'],
- lambda rhs: Ldr1(rhs[1], rhs[6]))
-
- self.add_keyword('pop')
- self.add_instruction(['pop', 'reg_list'], lambda rhs: Pop(rhs[1]))
- self.add_keyword('push')
- self.add_instruction(['push', 'reg_list'], lambda rhs: Push(rhs[1]))
-
- self.add_keyword('yield')
- self.add_instruction(['yield'], lambda rhs: Yield())
-
- self.add_keyword('b')
- self.add_keyword('bl')
- self.add_instruction(['b', 'ID'], lambda rhs: B(rhs[1].val))
- self.add_instruction(['bl', 'ID'], lambda rhs: Bl(rhs[1].val))
- self.add_keyword('beq')
- self.add_keyword('bne')
- self.add_keyword('blt')
- self.add_keyword('bgt')
- self.add_instruction(['beq', 'ID'], lambda rhs: Beq(rhs[1].val))
- self.add_instruction(['bne', 'ID'], lambda rhs: Bne(rhs[1].val))
- self.add_instruction(['blt', 'ID'], lambda rhs: Blt(rhs[1].val))
- self.add_instruction(['bgt', 'ID'], lambda rhs: Bgt(rhs[1].val))
-
- self.add_keyword('align')
- self.add_instruction(['align', 'imm8'], lambda rhs: Alignment(rhs[1]))
-
- self.add_instruction(['ldr', 'reg8', ',', 'ID'],
- lambda rhs: Ldr(rhs[1], rhs[3].val))
-
- # Additional rules:
-
- # Register list grammar:
- self.add_rule('reg_list', ['{', 'reg_list_inner', '}'],
- lambda rhs: rhs[1])
- self.add_rule('reg_list_inner', ['reg_or_range'],
- lambda rhs: rhs[0])
- self.add_rule('reg_list_inner', ['reg_or_range', ',', 'reg_list_inner'],
- lambda rhs: rhs[0] | rhs[2])
- self.add_rule('reg_or_range', ['reg8'], lambda rhs: {rhs[0]})
- self.add_rule('reg_or_range', ['lr'], lambda rhs: {LR})
- self.add_rule('reg_or_range', ['pc'], lambda rhs: {PC})
-
- self.add_rule('reg_or_range', ['reg8', '-', 'reg8'],
- lambda rhs: register_range(rhs[0], rhs[2]))
-
- self.add_keyword('r0')
- self.add_keyword('r1')
- self.add_keyword('r2')
- self.add_keyword('r3')
- self.add_keyword('r4')
- self.add_keyword('r5')
- self.add_keyword('r6')
- self.add_keyword('r7')
- self.add_keyword('sp')
- self.add_keyword('lr')
- self.add_keyword('pc')
- self.add_rule('reg8', ['r0'], lambda rhs: R0)
- self.add_rule('reg8', ['r1'], lambda rhs: R1)
- self.add_rule('reg8', ['r2'], lambda rhs: R2)
- self.add_rule('reg8', ['r3'], lambda rhs: R3)
- self.add_rule('reg8', ['r4'], lambda rhs: R4)
- self.add_rule('reg8', ['r5'], lambda rhs: R5)
- self.add_rule('reg8', ['r6'], lambda rhs: R6)
- self.add_rule('reg8', ['r7'], lambda rhs: R7)
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/thumb/armtoken.py
--- a/python/ppci/target/thumb/armtoken.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-
-from ..token import Token, u16, bit_range
-
-class ThumbToken(Token):
- def __init__(self):
- super().__init__(16)
-
- rd = bit_range(0, 3)
-
- def encode(self):
- return u16(self.bit_value)
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/thumb/frame.py
--- a/python/ppci/target/thumb/frame.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-from ... import ir
-from ..basetarget import Label, Alignment
-from ...irmach import AbstractInstruction, Frame
-from .instructions import Dcd, AddSp, SubSp, Push, Pop, Mov2
-from ..arm.registers import R0, R1, R2, R3, R4, R5, R6, R7, LR, PC, SP
-
-
-class ArmFrame(Frame):
- """ Arm specific frame for functions. """
- def __init__(self, name):
- # We use r7 as frame pointer.
- super().__init__(name)
- self.regs = [R0, R1, R2, R3, R4, R5, R6]
- self.rv = ir.Temp('special_RV')
- self.p1 = ir.Temp('special_P1')
- self.p2 = ir.Temp('special_P2')
- self.p3 = ir.Temp('special_P3')
- self.p4 = ir.Temp('special_P4')
- self.fp = ir.Temp('special_FP')
- # Pre-colored registers:
- self.tempMap = {}
- self.tempMap[self.rv] = R0
- self.tempMap[self.p1] = R1
- self.tempMap[self.p2] = R2
- self.tempMap[self.p3] = R3
- self.tempMap[self.p4] = R4
- self.tempMap[self.fp] = R7
- self.locVars = {}
- self.parMap = {}
- # Literal pool:
- self.constants = []
-
- def argLoc(self, pos):
- """
- Gets the function parameter location in IR-code format.
- """
- if pos == 0:
- return self.p1
- elif pos == 1:
- return self.p2
- elif pos == 2:
- return self.p3
- elif pos == 3:
- return self.p4
- else:
- raise NotImplementedError('No more than 4 parameters implemented')
-
- def allocVar(self, lvar):
- if lvar not in self.locVars:
- self.locVars[lvar] = self.stacksize
- self.stacksize = self.stacksize + 4
- return self.locVars[lvar]
-
- def addConstant(self, value):
- lab_name = '{}_literal_{}'.format(self.name, len(self.constants))
- self.constants.append((lab_name, value))
- return lab_name
-
- def prologue(self):
- """ Returns prologue instruction sequence """
- pre = [
- Label(self.name), # Label indication function
- Push({LR, R7})
- ]
- if self.stacksize > 0:
- pre.append(SubSp(self.stacksize)) # Reserve stack space
- pre += [
- Mov2(R7, SP) # Setup frame pointer
- ]
- return pre
-
- def epilogue(self):
- """ Return epilogue sequence for a frame. Adjust frame pointer and add constant pool """
- post = []
- if self.stacksize > 0:
- post.append(AddSp(self.stacksize))
- post += [
- Pop({PC, R7}),
- Alignment(4) # Align at 4 bytes
- ]
- # Add constant literals:
- for ln, v in self.constants:
- post.extend([Label(ln), Dcd(v)])
- return post
-
- def EntryExitGlue3(self):
- """
- Add code for the prologue and the epilogue. Add a label, the
- return instruction and the stack pointer adjustment for the frame.
- """
- for index, ins in enumerate(self.prologue()):
- self.instructions.insert(index, AbstractInstruction(ins))
-
- # Postfix code:
- for ins in self.epilogue():
- self.instructions.append(AbstractInstruction(ins))
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/thumb/instructions.py
--- a/python/ppci/target/thumb/instructions.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,489 +0,0 @@
-from ..basetarget import Register, Instruction, Target, Label
-from ..token import u16, u32
-from .armtoken import ThumbToken
-from ..arm.registers import R0, ArmRegister, SP
-
-
-# Instructions:
-
-class ThumbInstruction(Instruction):
- pass
-
-
-class Dcd(ThumbInstruction):
- def __init__(self, expr):
- if isinstance(expr, int):
- self.expr = expr
- self.label = None
- else:
- raise NotImplementedError()
-
- def encode(self):
- return u32(self.expr)
-
- def relocations(self):
- return []
-
- def __repr__(self):
- return 'DCD 0x{0:X}'.format(self.expr)
-
-
-class nop_ins(ThumbInstruction):
- def encode(self):
- return bytes()
-
- def __repr__(self):
- return 'NOP'
-
-
-# Memory related
-
-class LS_imm5_base(ThumbInstruction):
- """ ??? Rt, [Rn, imm5] """
- def __init__(self, rt, rn, imm5):
- assert imm5 % 4 == 0
- self.imm5 = imm5 >> 2
- self.rn = rn
- self.rt = rt
- assert self.rn.num < 8
- assert self.rt.num < 8
- self.token = ThumbToken()
-
- def encode(self):
- Rn = self.rn.num
- Rt = self.rt.num
- imm5 = self.imm5
- self.token[0:3] = Rt
- self.token[3:6] = Rn
- self.token[6:11] = imm5
- self.token[11:16] = self.opcode
- return self.token.encode()
-
- def __repr__(self):
- mnemonic = "???"
- return '{} {}, [{}, {}]'.format(mnemonic, self.rt, self.rn, self.imm5)
-
-
-class Str2(LS_imm5_base):
- opcode = 0xC
-
-
-class Ldr2(LS_imm5_base):
- opcode = 0xD
-
-
-class ls_sp_base_imm8(ThumbInstruction):
- def __init__(self, rt, offset):
- self.rt = rt
- self.offset = offset
-
- def encode(self):
- rt = self.rt.num
- assert rt < 8
- imm8 = self.offset >> 2
- assert imm8 < 256
- h = (self.opcode << 8) | (rt << 8) | imm8
- return u16(h)
-
- def __repr__(self):
- mnemonic = self.__class__.__name__
- return '{} {}, [sp,#{}]'.format(mnemonic, self.rt, self.offset)
-
-
-def Ldr(*args):
- if len(args) == 2 and isinstance(args[0], ArmRegister) \
- and isinstance(args[1], str):
- return Ldr3(*args)
- else:
- raise Exception()
-
-
-class Ldr3(ThumbInstruction):
- """ ldr Rt, LABEL, load value from pc relative position """
- def __init__(self, rt, label):
- self.rt = rt
- self.label = label
-
- def relocations(self):
- return [(self.label, 'lit_add_8')]
-
- def encode(self):
- rt = self.rt.num
- assert rt < 8
- imm8 = 0
- h = (0x9 << 11) | (rt << 8) | imm8
- return u16(h)
-
- def __repr__(self):
- return 'LDR {}, {}'.format(self.rt, self.label)
-
-
-class Ldr1(ls_sp_base_imm8):
- """ ldr Rt, [SP, imm8] """
- opcode = 0x98
-
-
-class Str1(ls_sp_base_imm8):
- """ str Rt, [SP, imm8] """
- opcode = 0x90
-
-
-class Mov3(ThumbInstruction):
- """ mov Rd, imm8, move immediate value into register """
- opcode = 4 # 00100 Rd(3) imm8
- def __init__(self, rd, imm):
- assert imm < 256
- self.imm = imm
- self.rd = rd
- self.token = ThumbToken()
-
- def encode(self):
- rd = self.rd.num
- self.token[8:11] = rd
- self.token[0:8] = self.imm
- self.token[11:16] = self.opcode
- return self.token.encode()
-
- def __repr__(self):
- return 'MOV {}, {}'.format(self.rd, self.imm)
-
-
-# Arithmatics:
-
-
-class regregimm3_base(ThumbInstruction):
- def __init__(self, rd, rn, imm3):
- self.rd = rd
- self.rn = rn
- assert imm3 < 8
- self.imm3 = imm3
- self.token = ThumbToken()
-
- def encode(self):
- rd = self.rd.num
- self.token[0:3] = rd
- self.token[3:6] = self.rn.num
- self.token[6:9] = self.imm3
- self.token[9:16] = self.opcode
- return self.token.encode()
-
- def __repr__(self):
- mnemonic = self.__class__.__name__
- return '{} {}, {}, {}'.format(mnemonic, self.rd, self.rn, self.imm3)
-
-
-
-class Add2(regregimm3_base):
- """ add Rd, Rn, imm3 """
- opcode = 0b0001110
-
-
-class Sub2(regregimm3_base):
- """ sub Rd, Rn, imm3 """
- opcode = 0b0001111
-
-
-def Sub(*args):
- if len(args) == 3 and args[0] is SP and args[1] is SP and \
- isinstance(args[2], int) and args[2] < 256:
- return SubSp(args[2])
- elif len(args) == 3 and isinstance(args[0], ArmRegister) and \
- isinstance(args[1], ArmRegister) and isinstance(args[2], int) and \
- args[2] < 8:
- return Sub2(args[0], args[1], args[2])
- else:
- raise Exception()
-
-
-def Add(*args):
- if len(args) == 3 and args[0] is SP and args[1] is SP and \
- isinstance(args[2], int) and args[2] < 256:
- return AddSp(args[2])
- elif len(args) == 3 and isinstance(args[0], ArmRegister) and \
- isinstance(args[1], ArmRegister) and isinstance(args[2], int) and \
- args[2] < 8:
- return Add2(args[0], args[1], args[2])
- else:
- raise Exception()
-
-
-class regregreg_base(ThumbInstruction):
- """ ??? Rd, Rn, Rm """
- def __init__(self, rd, rn, rm):
- self.rd = rd
- self.rn = rn
- self.rm = rm
-
- def encode(self):
- at = ThumbToken()
- at.rd = self.rd.num
- rn = self.rn.num
- rm = self.rm.num
- at[3:6] = rn
- at[6:9] = rm
- at[9:16] = self.opcode
- return at.encode()
-
- def __repr__(self):
- return '{} {}, {}, {}'.format(self.mnemonic, self.rd, self.rn, self.rm)
-
-
-class Add3(regregreg_base):
- mnemonic = 'ADD'
- opcode = 0b0001100
-
-
-class Sub3(regregreg_base):
- mnemonic = 'SUB'
- opcode = 0b0001101
-
-
-class Mov2(ThumbInstruction):
- """ mov rd, rm """
- mnemonic = 'MOV'
- def __init__(self, rd, rm):
- self.rd = rd
- self.rm = rm
-
- def encode(self):
- at = ThumbToken()
- at.rd = self.rd.num & 0x7
- D = (self.rd.num >> 3) & 0x1
- Rm = self.rm.num
- opcode = 0b01000110
- at[8:16] = opcode
- at[3:7] = Rm
- at[7] = D
- return at.encode()
-
- def __repr__(self):
- return '{} {}, {}'.format(self.mnemonic, self.rd, self.rm)
-
-
-class Mul(ThumbInstruction):
- """ mul Rn, Rdm """
- mnemonic = 'MUL'
- def __init__(self, rn, rdm):
- self.rn = rn
- self.rdm = rdm
-
- def encode(self):
- at = ThumbToken()
- rn = self.rn.num
- at.rd = self.rdm.num
- opcode = 0b0100001101
- #h = (opcode << 6) | (rn << 3) | rdm
- at[6:16] = opcode
- at[3:6] = rn
- return at.encode()
-
- def __repr__(self):
- return '{} {}, {}'.format(self.mnemonic, self.rn, self.rdm)
-
-
-class regreg_base(ThumbInstruction):
- """ ??? Rdn, Rm """
- def __init__(self, rdn, rm):
- self.rdn = rdn
- self.rm = rm
-
- def encode(self):
- at = ThumbToken()
- at.rd = self.rdn.num
- rm = self.rm.num
- at[3:6] = rm
- at[6:16] = self.opcode
- return at.encode()
-
- def __repr__(self):
- mnemonic = self.__class__.__name__
- return '{} {}, {}'.format(mnemonic, self.rdn, self.rm)
-
-
-class movregreg_ins(regreg_base):
- """ mov Rd, Rm (reg8 operands) """
- opcode = 0
-
-
-class And(regreg_base):
- opcode = 0b0100000000
-
-
-class Orr(regreg_base):
- opcode = 0b0100001100
-
-
-class Cmp(regreg_base):
- opcode = 0b0100001010
-
-
-class Lsl(regreg_base):
- opcode = 0b0100000010
-
-
-class Cmp2(ThumbInstruction):
- """ cmp Rn, imm8 """
- opcode = 5 # 00101
- def __init__(self, rn, imm):
- self.rn = rn
- self.imm = imm
-
- def encode(self):
- at = ThumbToken()
- at[0:8] = self.imm
- at[8:11] = self.rn.num
- at[11:16] = self.opcode
- return at.encode()
-
-
-# Jumping:
-
-class jumpBase_ins(ThumbInstruction):
- def __init__(self, target_label):
- assert type(target_label) is str
- self.target = target_label
- self.offset = 0
-
- def __repr__(self):
- mnemonic = self.__class__.__name__
- return '{} {}'.format(mnemonic, self.target)
-
-
-class B(jumpBase_ins):
- def encode(self):
- h = (0b11100 << 11) | 0
- # | 1 # 1 to enable thumb mode
- return u16(h)
-
- def relocations(self):
- return [(self.target, 'wrap_new11')]
-
-class Bl(jumpBase_ins):
- def encode(self):
- imm11 = 0
- imm10 = 0
- j1 = 1 # TODO: what do these mean?
- j2 = 1
- s = 0
- h1 = (0b11110 << 11) | (s << 10) | imm10
- h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11) | imm11
- return u16(h1) + u16(h2)
-
- def relocations(self):
- return [(self.target, 'bl_imm11_imm10')]
-
-
-class cond_base_ins(jumpBase_ins):
- def encode(self):
- imm8 = 0
- h = (0b1101 << 12) | (self.cond << 8) | imm8
- return u16(h)
-
- def relocations(self):
- return [(self.target, 'rel8')]
-
-
-class cond_base_ins_long(jumpBase_ins):
- """ Encoding T3 """
- def encode(self):
- j1 = 1 # TODO: what do these mean?
- j2 = 1
- h1 = (0b11110 << 11) | (self.cond << 6)
- h2 = (0b1101 << 12) | (j1 << 13) | (j2 << 11)
- return u16(h1) + u16(h2)
-
- def relocations(self):
- return [(self.target, 'b_imm11_imm6')]
-
-
-class Beq(cond_base_ins):
- cond = 0
-
-
-class Bne(cond_base_ins):
- cond = 1
-
-
-class Blt(cond_base_ins):
- cond = 0b1011
-
-
-class Bgt(cond_base_ins):
- cond = 0b1100
-
-
-class Push(ThumbInstruction):
- def __init__(self, regs):
- assert type(regs) is set
- self.regs = regs
-
- def __repr__(self):
- return 'Push {{{}}}'.format(self.regs)
-
- def encode(self):
- at = ThumbToken()
- for n in register_numbers(self.regs):
- if n < 8:
- at[n] = 1
- elif n == 14:
- at[8] = 1
- else:
- raise NotImplementedError('not implemented for {}'.format(n))
- at[9:16] = 0x5a
- return at.encode()
-
-
-
-def register_numbers(regs):
- for r in regs:
- yield r.num
-
-class Pop(ThumbInstruction):
- def __init__(self, regs):
- assert type(regs) is set
- self.regs = regs
- self.token = ThumbToken()
-
- def __repr__(self):
- return 'Pop {{{}}}'.format(self.regs)
-
- def encode(self):
- for n in register_numbers(self.regs):
- if n < 8:
- self.token[n] = 1
- elif n == 15:
- self.token[8] = 1
- else:
- raise NotImplementedError('not implemented for this register')
- self.token[9:16] = 0x5E
- return self.token.encode()
-
-
-
-class Yield(ThumbInstruction):
- def encode(self):
- return u16(0xbf10)
-
-# misc:
-
-# add/sub SP:
-class addspsp_base(ThumbInstruction):
- def __init__(self, imm7):
- self.imm7 = imm7
- assert self.imm7 % 4 == 0
- self.imm7 >>= 2
-
- def encode(self):
- return u16((self.opcode << 7) | self.imm7)
-
- def __repr__(self):
- mnemonic = self.__class__.__name__
- return '{} sp, sp, {}'.format(mnemonic, self.imm7 << 2)
-
-
-class AddSp(addspsp_base):
- opcode = 0b101100000
-
-
-class SubSp(addspsp_base):
- opcode = 0b101100001
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/token.py
--- a/python/ppci/target/token.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-
-import struct
-
-def u16(h):
- return struct.pack('':'jg', '<':'jl', '==':'je'}
- if i.cond in jmps:
- j = jmps[i.cond]
- self.emit('{0} {1}'.format(j, i.lab1.name))
- else:
- raise NotImplementedError('condition {0}'.format(i.cond))
- self.emit('jmp {0}'.format(i.lab2.name))
- elif type(i) is ir.Branch:
- self.emit('jmp {0}'.format(i.target.name))
- elif type(i) is ir.Alloc:
- pass
- else:
- raise NotImplementedError('{0}'.format(i))
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/target/x86/x86_2.py
--- a/python/ppci/target/x86/x86_2.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,356 +0,0 @@
-"""
- X86 target descriptions and encodings.
-
-"""
-
-from target import Register, Instruction, Target, Imm8, Label, Imm3, LabelRef
-
-
-modrm = {'rax': 0, 'rbx': 1}
-
-# Table 3.1 of the intel manual:
-# use REX.W on the table below:
-regs64 = {'rax': 0,'rcx':1,'rdx':2,'rbx':3,'rsp':4,'rbp':5,'rsi':6,'rdi':7,'r8':0,'r9':1,'r10':2,'r11':3,'r12':4,'r13':5,'r14':6,'r15':7}
-regs32 = {'eax': 0, 'ecx':1, 'edx':2, 'ebx': 3, 'esp': 4, 'ebp': 5, 'esi':6, 'edi':7}
-regs8 = {'al':0,'cl':1,'dl':2,'bl':3,'ah':4,'ch':5,'dh':6,'bh':7}
-
-# Calculation of the rexb bit:
-rexbit = {'rax': 0, 'rcx':0, 'rdx':0, 'rbx': 0, 'rsp': 0, 'rbp': 0, 'rsi':0, 'rdi':0,'r8':1,'r9':1,'r10':1,'r11':1,'r12':1,'r13':1,'r14':1,'r15':1}
-
-# Helper functions:
-def imm64(x):
- """ represent 64 bits integer in little endian 8 bytes"""
- if x < 0:
- x = x + (1 << 64)
- x = x & 0xFFFFFFFFFFFFFFFF
- return [ (x >> (p*8)) & 0xFF for p in range(8) ]
-
-def imm32(x):
- """ represent 32 bits integer in little endian 4 bytes"""
- if x < 0:
- x = x + (1 << 32)
- x = x & 0xFFFFFFFF
- return [ (x >> (p*8)) & 0xFF for p in range(4) ]
-
-def imm8(x):
- if x < 0:
- x = x + (1 << 8)
- x = x & 0xFF
- return [ x ]
-
-def modrm(mod=0, rm=0, reg=0):
- """ Construct the modrm byte from its components """
- assert(mod <= 3)
- assert(rm <= 7)
- assert(reg <= 7)
- return (mod << 6) | (reg << 3) | rm
-
-def rex(w=0, r=0, x=0, b=0):
- """ Create a REX prefix byte """
- assert(w <= 1)
- assert(r <= 1)
- assert(x <= 1)
- assert(b <= 1)
- return 0x40 | (w<<3) | (r<<2) | (x<<1) | b
-
-def sib(ss=0, index=0, base=0):
- assert(ss <= 3)
- assert(index <= 7)
- assert(base <= 7)
- return (ss << 6) | (index << 3) | base
-
-tttn = {'L':0xc,'G':0xf,'NE':0x5,'GE':0xd,'LE':0xe, 'E':0x4}
-
-# Actual instructions:
-def nearjump(distance, condition=None):
- """ jmp imm32 """
- lim = (1<<30)
- if abs(distance) > lim:
- Error('near jump cannot jump over more than {0} bytes'.format(lim))
- if condition:
- if distance < 0:
- distance -= 6 # Skip own instruction
- opcode = 0x80 | tttn[condition] # Jcc imm32
- return [0x0F, opcode] + imm32(distance)
- else:
- if distance < 0:
- distance -= 5 # Skip own instruction
- return [ 0xE9 ] + imm32(distance)
-
-def shortjump(distance, condition=None):
- """ jmp imm8 """
- lim = 118
- if abs(distance) > lim:
- Error('short jump cannot jump over more than {0} bytes'.format(lim))
- if distance < 0:
- distance -= 2 # Skip own instruction
- if condition:
- opcode = 0x70 | tttn[condition] # Jcc rel8
- else:
- opcode = 0xeb # jmp rel8
- return [opcode] + imm8(distance)
-
-# Helper that determines jump type:
-def reljump(distance):
- if abs(distance) < 110:
- return shortjump(distance)
- else:
- return nearjump(distance)
-
-def push(reg):
- if reg in regs64:
- if rexbit[reg] == 1:
- return [0x41, 0x50 + regs64[reg]]
- else:
- return [0x50 + regs64[reg]]
- else:
- Error('push for {0} not implemented'.format(reg))
-
-def pop(reg):
- if reg in regs64:
- if rexbit[reg] == 1:
- rexprefix = rex(b=1)
- opcode = 0x58 + regs64[reg]
- return [rexprefix, opcode]
- else:
- opcode = 0x58 + regs64[reg]
- return [ opcode ]
- else:
- Error('pop for {0} not implemented'.format(reg))
-
-def INT(number):
- opcode = 0xcd
- return [opcode] + imm8(number)
-
-def syscall():
- return [0x0F, 0x05]
-
-def call(distance):
- if type(distance) is int:
- return [0xe8]+imm32(distance)
- elif type(distance) is str and distance in regs64:
- reg = distance
- opcode = 0xFF # 0xFF /2 == call r/m64
- mod_rm = modrm(mod=3, reg=2, rm=regs64[reg])
- if rexbit[reg] == 1:
- rexprefix = rex(b=rexbit[reg])
- return [rexprefix, opcode, mod_rm]
- else:
- return [opcode, mod_rm]
- else:
- Error('Cannot call to {0}'.format(distance))
-
-def ret():
- return [ 0xc3 ]
-
-def increg64(reg):
- assert(reg in regs64)
- rexprefix = rex(w=1, b=rexbit[reg])
- opcode = 0xff
- mod_rm = modrm(mod=3, rm=regs64[reg])
- return [rexprefix, opcode, mod_rm]
-
-def prepost8(r8, rm8):
- assert(r8 in regs8)
- pre = []
- if type(rm8) is list:
- # TODO: merge mem access with prepost for 64 bits
- if len(rm8) == 1:
- base, = rm8
- if type(base) is str and base in regs64:
- assert(not base in ['rbp', 'rsp', 'r12', 'r13'])
- mod_rm = modrm(mod=0, rm=regs64[base], reg=regs8[r8])
- if rexbit[base] == 1:
- pre.append(rex(b=1))
- post = [mod_rm]
- else:
- Error('One arg of type {0} not implemented'.format(base))
- elif len(rm8) == 2:
- base, offset = rm8
- assert(type(offset) is int)
- assert(base in regs64)
-
- if base == 'rsp' or base == 'r12':
- Error('Cannot use rsp or r12 as base yet')
- if rexbit[base] == 1:
- pre.append( rex(b=1) )
- mod_rm = modrm(mod=1, rm=regs64[base], reg=regs8[r8])
- post = [mod_rm] + imm8(offset)
- else:
- Error('not supporting prepost8 with list len {0}'.format(len(rm8)))
- else:
- Error('Not supporting move with reg8 {0}'.format(r8))
- return pre, post
-
-def prepost(r64, rm64):
- assert(r64 in regs64)
- if type(rm64) is list:
- if len(rm64) == 3:
- base, index, disp = rm64
- assert(base in regs64)
- assert(index in regs64)
- assert(type(disp) is int)
- # Assert that no special cases are used:
- # TODO: swap base and index to avoid special cases
- # TODO: exploit special cases and make better code
- assert(index != 'rsp')
-
- rexprefix = rex(w=1, r=rexbit[r64], x=rexbit[index], b=rexbit[base])
- # mod=1 and rm=4 indicates a SIB byte: [--][--]+imm8
- mod_rm = modrm(mod=1, rm=4, reg=regs64[r64])
- si_b = sib(ss=0, index=regs64[index], base=regs64[base])
- return [rexprefix], [mod_rm, si_b] + imm8(disp)
- elif len(rm64) == 2:
- base, offset = rm64
- assert(type(offset) is int)
- if base == 'RIP':
- # RIP pointer relative addressing mode!
- rexprefix = rex(w=1, r=rexbit[r64])
- mod_rm = modrm(mod=0, rm=5, reg=regs64[r64])
- return [rexprefix], [mod_rm] + imm32(offset)
- else:
- assert(base in regs64)
-
- if base == 'rsp' or base == 'r12':
- # extended function that uses SIB byte
- rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[base])
- # rm=4 indicates a SIB byte follows
- mod_rm = modrm(mod=1, rm=4, reg=regs64[r64])
- # index=4 indicates that index is not used
- si_b = sib(ss=0, index=4, base=regs64[base])
- return [rexprefix], [mod_rm, si_b] + imm8(offset)
- else:
- rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[base])
- mod_rm = modrm(mod=1, rm=regs64[base], reg=regs64[r64])
- return [rexprefix], [mod_rm] + imm8(offset)
- elif len(rm64) == 1:
- offset = rm64[0]
- if type(offset) is int:
- rexprefix = rex(w=1, r=rexbit[r64])
- mod_rm = modrm(mod=0, rm=4,reg=regs64[r64])
- si_b = sib(ss=0, index=4,base=5) # 0x25
- return [rexprefix], [mod_rm, si_b] + imm32(offset)
- else:
- Error('Memory reference of type {0} not implemented'.format(offset))
- else:
- Error('Memory reference not implemented')
- elif rm64 in regs64:
- rexprefix = rex(w=1, r=rexbit[r64], b=rexbit[rm64])
- mod_rm = modrm(3, rm=regs64[rm64], reg=regs64[r64])
- return [rexprefix], [mod_rm]
-
-def leareg64(rega, m):
- opcode = 0x8d # lea r64, m
- pre, post = prepost(rega, m)
- return pre + [opcode] + post
-
-def mov(rega, regb):
- if type(regb) is int:
- pre = [rex(w=1, b=rexbit[rega])]
- opcode = 0xb8 + regs64[rega]
- post = imm64(regb)
- elif type(regb) is str:
- if regb in regs64:
- opcode = 0x89 # mov r/m64, r64
- pre, post = prepost(regb, rega)
- elif regb in regs8:
- opcode = 0x88 # mov r/m8, r8
- pre, post = prepost8(regb, rega)
- else:
- Error('Unknown register {0}'.format(regb))
- elif type(rega) is str:
- if rega in regs64:
- opcode = 0x8b # mov r64, r/m64
- pre, post = prepost(rega, regb)
- else:
- Error('Unknown register {0}'.format(rega))
- else:
- Error('Move of this kind {0}, {1} not implemented'.format(rega, regb))
- return pre + [opcode] + post
-
-def xorreg64(rega, regb):
- rexprefix = rex(w=1, r=rexbit[regb], b=rexbit[rega])
- opcode = 0x31 # XOR r/m64, r64
- # Alternative is 0x33 XOR r64, r/m64
- mod_rm = modrm(3, rm=regs64[rega], reg=regs64[regb])
- return [rexprefix, opcode, mod_rm]
-
-# integer arithmatic:
-def addreg64(rega, regb):
- if regb in regs64:
- pre, post = prepost(regb, rega)
- opcode = 0x01 # ADD r/m64, r64
- return pre + [opcode] + post
- elif type(regb) is int:
- if regb < 100:
- rexprefix = rex(w=1, b=rexbit[rega])
- opcode = 0x83 # add r/m, imm8
- mod_rm = modrm(3, rm=regs64[rega], reg=0)
- return [rexprefix, opcode, mod_rm]+imm8(regb)
- elif regb < (1<<31):
- rexprefix = rex(w=1, b=rexbit[rega])
- opcode = 0x81 # add r/m64, imm32
- mod_rm = modrm(3, rm=regs64[rega], reg=0)
- return [rexprefix, opcode, mod_rm]+imm32(regb)
- else:
- Error('Constant value too large!')
- else:
- Error('unknown second operand!'.format(regb))
-
-def subreg64(rega, regb):
- if regb in regs64:
- pre, post = prepost(regb, rega)
- opcode = 0x29 # SUB r/m64, r64
- return pre + [opcode] + post
- elif type(regb) is int:
- if regb < 100:
- rexprefix = rex(w=1, b=rexbit[rega])
- opcode = 0x83 # sub r/m, imm8
- mod_rm = modrm(3, rm=regs64[rega], reg=5)
- return [rexprefix, opcode, mod_rm]+imm8(regb)
- elif regb < (1<<31):
- rexprefix = rex(w=1, b=rexbit[rega])
- opcode = 0x81 # sub r/m64, imm32
- mod_rm = modrm(3, rm=regs64[rega], reg=5)
- return [rexprefix, opcode, mod_rm]+imm32(regb)
- else:
- Error('Constant value too large!')
-
- else:
- Error('unknown second operand!'.format(regb))
-
-def idivreg64(reg):
- rexprefix = rex(w=1, b=rexbit[reg])
- opcode = 0xf7 # IDIV r/m64
- mod_rm = modrm(3, rm=regs64[reg], reg=7)
- return [rexprefix, opcode, mod_rm]
-
-def imulreg64_rax(reg):
- rexprefix = rex(w=1, b=rexbit[reg])
- opcode = 0xf7 # IMUL r/m64
- mod_rm = modrm(3, rm=regs64[reg], reg=5)
- return [rexprefix, opcode, mod_rm]
-
-def imulreg64(rega, regb):
- pre, post = prepost(rega, regb)
- opcode = 0x0f # IMUL r64, r/m64
- opcode2 = 0xaf
- return pre + [opcode, opcode2] + post
-
-def cmpreg64(rega, regb):
- if regb in regs64:
- pre, post = prepost(regb, rega)
- opcode = 0x39 # CMP r/m64, r64
- return pre + [opcode] + post
- elif type(regb) is int:
- rexprefix = rex(w=1, b=rexbit[rega])
- opcode = 0x83 # CMP r/m64, imm8
- mod_rm = modrm(3, rm=regs64[rega], reg=7)
- return [rexprefix, opcode, mod_rm] + imm8(regb)
-
- else:
- Error('not implemented cmp64')
-
-# Mapping that maps string names to the right functions:
-opcodes = {'mov':(mov,2), 'lea':(leareg64,2), 'int':(INT,1), 'syscall':(syscall,0)}
-
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/tasks.py
--- a/python/ppci/tasks.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-"""
- This module defines tasks and a runner for these tasks. Tasks can
- have dependencies and it can be determined if they need to be run.
-"""
-
-import logging
-
-class TaskError(Exception):
- def __init__(self, msg):
- self.msg = msg
-
-
-class Task:
- """ Task that can run, and depend on other tasks """
- def __init__(self, name):
- self.name = name
- self.completed = False
- self.dependencies = set()
- self.duration = 1
-
- def run(self):
- raise NotImplementedError("Implement this abstract method!")
-
- def fire(self):
- """ Wrapper around run that marks the task as done """
- assert all(t.completed for t in self.dependencies)
- self.run()
- self.completed = True
-
- def add_dependency(self, task):
- """ Add another task as a dependency for this task """
- if task is self:
- raise TaskError('Can not add dependency on task itself!')
- if self in task.down_stream_tasks:
- raise TaskError('Can not introduce circular task')
- self.dependencies.add(task)
- return task
-
- @property
- def down_stream_tasks(self):
- """ Return a set of all tasks that follow this task """
- # TODO: is this upstream or downstream???
- cdst = list(dep.down_stream_tasks for dep in self.dependencies)
- cdst.append(self.dependencies)
- return set.union(*cdst)
-
- def __gt__(self, other):
- return other in self.down_stream_tasks
-
- def __repr__(self):
- return 'Task "{}"'.format(self.name)
-
-
-class EmptyTask(Task):
- """ Basic task that does nothing """
- def run(self):
- pass
-
-
-class TaskRunner:
- """ Basic task runner that can run some tasks in sequence """
- def __init__(self):
- self.logger = logging.getLogger('taskrunner')
- self.task_list = []
-
- def add_task(self, task):
- self.task_list.append(task)
-
- @property
- def total_duration(self):
- return sum(t.duration for t in self.task_list)
-
- def run_tasks(self):
- # First sort tasks:
- self.task_list.sort()
-
- # Run tasks:
- passed_time = 0.0
- total_time = self.total_duration
- try:
- for t in self.task_list:
- self.report_progress(passed_time / total_time, t.name)
- t.fire()
- passed_time += t.duration
- except TaskError as e:
- self.logger.error(str(e.msg))
- return 1
- self.report_progress(1, 'OK')
- return 0
-
- def display(self):
- """ Display task how they would be run """
- for task in self.task_list:
- print(task)
-
- def report_progress(self, percentage, text):
- self.logger.info('[{:3.1%}] {}'.format(percentage, text))
diff -r 742588fb8cd6 -r f381cea07fec python/ppci/transform.py
--- a/python/ppci/transform.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-"""
- Transformation to optimize IR-code
-"""
-
-import logging
-from . import ir
-# Standard passes:
-
-class FunctionPass:
- def __init__(self):
- self.logger = logging.getLogger(str(self.__class__.__name__))
-
- def run(self, ir):
- """ Main entry point for the pass """
- self.logger.debug('Running pass {}'.format(self.__class__.__name__))
- self.prepare()
- for f in ir.Functions:
- self.onFunction(f)
-
- def onFunction(self, f):
- """ Override this virtual method """
- raise NotImplementedError()
-
- def prepare(self):
- pass
-
-
-class BasicBlockPass(FunctionPass):
- def onFunction(self, f):
- for bb in f.Blocks:
- self.onBasicBlock(bb)
-
- def onBasicBlock(self, bb):
- """ Override this virtual method """
- raise NotImplementedError()
-
-
-class InstructionPass(BasicBlockPass):
- def onBasicBlock(self, bb):
- for ins in iter(bb.Instructions):
- self.onInstruction(ins)
-
- def onInstruction(self, ins):
- """ Override this virtual method """
- raise NotImplementedError()
-
-
-class BasePass(BasicBlockPass):
- def onBasicBlock(self, bb):
- pass
-
-
-# Usefull transforms:
-class ConstantFolder(BasePass):
- def __init__(self):
- super().__init__()
- self.ops = {}
- self.ops['+'] = lambda x, y: x + y
- self.ops['-'] = lambda x, y: x - y
- self.ops['*'] = lambda x, y: x * y
- self.ops['<<'] = lambda x, y: x << y
-
- def postExpr(self, expr):
- if type(i) is BinaryOperator and i.operation in self.ops.keys() and type(i.a) is Const and type(i.b) is Const:
- vr = self.ops[i.operation](i.a.value, i.b.value)
- return Const(vr)
- else:
- return expr
-
-
-class DeadCodeDeleter(BasicBlockPass):
- def onBasicBlock(self, bb):
- def instructionUsed(ins):
- if not type(ins) in [ImmLoad, BinaryOperator]:
- return True
- if len(ins.defs) == 0:
- # In case this instruction does not define any
- # variables, assume it is usefull.
- return True
- return any(d.Used for d in ins.defs)
-
- change = True
- while change:
- change = False
- for i in bb.Instructions:
- if instructionUsed(i):
- continue
- bb.removeInstruction(i)
- change = True
-
-
-class CommonSubexpressionElimination(BasicBlockPass):
- def onBasicBlock(self, bb):
- constMap = {}
- to_remove = []
- for i in bb.Instructions:
- if isinstance(i, ImmLoad):
- if i.value in constMap:
- t_new = constMap[i.value]
- t_old = i.target
- logging.debug('Replacing {} with {}'.format(t_old, t_new))
- t_old.replaceby(t_new)
- to_remove.append(i)
- else:
- constMap[i.value] = i.target
- elif isinstance(i, BinaryOperator):
- k = (i.value1, i.operation, i.value2)
- if k in constMap:
- t_old = i.result
- t_new = constMap[k]
- logging.debug('Replacing {} with {}'.format(t_old, t_new))
- t_old.replaceby(t_new)
- to_remove.append(i)
- else:
- constMap[k] = i.result
- for i in to_remove:
- self.logger.debug('removing {}'.format(i))
- bb.removeInstruction(i)
-
-class RemoveAddZero(InstructionPass):
- def onInstruction(self, i):
- if type(i) is ir.Binop:
- print(i)
- pass
-
-class CleanPass(FunctionPass):
- def onFunction(self, f):
- self.remove_empty_blocks(f)
- self.remove_one_preds(f)
-
- def remove_empty_blocks(self, f):
- """ Remove empty basic blocks from function. """
- # If a block only contains a branch, it can be removed:
- empty = lambda b: type(b.FirstInstruction) is ir.Jump
- empty_blocks = list(filter(empty, f.Blocks))
- for b in empty_blocks:
- # Update predecessors
- preds = b.Predecessors
- if b not in preds + [f.entry]:
- # Do not remove if preceeded by itself
- tgt = b.LastInstruction.target
- for pred in preds:
- pred.LastInstruction.changeTarget(b, tgt)
- self.logger.debug('Removing empty block: {}'.format(b))
- f.removeBlock(b)
-
- def remove_one_preds(self, f):
- """ Remove basic blocks with only one predecessor """
- change = True
- while change:
- change = False
- for block in f.Blocks:
- preds = block.Predecessors
- if len(preds) == 1 and block not in preds and type(preds[0].LastInstruction) is ir.Jump and block is not f.epiloog:
- self.glue_blocks(preds[0], block, f)
- change = True
-
- def glue_blocks(self, block1, block2, f):
- """ Glue two blocks together into the first block """
- self.logger.debug('Merging {} and {}'.format(block1.name, block2.name))
-
- # Remove the last jump:
- block1.removeInstruction(block1.LastInstruction)
-
- # Copy all instructions to block1:
- for instruction in block2.Instructions:
- block1.addInstruction(instruction)
- # This does not work somehow:
- #block2.parent.removeBlock(block2)
diff -r 742588fb8cd6 -r f381cea07fec python/pyburg.py
--- a/python/pyburg.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,340 +0,0 @@
-#!/usr/bin/python
-
-"""
-Bottom up rewrite generator
----------------------------
-
-This script takes as input a description of patterns and outputs a
-matcher class that can match trees given the patterns.
-
-Patterns are specified as follows::
-
- reg -> ADDI32(reg, reg) 2 (. add NT0 NT1 .)
- reg -> MULI32(reg, reg) 3 (. .)
-
-or a multiply add::
-
- reg -> ADDI32(MULI32(reg, reg), reg) 4 (. muladd $1, $2, $3 .)
-
-The general specification pattern is::
-
- [result] -> [tree] [cost] [template code]
-
-Trees
------
-
-A tree is described using parenthesis notation. For example a node X with
-three child nodes is described as:
-
- X(a, b, b)
-
-Trees can be nested:
-
- X(Y(a, a), a)
-
-The 'a' in the example above indicates an open connection to a next tree
-pattern.
-
-
-In the example above 'reg' is a non-terminal. ADDI32 is a terminal. non-terminals
-cannot have child nodes. A special case occurs in this case:
-
- reg -> rc
-
-where 'rc' is a non-terminal. This is an example of a chain rule. Chain rules
-can be used to allow several variants of non-terminals.
-
-The generated matcher uses dynamic programming to find the best match of the
-tree. This strategy consists of two steps:
-
- - label: During this phase the given tree is traversed in a bottom up way.
- each node is labelled with a possible matching rule and the corresponding cost.
- - select: In this step, the tree is traversed again, selecting at each point
- the cheapest way to get to the goal.
-
-"""
-
-import sys
-import os
-import io
-import types
-import argparse
-from ppci import Token
-from pyyacc import ParserException, EOF
-import yacc
-import baselex
-from tree import Tree
-
-# Generate parser on the fly:
-spec_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'burg.x')
-burg_parser = yacc.load_as_module(spec_file)
-
-
-class BurgLexer:
- def feed(self, txt):
- tok_spec = [
- ('id', r'[A-Za-z][A-Za-z\d_]*', lambda typ, val: (typ, val)),
- ('kw', r'%[A-Za-z][A-Za-z\d_]*', lambda typ, val: (val, val)),
- ('number', r'\d+', lambda typ, val: (typ, int(val))),
- ('STRING', r"'[^']*'", lambda typ, val: ('id', val[1:-1])),
- ('template', r"\(\..*\.\)", lambda typ, val: (typ, val)),
- ('OTHER', r'[:;\|\(\),]', lambda typ, val: (val, val)),
- ('SKIP', r'[ ]', None)
- ]
-
- lines = txt.split('\n')
- header_lines = []
-
- def tokenize():
- section = 0
- for line in lines:
- line = line.strip()
- if not line:
- continue # Skip empty lines
- elif line == '%%':
- section += 1
- if section == 1:
- yield Token('header', header_lines)
- yield Token('%%', '%%')
- else:
- if section == 0:
- header_lines.append(line)
- else:
- yield from baselex.tokenize(tok_spec, line)
- yield Token(EOF, EOF)
- self.tokens = tokenize()
- self.token = self.tokens.__next__()
-
- def next_token(self):
- t = self.token
- if t.typ != EOF:
- self.token = self.tokens.__next__()
- return t
-
-
-class Rule:
- """ A rewrite rule. Specifies a tree that can be rewritten into a result
- at a specific cost """
- def __init__(self, non_term, tree, cost, template):
- self.non_term = non_term
- self.tree = tree
- self.cost = cost
- self.template = template
- self.nr = 0
-
- def __repr__(self):
- return '{} -> {} ${}'.format(self.non_term, self.tree, self.cost)
-
-
-class Symbol:
- def __init__(self, name):
- self.name = name
-
-
-class Term(Symbol):
- pass
-
-
-class Nonterm(Symbol):
- def __init__(self, name):
- super().__init__(name)
- self.chain_rules = []
-
-
-class BurgSystem:
- def __init__(self):
- self.rules = []
- self.symbols = {}
- self.goal = None
-
- def symType(self, t):
- return (s.name for s in self.symbols.values() if type(s) is t)
-
- terminals = property(lambda s: s.symType(Term))
-
- non_terminals = property(lambda s: s.symType(Nonterm))
-
- def add_rule(self, non_term, tree, cost, template):
- template = template[2:-2].strip()
- if not template:
- template = 'pass'
- rule = Rule(non_term, tree, cost, template)
- if len(tree.children) == 0 and tree.name not in self.terminals:
- self.non_term(tree.name).chain_rules.append(rule)
- self.non_term(rule.non_term)
- self.rules.append(rule)
- rule.nr = len(self.rules)
-
- def non_term(self, name):
- if name in self.terminals:
- raise BurgError('Cannot redefine terminal')
- if not self.goal:
- self.goal = name
- return self.install(name, Nonterm)
-
- def tree(self, name, *args):
- return Tree(name, *args)
-
- def install(self, name, t):
- assert type(name) is str
- if name in self.symbols:
- assert type(self.symbols[name]) is t
- else:
- self.symbols[name] = t(name)
- return self.symbols[name]
-
- def add_terminal(self, terminal):
- self.install(terminal, Term)
-
-
-class BurgError(Exception):
- pass
-
-
-class BurgParser(burg_parser.Parser):
- """ Derived from automatically generated parser """
- def parse(self, l):
- self.system = BurgSystem()
- super().parse(l)
- return self.system
-
-
-class BurgGenerator:
- def print(self, *args):
- """ Print helper function that prints to output file """
- print(*args, file=self.output_file)
-
- def generate(self, system, output_file):
- """ Generate script that implements the burg spec """
- self.output_file = output_file
- self.system = system
-
- self.print('#!/usr/bin/python')
- self.print('from tree import Tree, BaseMatcher, State')
- for header in self.system.header_lines:
- self.print(header)
- self.print()
- self.print('class Matcher(BaseMatcher):')
- self.print(' def __init__(self):')
- self.print(' self.kid_functions = {}')
- self.print(' self.nts_map = {}')
- self.print(' self.pat_f = {}')
- for rule in self.system.rules:
- kids, dummy = self.compute_kids(rule.tree, 't')
- rule.num_nts = len(dummy)
- lf = 'lambda t: [{}]'.format(', '.join(kids), rule)
- pf = 'self.P{}'.format(rule.nr)
- self.print(' # {}: {}'.format(rule.nr, rule))
- self.print(' self.kid_functions[{}] = {}'.format(rule.nr, lf))
- self.print(' self.nts_map[{}] = {}'.format(rule.nr, dummy))
- self.print(' self.pat_f[{}] = {}'.format(rule.nr, pf))
- self.print()
- for rule in self.system.rules:
- if rule.num_nts > 0:
- args = ', ' + ', '.join('nt{}'.format(x) for x in range(rule.num_nts))
- else:
- args = ''
- self.print(' def P{}(self, tree{}):'.format(rule.nr, args))
- template = rule.template
- template = template.replace('$$', 'tree')
- for i in range(rule.num_nts):
- template = template.replace('${}'.format(i+1), 'nt{}'.format(i))
- for t in template.split(';'):
- self.print(' {}'.format(t.strip()))
- self.emit_state()
- self.print(' def gen(self, tree):')
- self.print(' self.burm_label(tree)')
- self.print(' if not tree.state.has_goal("{}"):'.format(self.system.goal))
- self.print(' raise Exception("Tree {} not covered".format(tree))')
- self.print(' return self.apply_rules(tree, "{}")'.format(self.system.goal))
-
- def emit_record(self, rule, state_var):
- # TODO: check for rules fullfilled (by not using 999999)
- self.print(' nts = self.nts({})'.format(rule.nr))
- self.print(' kids = self.kids(tree, {})'.format(rule.nr))
- self.print(' c = sum(x.state.get_cost(y) for x, y in zip(kids, nts)) + {}'.format(rule.cost))
- self.print(' tree.state.set_cost("{}", c, {})'.format(rule.non_term, rule.nr))
- for cr in self.system.symbols[rule.non_term].chain_rules:
- self.print(' # Chain rule: {}'.format(cr))
- self.print(' tree.state.set_cost("{}", c + {}, {})'.format(cr.non_term, cr.cost, cr.nr))
-
- def emit_state(self):
- """ Emit a function that assigns a new state to a node """
- self.print(' def burm_state(self, tree):')
- self.print(' tree.state = State()')
- for term in self.system.terminals:
- self.emitcase(term)
- self.print()
-
- def emitcase(self, term):
- rules = [rule for rule in self.system.rules if rule.tree.name == term]
- for rule in rules:
- condition = self.emittest(rule.tree, 'tree')
- self.print(' if {}:'.format(condition))
- self.emit_record(rule, 'state')
-
- def compute_kids(self, t, root_name):
- """ Compute of a pattern the blanks that must be provided from below in the tree """
- if t.name in self.system.non_terminals:
- return [root_name], [t.name]
- else:
- k = []
- nts = []
- for i, c in enumerate(t.children):
- pfx = root_name + '.children[{}]'.format(i)
- kf, dummy = self.compute_kids(c, pfx)
- nts.extend(dummy)
- k.extend(kf)
- return k, nts
-
-
- def emittest(self, tree, prefix):
- """ Generate condition for a tree pattern """
- ct = (c for c in tree.children if c.name not in self.system.non_terminals)
- child_tests = (self.emittest(c, prefix + '.children[{}]'.format(i)) for i, c in enumerate(ct))
- child_tests = ('({})'.format(ct) for ct in child_tests)
- child_tests = ' and '.join(child_tests)
- child_tests = ' and ' + child_tests if child_tests else ''
- tst = '{}.name == "{}"'.format(prefix, tree.name)
- return tst + child_tests
-
-
-def make_argument_parser():
- """ Constructs an argument parser """
- parser = argparse.ArgumentParser(description='pyburg bottom up rewrite system generator compiler compiler')
- parser.add_argument('source', type=argparse.FileType('r'), \
- help='the parser specification')
- parser.add_argument('-o', '--output', type=argparse.FileType('w'), \
- default=sys.stdout)
- return parser
-
-def load_as_module(filename):
- """ Load a parser spec file, generate LR tables and create module """
- ob = io.StringIO()
- args = argparse.Namespace(source=open(filename), output=ob)
- main(args)
-
- matcher_mod = types.ModuleType('generated_matcher')
- exec(ob.getvalue(), matcher_mod.__dict__)
- return matcher_mod
-
-
-def main(args):
- src = args.source.read()
- args.source.close()
-
- # Parse specification into burgsystem:
- l = BurgLexer()
- p = BurgParser()
- l.feed(src)
- burg_system = p.parse(l)
-
- # Generate matcher:
- generator = BurgGenerator()
- generator.generate(burg_system, args.output)
-
-
-if __name__ == '__main__':
- # Parse arguments:
- args = make_argument_parser().parse_args()
- main(args)
diff -r 742588fb8cd6 -r f381cea07fec python/pyyacc.py
--- a/python/pyyacc.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,405 +0,0 @@
-"""
- Parser generator script
-"""
-
-from ppci import Token
-
-EPS = 'EPS'
-EOF = 'EOF'
-
-
-class ParserGenerationException(Exception):
- """ Raised when something goes wrong during parser generation """
- pass
-
-
-class ParserException(Exception):
- """ Raised during a failure in the parsing process """
- pass
-
-
-class Action:
- def __repr__(self):
- return 'Action'
-
- def __eq__(self, other):
- return str(self) == str(other)
-
-
-class Shift(Action):
- def __init__(self, to_state):
- self.to_state = to_state
-
- def __repr__(self):
- return 'Shift({})'.format(self.to_state)
-
-
-class Reduce(Action):
- def __init__(self, rule):
- self.rule = rule
-
- def __repr__(self):
- return 'Reduce({})'.format(self.rule)
-
-
-class Accept(Reduce):
- def __repr__(self):
- return 'Accept({})'.format(self.rule)
-
-
-def print_grammar(g):
- """ Pretty print a grammar """
- print(g)
- for production in g.productions:
- print(production)
-
-
-def calculate_first_sets(grammar):
- """
- Calculate first sets for each grammar symbol
- This is a dictionary which maps each grammar symbol
- to a set of terminals that can be encountered first
- when looking for the symbol.
- """
- first = {}
- nullable = {}
- for terminal in grammar.terminals | {EOF, EPS}:
- first[terminal] = set([terminal])
- nullable[terminal] = False
- for nt in grammar.nonterminals:
- first[nt] = set()
- nullable[nt] = False
- while True:
- some_change = False
- for rule in grammar.productions:
- # Check for null-ability:
- if all(nullable[beta] for beta in rule.symbols):
- if not nullable[rule.name]:
- nullable[rule.name] = True
- some_change = True
- # Update first sets:
- for beta in rule.symbols:
- if not nullable[beta]:
- if first[beta] - first[rule.name]:
- first[rule.name] |= first[beta]
- some_change = True
- break
- if not some_change:
- break
- return first
-
-
-class Grammar:
- """ Defines a grammar of a language """
- def __init__(self, terminals):
- self.terminals = set(terminals)
- self.nonterminals = set()
- self.productions = []
- self._first = None # Cached first set
- self.start_symbol = None
-
- def __repr__(self):
- return 'Grammar with {} rules'.format(len(self.productions))
-
- def add_production(self, name, symbols, f=None):
- """ Add a production rule to the grammar """
- production = Production(name, symbols, f)
- self.productions.append(production)
- if name in self.terminals:
- raise ParserGenerationException("Cannot redefine terminal {0}".format(name))
- self.nonterminals.add(name)
- self._first = None # Invalidate cached version
-
- def productionsForName(self, name):
- """ Retrieve all productions for a non terminal """
- return [p for p in self.productions if p.name == name]
-
- @property
- def Symbols(self):
- """ Get all the symbols defined by this grammar """
- return self.nonterminals | self.terminals
-
- @property
- def first(self):
- """
- The first set is a mapping from a grammar symbol to a set of
- set of all terminal symbols that can be the first terminal when
- looking for the grammar symbol
- """
- if not self._first:
- self._first = calculate_first_sets(self)
- return self._first
-
- def closure(self, itemset):
- """ Expand itemset by using epsilon moves """
- worklist = list(itemset)
- def addIt(itm):
- if not itm in itemset:
- itemset.add(itm)
- worklist.append(itm)
- def first2(itm):
- # When using the first sets, create a copy:
- f = set(self.first[itm.NextNext])
- if EPS in f:
- f.discard(EPS)
- f.add(itm.look_ahead)
- return f
- # Start of algorithm:
- while worklist:
- item = worklist.pop(0)
- if not item.IsShift:
- continue
- if not (item.Next in self.nonterminals):
- continue
- C = item.Next
- for add_p in self.productionsForName(C):
- for b in first2(item):
- addIt(Item(add_p, 0, b))
- return frozenset(itemset)
-
- def initialItemSet(self):
- """ Calculates the initial item set """
- iis = set()
- for p in self.productionsForName(self.start_symbol):
- iis.add(Item(p, 0, EOF))
- return self.closure(iis)
-
- def nextItemSet(self, itemset, symbol):
- """
- Determines the next itemset for the current set and a symbol
- This is the goto procedure
- """
- next_set = set()
- for item in itemset:
- if item.can_shift_over(symbol):
- next_set.add(item.shifted())
- return self.closure(next_set)
-
- def genCanonicalSet(self, iis):
- states = []
- worklist = []
- transitions = {}
- def addSt(s):
- if not (s in states):
- worklist.append(s)
- states.append(s)
- addSt(iis)
- while len(worklist) > 0:
- itemset = worklist.pop(0)
- for symbol in self.Symbols:
- nis = self.nextItemSet(itemset, symbol)
- if not nis:
- continue
- addSt(nis)
- transitions[(states.index(itemset), symbol)] = states.index(nis)
- return states, transitions
-
- def checkSymbols(self):
- """ Checks no symbols are undefined """
- for production in self.productions:
- for symbol in production.symbols:
- if symbol not in self.Symbols:
- raise ParserGenerationException('Symbol {0} undefined'.format(symbol))
-
- def generate_parser(self):
- """ Generates a parser from the grammar """
- action_table, goto_table = self.generate_tables()
- p = LRParser(action_table, goto_table, self.start_symbol)
- p.grammar = self
- return p
-
- def generate_tables(self):
- """ Generate parsing tables """
- if not self.start_symbol:
- self.start_symbol = self.productions[0].name
- self.checkSymbols()
- action_table = {}
- goto_table = {}
- iis = self.initialItemSet()
-
- # First generate all item sets by using the nextItemset function:
- states, transitions = self.genCanonicalSet(iis)
-
- def setAction(state, t, action):
- assert isinstance(action, Action)
- key = (state, t)
- assert type(state) is int
- assert type(t) is str
- if key in action_table:
- action2 = action_table[key]
- if action != action2:
- if (type(action2) is Reduce) and (type(action) is Shift):
- # Automatically resolve and do the shift action!
- # Simple, but almost always what you want!!
- action_table[key] = action
- elif isinstance(action2, Shift) and isinstance(action, Reduce):
- pass
- else:
- a1 = str(action)
- a2 = str(action2)
- raise ParserGenerationException('LR construction conflict {0} vs {1}'.format(a1, a2))
- else:
- action_table[key] = action
-
- # Fill action table:
- for state in states:
- # Detect conflicts:
- for item in state:
- if item.IsShift and item.Next in self.terminals:
- # Rule 1, a shift item:
- nextstate = transitions[(states.index(state), item.Next)]
- setAction(states.index(state), item.Next, Shift(nextstate))
- if item.IsReduce:
- if item.production.name == self.start_symbol and item.look_ahead == EOF:
- # Rule 3: accept:
- act = Accept(self.productions.index(item.production))
- else:
- # Rule 2, reduce item:
- act = Reduce(self.productions.index(item.production))
- setAction(states.index(state), item.look_ahead, act)
- for nt in self.nonterminals:
- key = (states.index(state), nt)
- if key in transitions:
- goto_table[key] = transitions[key]
- return action_table, goto_table
-
-
-class Production:
- """ Production rule for a grammar """
- def __init__(self, name, symbols, f):
- self.name = name
- self.symbols = symbols
- self.f = f
-
- def __repr__(self):
- action = ' ' + str(self.f) if self.f else ''
- return '{0} -> {1}'.format(self.name, self.symbols) + action
-
-
-class Item:
- """
- Represents a partially parsed item
- It has a production it is looking for, a position
- in this production called the 'dot' and a look ahead
- symbol that must follow this item.
- """
- def __init__(self, production, dotpos, look_ahead):
- self.production = production
- self.dotpos = dotpos
- assert self.dotpos <= len(self.production.symbols)
- self.look_ahead = look_ahead
- self._is_shift = self.dotpos < len(self.production.symbols)
-
- def getdata(self):
- """ Gets the members as a tuple """
- return (self.production, self.dotpos, self.look_ahead)
-
- def __eq__(self, other):
- if type(other) is type(self):
- return self.getdata() == other.getdata()
- return False
-
- def __hash__(self):
- return self.getdata().__hash__()
-
- @property
- def IsReduce(self):
- """ Check if this item has the dot at the end """
- return not self._is_shift
-
- @property
- def IsShift(self):
- """ Check if this item is a shift item, i.e. the dot can proceed """
- return self._is_shift
-
- @property
- def Next(self):
- """ Returns the symbol after the dot """
- return self.production.symbols[self.dotpos]
-
- def can_shift_over(self, symbol):
- """ Determines if this item can shift over the given symbol """
- return self.IsShift and self.Next == symbol
-
- def shifted(self):
- """ Creates a new item that is shifted one position """
- return Item(self.production, self.dotpos + 1, self.look_ahead)
-
- @property
- def NextNext(self):
- """ Gets the symbol after the next symbol, or EPS if at the end """
- if self.dotpos + 1 >= len(self.production.symbols):
- return EPS
- else:
- return self.production.symbols[self.dotpos + 1]
-
- def __repr__(self):
- prod = self.production
- predot = ' '.join(prod.symbols[0:self.dotpos])
- postdot = ' '.join(prod.symbols[self.dotpos:])
- name = prod.name
- args = (name, predot, postdot, self.look_ahead)
- return '[{0} -> {1} . {2} -> {3}]'.format(*args)
-
-
-class LRParser:
- """ LR parser automata """
- def __init__(self, action_table, goto_table, start_symbol):
- self.action_table = action_table
- self.goto_table = goto_table
- self.start_symbol = start_symbol
-
- def parse(self, lexer):
- """ Parse an iterable with tokens """
- assert hasattr(lexer, 'next_token'), '{0} is no lexer'.format(type(lexer))
- stack = [0]
- r_data_stack = []
- look_ahead = lexer.next_token()
- assert type(look_ahead) is Token
- # TODO: exit on this condition:
- while stack != [0, self.start_symbol, 2222]:
- state = stack[-1] # top of stack
- key = (state, look_ahead.typ)
- if not key in self.action_table:
- raise ParserException('Error parsing at character {0}'.format(look_ahead))
- action = self.action_table[key]
- if type(action) is Reduce:
- f_args = []
- prod = self.grammar.productions[action.rule]
- for s in prod.symbols:
- stack.pop()
- stack.pop()
- f_args.append(r_data_stack.pop())
- f_args.reverse()
- r_data = None
- if prod.f:
- r_data = prod.f(*f_args)
- state = stack[-1]
- stack.append(prod.name)
- stack.append(self.goto_table[(state, prod.name)])
- r_data_stack.append(r_data)
- elif type(action) is Shift:
- stack.append(look_ahead.typ)
- stack.append(action.to_state)
- r_data_stack.append(look_ahead)
- look_ahead = lexer.next_token()
- assert type(look_ahead) is Token
- elif type(action) is Accept:
- # Pop last rule data off the stack:
- f_args = []
- param = self.grammar.productions[action.rule]
- for s in param.symbols:
- stack.pop()
- stack.pop()
- f_args.append(r_data_stack.pop())
- f_args.reverse()
- if param.f:
- ret_val = param.f(*f_args)
- else:
- ret_val = None
- # Break out!
- break
- # At exit, the stack must be 1 long
- # TODO: fix that this holds:
- #assert len(stack) == 1, 'stack {0} not totally reduce'.format(stack)
- return ret_val
diff -r 742588fb8cd6 -r f381cea07fec python/tree.py
--- a/python/tree.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-
-class Tree:
- """ Tree node with a name and possibly some child nodes """
- def __init__(self, name, *args):
- self.name = name
- self.value = None
- self.children = args
-
- def __repr__(self):
- if self.children:
- ch = ', '.join(str(c) for c in self.children)
- return '{}({})'.format(self.name, ch)
- else:
- return '{}'.format(self.name)
-
-
-class State:
- """ State used to label tree nodes """
- def __init__(self):
- self.labels = {}
-
- def has_goal(self, goal):
- return goal in self.labels
-
- def get_cost(self, goal):
- return self.labels[goal][0]
-
- def get_rule(self, goal):
- return self.labels[goal][1]
-
- def set_cost(self, goal, cost, rule):
- if self.has_goal(goal):
- if self.get_cost(goal) > cost:
- self.labels[goal] = (cost, rule)
- else:
- self.labels[goal] = (cost, rule)
-
-
-class BaseMatcher:
- """ Base class for matcher objects. """
- def kids(self, tree, rule):
- return self.kid_functions[rule](tree)
-
- def nts(self, rule):
- return self.nts_map[rule]
-
- def burm_label(self, tree):
- """ Label all nodes in the tree bottom up """
- for c in tree.children:
- self.burm_label(c)
- self.burm_state(tree)
-
- def apply_rules(self, tree, goal):
- rule = tree.state.get_rule(goal)
- results = [self.apply_rules(kid_tree, kid_goal)
- for kid_tree, kid_goal in zip(self.kids(tree, rule), self.nts(rule))]
- return self.pat_f[rule](tree, *results)
diff -r 742588fb8cd6 -r f381cea07fec python/utils/__init__.py
--- a/python/utils/__init__.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-
-
-from .hexfile import HexFile, HexFileException
-
diff -r 742588fb8cd6 -r f381cea07fec python/utils/adi.py
--- a/python/utils/adi.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-
-# Implementation of the ADI (ARM Debug Interface) v5 interface.
-
-COMPONENT_CLASSES = {0x1: 'ROM table'}
-
-class Adi:
- def __init__(self, iface):
- self.iface = iface
- def r32(self, address):
- return self.iface.read_debug32(address)
- def w32(self, address, value):
- self.iface.write_debug32(address, value)
- def getId(self, offset):
- print('reading id from {0:X}'.format(offset))
- pid4 = self.r32(offset + 0xFD0)
- #print('pid4', pid4)
- pid5 = self.r32(offset + 0xFD4)
- pid6 = self.r32(offset + 0xFD8)
- pid7 = self.r32(offset + 0xFDC)
- pid0 = self.r32(offset + 0xFE0)
- pid1 = self.r32(offset + 0xFE4)
- pid2 = self.r32(offset + 0xFE8)
- pid3 = self.r32(offset + 0xFEC)
- cid0 = self.r32(offset + 0xFF0)
- cid1 = self.r32(offset + 0xFF4)
- cid2 = self.r32(offset + 0xFF8)
- cid3 = self.r32(offset + 0xFFC)
- pids = [pid0, pid1, pid2, pid3, pid4, pid5, pid6, pid7]
- cids = [cid0, cid1, cid2, cid3]
- print('cids:', [hex(x) for x in cids], 'pids', [hex(x) for x in pids])
- valid = cid0 == 0xD and (cid1 & 0xF) == 0x0 and cid2 == 0x5 and cid3 == 0xB1
- if valid:
- component_class = cid1 >> 4
- else:
- print('invalid class')
- component_class = 0
- # TODO: use pids
- return component_class, pids
-
- def parseRomTable(self, offset):
- assert (offset & 0xFFF) == 0
- component_class, pid = self.getId(offset)
- assert component_class == 1
- print('Component class:', COMPONENT_CLASSES[component_class])
- print('memory also on this bus:', self.r32(offset + 0xFCC))
- idx = 0
- entry = self.r32(offset + idx * 4)
- while entry != 0:
- #print('Entry: {0:X}'.format(entry))
- entryOffset = entry & 0xFFFFF000
- cls, pids = self.getId((offset + entryOffset) & 0xFFFFFFFF)
- print('class:', cls)
- if cls == 9:
- print('Debug block found!')
-
- idx += 1
- entry = self.r32(offset + idx * 4)
-
-
diff -r 742588fb8cd6 -r f381cea07fec python/utils/devices.py
--- a/python/utils/devices.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-import sys
-import usb
-
-# Global device list to which devices are registered.
-devices = {}
-
-def registerDevice(chipId):
- """ Decorator to register a device """
- def wrapper(dev):
- devices[chipId] = dev
- return dev
- return wrapper
-
-# Global interface dictionary.
-interfaces = {}
-
-def registerInterface(vid_pid):
- def wrapper(iface):
- interfaces[vid_pid] = iface
- return iface
- return wrapper
-
-def createInterfaces():
- """ Create a list of detected interfaces """
- ctx = usb.UsbContext()
-
- # Retrieve all usb devices:
- devs = ctx.DeviceList
- keys = interfaces.keys()
-
- # Filter function to filter only registered interfaces:
- def filt(usbiface):
- return (usbiface.VendorId, usbiface.ProductId) in keys
- def buildInterface(usbiface):
- key = (usbiface.VendorId, usbiface.ProductId)
- iface = interfaces[key]
- return iface(usbiface)
- return [buildInterface(uif) for uif in filter(filt, devs)]
-
-class Device:
- """
- Base class for a device possibly connected via an interface.
- """
- def __init__(self, iface):
- # Store the interface through which this device is connected:
- assert isinstance(iface, Interface)
- self.iface = iface
-
-class Interface:
- """
- Generic interface class. Connected via Usb to a JTAG interface.
- Possibly is connected with a certain chip.
- """
- def createDevice(self):
- """ Try to get the device connected to this interface """
- if self.ChipId in devices:
- return devices[self.ChipId](self)
- raise STLinkException('No device found!')
-
-class STLinkException(Exception):
- """ Exception used for interfaces and devices """
- pass
-
diff -r 742588fb8cd6 -r f381cea07fec python/utils/hexfile.py
--- a/python/utils/hexfile.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,158 +0,0 @@
-import os
-import struct
-import binascii
-
-DATA = 0
-EOF = 1
-EXTLINADR = 4
-
-class HexFileException(Exception):
- pass
-
-
-def parseHexLine(line):
- """ Parses a hexfile line into three parts """
- line = line[1:] # Remove ':'
- nums = bytes.fromhex(line)
- bytecount = nums[0]
- if len(nums) != bytecount + 5:
- raise HexFileException('byte count field incorrect')
- crc = sum(nums)
- if (crc & 0xFF) != 0:
- raise HexFileException('crc incorrect')
- address = struct.unpack('>H', nums[1:3])[0]
- typ = nums[3]
- data = nums[4:-1]
- return (address, typ, data)
-
-def makeHexLine(address, typ, data=bytes()):
- bytecount = len(data)
- nums = bytearray()
- nums.append(bytecount)
- nums.extend(struct.pack('>H', address))
- nums.append(typ)
- nums.extend(data)
- crc = sum(nums)
- crc = ((~crc) + 1) & 0xFF
- nums.append(crc)
- line = ':' + binascii.hexlify(nums).decode('ascii')
- return line
-
-def chunks(data, csize=16):
- idx = 0
- while idx < len(data):
- s = min(len(data) - idx, csize)
- yield data[idx:idx+s]
- idx += s
-
-def hexfields(f):
- for line in f:
- line = line.strip() # Strip spaces and newlines
- if not line:
- continue # Skip empty lines
- if line[0] != ':':
- continue # Skip lines that do not start with a ':'
- yield parseHexLine(line)
-
-
-class HexFile:
- """ Represents an intel hexfile """
- def __init__(self):
- self.regions = []
- self.startAddress = 0
-
- def load(self, f):
- endOfFile = False
- ext = 0
- for address, typ, data in hexfields(f):
- if endOfFile:
- raise HexFileException('hexfile line after end of file record')
- if typ == 0x0: # Data record
- self.addRegion(address + ext, data)
- elif typ == EXTLINADR: # Extended linear address record
- ext = (struct.unpack('>H', data[0:2])[0]) << 16
- elif typ == EOF: # End of file record
- if len(data) != 0:
- raise HexFileException('end of file not empty')
- endOfFile = True
- elif typ == 0x5: # Start address record (where IP goes after loading)
- self.startAddress = struct.unpack('>I', data[0:4])[0]
- else:
- raise HexFileException('record type {0} not implemented'.format(typ))
-
- def __repr__(self):
- size = sum(r.Size for r in self.regions)
- return 'Hexfile containing {} bytes'.format(size)
-
- def dump(self):
- print(self)
- for r in self.regions:
- print(r)
-
- def __eq__(self, other):
- regions = self.regions
- oregions = other.regions
- if len(regions) != len(oregions):
- return False
- return all(rs == ro for rs, ro in zip(regions, oregions))
-
- def addRegion(self, address, data):
- r = HexFileRegion(address, data)
- self.regions.append(r)
- self.check()
-
- def check(self):
- self.regions.sort(key=lambda r: r.address)
- change = True
- while change and len(self.regions) > 1:
- change = False
- for r1, r2 in zip(self.regions[:-1], self.regions[1:]):
- if r1.EndAddress == r2.address:
- r1.addData(r2.data)
- self.regions.remove(r2)
- change = True
- elif r1.EndAddress > r2.address:
- raise HexFileException('Overlapping regions')
-
- def merge(self, other):
- for r in other.regions:
- self.addRegion(r.address, r.data)
-
- def save(self, f):
- def emit(address, typ, data=bytes()):
- print(makeHexLine(address, typ, data), file=f)
- for r in self.regions:
- ext = r.address & 0xFFFF0000
- emit(0, EXTLINADR, struct.pack('>H', ext >> 16))
- address = r.address - ext
- for chunk in chunks(r.data):
- if address >= 0x10000:
- ext += 0x10000
- emit(0, EXTLINADR, struct.pack('>H', ext >> 16))
- address -= 0x10000
- emit(address, DATA, chunk)
- address += len(chunk)
- emit(0, EOF)
-
-
-class HexFileRegion:
- def __init__(self, address, data = bytes()):
- self.address = address
- self.data = data
-
- def __repr__(self):
- return 'Region at 0x{:08X} of {} bytes'.format(self.address, len(self.data))
-
- def __eq__(self, other):
- return (self.address, self.data) == (other.address, other.data)
-
- def addData(self, d):
- self.data = self.data + d
-
- @property
- def Size(self):
- return len(self.data)
-
- @property
- def EndAddress(self):
- return self.address + len(self.data)
diff -r 742588fb8cd6 -r f381cea07fec python/utils/iso9660.py
--- a/python/utils/iso9660.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-#!/usr/bin/env python
-
-import argparse
-
-__doc__ = """
- ISO 9660 filesystem utility.
-"""
-
-
-class VolumeDescriptor:
- @classmethod
- def FromData(cls, d):
- ty = d[0]
- Id = d[1:6]
- assert Id == 'CD001'.encode('ascii')
- ver = d[6]
- assert ver == 1
- cls = vol_desc_types[ty]
- return cls(d)
-
-
-vol_desc_types = {}
-def vol_type(t):
- def reg_func(cls):
- vol_desc_types[t] = cls
- return cls
- return reg_func
-
-
-@vol_type(0)
-class BootRecordVolumeDescriptor(VolumeDescriptor):
- def __init__(self, d):
- boot_sys_id = d[7:39]
- boot_id = d[39:71]
- print(boot_sys_id)
- print(boot_id)
-
-
-@vol_type(1)
-class PrimaryVolumeDescriptor(VolumeDescriptor):
- def __init__(self, d):
- sys_id = d[8:40]
- vol_id = d[40:72]
- print(sys_id)
- print(vol_id)
-
-
-@vol_type(255)
-class VolumeDescriptorTerminator(VolumeDescriptor):
- def __init__(self, d):
- pass
-
-
-class ISOfs:
- def __init__(self):
- self.vol_descriptors = []
-
- def read(self, f):
- # System area:
- self.system_area = f.read(16 * 2048)
- while True:
- d = f.read(2048)
- desc = VolumeDescriptor.FromData(d)
- self.vol_descriptors.append(desc)
- if type(desc) is VolumeDescriptorTerminator:
- break
-
- def dump(self):
- for vd in self.vol_descriptors:
- print(vd)
-
-
-if __name__ == '__main__':
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument('filename')
- args = parser.parse_args()
- fs = ISOfs()
- with open(args.filename, 'rb') as f:
- fs.read(f)
- fs.dump()
-
-
diff -r 742588fb8cd6 -r f381cea07fec python/utils/lsusb.py
--- a/python/utils/lsusb.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-#!/usr/bin/python
-
-from usb import UsbContext
-
-# try to read usb.ids:
-vids = {}
-pids = {}
-try:
- with open('usb.ids', 'r', errors='ignore') as f:
- vid = 0
- for l in f:
- if l.startswith('#') or not l.strip():
- continue
- if l.startswith('\t\t'):
- print('iface:', l)
- elif l.startswith('\t'):
- print('product', l)
- pid = int(l[1:5], 16)
- print('product', hex(pid), l)
- else:
- print('vendor', l)
- vid = int(l[0:4], 16)
- print('vendor', hex(vid), l)
-
-except IOError as e:
- print("Error loading usb id's: {0}".format(e))
-
-context = UsbContext()
-for d in context.DeviceList:
- print(d)
-
diff -r 742588fb8cd6 -r f381cea07fec python/utils/st-flash.py
--- a/python/utils/st-flash.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-#!/usr/bin/python
-
-import argparse, sys
-import stlink, stm32
-import hexfile
-
-def hex2int(s):
- if s.startswith('0x'):
- s = s[2:]
- return int(s, 16)
- raise ValueError('Hexadecimal value must begin with 0x')
-
-parser = argparse.ArgumentParser(
- description='ST-link flash utility by Windel Bouwman')
-subparsers = parser.add_subparsers(title='commands',
- description='possible commands', dest='command')
-
-readparser = subparsers.add_parser('read', help='read flash contents')
-readparser.add_argument('filename', type=argparse.FileType('wb', 0))
-readparser.add_argument('address', type=hex2int)
-readparser.add_argument('size', type=hex2int)
-
-writeparser = subparsers.add_parser('write', help='write flash contents')
-writeparser.add_argument('filename', type=argparse.FileType('rb'))
-writeparser.add_argument('address', type=hex2int)
-
-hexwriteparser = subparsers.add_parser('hexwrite', help='write hexfile to flash')
-hexwriteparser.add_argument('hexfile', type=argparse.FileType('r'))
-
-verifyparser = subparsers.add_parser('verify', help='verify flash contents')
-verifyparser.add_argument('filename', type=argparse.FileType('rb'))
-verifyparser.add_argument('address', type=hex2int)
-
-eraseparser = subparsers.add_parser('erase', help='erase flash contents')
-
-args = parser.parse_args()
-if not args.command:
- parser.print_usage()
- sys.exit(1)
-
-# In any command case, open a device:
-stl = stlink.STLink2()
-stl.open()
-
-# Enter the right mode:
-if stl.CurrentMode == stlink.DFU_MODE:
- stl.exitDfuMode()
-
-if stl.CurrentMode != stlink.DEBUG_MODE:
- stl.enterSwdMode()
-
-if stl.ChipId != 0x10016413:
- print('Only working on stm32f4discovery board for now.')
- sys.exit(2)
-
-# Retrieve the connected device, if any:
-dev = stl.createDevice()
-
-if args.command == 'read':
- dev_content = dev.readFlash(args.address, args.size)
- args.filename.write(dev_content)
-elif args.command == 'write':
- content = args.filename.read()
- dev.writeFlash(args.address, content)
-elif args.command == 'hexwrite':
- hf = hexfile.HexFile()
- hf.load(args.hexfile)
- r = hf.regions[0]
- dev.writeFlash(r.address, r.data)
-elif args.command == 'verify':
- content = args.filename.read()
- dev.verifyFlash(args.address, content)
-elif args.command == 'erase':
- dev.eraseFlash()
-else:
- print('unknown command', args.command)
-
-stl.reset()
-stl.run()
-stl.exitDebugMode()
-
diff -r 742588fb8cd6 -r f381cea07fec python/utils/stlink.py
--- a/python/utils/stlink.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,367 +0,0 @@
-import struct, time
-from usb import UsbContext, UsbDevice
-from devices import Interface, STLinkException, registerInterface
-import adi
-
-"""
- More or less copied from:
- https://github.com/texane/stlink
- Tracing from:
- https://github.com/obe1line/stlink-trace
-
-"""
-ST_VID, STLINK2_PID = 0x0483, 0x3748
-
-def checkDevice(device):
- return device.VendorId == ST_VID and device.ProductId == STLINK2_PID
-
-DFU_MODE, MASS_MODE, DEBUG_MODE = 0, 1, 2
-
-CORE_RUNNING = 0x80
-CORE_HALTED = 0x81
-
-# Commands:
-GET_VERSION = 0xf1
-DEBUG_COMMAND = 0xf2
-DFU_COMMAND = 0xf3
-GET_CURRENT_MODE = 0xf5
-
-# dfu commands:
-DFU_EXIT = 0x7
-
-# debug commands:
-DEBUG_ENTER = 0x20
-DEBUG_EXIT = 0x21
-DEBUG_ENTER_SWD = 0xa3
-DEBUG_GETSTATUS = 0x01
-DEBUG_FORCEDEBUG = 0x02
-DEBUG_RESETSYS = 0x03
-DEBUG_READALLREGS = 0x04
-DEBUG_READREG = 0x5
-DEBUG_WRITEREG = 0x6
-DEBUG_READMEM_32BIT = 0x7
-DEBUG_WRITEMEM_32BIT = 0x8
-DEBUG_RUNCORE = 0x9
-DEBUG_STEPCORE = 0xa
-
-JTAG_WRITEDEBUG_32BIT = 0x35
-JTAG_READDEBUG_32BIT = 0x36
-TRACE_GET_BYTE_COUNT = 0x42
-
-# cortex M3
-CM3_REG_CPUID = 0xE000ED00
-
-@registerInterface((ST_VID, STLINK2_PID))
-class STLink2(Interface):
- """ STlink2 interface implementation. """
- def __init__(self, stlink2=None):
- self.devHandle = None
- if not stlink2:
- context = UsbContext()
- stlink2s = list(filter(checkDevice, context.DeviceList))
- if not stlink2s:
- raise STLinkException('Could not find an ST link 2 interface')
- if len(stlink2s) > 1:
- print('More then one stlink2 found, picking first one')
- stlink2 = stlink2s[0]
- assert isinstance(stlink2, UsbDevice) # Nifty type checking
- assert checkDevice(stlink2)
- self.stlink2 = stlink2
- def __del__(self):
- if self.IsOpen:
- if self.CurrentMode == DEBUG_MODE:
- self.exitDebugMode()
- self.close()
- def __str__(self):
- if self.IsOpen:
- return 'STlink2 device version {0}'.format(self.Version)
- else:
- return 'STlink2 device'
- def open(self):
- if self.IsOpen:
- return
- self.devHandle = self.stlink2.open()
- if self.devHandle.Configuration != 1:
- self.devHandle.Configuration = 1
- self.devHandle.claimInterface(0)
-
- # First initialization:
- if self.CurrentMode == DFU_MODE:
- self.exitDfuMode()
- if self.CurrentMode != DEBUG_MODE:
- self.enterSwdMode()
- #self.reset()
- def close(self):
- if self.IsOpen:
- self.devHandle.close()
- self.devHandle = None
- @property
- def IsOpen(self):
- return self.devHandle != None
- # modes:
- def getCurrentMode(self):
- cmd = bytearray(16)
- cmd[0] = GET_CURRENT_MODE
- reply = self.send_recv(cmd, 2) # Expect 2 bytes back
- return reply[0]
- CurrentMode = property(getCurrentMode)
- @property
- def CurrentModeString(self):
- modes = {DFU_MODE: 'dfu', MASS_MODE: 'massmode', DEBUG_MODE:'debug'}
- return modes[self.CurrentMode]
- def exitDfuMode(self):
- cmd = bytearray(16)
- cmd[0:2] = DFU_COMMAND, DFU_EXIT
- self.send_recv(cmd)
- def enterSwdMode(self):
- cmd = bytearray(16)
- cmd[0:3] = DEBUG_COMMAND, DEBUG_ENTER, DEBUG_ENTER_SWD
- self.send_recv(cmd)
- def exitDebugMode(self):
- cmd = bytearray(16)
- cmd[0:2] = DEBUG_COMMAND, DEBUG_EXIT
- self.send_recv(cmd)
-
- def getVersion(self):
- cmd = bytearray(16)
- cmd[0] = GET_VERSION
- data = self.send_recv(cmd, 6) # Expect 6 bytes back
- # Parse 6 bytes into various versions:
- b0, b1, b2, b3, b4, b5 = data
- stlink_v = b0 >> 4
- jtag_v = ((b0 & 0xf) << 2) | (b1 >> 6)
- swim_v = b1 & 0x3f
- vid = (b3 << 8) | b2
- pid = (b5 << 8) | b4
- return 'stlink={0} jtag={1} swim={2} vid:pid={3:04X}:{4:04X}'.format(\
- stlink_v, jtag_v, swim_v, vid, pid)
- Version = property(getVersion)
-
- @property
- def ChipId(self):
- return self.read_debug32(0xE0042000)
- @property
- def CpuId(self):
- u32 = self.read_debug32(CM3_REG_CPUID)
- implementer_id = (u32 >> 24) & 0x7f
- variant = (u32 >> 20) & 0xf
- part = (u32 >> 4) & 0xfff
- revision = u32 & 0xf
- return implementer_id, variant, part, revision
- def getStatus(self):
- cmd = bytearray(16)
- cmd[0:2] = DEBUG_COMMAND, DEBUG_GETSTATUS
- reply = self.send_recv(cmd, 2)
- return reply[0]
- Status = property(getStatus)
- @property
- def StatusString(self):
- s = self.Status
- statii = {CORE_RUNNING: 'CORE RUNNING', CORE_HALTED: 'CORE HALTED'}
- if s in statii:
- return statii[s]
- return 'Unknown status'
-
- def reset(self):
- cmd = bytearray(16)
- cmd[0:2] = DEBUG_COMMAND, DEBUG_RESETSYS
- self.send_recv(cmd, 2)
-
- # debug commands:
- def step(self):
- cmd = bytearray(16)
- cmd[0:2] = DEBUG_COMMAND, DEBUG_STEPCORE
- self.send_recv(cmd, 2)
- def run(self):
- cmd = bytearray(16)
- cmd[0:2] = DEBUG_COMMAND, DEBUG_RUNCORE
- self.send_recv(cmd, 2)
- def halt(self):
- cmd = bytearray(16)
- cmd[0:2] = DEBUG_COMMAND, DEBUG_FORCEDEBUG
- self.send_recv(cmd, 2)
-
- # Tracing:
- def traceEnable(self):
- self.write_debug32(0xE000EDF0, 0xA05F0003)
-
- # Enable TRCENA:
- DEMCR = 0xE000EDFC
- v = self.read_debug32(DEMCR)
- v |= (1 << 24)
- self.write_debug32(DEMCR, v)
-
- # ?? Enable write??
- self.write_debug32(0xE0002000, 0x2) #
-
- # DBGMCU_CR:
- self.write_debug32(0xE0042004, 0x27) # Enable trace in async mode
-
- # TPIU config:
- self.write_debug32(0xE0040004, 0x00000001) # current port size register --> 1 == port size = 1
- self.write_debug32(0xE0040010, 0x23) # random clock divider??
- self.write_debug32(0xE00400F0, 0x2) # selected pin protocol (2 == NRZ)
- self.write_debug32(0xE0040304, 0x100) # continuous formatting
-
- # ITM config:
- self.write_debug32(0xE0000FB0, 0xC5ACCE55) # Unlock write access to ITM
- self.write_debug32(0xE0000F80, 0x00010005) # ITM Enable, sync enable, ATB=1
- self.write_debug32(0xE0000E00, 0xFFFFFFFF) # Enable all trace ports in ITM
- self.write_debug32(0xE0000E40, 0x0000000F) # Set privilege mask for all 32 ports.
- def writePort0(self, v32):
- self.write_debug32(0xE0000000, v32)
- def getTraceByteCount(self):
- cmd = bytearray(16)
- cmd[0:2] = DEBUG_COMMAND, 0x42
- reply = self.send_recv(cmd, 2)
- return struct.unpack(' 0:
- td = self.recv_ep3(bsize)
- print(td)
- else:
- print('no trace data')
-
- # Helper 1 functions:
- def write_debug32(self, address, value):
- cmd = bytearray(16)
- cmd[0:2] = DEBUG_COMMAND, JTAG_WRITEDEBUG_32BIT
- cmd[2:10] = struct.pack(' 0:
- return self.devHandle.bulkRead(1, rxsize) # read from endpoint 1
- def recv_ep3(self, rxsize):
- return self.devHandle.bulkRead(3, rxsize)
-
-if __name__ == '__main__':
- # Test program
- sl = STLink2()
- sl.open()
- sl.reset()
- print('version:', sl.Version)
- print('mode before doing anything:', sl.CurrentModeString)
- if sl.CurrentMode == DFU_MODE:
- sl.exitDfuMode()
- sl.enterSwdMode()
- print('mode after entering swd mode:', sl.CurrentModeString)
-
- i = sl.ChipId
- print('chip id: 0x{0:X}'.format(i))
- print('cpu: {0}'.format(sl.CpuId))
-
- print('status: {0}'.format(sl.StatusString))
-
- # test registers:
- sl.write_reg(0, 0xdeadbeef)
- sl.write_reg(1, 0xcafebabe)
- sl.write_reg(2, 0xc0ffee)
- sl.write_reg(3, 0x1337)
- sl.write_reg(5, 0x1332)
- sl.write_reg(6, 0x12345)
- assert sl.read_reg(3) == 0x1337
- assert sl.read_reg(5) == 0x1332
- assert sl.read_reg(6) == 0x12345
- regs = sl.read_all_regs()
- for i in range(len(regs)):
- print('R{0}=0x{1:X}'.format(i, regs[i]))
-
- print('tracing')
- sl.traceEnable()
- sl.run()
- sl.writePort0(0x1337) # For test
- time.sleep(0.1)
- td = sl.readTraceData()
- print('trace data:', td)
-
- # Test CoreSight registers:
- idr4 = sl.read_debug32(0xE0041fd0)
- print('idr4 =', idr4)
-
- print('== ADI ==')
- a = adi.Adi(sl)
- a.parseRomTable(0xE00FF000) # why is rom table at 0xE00FF000?
- print('== ADI ==')
-
- # Detect ROM table:
- id4 = sl.read_debug32(0xE00FFFD0)
- id5 = sl.read_debug32(0xE00FFFD4)
- id6 = sl.read_debug32(0xE00FFFD8)
- id7 = sl.read_debug32(0xE00FFFDC)
- id0 = sl.read_debug32(0xE00FFFE0)
- id1 = sl.read_debug32(0xE00FFFE4)
- id2 = sl.read_debug32(0xE00FFFE8)
- id3 = sl.read_debug32(0xE00FFFEC)
- pIDs = [id0, id1, id2, id3, id4, id5, id6, id7]
- print(pIDs)
-
- print('reading from 0xE00FF000')
- scs = sl.read_debug32(0xE00FF000)
- print('scs {0:08X}'.format(scs))
- dwt = sl.read_debug32(0xE00FF004)
- print('dwt {0:08X}'.format(dwt))
- fpb = sl.read_debug32(0xE00FF008)
- print('fpb {0:08X}'.format(fpb))
- itm = sl.read_debug32(0xE00FF00C)
- print('itm {0:08X}'.format(itm))
- tpiu = sl.read_debug32(0xE00FF010)
- print('tpiu {0:08X}'.format(tpiu))
- etm = sl.read_debug32(0xE00FF014)
- print('etm {0:08X}'.format(etm))
- assert sl.read_debug32(0xE00FF018) == 0x0 # end marker
-
- devid = sl.read_debug32(0xE0040FC8)
- print('TPIU_DEVID: {0:X}'.format(devid))
- devtype = sl.read_debug32(0xE0040FCC)
- print('TPIU_TYPEID: {0:X}'.format(devtype))
-
- sl.exitDebugMode()
- print('mode at end:', sl.CurrentModeString)
-
- sl.close()
- print('Test succes!')
-
diff -r 742588fb8cd6 -r f381cea07fec python/utils/stm32.py
--- a/python/utils/stm32.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,264 +0,0 @@
-import time
-import logging
-from devices import Device, registerDevice, STLinkException, Interface
-import stlink
-
-# F4 specifics:
-STM32_FLASH_BASE = 0x08000000
-STM32_SRAM_BASE = 0x20000000
-
-# flash registers:
-FLASH_F4_REGS_ADDR = 0x40023c00
-FLASH_F4_KEYR = FLASH_F4_REGS_ADDR + 0x04
-FLASH_F4_SR = FLASH_F4_REGS_ADDR + 0x0c
-FLASH_F4_CR = FLASH_F4_REGS_ADDR + 0x10
-
-FLASH_F4_CR_START = 16
-FLASH_F4_CR_LOCK = 31
-FLASH_CR_PG = 0
-FLASH_F4_CR_SER = 1
-FLASH_CR_MER = 2
-FLASH_F4_CR_SNB = 3
-FLASH_F4_CR_SNB_MASK = 0x38
-FLASH_F4_SR_BSY = 16
-
-class Stm32F4(Device):
- """
- Implementation of the specifics of the STM32F4xx device series.
- """
- def __init__(self, iface):
- super().__init__(iface)
- self.logger = logging.getLogger('stm32')
-
- def __str__(self):
- return 'STM32F4 device size=0x{1:X} id=0x{0:X}'.format(\
- self.UID, self.FlashSize)
-
- def calculate_F4_sector(self, address):
- sectorstarts = []
- a = STM32_FLASH_BASE
- for sectorsize in self.sectorsizes:
- sectorstarts.append(a)
- a += sectorsize
- # linear search:
- sec = 0
- while sec < len(self.sectorsizes) and address >= sectorstarts[sec]:
- sec += 1
- sec -= 1 # one back.
- return sec, self.sectorsizes[sec]
-
- def calcSectors(self, address, size):
- off = 0
- sectors = []
- while off < size:
- sectornum, sectorsize = self.calculate_F4_sector(address + off)
- sectors.append((sectornum, sectorsize))
- off += sectorsize
- return sectors
-
- # Device registers:
- @property
- def UID(self):
- uid_base = 0x1FFF7A10
- uid1 = self.iface.read_debug32(uid_base)
- uid2 = self.iface.read_debug32(uid_base + 0x4)
- uid3 = self.iface.read_debug32(uid_base + 0x8)
- return (uid3 << 64) | (uid2 << 32) | uid1
-
- @property
- def FlashSize(self):
- f_id = self.iface.read_debug32(0x1FFF7A22)
- f_id = f_id >> 16
- return f_id * 1024
-
- @property
- def Running(self):
- return self.iface.Status == stlink.CORE_RUNNING
-
- # flashing commands:
- def writeFlash(self, address, content):
- flashsize = self.FlashSize
- pagesize = min(self.sectorsizes)
-
- # Check address range:
- if address < STM32_FLASH_BASE:
- raise STLinkException('Flashing below flash start')
- if address + len(content) > STM32_FLASH_BASE + flashsize:
- raise STLinkException('Flashing above flash size')
- if address & 1 == 1:
- raise STLinkException('Unaligned flash')
- if len(content) & 1 == 1:
- self.logger.warning('unaligned length, padding with zero')
- content += bytes([0])
- if address & (pagesize - 1) != 0:
- raise STLinkException('Address not aligned with pagesize')
- # erase required space
- sectors = self.calcSectors(address, len(content))
- self.logger.info('erasing {0} sectors'.format(len(sectors)))
- for sector, secsize in sectors:
- self.logger.info('erasing sector {0} of {1} bytes'.format(sector, secsize))
- self.eraseFlashSector(sector)
- # program pages:
- self.unlockFlashIf()
- self.writeFlashCrPsiz(2) # writes are 32 bits aligned
- self.setFlashCrPg()
- self.logger.info('writing {0} bytes'.format(len(content)))
- offset = 0
- t1 = time.time()
- while offset < len(content):
- size = len(content) - offset
- if size > 0x8000:
- size = 0x8000
- chunk = content[offset:offset + size]
- while len(chunk) % 4 != 0:
- chunk = chunk + bytes([0])
- # Use simple mem32 writes:
- self.iface.write_mem32(address + offset, chunk)
- offset += size
- self.logger.info('{}%'.format(offset*100/len(content)))
- self.logger.info('Done!')
- self.lockFlash()
- # verfify program:
- self.verifyFlash(address, content)
-
- def eraseFlashSector(self, sector):
- self.waitFlashBusy()
- self.unlockFlashIf()
- self.writeFlashCrSnb(sector)
- self.setFlashCrStart()
- self.waitFlashBusy()
- self.lockFlash()
-
- def eraseFlash(self):
- self.waitFlashBusy()
- self.unlockFlashIf()
- self.setFlashCrMer()
- self.setFlashCrStart()
- self.waitFlashBusy()
- self.clearFlashCrMer()
- self.lockFlash()
-
- def verifyFlash(self, address, content):
- device_content = self.readFlash(address, len(content))
- ok = content == device_content
- if ok:
- self.logger.info('Verify: OK')
- else:
- self.logger.warning('Verify: Mismatch')
-
- def readFlash(self, address, size):
- self.logger.info('Reading {1} bytes from 0x{0:X}'.format(address, size))
- offset = 0
- tmp_size = 0x1800
- image = bytes()
- while offset < size:
- # Correct for last page:
- if offset + tmp_size > size:
- tmp_size = size - offset
-
- # align size to 4 bytes:
- aligned_size = tmp_size
- while aligned_size % 4 != 0:
- aligned_size += 1
-
- mem = self.iface.read_mem32(address + offset, aligned_size)
- image += mem[:tmp_size]
-
- # indicate progress:
- self.logger.info('{}%'.format(100*len(image) / size))
-
- # increase for next piece:
- offset += tmp_size
- assert size == len(image)
- self.logger.info('Done!')
- return image
-
- def waitFlashBusy(self):
- """ block until flash operation completes. """
- while self.isFlashBusy():
- time.sleep(0.01)
-
- def isFlashLocked(self):
- mask = 1 << FLASH_F4_CR_LOCK
- return self.Cr & mask == mask
-
- def unlockFlashIf(self):
- FLASH_KEY1, FLASH_KEY2 = 0x45670123, 0xcdef89ab
- if self.isFlashLocked():
- self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY1)
- self.iface.write_debug32(FLASH_F4_KEYR, FLASH_KEY2)
- if self.isFlashLocked():
- raise STLinkException('Failed to unlock')
-
- def lockFlash(self):
- self.Cr = self.Cr | (1 << FLASH_F4_CR_LOCK)
-
- def readFlashSr(self):
- return self.iface.read_debug32(FLASH_F4_SR)
-
- def readFlashCr(self):
- return self.iface.read_debug32(FLASH_F4_CR)
-
- def writeFlashCr(self, x):
- self.iface.write_debug32(FLASH_F4_CR, x)
-
- Cr = property(readFlashCr, writeFlashCr)
-
- def writeFlashCrSnb(self, sector):
- x = self.Cr
- x &= ~FLASH_F4_CR_SNB_MASK
- x |= sector << FLASH_F4_CR_SNB
- x |= 1 << FLASH_F4_CR_SER
- self.Cr = x
-
- def setFlashCrMer(self):
- self.Cr = self.Cr | (1 << FLASH_CR_MER)
-
- def setFlashCrPg(self):
- self.Cr = self.Cr | (1 << FLASH_CR_PG)
-
- def writeFlashCrPsiz(self, n):
- x = self.Cr
- x &= (0x3 << 8)
- x |= n << 8
- self.Cr = x
-
- def clearFlashCrMer(self):
- x = self.Cr
- x &= ~(1 << FLASH_CR_MER)
- self.Cr = x
-
- def setFlashCrStart(self):
- self.Cr = self.Cr | (1 << FLASH_F4_CR_START)
-
- def isFlashBusy(self):
- mask = 1 << FLASH_F4_SR_BSY
- sr = self.readFlashSr()
- # Check for error bits:
- errorbits = {}
- errorbits[7] = 'Programming sequence error'
- errorbits[6] = 'Programming parallelism error'
- errorbits[5] = 'Programming alignment error'
- errorbits[4] = 'Write protection error'
- errorbits[1] = 'Operation error'
- #errorbits[0] = 'End of operation'
- for bit, msg in errorbits.items():
- if sr & (1 << bit) == (1 << bit):
- raise STLinkException(msg)
- return sr & mask == mask
-
-
-@registerDevice(0x10016413)
-class Stm32F40x(Stm32F4):
- """ STM32F40x and STM32F41x device series """
- def __init__(self, iface):
- super().__init__(iface)
- # Assert the proper size for this device:
- assert self.FlashSize == 0x100000
- """
- from 0x8000000 to 0x80FFFFF
- 4 sectors of 0x4000 (16 kB)
- 1 sector of 0x10000 (64 kB)
- 7 of 0x20000 (128 kB)
- """
- self.sectorsizes = [0x4000] * 4 + [0x10000] + [0x20000] * 7
diff -r 742588fb8cd6 -r f381cea07fec python/utils/usb.py
--- a/python/utils/usb.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,245 +0,0 @@
-from ctypes import Structure, POINTER, CDLL, CFUNCTYPE
-from ctypes import c_uint16, c_uint8, c_int, c_uint, c_ssize_t, c_void_p
-from ctypes import byref, create_string_buffer
-
-# libusb wrapper:
-libusb = CDLL('libusb-1.0.so')
-
-# helper:
-def buildfunc(name, argtypes, restype=c_int):
- f = getattr(libusb, name)
- f.argtypes = argtypes
- f.restype = restype
- globals()[name] = f
- return f
-def enum(**enums):
- reverse = dict((value, key) for key, value in enums.items())
- enums['reverse_mapping'] = reverse
- return type('enum', (), enums)
-
-# enums
-libusb_class_code = enum(PER_INTERFACE=0, AUDIO=1, COMM=2, HID=3, \
- PHYSICAL=5, PRINTER=7, PTP=6, MASS_STORAGE=8, HUB=9, \
- DATA=10, SMART_CARD=0xb, CONTENT_SECURITY=0xd, VIDEO=0xe, \
- PERSONAL_HEALTHCARE=0xf, DIAGNOSTIC_DEVICE=0xdc, WIRELESS=0xe,\
- APPLICATION=0xfe, VENDOR_SPEC=0xff)
-libusb_speed = enum(UNKNOWN=0, LOW=1, FULL=2, HIGH=3, SUPER=4)
-libusb_error = enum(SUCCES=0, ERROR_IO=-1, ERROR_INVALID_PARAM=-2, \
- ERROR_ACCESS=-3, ERROR_NO_DEVICE=-4, ERROR_NOT_FOUND=-5, \
- ERROR_BUSY=-6, ERROR_TIMEOUT=-7, ERROR_OVERFLOW=-8, \
- ERROR_PIPE=-9, ERROR_INTERRUPTED=-10, ERROR_NO_MEM=-11, \
- ERROR_NOT_SUPPORTED=-12, ERROR_OTHER=-99)
-libusb_transfer_status = enum(\
- COMPLETED=0, ERROR=1, TIMED_OUT=2, \
- CANCELLED=3, STALL=4, NO_DEVICE=5, OVERFLOW=6)
-
-# types
-c_int_p = POINTER(c_int)
-class libusb_context(Structure):
- pass
-libusb_context_p = POINTER(libusb_context)
-libusb_context_p_p = POINTER(libusb_context_p)
-
-class libusb_device(Structure):
- pass
-libusb_device_p = POINTER(libusb_device)
-libusb_device_p_p = POINTER(libusb_device_p)
-libusb_device_p_p_p = POINTER(libusb_device_p_p)
-
-class libusb_device_handle(Structure):
- pass
-libusb_device_handle_p = POINTER(libusb_device_handle)
-libusb_device_handle_p_p = POINTER(libusb_device_handle_p)
-
-class libusb_device_descriptor(Structure):
- _fields_ = [
- ('bLength', c_uint8),
- ('bDescriptorType', c_uint8),
- ('bcdUSB', c_uint16),
- ('bDeviceClass', c_uint8),
- ('bDeviceSubClass', c_uint8),
- ('bDeviceProtocol', c_uint8),
- ('bMaxPacketSize0', c_uint8),
- ('idVendor', c_uint16),
- ('idProduct', c_uint16),
- ('bcdDevice', c_uint16),
- ('iManufacturer', c_uint8),
- ('iProduct', c_uint8),
- ('iSerialNumber', c_uint8),
- ('iNumConfigurations', c_uint8)
- ]
-libusb_device_descriptor_p = POINTER(libusb_device_descriptor)
-
-"""
-class libusb_transfer(Structure):
- pass
-libusb_transfer_p = POINTER(libusb_transfer)
-libusb_transfer_cb_fn = CFUNCTYPE(None, libusb_transfer_p)
-libusb_transfer._fields_ = [
- ('dev_handle', libusb_device_handle_p),
- ('flags', c_uint8),
- ('endpoint', c_uchar),
- ('type', c_uchar),
- ('timeout', c_uint),
- ('status', c_int), # enum libusb_transfer_status
- ('length', c_int),
- ('actual_length', c_int),
- ('callback', libusb_transfer_cb_fn),
- ('userdata', c_void_p),
- ('buffer', c_void_p),
- ('num_iso_packets', c_int),
- ('iso_packet_desc', libusb_iso_packet_descriptor)
- ]
-"""
-# functions
-buildfunc('libusb_init', [libusb_context_p_p], c_int)
-
-buildfunc('libusb_get_device_list', \
- [libusb_context_p, libusb_device_p_p_p], c_ssize_t)
-buildfunc('libusb_free_device_list', [libusb_device_p_p, c_int], None)
-buildfunc('libusb_get_bus_number', [libusb_device_p], c_uint8)
-buildfunc('libusb_get_device_address', [libusb_device_p], c_uint8)
-buildfunc('libusb_get_device_speed', [libusb_device_p])
-buildfunc('libusb_unref_device', [libusb_device_p], None)
-buildfunc('libusb_open', [libusb_device_p, libusb_device_handle_p_p])
-buildfunc('libusb_close', [libusb_device_handle_p], None)
-buildfunc('libusb_get_configuration',[libusb_device_handle_p,POINTER(c_int)])
-buildfunc('libusb_set_configuration', [libusb_device_handle_p, c_int])
-buildfunc('libusb_claim_interface', [libusb_device_handle_p, c_int])
-
-buildfunc('libusb_get_device_descriptor',\
- [libusb_device_p, libusb_device_descriptor_p])
-
-# synchronous functions:
-buildfunc('libusb_bulk_transfer', [libusb_device_handle_p, c_uint8, \
- c_void_p, c_int, c_int_p, c_uint])
-
-# pythonic API:
-
-class UsbError(Exception):
- def __init__(self, msg, errorcode):
- if errorcode in libusb_error.reverse_mapping:
- errorcode = libusb_error.reverse_mapping[errorcode]
- msg = msg + 'Error code: {0}'.format(errorcode)
- super().__init__(msg)
-
-class UsbContext(object):
- """ A usb context in case of multiple use """
- def __init__(self):
- self.context_p = libusb_context_p()
- r = libusb_init(byref(self.context_p))
- if r != 0:
- raise UsbError('libusb_init error!', r)
- def getDeviceList(self):
- devlist = libusb_device_p_p()
- count = libusb_get_device_list(self.context_p, byref(devlist))
- if count < 0:
- raise UsbError('Error getting device list', count)
- l = [UsbDevice(self, device_p.contents) for device_p in devlist[0:count]]
- libusb_free_device_list(devlist, 0)
- return l
- DeviceList = property(getDeviceList)
-
-class UsbDevice:
- """ A detected usb device """
- def __init__(self, context, device_p):
- self.context = context
- self.dev_p = device_p
- def __del__(self):
- libusb_unref_device(self.dev_p)
- def getBusNumber(self):
- return libusb_get_bus_number(self.dev_p)
- BusNumber = property(getBusNumber)
- def getDeviceAddress(self):
- return libusb_get_device_address(self.dev_p)
- DeviceAddress = property(getDeviceAddress)
- def getSpeed(self):
- s = libusb_get_device_speed(self.dev_p)
- if s in libusb_speed.reverse_mapping:
- s = libusb_speed.reverse_mapping[s]
- return s
- Speed = property(getSpeed)
- def getDescriptor(self):
- descriptor = libusb_device_descriptor()
- r = libusb_get_device_descriptor(self.dev_p, byref(descriptor))
- if r != 0:
- raise UsbError('Error getting descriptor', r)
- return descriptor
- Descriptor = property(getDescriptor)
- VendorId = property(lambda self: self.Descriptor.idVendor)
- ProductId = property(lambda self: self.Descriptor.idProduct)
- NumConfigurations = property(lambda self: self.Descriptor.bNumConfigurations)
- def open(self):
- """ Opens this device and returns a handle """
- handle_p = libusb_device_handle_p()
- r = libusb_open(self.dev_p, byref(handle_p))
- if r != 0:
- raise UsbError('error opening device', r)
- return UsbDeviceHandle(self, handle_p)
- def __repr__(self):
- r2 = 'Usb device: bus {0} address {1} {2:04X}:{3:04X} speed {4}' \
- .format( \
- self.BusNumber, self.DeviceAddress, self.VendorId, \
- self.ProductId, self.Speed)
- return r2
-
-USB_ENDPOINT_DIR_MASK = 0x80
-USB_ENDPOINT_IN = 0x80
-USB_ENDPOINT_OUT = 0x0
-
-class UsbDeviceHandle:
- """ Handle to a detected usb device """
- def __init__(self, device, handle_p):
- self.device = device
- self.handle_p = handle_p
- def __del__(self):
- self.close()
- def close(self):
- if self.handle_p:
- libusb_close(self.handle_p)
- self.handle_p = None
- def getConfiguration(self):
- config = c_int()
- r = libusb_get_configuration(self.handle_p, byref(config))
- if r != 0: raise UsbError('Error getting configuration', r)
- return config.value
- def setConfiguration(self, config):
- r = libusb_set_configuration(self.handle_p, config)
- if r != 0: raise UsbError('Error setting configuration', r)
- Configuration = property(getConfiguration, setConfiguration)
- def claimInterface(self, interface_number):
- r = libusb_claim_interface(self.handle_p, interface_number)
- if r != 0: raise UsbError('Error claiming interface', r)
- def bulkWrite(self, endpoint, data, timeout=0):
- """ Synchronous bulk write """
- assert type(data) is bytes
- # assure the endpoint indicates the correct:
- endpoint = (endpoint & (~USB_ENDPOINT_DIR_MASK)) | USB_ENDPOINT_OUT
- buf = create_string_buffer(data)
- transferred = c_int()
- r = libusb_bulk_transfer(self.handle_p, endpoint, buf, len(data), \
- byref(transferred), timeout)
- if r != 0:
- raise UsbError('Bulk write failed', r)
- if transferred.value != len(data):
- raise UsbError('Not all {0} transferred {1}'.format(len(data), \
- transferred.value))
- def bulkRead(self, endpoint, numbytes, timeout=0):
- """ Synchronous bulk read """
- # assure the endpoint indicates the correct:
- endpoint = (endpoint & (~USB_ENDPOINT_DIR_MASK)) | USB_ENDPOINT_IN
- buf = create_string_buffer(numbytes)
- transferred = c_int()
- r = libusb_bulk_transfer(self.handle_p, endpoint, buf, numbytes, \
- byref(transferred), timeout)
- if r != 0:
- raise UsbError('Bulk read failed', r)
- if transferred.value != numbytes:
- raise UsbError('Not all {0} transferred {1}'.format(numbytes, \
- transferred.value))
- data = buf.raw[0:numbytes]
- return data
-
-class UsbTransfer:
- def __init__(self):
- libusb_alloc_transfer(0)
diff -r 742588fb8cd6 -r f381cea07fec python/yacc.py
--- a/python/yacc.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,307 +0,0 @@
-#!/usr/bin/python
-
-"""
-Parser generator utility. This script can generate a python script from a
-grammar description.
-
-Invoke the script on a grammar specification file:
-
-.. code::
-
- $ ./yacc.py test.x -o test_parser.py
-
-And use the generated parser by deriving a user class:
-
-
-.. code::
-
- import test_parser
- class MyParser(test_parser.Parser):
- pass
- p = MyParser()
- p.parse()
-
-
-Alternatively you can load the parser on the fly:
-
-.. code::
-
- import yacc
- parser_mod = yacc.load_as_module('mygrammar.x')
- class MyParser(parser_mod.Parser):
- pass
- p = MyParser()
- p.parse()
-
-"""
-
-import argparse
-import re
-import sys
-import datetime
-import types
-import io
-import logging
-from pyyacc import Grammar
-
-
-class XaccLexer:
- def __init__(self):
- pass
-
- def feed(self, txt):
- # Create a regular expression for the lexing part:
- tok_spec = [
- ('ID', r'[A-Za-z][A-Za-z\d_]*'),
- ('STRING', r"'[^']*'"),
- ('BRACEDCODE', r"\{[^\}]*\}"),
- ('OTHER', r'[:;\|]'),
- ('SKIP', r'[ ]')
- ]
- tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec)
- gettok = re.compile(tok_re).match
-
- lines = txt.split('\n')
-
- def tokenize_line(line):
- """ Generator that splits up a line into tokens """
- mo = gettok(line)
- pos = 0
- while mo:
- typ = mo.lastgroup
- val = mo.group(typ)
- if typ == 'ID':
- yield (typ, val)
- elif typ == 'STRING':
- typ = 'ID'
- yield (typ, val[1:-1])
- elif typ == 'OTHER':
- typ = val
- yield (typ, val)
- elif typ == 'BRACEDCODE':
- yield (typ, val)
- elif typ == 'SKIP':
- pass
- else:
- raise NotImplementedError(str(typ))
- pos = mo.end()
- mo = gettok(line, pos)
- if len(line) != pos:
- raise ParseError('Lex fault at {}'.format(line))
-
- def tokenize():
- section = 0
- for line in lines:
- line = line.strip()
- if not line:
- continue # Skip empty lines
- if line == '%%':
- section += 1
- yield('%%', '%%')
- continue
- if section == 0:
- if line.startswith('%tokens'):
- yield('%tokens', '%tokens')
- yield from tokenize_line(line[7:])
- else:
- yield ('HEADER', line)
- elif section == 1:
- yield from tokenize_line(line)
- yield ('eof', 'eof')
- self.tokens = tokenize()
- self.token = self.tokens.__next__()
-
- def next_token(self):
- t = self.token
- if t[0] != 'eof':
- self.token = self.tokens.__next__()
- return t
-
-
-class ParseError(Exception):
- pass
-
-
-class XaccParser:
- """ Implements a recursive descent parser to parse grammar rules.
- We could have made an generated parser, but that would yield a chicken
- egg issue.
- """
- def __init__(self, lexer):
- self.lexer = lexer
-
- @property
- def Peak(self):
- """ Sneak peak to the next token in line """
- return self.lexer.token[0]
-
- def next_token(self):
- """ Take the next token """
- return self.lexer.next_token()
-
- def consume(self, typ):
- """ Eat next token of type typ or raise an exception """
- if self.Peak == typ:
- return self.next_token()
- else:
- raise ParseError('Expected {}, but got {}'.format(typ, self.Peak))
-
- def has_consumed(self, typ):
- """ Consume typ if possible and return true if so """
- if self.Peak == typ:
- self.consume(typ)
- return True
- return False
-
- def parse_grammar(self):
- """ Entry parse function into recursive descent parser """
- # parse header
- headers = []
- terminals = []
- while self.Peak in ['HEADER', '%tokens']:
- if self.Peak == '%tokens':
- self.consume('%tokens')
- while self.Peak == 'ID':
- terminals.append(self.consume('ID')[1])
- else:
- headers.append(self.consume('HEADER')[1])
- self.consume('%%')
- self.headers = headers
- self.grammar = Grammar(terminals)
- while self.Peak != 'eof':
- self.parse_rule()
- return self.grammar
-
- def parse_symbol(self):
- return self.consume('ID')[1]
-
- def parse_rhs(self):
- """ Parse the right hand side of a rule definition """
- symbols = []
- while self.Peak not in [';', 'BRACEDCODE', '|']:
- symbols.append(self.parse_symbol())
- if self.Peak == 'BRACEDCODE':
- action = self.consume('BRACEDCODE')[1]
- action = action[1:-1].strip()
- else:
- action = None
- return symbols, action
-
- def parse_rule(self):
- """ Parse a rule definition """
- p = self.parse_symbol()
- self.consume(':')
- symbols, action = self.parse_rhs()
- self.grammar.add_production(p, symbols, action)
- while self.has_consumed('|'):
- symbols, action = self.parse_rhs()
- self.grammar.add_production(p, symbols, action)
- self.consume(';')
-
-
-class XaccGenerator:
- """ Generator that writes generated parser to file """
- def __init__(self):
- self.logger = logging.getLogger('yacc')
-
- def generate(self, grammar, headers, output_file):
- self.output_file = output_file
- self.grammar = grammar
- self.headers = headers
- self.logger.info('Generating parser for grammar {}'.format(grammar))
- self.action_table, self.goto_table = grammar.generate_tables()
- self.generate_python_script()
-
- def print(self, *args):
- """ Print helper function that prints to output file """
- print(*args, file=self.output_file)
-
- def generate_python_script(self):
- """ Generate python script with the parser table """
- self.print('#!/usr/bin/python')
- stamp = datetime.datetime.now().ctime()
- self.print('""" Automatically generated by xacc on {} """'.format(stamp))
- self.print('from pyyacc import LRParser, Reduce, Shift, Accept, Production, Grammar')
- self.print('from ppci import Token')
- self.print('')
- for h in self.headers:
- print(h, file=output_file)
- self.print('')
- self.print('class Parser(LRParser):')
- self.print(' def __init__(self):')
- # Generate rules:
- self.print(' self.start_symbol = "{}"'.format(self.grammar.start_symbol))
- self.print(' self.grammar = Grammar({})'.format(self.grammar.terminals))
- for rule_number, rule in enumerate(self.grammar.productions):
- rule.f_name = 'action_{}_{}'.format(rule.name, rule_number)
- self.print(' self.grammar.add_production("{}", {}, self.{})'.format(rule.name, rule.symbols, rule.f_name))
- # Fill action table:
- self.print(' self.action_table = {}')
- for state in self.action_table:
- action = self.action_table[state]
- self.print(' self.action_table[{}] = {}'.format(state, action))
- self.print('')
-
- # Fill goto table:
- self.print(' self.goto_table = {}')
- for state_number in self.goto_table:
- to = self.goto_table[state_number]
- self.print(' self.goto_table[{}] = {}'.format(state_number, to))
- self.print('')
-
- # Generate a function for each action:
- for rule in self.grammar.productions:
- num_symbols = len(rule.symbols)
- args = ', '.join('arg{}'.format(n + 1) for n in range(num_symbols))
- self.print(' def {}(self, {}):'.format(rule.f_name, args))
- if rule.f == None:
- semantics = 'pass'
- else:
- semantics = str(rule.f)
- if semantics.strip() == '':
- semantics = 'pass'
- for n in range(num_symbols):
- semantics = semantics.replace('${}'.format(n + 1), 'arg{}'.format(n + 1))
- self.print(' {}'.format(semantics))
- self.print('')
-
-
-def make_argument_parser():
- # Parse arguments:
- parser = argparse.ArgumentParser(description='xacc compiler compiler')
- parser.add_argument('source', type=argparse.FileType('r'), \
- help='the parser specification')
- parser.add_argument('-o', '--output', type=argparse.FileType('w'), \
- default=sys.stdout)
- return parser
-
-
-def load_as_module(filename):
- """ Load a parser spec file, generate LR tables and create module """
- ob = io.StringIO()
- args = argparse.Namespace(source=open(filename), output=ob)
- main(args)
-
- parser_mod = types.ModuleType('generated_parser')
- exec(ob.getvalue(), parser_mod.__dict__)
- return parser_mod
-
-
-def main(args):
- src = args.source.read()
- args.source.close()
-
- # Construction of generator parts:
- lexer = XaccLexer()
- parser = XaccParser(lexer)
- generator = XaccGenerator()
-
- # Sequence source through the generator parts:
- lexer.feed(src)
- grammar = parser.parse_grammar()
- generator.generate(grammar, parser.headers, args.output)
-
-
-if __name__ == '__main__':
- args = make_argument_parser().parse_args()
- main(args)
diff -r 742588fb8cd6 -r f381cea07fec python/zcc.py
--- a/python/zcc.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import os
-import argparse
-import logging
-
-from ppci.buildtasks import Compile, Assemble, Link
-from ppci.tasks import TaskRunner
-from ppci.report import RstFormatter
-from ppci.objectfile import ObjectFile
-from ppci.target.target_list import target_list
-from ppci.recipe import RecipeLoader
-import ppci
-
-
-def logLevel(s):
- """ Converts a string to a valid logging level """
- numeric_level = getattr(logging, s.upper(), None)
- if not isinstance(numeric_level, int):
- raise ValueError('Invalid log level: {}'.format(s))
- return numeric_level
-
-
-targets = {t.name: t for t in target_list}
-targetnames = list(targets.keys())
-
-def make_parser():
- parser = argparse.ArgumentParser(description='lcfos Compiler')
-
- parser.add_argument('--log', help='Log level (INFO,DEBUG,[WARN])',
- type=logLevel, default='INFO')
- parser.add_argument('--display-build-steps', action='store_true')
- sub_parsers = parser.add_subparsers(title='commands',
- description='possible commands', dest='command')
- recipe_parser = sub_parsers.add_parser('recipe', help="Bake recipe")
- recipe_parser.add_argument('recipe_file', help='recipe file')
-
- compile_parser = sub_parsers.add_parser('compile', help="compile source")
- compile_parser.add_argument('source', type=argparse.FileType('r'),
- help='the source file to build', nargs="+")
- compile_parser.add_argument('-i', '--imp', type=argparse.FileType('r'),
- help='Possible import module', action='append', default=[])
- compile_parser.add_argument('--target', help="Backend selection",
- choices=targetnames, required=True)
- compile_parser.add_argument('-o', '--output', help='Output file',
- metavar='filename')
- compile_parser.add_argument('--report',
- help='Specify a file to write the compile report to',
- type=argparse.FileType('w'))
- return parser
-
-
-
-def main(args):
- # Configure some logging:
- logging.getLogger().setLevel(logging.DEBUG)
- ch = logging.StreamHandler()
- ch.setFormatter(logging.Formatter(ppci.logformat))
- ch.setLevel(args.log)
- logging.getLogger().addHandler(ch)
-
- runner = TaskRunner()
- if args.command == 'compile':
- tg = targets[args.target]
- output = ObjectFile()
- runner.add_task(Compile(args.source, args.imp, tg, output))
- elif args.command == 'recipe':
- recipe_loader = RecipeLoader()
- recipe_loader.load_file(args.recipe_file, runner)
- else:
- raise NotImplementedError('Invalid option')
-
- if args.display_build_steps:
- runner.display()
- res = 0
- else:
- res = runner.run_tasks()
-
- logging.getLogger().removeHandler(ch)
- return res
-
-
-if __name__ == '__main__':
- parser = make_parser()
- arguments = parser.parse_args()
- if not arguments.command:
- parser.print_usage()
- sys.exit(1)
- sys.exit(main(arguments))
diff -r 742588fb8cd6 -r f381cea07fec readme.rst
--- a/readme.rst Fri Mar 07 17:10:21 2014 +0100
+++ b/readme.rst Thu Feb 19 14:10:52 2015 +0100
@@ -15,54 +15,61 @@
'kernel' contains the microkernel.
'python' contains the python utilities.
-Software dependencies
----------------------
+
+How to run this?
+----------------
+
+Install required software:
* python3.3
-* pyyaml for yaml module
* (optional) pyqt5, pyqt4 or pyside
-How to start the IDE
---------------------
+Checkout the code:
.. code:: bash
- cd python
- python ide.py
+ hg clone https://bitbucket.org/windel/lcfos
+ cd lcfos
+
+Run some unit tests:
+
+.. code:: bash
+
+ cd test
+ python3 run_tests.py
-Source code
------------
+Weblinks
+--------
+
+Docs are located here:
+http://lcfos.readthedocs.org/en/latest/
Sources are located here:
https://bitbucket.org/windel/lcfos
-
-Docs
-----
-
-Docs are located here:
-http://lcfos.readthedocs.org/en/latest/
+here:
+http://hg.assembla.com/lcfOS/
-Run unittests
--------------
-
-.. code:: bash
+and here:
+https://pikacode.com/windel/lcfos/
- cd test
- ./runtests.sh
-
-
-Status
-------
The project is contains tests which are run continuously at drone.io.
.. image:: https://drone.io/bitbucket.org/windel/lcfos/status.png
+https://drone.io/bitbucket.org/windel/lcfos
+
+Repository metrics:
+
.. image:: https://www.ohloh.net/p/lcfos/widgets/project_thin_badge.gif
+http://www.ohloh.net/p/lcfos
+
-https://drone.io/bitbucket.org/windel/lcfos
+Live demo is at redhat openshift:
+
+http://lcfos-windel.rhcloud.com/
diff -r 742588fb8cd6 -r f381cea07fec run.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/run.sh Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+set -e
+
+# -S means halt at start:
+qemu-system-arm -M vexpress-a9 -m 128M -kernel kernel_arm.bin \
+ -serial stdio
+
diff -r 742588fb8cd6 -r f381cea07fec test/grind.py
--- a/test/grind.py Fri Mar 07 17:10:21 2014 +0100
+++ b/test/grind.py Thu Feb 19 14:10:52 2015 +0100
@@ -17,5 +17,6 @@
p = cProfile.Profile()
s = p.run('runtests()')
stats = pstats.Stats(p)
- stats.sort_stats('tottime')
+ #stats.sort_stats('tottime')
+ stats.sort_stats('cumtime')
stats.print_stats(.1)
diff -r 742588fb8cd6 -r f381cea07fec test/m3_bare/m3bare.mmap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/m3_bare/m3bare.mmap Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,10 @@
+
+MEMORY flash LOCATION=0x0 SIZE=0x10000 {
+ SECTION(code)
+}
+
+MEMORY ram LOCATION=0x20000000 SIZE=0x10000 {
+ SECTION(data)
+}
+
+
diff -r 742588fb8cd6 -r f381cea07fec test/m3_bare/recipe.yaml
--- a/test/m3_bare/recipe.yaml Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-
-link:
- inputs:
- - assemble:
- source: startup_m3.asm
- machine: thumb
- - compile:
- sources: [hello.c3]
- includes: []
- machine: thumb
- layout:
- code: 0x0
- data: 0x20000000
- output: bare.bin
-
diff -r 742588fb8cd6 -r f381cea07fec test/m3_bare/startup_m3.asm
--- a/test/m3_bare/startup_m3.asm Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-
-
-DCD 0x20000678 ; Setup stack pointer
-DCD 0x00000009 ; Reset vector, jump to address 8
-B hello_main ; Branch to main (this is actually in the interrupt vector)
-
diff -r 742588fb8cd6 -r f381cea07fec test/run_tests.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/run_tests.py Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,17 @@
+import sys
+import unittest
+
+if sys.version_info.major < 3:
+ print('Requires python 3 at least')
+ sys.exit()
+
+sys.path.insert(0, '../python')
+
+loader = unittest.TestLoader()
+suite = unittest.TestSuite()
+
+for test in loader.discover('.'):
+ suite.addTest(test)
+
+unittest.TextTestRunner().run(suite)
+
diff -r 742588fb8cd6 -r f381cea07fec test/runtests.sh
--- a/test/runtests.sh Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-#!/usr/bin/env bash
-
-export PYTHONPATH=$PYTHONPATH:`pwd`/../python:`pwd`/../python/ide
-
-if [ "$1" == "loop" ]
-then
- DIR=..
- while :; do
- python -m unittest
- #python -m unittest -v
- echo "Awaiting changes in $DIR"
- inotifywait -r -e modify $DIR
- done
-else
- set -e
- python -m unittest
-fi
-
-
diff -r 742588fb8cd6 -r f381cea07fec test/sample4.brg
--- a/test/sample4.brg Fri Mar 07 17:10:21 2014 +0100
+++ b/test/sample4.brg Thu Feb 19 14:10:52 2015 +0100
@@ -6,17 +6,17 @@
%%
-stmt: ASGNI(disp, reg) 1 (. self.tr(1) .)
-stmt: reg 0 (. self.tr(2).)
-reg: ADDI(reg, rc) 1 (. self.tr(3) .)
-reg: CVCI(INDIRC(disp)) 1 (. self.tr(4) .)
-reg: IOI 0 (. self.tr(5).)
-reg: disp 1 (. self.tr(6).)
-disp: ADDI(reg, con) 1 (. self.tr(7).)
-disp: ADDRLP 0 (. self.tr(8).)
-rc: con 0 (. self.tr(9).)
-rc: reg 0 (. self.tr(10).)
-con: CNSTI 0 (. self.tr(11).)
-con: IOI 0 (. self.tr(12).)
+stmt: ASGNI(disp, reg) 1 'self.tr(1) '
+stmt: reg 0 ' self.tr(2)'
+reg: ADDI(reg, rc) 1 'self.tr(3) '
+reg: CVCI(INDIRC(disp)) 1 'self.tr(4) '
+reg: IOI 0 'self.tr(5)'
+reg: disp 1 'self.tr(6)'
+disp: ADDI(reg, con) 1 'self.tr(7)'
+disp: ADDRLP 0 ' self.tr(8)'
+rc: con 0 ' self.tr(9)'
+rc: reg 0 'self.tr(10)'
+con: CNSTI 0 ' self.tr(11)'
+con: IOI 0 ' self.tr(12)'
diff -r 742588fb8cd6 -r f381cea07fec test/setenv.sh
--- a/test/setenv.sh Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-#!/usr/bin/env bash
-
-export PYTHONPATH=$PYTHONPATH:`pwd`/../python
-
-export TESTEMU=1
-
diff -r 742588fb8cd6 -r f381cea07fec test/test_burm.py
--- a/test/test_burm.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-import unittest
-import io
-import argparse
-
-from tree import Tree
-import pyburg
-
-
-class testBURG(unittest.TestCase):
- def testSample4(self):
- """ Test sample4 burg system """
- # Generate matcher from spec:
- buf = io.StringIO()
- args = argparse.Namespace(source=open('sample4.brg'), output=buf)
- pyburg.main(args)
-
- # Execute generated script into global scope:
- exec(buf.getvalue(), globals())
-
- # Sample tree:
- t = Tree('ASGNI',
- Tree('ADDRLP'),
- Tree('ADDI',
- Tree('CVCI', Tree('INDIRC', Tree('ADDRLP'))),
- Tree('CNSTI')
- )
- )
-
- # Subclass generated matcher:
- class MyMatcher(Matcher):
- def __init__(self):
- super().__init__()
- self.trace = []
-
- def tr(self, r):
- self.trace.append(r)
-
- # Match tree:
- mm = MyMatcher()
- mm.gen(t)
- self.assertSequenceEqual([8,8,4,11,9,3,1], mm.trace)
-
-if __name__ == '__main__':
- unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testarmasm.py
--- a/test/testarmasm.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-import unittest
-from ppci.outstream import BinaryOutputStream
-from ppci.objectfile import ObjectFile
-from asm import Assembler
-from testasm import AsmTestCaseBase
-from ppci.target.target_list import arm_target
-
-
-a = Assembler(arm_target)
-
-class ArmAssemblerTestCase(AsmTestCaseBase):
- """ ARM-mode (not thumb-mode) instruction assembly test case """
- def setUp(self):
- self.t = arm_target
- self.obj = ObjectFile()
- self.ostream = BinaryOutputStream(self.obj)
- self.ostream.selectSection('.text')
- self.a = a #Assembler(target=self.t)
-
- def testMovImm(self):
- self.feed('mov r4, 100')
- self.check('6440a0e3')
-
- def testMovImm2(self):
- self.feed('mov sp, 0x6000')
- self.check('06daa0e3')
-
- def testAdd2(self):
- self.feed('add r12, r11, 300')
- self.check('4bcf8be2')
-
- def testAdd1(self):
- self.feed('add r9, r7, r2')
- self.check('029087e0')
-
- def testSub1(self):
- self.feed('sub r5, r6, r2')
- self.check('025046e0')
-
- def testSub2(self):
- self.feed('sub r0, r1, 0x80000001')
- self.check('060141e2')
-
- def testOrr1(self):
- self.feed('orr r8, r7, r6')
- self.check('068087e1')
-
- def testBranches(self):
- self.feed('b sjakie')
- self.feed('ble sjakie')
- self.feed('bgt sjakie')
- self.feed('beq sjakie')
- self.feed('bl sjakie')
- self.feed('sjakie:')
- self.feed('b sjakie')
- self.feed('ble sjakie')
- self.feed('bgt sjakie')
- self.feed('beq sjakie')
- self.feed('bl sjakie')
- self.check('030000ea 020000da 010000ca 0000000a ffffffeb feffffea fdffffda fcffffca fbffff0a faffffeb')
-
- def testPush(self):
- self.feed('push {r11,r5,r4,lr}')
- self.check('30482de9')
-
- def testPop(self):
- self.feed('pop {r4,r5,r6}')
- self.check('7000bde8')
-
- def testStr(self):
- self.feed('str r9, [r2, 33]')
- self.check('219082e5')
-
- def testLdr(self):
- self.feed('ldr r5, [r3, 87]')
- self.check('575093e5')
-
- def testSequence1(self):
- self.feed('sub r4,r5,23')
- self.feed('blt x')
- self.feed('x:')
- self.feed('mul r4,r5,r2')
- self.check('174045e2 ffffffba 950204e0')
-
-
-if __name__ == '__main__':
- unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testasm.py
--- a/test/testasm.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-#!/usr/bin/python
-
-import unittest
-from ppci import CompilerError
-from ppci.assembler import tokenize, Assembler, Lexer
-from ppci.objectfile import ObjectFile
-from ppci.linker import Linker
-from ppci.outstream import BinaryOutputStream
-from ppci.target.basetarget import Label
-
-
-class AssemblerLexingCase(unittest.TestCase):
- """ Tests the assemblers lexer """
-
- def testLex0(self):
- """ Check if the lexer is OK """
- asmline, toks = 'mov rax, rbx ', ['ID', 'ID', ',', 'ID', 'EOF']
- self.assertSequenceEqual([tok.typ for tok in tokenize(asmline, [])], toks)
-
- def testLex1(self):
- """ Test if lexer correctly maps some tokens """
- asmline, toks = 'lab1: mov rax, rbx ', ['ID', ':', 'ID', 'ID', ',', 'ID', 'EOF']
- self.assertSequenceEqual([tok.typ for tok in tokenize(asmline, [])], toks)
-
- def testLex2(self):
- """ Test if lexer correctly maps some tokens """
- asmline, toks = 'mov 3.13 0xC 13', ['ID', 'REAL', 'val5', 'val5', 'EOF']
- self.assertSequenceEqual([tok.typ for tok in tokenize(asmline, [])], toks)
-
- def testLex3(self):
- """ Test if lexer fails on a token that is invalid """
- asmline = '0z4: mov rax, rbx $ '
- with self.assertRaises(CompilerError):
- list(tokenize(asmline, []))
-
-
-class AssemblerParsingTestCase(unittest.TestCase):
- """
- Tests the assembler parts
- """
- def setUp(self):
- self.skipTest('refactoring asm parser')
- self.parser = asmParser
- self.stack = []
-
- def emit(self, x):
- self.stack.append(x)
-
- def parse_line(self, line):
- self.parser.parse(Lexer(line), self.emit)
-
- def testParse(self):
- asmline = 'lab1: mov rax, rbx'
- self.parse_line(asmline)
-
- def expectTree(self, asmline, stack):
- self.parse_line(asmline)
- self.assertSequenceEqual(stack, self.stack)
-
- def testParse2(self):
- asmline = 'a: mov rax, [rbx + 2]'
- output = []
- output.append(ALabel('a'))
- output.append(AInstruction('mov', [ASymbol('rax'), AUnop('[]', ASymbol('rbx') + ANumber(2))]))
- self.expectTree(asmline, output)
-
- def testParse3(self):
- # A label must be optional:
- asmline = 'mov rax, 1'
- output = [AInstruction('mov', [ASymbol('rax'), ANumber(1)])]
- self.expectTree(asmline, output)
-
- def testParse4(self):
- # Test 3 operands:
- asmline = 'add rax, [4*rbx + 22], rcx'
- ops = []
- ops.append(ASymbol('rax'))
- ops.append(AUnop('[]', ANumber(4) * ASymbol('rbx') + ANumber(22)))
- ops.append(ASymbol('rcx'))
- output = [AInstruction('add', ops)]
- self.expectTree(asmline, output)
-
- def testParse5(self):
- # An instruction must be optional:
- asmline = 'lab1:'
- output = []
- output.append(ALabel('lab1'))
- self.expectTree(asmline, output)
-
- def testParse6(self):
- # A line can be empty
- self.parse_line('')
-
-
-class OustreamTestCase(unittest.TestCase):
- def test1(self):
- obj = ObjectFile()
- o = BinaryOutputStream(obj)
- o.selectSection('.text')
- o.emit(Label('a'))
- self.assertSequenceEqual(bytes(), obj.get_section('.text').data)
-
-
-class AsmTestCaseBase(unittest.TestCase):
- """ Base testcase for assembly """
- def feed(self, line):
- self.a.assemble(line, self.ostream)
-
- def check(self, hexstr):
- l = Linker()
- self.obj = l.link([self.obj])
- data = bytes(self.obj.get_section('.text').data)
- self.assertSequenceEqual(bytes.fromhex(hexstr), data)
-
-
-if __name__ == '__main__':
- unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testbintools.py
--- a/test/testbintools.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-import unittest
-import sys
-from ppci.target.arm.token import ArmToken
-from ppci.linker import Linker
-from ppci.objectfile import ObjectFile
-from ppci import CompilerError
-from ppci.tasks import EmptyTask, TaskRunner, TaskError
-
-
-class TaskTestCase(unittest.TestCase):
- def testCircular(self):
- t1 = EmptyTask('t1')
- t2 = EmptyTask('t2')
- t1.add_dependency(t2)
- with self.assertRaises(TaskError):
- t2.add_dependency(t1)
-
- def testCircularDeeper(self):
- t1 = EmptyTask('t1')
- t2 = EmptyTask('t2')
- t3 = EmptyTask('t3')
- t1.add_dependency(t2)
- t2.add_dependency(t3)
- with self.assertRaises(TaskError):
- t3.add_dependency(t1)
-
- def testSort(self):
- t1 = EmptyTask('t1')
- t2 = EmptyTask('t2')
- runner = TaskRunner()
- t1.add_dependency(t2)
- runner.add_task(t1)
- runner.add_task(t2)
- runner.run_tasks()
-
-
-class TokenTestCase(unittest.TestCase):
- def testSetBits(self):
- at = ArmToken()
- at[2:4] = 0b11
- self.assertEqual(0xc, at.bit_value)
-
- def testSetBits(self):
- at = ArmToken()
- at[4:8] = 0b1100
- self.assertEqual(0xc0, at.bit_value)
-
-
-class LinkerTestCase(unittest.TestCase):
- def testUndefinedReference(self):
- l = Linker()
- o1 = ObjectFile()
- o1.get_section('.text')
- o1.add_relocation('undefined_sym', 0, 'rel8', '.text')
- o2 = ObjectFile()
- with self.assertRaises(CompilerError):
- o3 = l.link([o1, o2])
-
- def testDuplicateSymbol(self):
- l = Linker()
- o1 = ObjectFile()
- o1.get_section('.text')
- o1.add_symbol('a', 0, '.text')
- o2 = ObjectFile()
- o2.get_section('.text')
- o2.add_symbol('a', 0, '.text')
- with self.assertRaises(CompilerError):
- o3 = l.link([o1, o2])
-
- def testRel8Relocation(self):
- l = Linker()
- o1 = ObjectFile()
- o1.get_section('.text').add_data(bytes([0]*100))
- o1.add_relocation('a', 0, 'rel8', '.text')
- o2 = ObjectFile()
- o2.get_section('.text').add_data(bytes([0]*100))
- o2.add_symbol('a', 24, '.text')
- o3 = l.link([o1, o2])
-
- def testSymbolValues(self):
- l = Linker()
- o1 = ObjectFile()
- o1.get_section('.text').add_data(bytes([0]*108))
- o1.add_symbol('b', 24, '.text')
- o2 = ObjectFile()
- o2.get_section('.text').add_data(bytes([0]*100))
- o2.add_symbol('a', 2, '.text')
- o3 = l.link([o1, o2])
- self.assertEqual(110, o3.find_symbol('a').value)
- self.assertEqual(24, o3.find_symbol('b').value)
- self.assertEqual(208, o3.get_section('.text').Size)
-
- def testMemoryLayout(self):
- l = Linker()
- memory_layout = {'.text': 0x08000000, '.data':0x20000000}
- o1 = ObjectFile()
- o1.get_section('.text').add_data(bytes([0]*108))
- o1.add_symbol('b', 24, '.text')
- o2 = ObjectFile()
- o2.get_section('.text').add_data(bytes([0]*100))
- o2.get_section('.data').add_data(bytes([0]*100))
- o2.add_symbol('a', 2, '.data')
- o2.add_symbol('c', 2, '.text')
- o3 = l.link([o1, o2], layout=memory_layout)
- self.assertEqual(0x20000000+2, o3.find_symbol('a').value)
- self.assertEqual(0x08000000+24, o3.find_symbol('b').value)
- self.assertEqual(0x08000000+110, o3.find_symbol('c').value)
- self.assertEqual(208, o3.get_section('.text').Size)
- self.assertEqual(100, o3.get_section('.data').Size)
-
-
-if __name__ == '__main__':
- unittest.main()
- sys.exit()
diff -r 742588fb8cd6 -r f381cea07fec test/testbitfun.py
--- a/test/testbitfun.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-
-
-import unittest
-import sys
-from ppci.bitfun import rotate_left, rotate_right
-
-
-class BitRotationTestCase(unittest.TestCase):
- def testRightRotation(self):
- self.assertEqual(0xFF000000, rotate_right(0xFF, 8))
- self.assertEqual(0x0FF00000, rotate_right(0xFF, 12))
-
- def testLeftRotation(self):
- self.assertEqual(0x0000FF00, rotate_left(0xFF, 8))
- self.assertEqual(0x001FE000, rotate_left(0xFF, 13))
-
-
-if __name__ == '__main__':
- unittest.main()
- sys.exit()
diff -r 742588fb8cd6 -r f381cea07fec test/testc3.py
--- a/test/testc3.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,476 +0,0 @@
-import unittest
-import io
-from ppci.c3 import Builder, Lexer
-from ppci.target import SimpleTarget
-import ppci
-
-
-class testLexer(unittest.TestCase):
- def setUp(self):
- diag = ppci.DiagnosticsManager()
- self.l = Lexer(diag)
-
- def testUnexpectedCharacter(self):
- snippet = io.StringIO(""" var s \u6c34 """)
- with self.assertRaises(ppci.CompilerError):
- list(self.l.tokenize(snippet))
-
- def check(self, snippet, toks):
- toks2 = list(tok.typ for tok in self.l.tokenize(io.StringIO(snippet)))
- self.assertSequenceEqual(toks, toks2)
-
- def testBlockComment(self):
- snippet = """
- /* Demo */
- var int x = 0;
- """
- toks = ['var', 'ID', 'ID', '=', 'NUMBER', ';', 'END']
- self.check(snippet, toks)
-
- def testBlockCommentMultiLine(self):
- snippet = """
- /* Demo
- bla1
- bla2
- */
- var int x = 0;
- """
- toks = ['var', 'ID', 'ID', '=', 'NUMBER', ';', 'END']
- self.check(snippet, toks)
-
-
-class testBuilder(unittest.TestCase):
- def setUp(self):
- self.diag = ppci.DiagnosticsManager()
- self.builder = Builder(self.diag, SimpleTarget())
- self.diag.clear()
-
- def makeFileList(self, snippet):
- """ Try to make a list with opened files """
- if type(snippet) is list:
- l2 = []
- for s in snippet:
- if type(s) is str:
- l2.append(io.StringIO(s))
- else:
- l2.append(s)
- return l2
- else:
- return [io.StringIO(snippet)]
-
- def expectErrors(self, snippet, rows):
- """ Helper to test for expected errors on rows """
- ircode = list(self.builder.build([io.StringIO(snippet)]))
- actualErrors = [err.row for err in self.diag.diags]
- if rows != actualErrors:
- self.diag.printErrors()
- self.assertSequenceEqual(rows, actualErrors)
- # self.assertFalse(all(ircode))
-
- def expectOK(self, snippet):
- """ Expect a snippet to be OK """
- ircode = list(self.builder.build(self.makeFileList(snippet)))
- if len(self.diag.diags) > 0:
- self.diag.printErrors()
- self.assertTrue(all(ircode))
- self.assertEqual(0, len(self.diag.diags))
- return ircode
-
- def testPackage(self):
- p1 = """module p1;
- type int A;
- """
- p2 = """module p2;
- import p1;
- var p1.A b;
- """
- self.expectOK([p1, p2])
-
- def testPackageMutual(self):
- p1 = """module p1;
- import p2;
- type int A;
- var p2.B b;
- """
- p2 = """module p2;
- import p1;
- var p1.A a;
- """
- self.expectOK([p1, p2])
-
- def testConstant(self):
- snip = """module C;
- const int a = 2;
- """
- i = self.expectOK(snip)
-
- @unittest.skip('Not checked yet')
- def testConstantMutual(self):
- snip = """module C;
- const int a = b + 1;
- const int b = a + 1;
- function void f()
- {
- return b;
- }
- """
- i = self.expectOK(snip)
-
- def testPackageNotExists(self):
- p1 = """module p1;
- import p23;
- """
- self.expectErrors(p1, [0])
-
- def testFunctArgs(self):
- snippet = """
- module testargs;
- function void t2(int a, double b)
- {
- t2(2, 2);
- t2(2);
- t2(1, 1.2);
- }
- """
- self.expectErrors(snippet, [5, 6])
-
- def testReturn(self):
- snippet = """
- module testreturn;
- function void t()
- {
- return;
- }
- """
- self.expectOK(snippet)
-
- def testReturn2(self):
- snippet = """
- module testreturn;
- function int t()
- {
- return 2;
- }
- """
- self.expectOK(snippet)
-
- def testExpressions(self):
- snippet = """
- module test;
- function void t(int a, double b)
- {
- var int a2;
- var bool c;
-
- a2 = b * a;
- c = a;
- }
- """
- self.expectErrors(snippet, [8, 9])
-
- def testExpression1(self):
- snippet = """
- module testexpr1;
- function void t()
- {
- var int a, b, c;
- a = 1;
- b = a * 2 + a * a;
- c = b * a - 3;
- }
- """
- self.expectOK(snippet)
-
- def testEmpty(self):
- snippet = """
- module A
- """
- self.expectErrors(snippet, [3])
-
- def testEmpty2(self):
- snippet = ""
- self.expectErrors(snippet, [1])
-
- def testRedefine(self):
- snippet = """
- module test;
- var int a;
- var int b;
- var int a;
- """
- self.expectErrors(snippet, [5])
-
- def testWhile(self):
- snippet = """
- module tstwhile;
- function void t()
- {
- var int i;
- i = 0;
- while (i < 1054)
- {
- i = i + 3;
- }
- }
- """
- self.expectOK(snippet)
-
- def testWhile2(self):
- snippet = """
- module tstwhile;
- function void t()
- {
- while(true)
- {
- }
-
- while(false)
- {
- }
- }
- """
- self.expectOK(snippet)
-
- def testIf(self):
- snippet = """
- module tstIFF;
- function void t(int b)
- {
- var int a;
- a = 2;
- if (a > b)
- {
- if (a > 1337)
- {
- b = 2;
- }
- }
- else
- {
- b = 1;
- }
-
- return b;
- }
- """
- self.expectOK(snippet)
-
- def testAndCondition(self):
- snippet = """
- module tst;
- function void t() {
- if (4 > 3 and 1 < 10) {
- }
- }
- """
- self.expectOK(snippet)
-
- def testOrCondition(self):
- snippet = """
- module tst;
- function void t() {
- if (3 > 4 or 3 < 10) {
- }
- }
- """
- self.expectOK(snippet)
-
- def testNonBoolCondition(self):
- snippet = """
- module tst;
- function void t() {
- if (3+3) {
- }
- }
- """
- self.expectErrors(snippet, [4])
-
- def testTypeDef(self):
- snippet = """
- module testtypedef;
- type int my_int;
- function void t()
- {
- var my_int a;
- var int b;
- a = 2;
- b = a + 2;
- }
- """
- self.expectOK(snippet)
-
- def testLocalVariable(self):
- snippet = """
- module testlocalvar;
- function void t()
- {
- var int a, b;
- a = 2;
- b = a + 2;
- }
- """
- self.expectOK(snippet)
-
- def testUnknownType(self):
- snippet = """module testlocalvar;
- function void t()
- {
- var int2 a;
- }
- """
- self.expectErrors(snippet, [4])
-
- def testStruct1(self):
- snippet = """
- module teststruct1;
- function void t()
- {
- var struct {int x, y;} a;
- a.x = 2;
- a.y = a.x + 2;
- }
- """
- self.expectOK(snippet)
-
- def testStruct2(self):
- """ Select struct member from non struct type """
- snippet = """
- module teststruct1;
- function void t() {
- var int a;
- a.z = 2;
- }
- """
- self.expectErrors(snippet, [5])
-
- def testStructCall(self):
- snippet = """
- module teststruct1;
- function void t()
- {
- var struct {int x, y;} a;
- a.x(9);
- }
- """
- self.expectErrors(snippet, [6])
-
- def testPointerType1(self):
- snippet = """
- module testpointer1;
- var int* pa;
- function void t()
- {
- var int a;
- pa = &a;
- *pa = 22;
- a = *pa + *pa * 8;
- }
- """
- self.expectOK(snippet)
-
- def testPointerType(self):
- snippet = """
- module testpointer;
- var int* pa, pb;
- function void t(int a, double b)
- {
- var int a2;
- a2 = a; // parameters cannot be escaped for now..
- pa = &a2;
- pb = pa;
- *pa = 22;
- }
- """
- self.expectOK(snippet)
-
- def testPointerTypeInCorrect(self):
- snippet = """
- module testpointerincorrect;
- var int* pa;
- function void t(int a, double b)
- {
- pa = 2; // type conflict
- pa = &a;
- pa = &2; // No valid lvalue
- &a = pa; // No valid lvalue
- **pa = 22; // Cannot deref int
- }
- """
- self.expectErrors(snippet, [6, 8, 9, 10])
-
- def testPointerTypeIr(self):
- snippet = """
- module testptr_ir;
- function void t()
- {
- var int* a;
- a = cast(40);
- *a = 2;
- }
- """
- self.expectOK(snippet)
-
- def testPointerTypeIr2(self):
- snippet = """
- module testptr_ir;
- type struct {int x,y;}* gpio;
- function void t()
- {
- var gpio a;
- a = cast(40);
- a->x = 2;
- a->y = a->x - 14;
- }
- """
- self.expectOK(snippet)
-
- def testWrongCast(self):
- snippet = """
- module testptr_ir;
- type struct {int x,y;}* gpio;
- function void t()
- {
- var gpio a;
- *cast(*a);
- }
- """
- self.expectErrors(snippet, [7])
-
- def testComplexType(self):
- snippet = """
- module testpointer;
- type int my_int;
-
- type struct {
- int x, y;
- } point;
-
- type struct {
- int mem1;
- int memb2;
- point P1;
- } my_struct;
-
- type my_struct* my_sptr;
- var int* pa;
-
- function void t(int a, int b, my_sptr x)
- {
- var my_struct *msp;
-
- var my_struct u, v;
- var point *pt;
-
- pt = &msp->P1;
- msp = x;
- *pa = 22 + u.mem1 * v.memb2 - u.P1.x;
- x->memb2 = *pa + a * b;
-
- msp->P1.x = a * x->P1.y;
- }
- """
- self.expectOK(snippet)
-
-
-if __name__ == '__main__':
- unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testcg.py
--- a/test/testcg.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-import unittest
-import ppci
-from ppci.codegen import CodeGenerator
-from ppci import ir
-from ppci.target.target_list import thumb_target
-from ppci.outstream import BinaryOutputStream
-
-
-def genTestFunction():
- m = ir.Module('tst')
- f = ir.Function('tst')
- m.add_function(f)
- return m, f, f.entry
-
-
-class testCodeGeneration(unittest.TestCase):
- def setUp(self):
- self.cg = CodeGenerator(thumb_target)
-
- def testFunction(self):
- s = BinaryOutputStream(ppci.objectfile.ObjectFile())
- m, f, bb = genTestFunction()
- bb.addInstruction(ir.Exp(ir.Const(123)))
- bb.addInstruction(ir.Jump(f.epiloog))
- obj = self.cg.generate(m, s)
- self.assertTrue(obj)
-
-
-class testArmCodeGeneration(unittest.TestCase):
- def testStack(self):
- s = BinaryOutputStream(ppci.objectfile.ObjectFile())
- cg = CodeGenerator(thumb_target)
- m, f, bb = genTestFunction()
- bb.addInstruction(ir.Move(ir.Mem(ir.Const(1)), ir.Const(22)))
- bb.addInstruction(ir.Jump(f.epiloog))
- cg.generate(m, s)
- #s.dump()
-
-
-if __name__ == '__main__':
- unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testdiagrameditor.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testdiagrameditor.py Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,74 @@
+
+import unittest
+import os
+import sys
+import time
+
+try:
+ otherpath = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'python','other'))
+ sys.path.insert(0, otherpath)
+ import diagrameditor
+
+ from PyQt5.QtWidgets import QApplication, QGraphicsItem
+ from PyQt5.QtTest import QTest
+ from PyQt5.QtCore import Qt, QTimer, QMimeData, QPointF
+ from PyQt5.QtGui import QDropEvent
+ skip_it = False
+
+ # When creating an app per testcase, this fails horribly..
+ app = QApplication(sys.argv)
+except ImportError as e:
+ skip_it = True
+
+
+if 'LCFOSGUITESTS' not in os.environ:
+ skip_it = True
+
+class DiagramEditorTestCase(unittest.TestCase):
+ def setUp(self):
+ if skip_it:
+ self.skipTest('No qt5 or X server')
+ return
+ #print('Instance:', QApplication.instance())
+ self.main = diagrameditor.Main()
+ self.main.show()
+ QTest.qWaitForWindowActive(self.main)
+
+ def tearDown(self):
+ QTimer.singleShot(100, app.quit)
+ app.exec_()
+
+ def cmdNewModel(self):
+ # Press ctrl+N:
+ QTest.keyClick(self.main, Qt.Key_N, Qt.ControlModifier)
+
+ def dragItemIntoScene(self):
+ library = self.main.findChild(diagrameditor.LibraryWidget, 'LibraryWidget')
+ editor = self.main.findChild(diagrameditor.EditorGraphicsView, 'Editor')
+ #ilibrary.
+ QTest.mousePress(library, Qt.LeftButton)
+ print(editor, type(editor))
+ QTest.mouseMove(editor)
+ QTest.mouseRelease(editor, Qt.LeftButton)
+ mimedata = QMimeData()
+ mimedata.setData('component/name', 'Block:blk'.encode('ascii'))
+ de = QDropEvent(QPointF(10, 10), Qt.CopyAction, mimedata,
+ Qt.LeftButton,
+ Qt.NoModifier)
+ editor.dropEvent(de)
+
+ def resizePlacedItem(self):
+ i = self.main.findChild(QGraphicsItem, "sizer_top_right")
+ print(i)
+
+ def testScenario1(self):
+ self.cmdNewModel()
+ self.dragItemIntoScene()
+ self.resizePlacedItem()
+
+ def testB(self):
+ print('b')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testemulation.py
--- a/test/testemulation.py Fri Mar 07 17:10:21 2014 +0100
+++ b/test/testemulation.py Thu Feb 19 14:10:52 2015 +0100
@@ -4,76 +4,126 @@
import subprocess
import socket
import time
+import shutil
from testzcc import ZccBaseTestCase
# Store testdir for safe switch back to directory:
testdir = os.path.dirname(os.path.abspath(__file__))
+def tryrm(fn):
+ try:
+ os.remove(fn)
+ except OSError:
+ pass
+
+qemu_app = 'qemu-system-arm'
+
+def has_qemu():
+ """ Determines if qemu is possible """
+ if not hasattr(shutil, 'which'):
+ return False
+ return bool(shutil.which(qemu_app))
+
+
+def runQemu(kernel, machine='lm3s811evb'):
+ """ Runs qemu on a given kernel file """
+
+ if not has_qemu():
+ return ''
+ tryrm('qemucontrol.sock')
+ tryrm('qemuserial.sock')
+
+ # Listen to the control socket:
+ qemu_control_serve = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ qemu_control_serve.bind('qemucontrol.sock')
+ qemu_control_serve.listen(0)
+
+ # Listen to the serial output:
+ qemu_serial_serve = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ qemu_serial_serve.bind('qemuserial.sock')
+ qemu_serial_serve.listen(0)
+
+ args = [qemu_app, '-M', machine, '-m', '16M',
+ '-nographic',
+ '-kernel', kernel,
+ '-monitor', 'unix:qemucontrol.sock',
+ '-serial', 'unix:qemuserial.sock',
+ '-S']
+ p = subprocess.Popen(args)
+
+ #qemu_serial Give process some time to boot:
+ qemu_serial_serve.settimeout(3)
+ qemu_control_serve.settimeout(3)
+ qemu_serial, address_peer = qemu_serial_serve.accept()
+ qemu_control, address_peer = qemu_control_serve.accept()
+
+ # Give the go command:
+ qemu_control.send('cont\n'.encode('ascii'))
+
+ qemu_serial.settimeout(0.2)
+
+ # Receive all data:
+ data = bytearray()
+ for i in range(400):
+ try:
+ data += qemu_serial.recv(1)
+ except socket.timeout as e:
+ break
+ data = data.decode('ascii')
+ # print(data)
+
+ # Send quit command:
+ qemu_control.send("quit\n".encode('ascii'))
+ if hasattr(subprocess, 'TimeoutExpired'):
+ try:
+ p.wait(timeout=3)
+ except subprocess.TimeoutExpired:
+ p.kill()
+ else:
+ time.sleep(2)
+ p.kill()
+ qemu_control.close()
+ qemu_serial.close()
+ qemu_control_serve.close()
+ qemu_serial_serve.close()
+
+ tryrm('qemucontrol.sock')
+ tryrm('qemuserial.sock')
+
+ # Check that output was correct:
+ return data
+
class EmulationTestCase(ZccBaseTestCase):
""" Tests the compiler driver """
def setUp(self):
- if 'TESTEMU' not in os.environ:
- self.skipTest('Not running emulation tests')
-
- def runQemu(self, kernel, machine='lm3s811evb'):
- args = ['qemu-system-arm', '-M', machine, '-m', '16M',
- '-nographic', '-kernel', kernel, '-monitor',
- 'unix:qemucontrol.sock,server',
- '-serial', 'unix:qemuserial.sock,server']
- p = subprocess.Popen(args)
-
- # Give process some time to boot:
- time.sleep(0.5)
-
- # Connect to the control socket:
- qemu_control = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- qemu_control.connect('qemucontrol.sock')
-
- time.sleep(0.5)
-
- # Now connect to the serial output:
- qemu_serial = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- qemu_serial.connect('qemuserial.sock')
-
- time.sleep(0.5)
-
- qemu_serial.settimeout(0.2)
-
- # Receive all data:
- data = bytearray()
- for i in range(40):
- try:
- data += qemu_serial.recv(1)
- except socket.timeout as e:
- break
- data = data.decode('ascii')
- # print(data)
-
- # Send quit command:
- qemu_control.send("quit\n".encode('ascii'))
- p.wait(timeout=3)
- qemu_control.close()
- qemu_serial.close()
-
- # Check that output was correct:
- return data
+ if not has_qemu():
+ self.skipTest('Not running Qemu test')
def testM3Bare(self):
""" Build bare m3 binary and emulate it """
- recipe = os.path.join(testdir, 'm3_bare', 'recipe.yaml')
+ recipe = os.path.join(testdir, 'm3_bare', 'build.xml')
self.buildRecipe(recipe)
- data = self.runQemu('m3_bare/bare.bin')
+ data = runQemu('m3_bare/bare.bin')
self.assertEqual('Hello worle', data)
def testA9Bare(self):
""" Build vexpress cortex-A9 binary and emulate it """
- recipe = os.path.join(testdir, '..', 'examples', 'qemu_a9_hello', 'recipe.yaml')
+ recipe = os.path.join(testdir, '..', 'examples', 'qemu_a9_hello',
+ 'build.xml')
self.buildRecipe(recipe)
- data = self.runQemu('../examples/qemu_a9_hello/hello.bin', machine='vexpress-a9')
+ data = runQemu('../examples/qemu_a9_hello/hello.bin',
+ machine='vexpress-a9')
self.assertEqual('Hello worle', data)
+ def testKernelVexpressA9(self):
+ """ Build vexpress cortex-A9 binary and emulate it """
+ recipe = os.path.join(testdir, '..', 'kernel', 'build.xml')
+ self.buildRecipe(recipe)
+ data = runQemu('../kernel/kernel_arm.bin', machine='vexpress-a9')
+ self.assertEqual('Welcome to lcfos!', data[:17])
+
if __name__ == '__main__':
unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testgraph.py
--- a/test/testgraph.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-#!/usr/bin/python
-
-import unittest
-from ppci.codegen.graph import Graph, Node, DiGraph, DiNode
-from ppci.codegen.interferencegraph import InterferenceGraph
-from ppci.codegen.flowgraph import FlowGraph
-from ppci import ir
-from ppci.irmach import AbstractInstruction as AI
-from ppci.target import Nop
-
-
-class GraphTestCase(unittest.TestCase):
- def testEdge(self):
- g = Graph()
- n1 = Node(g)
- g.add_node(n1)
- n2 = Node(g)
- g.add_node(n2)
- g.addEdge(n1, n2)
- self.assertTrue(g.hasEdge(n2, n1))
- self.assertTrue(g.hasEdge(n1, n2))
- g.delNode(n1)
- g.delNode(n2)
-
- def testDegree(self):
- g = Graph()
- n1 = Node(g)
- g.add_node(n1)
- n2 = Node(g)
- g.add_node(n2)
- n3 = Node(g)
- g.add_node(n3)
- g.addEdge(n1, n2)
- g.addEdge(n1, n3)
- self.assertEqual(2, n1.Degree)
- self.assertEqual(1, n2.Degree)
- g.delNode(n2)
- self.assertEqual(1, n1.Degree)
-
-
-class DigraphTestCase(unittest.TestCase):
- def testSuccessor(self):
- g = DiGraph()
- a = DiNode(g)
- b = DiNode(g)
- c = DiNode(g)
- g.add_node(a)
- g.add_node(b)
- g.add_node(c)
- g.addEdge(a, b)
- g.addEdge(b, c)
- self.assertEqual({b}, a.Succ)
- self.assertEqual({b}, c.Pred)
- g.delNode(c)
- self.assertEqual(set(), b.Succ)
-
-
-class InterferenceGraphTestCase(unittest.TestCase):
- def testNormalUse(self):
- t1 = ir.Temp('t1')
- t2 = ir.Temp('t2')
- t3 = ir.Temp('t3')
- t4 = ir.Temp('t4')
- t5 = ir.Temp('t5')
- t6 = ir.Temp('t6')
- instrs = []
- instrs.append(AI(Nop, dst=[t1]))
- instrs.append(AI(Nop, dst=[t2]))
- instrs.append(AI(Nop, dst=[t3]))
- cfg = FlowGraph(instrs)
- ig = InterferenceGraph(cfg)
-
- def testCombine(self):
- t1 = ir.Temp('t1')
- t2 = ir.Temp('t2')
- t3 = ir.Temp('t3')
- t4 = ir.Temp('t4')
- instrs = []
- instrs.append(AI(Nop, dst=[t1]))
- instrs.append(AI(Nop, dst=[t2]))
- instrs.append(AI(Nop, dst=[t3]))
- instrs.append(AI(Nop, dst=[t4], src=[t3]))
- instrs.append(AI(Nop, src=[t4]))
- instrs.append(AI(Nop, src=[t1]))
- instrs.append(AI(Nop, src=[t2]))
- cfg = FlowGraph(instrs)
- ig = InterferenceGraph(cfg)
- ig.Combine(ig.getNode(t4), ig.getNode(t3))
- self.assertIs(ig.getNode(t4), ig.getNode(t3))
-
-
-if __name__ == '__main__':
- unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testhexedit.py
--- a/test/testhexedit.py Fri Mar 07 17:10:21 2014 +0100
+++ b/test/testhexedit.py Thu Feb 19 14:10:52 2015 +0100
@@ -1,16 +1,23 @@
import sys
import unittest
-import hexedit
-#import ide
+try:
+ import hexedit
+ #import ide
-from PyQt5.QtWidgets import QApplication
-from PyQt5.QtTest import QTest
-from PyQt5.QtCore import Qt
+ from PyQt5.QtWidgets import QApplication
+ from PyQt5.QtTest import QTest
+ from PyQt5.QtCore import Qt
+ skip_it = False
+except ImportError as e:
+ skip_it = True
class HexEditorTest(unittest.TestCase):
def setUp(self):
+ if skip_it:
+ self.skipTest('No qt5')
+ return
self.app = QApplication(sys.argv)
self.ui = hexedit.HexEditor()
self.bv = self.ui.he.bv
diff -r 742588fb8cd6 -r f381cea07fec test/testhexfile.py
--- a/test/testhexfile.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-import unittest
-import io
-from utils import HexFile, HexFileException
-
-
-class testHexFile(unittest.TestCase):
- def saveload(self, hf):
- f = io.StringIO()
- hf.save(f)
- hf2 = HexFile()
- hf2.load(io.StringIO(f.getvalue()))
- self.assertEqual(hf, hf2)
-
- def testSave1(self):
- hf = HexFile()
- hf.addRegion(0x8000, bytes.fromhex('aabbcc'))
- self.saveload(hf)
-
- def testSave2(self):
- hf = HexFile()
- hf.addRegion(0x8000, bytes.fromhex('aabbcc'))
- hf.addRegion(0x118000, bytes.fromhex('aabbcc'))
- self.saveload(hf)
-
- def testSave3(self):
- hf = HexFile()
- hf.addRegion(0x8000, bytes.fromhex('aabbcc'))
- hf.addRegion(0xFFFE, bytes.fromhex('aabbcc'))
- self.saveload(hf)
-
- @unittest.skip('Takes too long')
- def testSave4(self):
- hf = HexFile()
- hf.addRegion(0xF000, bytes.fromhex('ab')*0x10000)
- self.saveload(hf)
-
- @unittest.skip('Takes too long')
- def testSave5(self):
- hf = HexFile()
- hf.addRegion(0xF003, bytes.fromhex('ab')*0x10000)
- self.saveload(hf)
-
- def testTwoRegions(self):
- hf = HexFile()
- hf2 = HexFile()
- hf.addRegion(0x100, bytes.fromhex('abcd'))
- hf.addRegion(0x200, bytes.fromhex('beef'))
- hf2.addRegion(0x200, bytes.fromhex('beef'))
- hf2.addRegion(0x100, bytes.fromhex('abcd'))
- self.assertEqual(hf, hf2)
-
- def testMerge(self):
- hf = HexFile()
- hf.addRegion(0x10, bytes.fromhex('abcdab'))
- hf.addRegion(0x13, bytes.fromhex('abcdab'))
- self.assertEqual(1, len(hf.regions))
-
- def testOverlapped(self):
- hf = HexFile()
- hf.addRegion(0x10, bytes.fromhex('abcdab'))
- with self.assertRaisesRegex(HexFileException, 'verlap'):
- hf.addRegion(0x12, bytes.fromhex('abcdab'))
-
- def testEqual(self):
- hf1 = HexFile()
- hf2 = HexFile()
- hf1.addRegion(10, bytes.fromhex('aabbcc'))
- hf2.addRegion(10, bytes.fromhex('aabbcc'))
- self.assertEqual(hf1, hf2)
-
- def testNotEqual(self):
- hf1 = HexFile()
- hf2 = HexFile()
- hf1.addRegion(10, bytes.fromhex('aabbcc'))
- hf2.addRegion(10, bytes.fromhex('aabbdc'))
- self.assertNotEqual(hf1, hf2)
-
- def testNotEqual2(self):
- hf1 = HexFile()
- hf2 = HexFile()
- hf1.addRegion(10, bytes.fromhex('aabbcc'))
- hf2.addRegion(10, bytes.fromhex('aabbcc'))
- hf2.addRegion(22, bytes.fromhex('aabbcc'))
- self.assertNotEqual(hf1, hf2)
-
- def testLoad(self):
- hf = HexFile()
- dummyhex = """:01400000aa15"""
- f = io.StringIO(dummyhex)
- hf.load(f)
- self.assertEqual(1, len(hf.regions))
- self.assertEqual(0x4000, hf.regions[0].address)
- self.assertSequenceEqual(bytes.fromhex('aa'), hf.regions[0].data)
-
- def testIncorrectCrc(self):
- hf = HexFile()
- txt = ":01400000aabb"
- f = io.StringIO(txt)
- with self.assertRaisesRegex(HexFileException, 'crc'):
- hf.load(f)
-
- def testIncorrectLength(self):
- hf = HexFile()
- txt = ":0140002200aabb"
- f = io.StringIO(txt)
- with self.assertRaisesRegex(HexFileException, 'count'):
- hf.load(f)
-
-if __name__ == '__main__':
- unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testir.py
--- a/test/testir.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-import unittest
-import os
-import sys
-import io
-import ppci
-from ppci import ir
-from ppci import irutils
-from ppci.transform import ConstantFolder
-
-
-class IrCodeTestCase(unittest.TestCase):
- def testAdd(self):
- v = ir.Add(ir.Const(1), ir.Const(2))
-
-
-class IrBuilderTestCase(unittest.TestCase):
- def setUp(self):
- self.b = irutils.Builder()
- self.m = ir.Module('test')
- self.b.setModule(self.m)
-
- def testBuilder(self):
- f = self.b.newFunction('add')
- self.b.setFunction(f)
- bb = self.b.newBlock()
- self.b.emit(ir.Jump(bb))
- self.b.setBlock(bb)
- self.b.emit(ir.Exp(ir.Const(0)))
- self.b.emit(ir.Jump(f.epiloog))
- # Run interpreter:
- # r = self.m.getFunction('add').call(1, 2)
- #self.assertEqual(3, r)
-
-
-class PatternMatchTestCase(unittest.TestCase):
- @unittest.skip('Not yet implemented')
- def testSimpleTree(self):
- t = ir.Term('x')
- pat = ir.Binop(ir.Const(2), '+', t)
- res, mp = ir.match_tree(ir.Binop(ir.Const(2), '+', 3), pat)
- self.assertTrue(res)
- self.assertIn(t, mp)
- self.assertEqual(3, mp[t])
-
- @unittest.skip('Not yet implemented')
- def testSimpleTree2(self):
- t = ir.Term('x')
- t2 = ir.Term('y')
- pat = ir.Binop(ir.Const(2), '+', ir.Binop(t, '-', t2))
- res, mp = ir.match_tree(ir.Binop(ir.Const(2), '+', ir.Binop(2,'-',3)), pat)
- self.assertTrue(res)
- self.assertIn(t, mp)
- self.assertEqual(2, mp[t])
- self.assertIn(t2, mp)
- self.assertEqual(3, mp[t2])
- res, mp = ir.match_tree(ir.Const(2), pat)
- self.assertFalse(res)
-
-
-class ConstantFolderTestCase(unittest.TestCase):
- def setUp(self):
- self.b = irutils.Builder()
- self.cf = ConstantFolder()
- self.m = ir.Module('test')
- self.b.setModule(self.m)
-
- def testBuilder(self):
- f = self.b.newFunction('test')
- self.b.setFunction(f)
- bb = self.b.newBlock()
- self.b.emit(ir.Jump(bb))
- self.b.setBlock(bb)
- v1 = ir.Const(5)
- v2 = ir.Const(7)
- v3 = ir.Add(v1, v2)
- self.b.emit(ir.Jump(f.epiloog))
- self.cf.run(self.m)
-
- def testAdd0(self):
- f = self.b.newFunction('test')
- self.b.setFunction(f)
- self.b.setBlock(self.b.newBlock())
- v1 = ir.Const(0)
- v3 = ir.Add(v1, ir.Const(0))
-
-
-class TestWriter(unittest.TestCase):
- def testWrite(self):
- writer = irutils.Writer()
- module = ir.Module('mod1')
- function = ir.Function('func1', module)
- f = io.StringIO()
- writer.write(module, f)
- #print(f.getvalue())
- f2 = io.StringIO(f.getvalue())
- reader = irutils.Reader()
- module2 = reader.read(f2)
- f = io.StringIO()
- writer.write(module2, f)
- #print(f.getvalue())
-
-
-class TestReader(unittest.TestCase):
- def testAddExample(self):
- reader = irutils.Reader()
- with open('../examples/pi/add.pi') as f:
- m = reader.read(f)
- self.assertTrue(m)
- #print(m)
-
-
-if __name__ == '__main__':
- unittest.main()
- sys.exit()
diff -r 742588fb8cd6 -r f381cea07fec test/testmsp430asm.py
--- a/test/testmsp430asm.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-#!/usr/bin/python
-
-import unittest
-from ppci.assembler import tokenize, Assembler
-from ppci.objectfile import ObjectFile
-from ppci.outstream import BinaryOutputStream
-from ppci.target.target_list import msp430target
-from testasm import AsmTestCaseBase
-
-a = Assembler(msp430target)
-
-class Msp430AssemblerTestCase(AsmTestCaseBase):
- def setUp(self):
- self.t = msp430target
- self.obj = ObjectFile()
- self.ostream = BinaryOutputStream(self.obj)
- self.ostream.selectSection('.text')
- self.a = a
-
- def testMov(self):
- self.feed("mov r14, r15")
- self.check('0F4E')
-
- def testMov1337(self):
- self.feed("mov 0x1337, r12")
- self.check('3C403713')
-
- def testAdd(self):
- self.feed("add r15, r13")
- self.check('0D5F')
-
- def testReti(self):
- self.feed("reti")
- self.check('0013')
-
-
-if __name__ == '__main__':
- unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testpyy.py
--- a/test/testpyy.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,250 +0,0 @@
-import unittest
-from pyyacc import Grammar, Item, ParserGenerationException, ParserException
-from pyyacc import EPS, EOF, calculate_first_sets
-from ppci import Token
-
-
-class genTokens:
- def __init__(self, lst):
- def tokGen():
- for t in lst:
- yield Token(t, t)
- while True:
- yield Token(EOF, EOF)
- self.tokens = tokGen()
- self.token = self.tokens.__next__()
-
- def next_token(self):
- t = self.token
- if t.typ != EOF:
- self.token = self.tokens.__next__()
- return t
-
-
-class testLR(unittest.TestCase):
- """ Test basic LR(1) parser generator constructs """
- def testSimpleGrammar(self):
- # 1. define a simple grammar:
- g = Grammar(['identifier', '(', ')', '+', '*'])
- g.add_production('input', ['expression'])
- g.add_production('expression', ['term'])
- g.add_production('expression', ['expression', '+', 'term'])
- g.add_production('term', ['factor'])
- g.add_production('term', ['term', '*', 'factor'])
- g.add_production('factor', ['(', 'expression', ')'])
- g.add_production('factor', ['identifier'])
- g.start_symbol = 'input'
- # 2. define input:
- tokens = genTokens(['identifier', '+', 'identifier', '+', 'identifier'])
- # 3. build parser:
- p = g.generate_parser()
- # 4. feed input:
- p.parse(tokens)
-
- def testReduceReduceConflict(self):
- """ Check if a reduce-reduce conflict is detected """
- # Define a grammar with an obvious reduce-reduce conflict:
- g = Grammar(['id'])
- g.add_production('goal', ['a'])
- g.add_production('a', ['b'])
- g.add_production('a', ['c'])
- g.add_production('b', ['id'])
- g.add_production('c', ['id'])
- g.start_symbol = 'goal'
- with self.assertRaises(ParserGenerationException):
- p = g.generate_parser()
-
- def testShiftReduceConflict(self):
- """ Must be handled automatically by doing shift """
- g = Grammar([EOF, 'if', 'then', 'else', 'ass'])
- # Ambiguous grammar:
- g.add_production('if_stmt', ['if', 'then', 'stmt'])
- g.add_production('if_stmt', ['if', 'then', 'stmt', 'else', 'stmt'])
- g.add_production('stmt', ['if_stmt'])
- g.add_production('stmt', ['ass'])
- g.start_symbol = 'stmt'
- p = g.generate_parser()
- # Ambiguous program:
- tokens = genTokens(['if', 'then','if', 'then', 'ass', 'else', 'ass'])
- p.parse(tokens)
-
- def testUndefinedTerminal(self):
- """ Test correct behavior when a terminal is undefined """
- g = Grammar(['b'])
- g.add_production('goal', ['a'])
- g.add_production('a', ['b'])
- g.add_production('a', ['c'])
- g.start_symbol = 'goal'
- with self.assertRaises(ParserGenerationException):
- g.generate_parser()
-
- def testRedefineTerminal(self):
- """ Test correct behavior when a terminal is redefined """
- g = Grammar([EOF, 'b', 'c'])
- g.add_production('goal', ['a'])
- with self.assertRaises(ParserGenerationException):
- g.add_production('b', ['c']) # Not allowed
- g.add_production('a', ['c'])
- g.start_symbol = 'goal'
- g.generate_parser()
-
- def testEmpty(self):
- """ Test empty token stream """
- g = Grammar([','])
- g.add_production('input', [','])
- g.start_symbol = 'input'
- p = g.generate_parser()
- tokens = genTokens([])
- with self.assertRaises(ParserException):
- p.parse(tokens)
-
- def testEps(self):
- """ Test epsilon terminal """
- g = Grammar(['a', 'b'])
- g.add_production('input', ['optional_a', 'b'])
- g.add_production('optional_a', ['a'])
- g.add_production('optional_a', [])
- g.start_symbol = 'input'
- p = g.generate_parser()
- tokens = genTokens(['b'])
- p.parse(tokens)
-
- def testEps2(self):
- g = Grammar(['id', ':'])
- g.add_production('input', ['opt_lab', 'ins', 'op1'])
- g.add_production('input', ['ins', 'op1'])
- g.add_production('opt_lab', ['id', ':'])
- g.add_production('ins', ['id'])
- g.add_production('op1', ['id'])
- g.start_symbol = 'input'
- p = g.generate_parser()
- tokens = genTokens(['id', ':', 'id', 'id']) # i.e. "lab_0: inc rax"
- p.parse(tokens)
- tokens = genTokens(['id', 'id']) # i.e. "inc rax"
- p.parse(tokens)
-
- def testEpsSequence(self):
- """ Test epsilon terminal for use in sequences """
- g = Grammar(['a'])
- g.add_production('aas', [])
- g.add_production('aas', ['aas', 'a'])
- g.start_symbol = 'aas'
- p = g.generate_parser()
- tokens = genTokens(['a', 'a', 'a'])
- p.parse(tokens)
- tokens = genTokens([])
- p.parse(tokens)
-
- def test_cb(self):
- """ Test callback of one rule and order or parameters """
- self.cb_called = False
- def cb(a, c, b):
- self.cb_called = True
- self.assertEqual(a.val, 'a')
- self.assertEqual(b.val, 'b')
- self.assertEqual(c.val, 'c')
- g = Grammar(['a', 'b', 'c'])
- g.add_production('goal', ['a', 'c', 'b'], cb)
- g.start_symbol = 'goal'
- p = g.generate_parser()
- tokens = genTokens(['a', 'c', 'b'])
- p.parse(tokens)
- self.assertTrue(self.cb_called)
-
-
-class testExpressionGrammar(unittest.TestCase):
- def setUp(self):
- g = Grammar(['EOF', 'identifier', '(', ')', '+', '*', 'num'])
- g.add_production('input', ['expression'])
- g.add_production('expression', ['term'])
- g.add_production('expression', ['expression', '+', 'term'])
- g.add_production('term', ['factor'])
- g.add_production('term', ['term', '*', 'factor'])
- g.add_production('factor', ['(', 'expression', ')'])
- g.add_production('factor', ['identifier'])
- g.add_production('factor', ['num'])
- g.start_symbol = 'input'
- self.g = g
-
- def testFirstSimpleGrammar(self):
- # 1. define a simple grammar:
- first = calculate_first_sets(self.g)
- self.assertEqual(first['input'], {'identifier', '(', 'num'})
- self.assertEqual(first['term'], {'identifier', '(', 'num'})
-
- def testCanonical(self):
- s0 = self.g.initialItemSet()
- s, gt = self.g.genCanonicalSet(s0)
- # Must result in 12 sets:
- self.assertEqual(len(s), 24)
-
-
-class testParserGenerator(unittest.TestCase):
- """ Tests several parts of the parser generator """
- def setUp(self):
- g = Grammar(['(', ')'])
- g.add_production('goal', ['list'])
- g.add_production('list', ['list', 'pair'])
- g.add_production('list', ['pair'])
- g.add_production('pair', ['(', 'pair', ')'])
- g.add_production('pair', ['(', ')'])
- g.start_symbol = 'goal'
- self.g = g
-
- def testFirstSet(self):
- for a in ['(', ')', EOF, 'EPS']:
- self.assertEqual(self.g.first[a], {a})
- for nt in ['list', 'pair', 'goal']:
- self.assertEqual(self.g.first[nt], {'('})
-
- def testInitItemSet(self):
- p0, p1, p2, p3, p4 = self.g.productions
- s0 = self.g.initialItemSet()
- self.assertEqual(len(s0), 9) # 9 with the goal rule included!
- self.assertIn(Item(p0, 0, EOF), s0)
- self.assertIn(Item(p1, 0, EOF), s0)
- self.assertIn(Item(p1, 0, '('), s0)
- self.assertIn(Item(p2, 0, EOF), s0)
- self.assertIn(Item(p2, 0, '('), s0)
- self.assertIn(Item(p3, 0, EOF), s0)
- self.assertIn(Item(p3, 0, '('), s0)
- self.assertIn(Item(p4, 0, EOF), s0)
- self.assertIn(Item(p4, 0, '('), s0)
-
- def testCanonical(self):
- s0 = self.g.initialItemSet()
- s, gt = self.g.genCanonicalSet(s0)
- # Must result in 12 sets:
- self.assertEqual(len(s), 12)
-
- def testClosure(self):
- p0, p1, p2, p3, p4 = self.g.productions
- s0 = set()
- s0.add(Item(p0, 0, EOF))
- self.assertEqual(len(s0), 1) # 1 rule
- self.assertIn(Item(p0, 0, EOF), s0)
-
- # Invoke closure on set:
- s0 = self.g.closure(s0)
- self.assertIn(Item(p0, 0, EOF), s0)
- self.assertIn(Item(p1, 0, EOF), s0)
- self.assertIn(Item(p1, 0, '('), s0)
- self.assertIn(Item(p2, 0, EOF), s0)
- self.assertIn(Item(p2, 0, '('), s0)
- self.assertIn(Item(p3, 0, EOF), s0)
- self.assertIn(Item(p3, 0, '('), s0)
- self.assertIn(Item(p4, 0, EOF), s0)
- self.assertIn(Item(p4, 0, '('), s0)
-
- def testParser(self):
- tokens = ['(', '(', ')', ')', '(', ')']
- # 3. build parser:
- p = self.g.generate_parser()
- self.assertEqual(len(p.goto_table), 5)
- self.assertEqual(len(p.action_table), 19)
-
- # 4. feed input:
- p.parse(genTokens(tokens))
-
-if __name__ == '__main__':
- unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec test/testregalloc.py
--- a/test/testregalloc.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-import unittest
-import os
-import sys
-from ppci.irmach import AbstractInstruction as makeIns, Frame
-from ppci.codegen.registerallocator import RegisterAllocator
-from ppci import ir
-from ppci.target import Nop
-
-
-class RegAllocTestCase(unittest.TestCase):
- def setUp(self):
- self.ra = RegisterAllocator()
-
- def testRegAlloc(self):
- f = Frame('tst')
- f.regs = [1,2,3,4,5,6] # for test use numbers!
- f.tempMap = {}
- t1 = ir.Temp('t1')
- t2 = ir.Temp('t2')
- t3 = ir.Temp('t3')
- t4 = ir.Temp('t4')
- t5 = ir.Temp('t5')
- f.instructions.append(makeIns(Nop, dst=[t1]))
- f.instructions.append(makeIns(Nop, dst=[t2]))
- f.instructions.append(makeIns(Nop, dst=[t3]))
- f.instructions.append(makeIns(Nop, dst=[t4], src=[t1, t2]))
- f.instructions.append(makeIns(Nop, dst=[t5], src=[t4, t3]))
- f.instructions.append(makeIns(Nop, src=[t5]))
- self.ra.allocFrame(f)
- self.conflict(t1, t2)
- self.conflict(t2, t3)
-
- def conflict(self, ta, tb):
- self.assertNotEqual(self.ra.Node(ta).color, self.ra.Node(tb).color)
-
- def testRegCoalesc(self):
- f = Frame('tst')
- f.regs = [1,2,3,4,5,6] # for test use numbers!
- f.tempMap = {}
- t1 = ir.Temp('t1')
- t2 = ir.Temp('t2')
- t3 = ir.Temp('t3')
- t4 = ir.Temp('t4')
- t5 = ir.Temp('t5')
- t6 = ir.Temp('t6')
- f.instructions.append(makeIns(Nop, dst=[t1]))
- f.instructions.append(makeIns(Nop, dst=[t2]))
- f.instructions.append(makeIns(Nop, dst=[t3]))
- f.instructions.append(makeIns(Nop, dst=[t4], src=[t2, t1]))
- f.instructions.append(makeIns(Nop, dst=[t5], src=[t3]))
- f.instructions.append(makeIns(Nop, dst=[t5], src=[t4, t5]))
- f.instructions.append(makeIns(Nop, dst=[t6], src=[t5]))
- f.instructions.append(makeIns(Nop, src=[t6]))
- self.ra.allocFrame(f)
- self.conflict(t1, t2)
- self.conflict(t2, t3)
- self.conflict(t1, t3)
-
-if __name__ == '__main__':
- unittest.main()
-
diff -r 742588fb8cd6 -r f381cea07fec test/testthumbasm.py
--- a/test/testthumbasm.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,151 +0,0 @@
-import unittest
-from ppci.outstream import BinaryOutputStream
-from ppci.objectfile import ObjectFile
-from asm import Assembler
-from testasm import AsmTestCaseBase
-from ppci.target.target_list import thumb_target
-
-a = Assembler(thumb_target)
-
-class ThumbAssemblerTestCase(AsmTestCaseBase):
- def setUp(self):
- self.t = thumb_target
- self.obj = ObjectFile()
- self.ostream = BinaryOutputStream(self.obj)
- self.ostream.selectSection('.text')
- self.a = a #
-
- def testMovImm8(self):
- self.feed('mov r4, 100')
- self.check('6424')
-
- @unittest.skip
- def testMovExt(self):
- self.feed('mov r3, sp')
- self.check('')
-
- def testYield(self):
- self.feed('yield')
- self.check('10bf')
-
- def testPush(self):
- self.feed('push {r2,r3,lr}')
- self.check('0cb5')
-
- def testPop(self):
- self.feed('pop {r4-r6, pc}')
- self.check('70bd')
-
- def testStr5(self):
- self.feed('str r4, [r1 + 0]')
- self.check('0c60')
-
- def testLdr5(self):
- self.feed('ldr r4, [r0 + 0]')
- self.check('0468')
-
- def testLdrSpRel(self):
- self.feed('ldr r0, [sp + 4]')
- self.check('0198')
-
- def testStrSpRel(self):
- self.feed('str r0, [sp + 4]')
- self.check('0190')
-
- def testLdrPcRel(self):
- self.feed('ldr r7, henkie')
- self.feed('ldr r6, henkie')
- self.feed('ldr r1, henkie')
- self.feed('align 4')
- self.feed('dcd 1')
- self.feed('henkie: dcd 2')
- self.check('024F024E 01490000 01000000 02000000')
-
- def testBranch(self):
- self.feed('start: b henkie')
- self.feed('beq henkie')
- self.feed('bne henkie')
- self.feed('henkie: b start')
- self.feed('eof: b eof')
- self.check('01e000d0 ffd1fbe7 fee7')
-
- def testConditions(self):
- self.feed('blt x')
- self.feed('bgt x')
- self.feed('x:')
- self.check('00dbffdc')
-
- def testBoff(self):
- self.feed('b henkie')
- self.feed('b henkie')
- self.feed('b henkie')
- self.feed('b henkie')
- self.feed('b henkie')
- self.feed('b henkie')
- self.feed('b henkie')
- self.feed('henkie:')
- self.feed('b henkie')
- self.feed('b henkie')
- self.feed('b henkie')
- self.feed('b henkie')
- self.check('05e004e0 03e002e0 01e000e0 ffe7fee7 fde7fce7 fbe7')
-
- def testBl(self):
- self.feed('bl henkie')
- self.feed('bl henkie')
- self.feed('henkie:')
- self.feed('bl henkie')
- self.feed('bl henkie')
- self.check('00f0 02f8 00f0 00f8 fff7 feff fff7 fcff')
-
- def testCmpRegReg(self):
- self.feed('cmp r0, r1')
- self.check('8842')
-
- def testAddimm3(self):
- self.feed('add r3, r5, 2')
- self.feed('add r4, r1, 6')
- self.check('ab1c8c1d')
-
- def testSubImm3(self):
- self.feed('sub r3, r5, 2')
- self.feed('sub r4, r1, 6')
- self.check('ab1e8c1f')
-
- def testLeftShift(self):
- self.feed('lsl r3, r5')
- self.check('ab40')
-
- def testAddSp(self):
- self.feed('add sp,sp,8')
- self.feed('add sp,sp,16')
- self.check('02b004b0')
-
- def testSubSp(self):
- self.feed('sub sp,sp,32')
- self.feed('sub sp,sp,4')
- self.check('88b081b0')
-
- def testSequence1(self):
- self.feed('mov r5, 3')
- self.feed('add r4, r5, 0')
- self.feed('loop: add r6, r4, 7')
- self.feed('cmp r6, 5')
- self.check('0325 2c1c e61d 052e')
-
- def testSequence2(self):
- self.feed('henkie:')
- self.feed('push {r1,r4,r5}')
- self.feed('add r5, r2, r4')
- self.feed('cmp r4, r2')
- self.feed('ldr r0, [sp + 4]')
- self.feed('str r3, [sp + 16]')
- self.feed('pop {r1, r4, r5}')
- self.feed('lsl r3, r4')
- self.feed('cmp r3, r5')
- self.feed('beq henkie')
- self.feed('bne henkie')
- self.feed('b henkie')
- self.check('32b41519 94420198 049332bc a340ab42 f6d0f5d1 f4e7')
-
-
diff -r 742588fb8cd6 -r f381cea07fec test/testx86asm.py
--- a/test/testx86asm.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-#!/usr/bin/python
-
-import unittest
-from testasm import AsmTestCaseBase
-
-
-class AssemblerTestCase(AsmTestCaseBase):
- """
- test methods start with 'test*'
- Checks several assembly constructs agains their bytecodes
- """
- def setUp(self):
- self.skipTest('not implemented yet')
- self.assembler = Assembler('x86-64')
- a = Assembler()
-
- @unittest.skip
- def testX86(self):
- self.feed('mov rax, rbx') # ; 0x48, 0x89, 0xd8
- self.feed('xor rcx, rbx') # ; 0x48, 0x31, 0xd9
- self.feed('inc rcx') # ; 0x48 0xff 0xc1
- self.check('48 89 d8 48 31 d9 48 ff c1')
-
- def tstAssembler(self):
- """ Check all kind of assembler cases """
- assert(assembler.shortjump(5) == [0xeb, 0x5])
- assert(assembler.shortjump(-2) == [0xeb, 0xfc])
- assert(assembler.shortjump(10,'GE') == [0x7d, 0xa])
- assert(assembler.nearjump(5) == [0xe9, 0x5,0x0,0x0,0x0])
- assert(assembler.nearjump(-2) == [0xe9, 0xf9, 0xff,0xff,0xff])
- assert(assembler.nearjump(10,'LE') == [0x0f, 0x8e, 0xa,0x0,0x0,0x0])
-
- def testCall(self):
- self.feed('call r10')
- self.check('')
- self.feed('call rcx')
-
- # assert(assembler.call('r10') == [0x41, 0xff, 0xd2])
- # assert(assembler.call('rcx') == [0xff, 0xd1])
-
- def testXOR(self):
- assert(assembler.xorreg64('rax', 'rax') == [0x48, 0x31, 0xc0])
- assert(assembler.xorreg64('r9', 'r8') == [0x4d, 0x31, 0xc1])
- assert(assembler.xorreg64('rbx', 'r11') == [0x4c, 0x31, 0xdb])
-
- def testINC(self):
- assert(assembler.increg64('r11') == [0x49, 0xff, 0xc3])
- assert(assembler.increg64('rcx') == [0x48, 0xff, 0xc1])
-
- def testPush(self):
- assert(assembler.push('rbp') == [0x55])
- assert(assembler.push('rbx') == [0x53])
- assert(assembler.push('r12') == [0x41, 0x54])
-
- def testPop(self):
- self.feed('pop rbx')
- self.feed('pop rbp')
- self.feed('pop r12')
- assert(assembler.pop('rbx') == [0x5b])
- assert(assembler.pop('rbp') == [0x5d])
- assert(assembler.pop('r12') == [0x41, 0x5c])
-
- def testAsmLoads(self):
- # TODO constant add testcases
- assert(assembler.mov('rbx', 'r14') == [0x4c, 0x89, 0xf3])
- assert(assembler.mov('r12', 'r8') == [0x4d, 0x89, 0xc4])
- assert(assembler.mov('rdi', 'rsp') == [0x48, 0x89, 0xe7])
-
- def testAsmMemLoads(self):
- assert(assembler.mov('rax', ['r8','r15',0x11]) == [0x4b,0x8b,0x44,0x38,0x11])
- assert(assembler.mov('r13', ['rbp','rcx',0x23]) == [0x4c,0x8b,0x6c,0xd,0x23])
-
- assert(assembler.mov('r9', ['rbp',-0x33]) == [0x4c,0x8b,0x4d,0xcd])
- #assert(assembler.movreg64('rbx', ['rax']) == [0x48, 0x8b,0x18])
-
- assert(assembler.mov('rax', [0xb000]) == [0x48,0x8b,0x4,0x25,0x0,0xb0,0x0,0x0])
- assert(assembler.mov('r11', [0xa0]) == [0x4c,0x8b,0x1c,0x25,0xa0,0x0,0x0,0x0])
-
- assert(assembler.mov('r11', ['RIP', 0xf]) == [0x4c,0x8b,0x1d,0x0f,0x0,0x0,0x0])
-
- def testAsmMemStores(self):
- assert(assembler.mov(['rbp', 0x13],'rbx') == [0x48,0x89,0x5d,0x13])
- assert(assembler.mov(['r12', 0x12],'r9') == [0x4d,0x89,0x4c,0x24,0x12])
- assert(assembler.mov(['rcx', 0x11],'r14') == [0x4c,0x89,0x71,0x11])
-
-
- assert(assembler.mov([0xab], 'rbx') == [0x48,0x89,0x1c,0x25,0xab,0x0,0x0,0x0])
- assert(assembler.mov([0xcd], 'r13') == [0x4c,0x89,0x2c,0x25,0xcd,0x0,0x0,0x0])
-
- assert(assembler.mov(['RIP', 0xf], 'r9') == [0x4c,0x89,0x0d,0x0f,0x0,0x0,0x0])
-
- def testAsmMOV8(self):
- assert(assembler.mov(['rbp', -8], 'al') == [0x88, 0x45, 0xf8])
- assert(assembler.mov(['r11', 9], 'cl') == [0x41, 0x88, 0x4b, 0x09])
-
- assert(assembler.mov(['rbx'], 'al') == [0x88, 0x03])
- assert(assembler.mov(['r11'], 'dl') == [0x41, 0x88, 0x13])
-
- def testAsmLea(self):
- assert(assembler.leareg64('r11', ['RIP', 0xf]) == [0x4c,0x8d,0x1d,0x0f,0x0,0x0,0x0])
- assert(assembler.leareg64('rsi', ['RIP', 0x7]) == [0x48,0x8d,0x35,0x07,0x0,0x0,0x0])
-
- assert(assembler.leareg64('rcx', ['rbp', -8]) == [0x48,0x8d,0x4d,0xf8])
-
- def testAssemblerCMP(self):
- assert(assembler.cmpreg64('rdi', 'r13') == [0x4c, 0x39, 0xef])
- assert(assembler.cmpreg64('rbx', 'r14') == [0x4c, 0x39, 0xf3])
- assert(assembler.cmpreg64('r12', 'r9') == [0x4d, 0x39, 0xcc])
-
- assert(assembler.cmpreg64('rdi', 1) == [0x48, 0x83, 0xff, 0x01])
- assert(assembler.cmpreg64('r11', 2) == [0x49, 0x83, 0xfb, 0x02])
-
- def testAssemblerADD(self):
- assert(assembler.addreg64('rbx', 'r13') == [0x4c, 0x01, 0xeb])
- assert(assembler.addreg64('rax', 'rbx') == [0x48, 0x01, 0xd8])
- assert(assembler.addreg64('r12', 'r13') == [0x4d, 0x01, 0xec])
-
- assert(assembler.addreg64('rbx', 0x13) == [0x48, 0x83, 0xc3, 0x13])
- assert(assembler.addreg64('r11', 0x1234567) == [0x49, 0x81, 0xc3, 0x67, 0x45,0x23,0x1])
- assert(assembler.addreg64('rsp', 0x33) == [0x48, 0x83, 0xc4, 0x33])
-
- def testAssemblerSUB(self):
- assert(assembler.subreg64('rdx', 'r14') == [0x4c, 0x29, 0xf2])
- assert(assembler.subreg64('r15', 'rbx') == [0x49, 0x29, 0xdf])
- assert(assembler.subreg64('r8', 'r9') == [0x4d, 0x29, 0xc8])
-
- assert(assembler.subreg64('rsp', 0x123456) == [0x48, 0x81, 0xec, 0x56,0x34,0x12,0x0])
- assert(assembler.subreg64('rsp', 0x12) == [0x48, 0x83, 0xec, 0x12])
-
- def testAssemblerIDIV(self):
- assert(assembler.idivreg64('r11') == [0x49, 0xf7, 0xfb])
- assert(assembler.idivreg64('rcx') == [0x48, 0xf7, 0xf9])
- assert(assembler.idivreg64('rsp') == [0x48, 0xf7, 0xfc])
-
- def testAssemblerIMUL(self):
- assert(assembler.imulreg64_rax('rdi') == [0x48, 0xf7, 0xef])
- assert(assembler.imulreg64_rax('r10') == [0x49, 0xf7, 0xea])
- assert(assembler.imulreg64_rax('rdx') == [0x48, 0xf7, 0xea])
-
- assert(assembler.imulreg64('r11', 'rdi') == [0x4c, 0xf, 0xaf, 0xdf])
- assert(assembler.imulreg64('r12', 'rbx') == [0x4c, 0xf, 0xaf, 0xe3])
- # nasm generates this machine code: 0x4d, 0x6b, 0xff, 0xee
- # This also works: 4D0FAFFE (another variant?? )
- assert(assembler.imulreg64('r15', 'r14') == [0x4d, 0x0f, 0xaf, 0xfe])
-
-
-if __name__ == '__main__':
- unittest.main()
-
diff -r 742588fb8cd6 -r f381cea07fec test/testzcc.py
--- a/test/testzcc.py Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-import unittest
-import os
-import sys
-
-import zcc
-from ppci.objectfile import ObjectFile
-import ppci
-import io
-from ppci.target import target_list
-
-# Store testdir for safe switch back to directory:
-testdir = os.path.dirname(os.path.abspath(__file__))
-
-def relpath(*args):
- return os.path.join(testdir, *args)
-
-class ZccBaseTestCase(unittest.TestCase):
- def callZcc(self, arg_list):
- parser = zcc.make_parser()
- arg_list = ['--log', 'warn'] + arg_list
- args = parser.parse_args(arg_list)
- self.assertEqual(0, zcc.main(args))
-
- def buildRecipe(self, recipe):
- arg_list = ['recipe', recipe]
- self.callZcc(arg_list)
-
-
-class ZccTestCase(ZccBaseTestCase):
- """ Tests the compiler driver """
- def setUp(self):
- os.chdir(testdir)
-
- def tearDown(self):
- os.chdir(testdir)
-
- def do(self, filenames, imps=[], extra_args=[]):
- basedir = os.path.join('..', 'examples', 'c3')
- arg_list = ['compile']
- arg_list += [os.path.join(basedir, fn) for fn in filenames]
- for fn in imps:
- arg_list.append('-i')
- arg_list.append(os.path.join(basedir, fn))
- arg_list.append('--target')
- arg_list.append('thumb')
- arg_list += extra_args
- self.callZcc(arg_list)
-
-
- def testDumpIr(self):
- basedir = relpath('..', 'examples', 'c3', 'comments.c3')
- arg_list = ['compile', basedir]
- arg_list.append('--target')
- arg_list.append('thumb')
- self.callZcc(arg_list)
-
- def testKernel(self):
- """ Build kernel using zcc: """
- recipe = relpath('..', 'kernel', 'recipe.yaml')
- self.buildRecipe(recipe)
-
- @unittest.skip('Too difficult to fix')
- def testKernelBuildsEqualTwice(self):
- """ Build kernel two times and check the output is equal """
- recipe = relpath('..', 'kernel', 'recipe.yaml')
- bin_filename = relpath('..', 'kernel', 'kernel.bin')
- self.buildRecipe(recipe)
- with open(bin_filename, 'rb') as f:
- a = f.read()
- self.buildRecipe(recipe)
- with open(bin_filename, 'rb') as f:
- b = f.read()
- self.assertSequenceEqual(a, b)
-
- def testUser(self):
- """ Build userspace using zcc: """
- recipe = relpath('..', 'user', 'recipe.yaml')
- self.buildRecipe(recipe)
-
- def testBurn2(self):
- self.do(['burn2.c3'], ['stm32f4xx.c3'])
-
- def testBurn2_recipe(self):
- recipe = relpath('..', 'examples', 'c3', 'recipe.yaml')
- self.buildRecipe(recipe)
-
- def test_hello_A9_c3_recipe(self):
- recipe = relpath('..', 'examples', 'qemu_a9_hello', 'recipe.yaml')
- self.buildRecipe(recipe)
-
- @unittest.skip('Skip because of logfile')
- def testBurn2WithLogging(self):
- self.do(['burn2.c3'], ['stm32f4xx.c3'], extra_args=['--report', 'x.rst'])
-
- def testCommentsExample(self):
- self.do(['comments.c3'])
-
- def testCast(self):
- self.do(['cast.c3'])
-
- def testFunctions(self):
- self.do(['functions.c3'])
-
- @unittest.skip('Revise this test')
- def testSectionAddress(self):
- src = """module tst;
- function void t2() {var int t3; t3 = 2;}
- """
- f = io.StringIO(src)
- out = ObjectFile()
- tg = target_list.armtarget
- tr = ppci.tasks.TaskRunner()
- tr.add_task(ppci.buildtasks.Compile([f], [], tg, out))
- tr.run_tasks()
- code = out.get_section('code')
- self.assertEqual(0x0, code.address)
-
-
-if __name__ == '__main__':
- unittest.main()
diff -r 742588fb8cd6 -r f381cea07fec user/app.mmap
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/user/app.mmap Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,9 @@
+
+MEMORY flash LOCATION=0x0 SIZE=0x10000 {
+ SECTION(code)
+}
+
+MEMORY ram LOCATION=0x20000000 SIZE=0x10000 {
+ SECTION(data)
+}
+
diff -r 742588fb8cd6 -r f381cea07fec user/build.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/user/build.xml Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -r 742588fb8cd6 -r f381cea07fec user/hello.c3
--- a/user/hello.c3 Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-module hello;
-import lib;
-
-/*
- Demo program running in userspace.
-*/
-
-function void start()
-{
- lib.print(9); // 'Hello space');
-}
-
diff -r 742588fb8cd6 -r f381cea07fec user/hello/hello.c3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/user/hello/hello.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,12 @@
+module hello;
+import lib;
+
+/*
+ Demo program running in userspace.
+*/
+
+function void start()
+{
+ lib.print("Hello space");
+}
+
diff -r 742588fb8cd6 -r f381cea07fec user/init/init.c3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/user/init/init.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,12 @@
+module init;
+import lib;
+
+/*
+Initial program run by the system.
+*/
+
+function void start()
+{
+ lib.print("Welcome to lcfos");
+}
+
diff -r 742588fb8cd6 -r f381cea07fec user/ipc.c3
--- a/user/ipc.c3 Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-
-module ipc;
-
-type struct {
- int sender;
- int cmd;
- int data1;
- int data2;
- int data3;
- int data4;
-} Msg;
-
-const int MSG_SEND=1;
-const int MSG_RECV=2;
-
-function int kernelTrap(int msgId, int a, int b)
-{
- // TODO: make this in assembler?
-}
-
-function void SendMessage(Msg *msg)
-{
- kernelTrap(MSG_SEND, 1, 0)
-}
-
-function void receive_message(Msg *msg)
-{
- kernelTrap(MSG_RECV, 2, 0);
-}
-
diff -r 742588fb8cd6 -r f381cea07fec user/lib.c3
--- a/user/lib.c3 Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-module lib;
-import ipc;
-
-/*
-Runtime library.
-
-*/
-
-function void print(int txt)
-{
- // TODO
- var ipc.Msg msg;
- ipc.SendMessage(&msg);
-}
-
-
diff -r 742588fb8cd6 -r f381cea07fec user/lib/ipc.c3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/user/lib/ipc.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,32 @@
+
+module ipc;
+
+type struct {
+ int sender;
+ int cmd;
+ int data1;
+ int data2;
+ int data3;
+ int data4;
+} Msg;
+
+const int MSG_SEND=1;
+const int MSG_RECV=2;
+
+function int kernelTrap(int msgId, int a, int b)
+{
+ // TODO: make this in assembler?
+}
+
+function void SendMessage(Msg *msg)
+{
+ var int x;
+ x=kernelTrap(MSG_SEND, 1, 0)
+}
+
+function void receive_message(Msg *msg)
+{
+ var int x;
+ x=kernelTrap(MSG_RECV, 2, 0);
+}
+
diff -r 742588fb8cd6 -r f381cea07fec user/lib/lib.c3
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/user/lib/lib.c3 Thu Feb 19 14:10:52 2015 +0100
@@ -0,0 +1,33 @@
+module lib;
+import ipc;
+
+/*
+Runtime library.
+*/
+
+// Hack until something better exists:
+function void putc(int c)
+{
+ var int *UART0DR;
+ UART0DR = cast(0x109000); // UART0 DR register when remapped at 1MB
+ *UART0DR = c;
+}
+
+function void print(string txt)
+{
+ // TODO
+ var ipc.Msg msg;
+ ipc.SendMessage(&msg);
+
+ // TBD: send text to putc or via send message??
+ var int i;
+ i = 0;
+
+ while (i < txt->len)
+ {
+ putc(cast(txt->txt[i]));
+ i = i + 1;
+ }
+}
+
+
diff -r 742588fb8cd6 -r f381cea07fec user/recipe.yaml
--- a/user/recipe.yaml Fri Mar 07 17:10:21 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-
-apps:
- - link:
- inputs:
- - compile:
- sources: [lib.c3, ipc.c3, hello.c3]
- includes: []
- machine: thumb
- output: kernel.elf2
- layout:
- code: 0x0
- data: 0x20000000
- output: 'hello.bin'
-
diff -r 742588fb8cd6 -r f381cea07fec util/test_patterns.txt
--- a/util/test_patterns.txt Fri Mar 07 17:10:21 2014 +0100
+++ b/util/test_patterns.txt Thu Feb 19 14:10:52 2015 +0100
@@ -4,10 +4,14 @@
mov sp, #0x6000
===
mov r3, sp
+mov pc, lr
+mov pc, r2
+mov sp, r4
+mov r5, r6
===
yield
===
-push {r11,r5,r4,lr}
+push {r4, r5, r11, lr}
===
pop {r4,r5,r6}
===
@@ -19,4 +23,45 @@
str r9, [r2, #33]
===
ldr r5, [r3, #87]
+===
+ldr r5, lab1
+ldr r11, lab1
+ldr r10, lab1
+lab1:
+.word 0x12345566
+===
+cmp r4, r11
+cmp r5, #0x50000
+===
+adr r5, cval
+adr r9, cval
+adr r8, cval
+cval:
+adr r11, cval
+adr r12, cval
+adr r1, cval
+pop {r2}
+===
+lsl r11, r5, r3
+lsl r4, r8, r6
+===
+lsr r9, r0, r2
+lsr r4, r8, r6
+===
+and r9, r0, r2
+and r4, r8, r6
+===
+mcr p15, 0, r1, c2, c0, 0
+mcr p14, 0, r1, c8, c7, 0
+===
+mrc p15, 0, r1, c2, c0, 0
+mrc p14, 0, r1, c8, c7, 0
+===
+ldr r8, =a
+a:
+===
+ldrb r5, [r3, #87]
+===
+strb r2, [r8, #11]
+