lkml.org 
[lkml]   [2011]   [Jan]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCHv1 5/8] unicore32 additional architecture files: low-level lib: io
    Date
    From: Guan Xuetao <guanxuetao@mprc.pku.edu.cn>

    Patch 5 implements low-level io libraries.

    Signed-off-by: Guan Xuetao <guanxuetao@mprc.pku.edu.cn>
    ---
    arch/unicore32/include/asm/io.h | 83 +++++++++++++++++++++++++
    arch/unicore32/lib/io-readsb.S | 130 +++++++++++++++++++++++++++++++++++++++
    arch/unicore32/lib/io-readsl.S | 83 +++++++++++++++++++++++++
    arch/unicore32/lib/io-readsw.S | 110 +++++++++++++++++++++++++++++++++
    arch/unicore32/lib/io-writesb.S | 90 +++++++++++++++++++++++++++
    arch/unicore32/lib/io-writesl.S | 69 +++++++++++++++++++++
    arch/unicore32/lib/io-writesw.S | 87 ++++++++++++++++++++++++++
    7 files changed, 652 insertions(+), 0 deletions(-)

    diff --git a/arch/unicore32/include/asm/io.h b/arch/unicore32/include/asm/io.h
    new file mode 100644
    index 0000000..67c5c03
    --- /dev/null
    +++ b/arch/unicore32/include/asm/io.h
    @@ -0,0 +1,83 @@
    +/*
    + * linux/arch/unicore32/include/asm/io.h
    + *
    + * Code specific to PKUnity SoC and UniCore ISA
    + *
    + * Copyright (C) 2001-2010 GUAN Xue-tao
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +#ifndef __UNICORE_IO_H__
    +#define __UNICORE_IO_H__
    +
    +#ifdef __KERNEL__
    +
    +#include <linux/types.h>
    +#include <asm/byteorder.h>
    +#include <asm/memory.h>
    +#include <asm/system.h>
    +
    +/*
    + * IO port access primitives
    + * -------------------------
    + *
    + * The UniCore doesn't have special IO access instructions; all IO is memory
    + * mapped. Note that these are defined to perform little endian accesses
    + * only. Their primary purpose is to access PCI peripherals.
    + *
    + * Note that we prevent GCC re-ordering or caching values in expressions
    + * by introducing sequence points into the in*() definitions. Note that
    + * __raw_* do not guarantee this behaviour.
    + *
    + * The {in,out}[bwl] macros are for emulating x86-style PCI IO space.
    + */
    +extern void __raw_writesb(void __iomem *addr, const void *data, int bytelen);
    +extern void __raw_writesw(void __iomem *addr, const void *data, int wordlen);
    +extern void __raw_writesl(void __iomem *addr, const void *data, int longlen);
    +
    +extern void __raw_readsb(const void __iomem *addr, void *data, int bytelen);
    +extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen);
    +extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
    +
    +#define outsb(p, d, l) __raw_writesb((void __iomem *)p, d, l)
    +#define outsw(p, d, l) __raw_writesw((void __iomem *)p, d, l)
    +#define outsl(p, d, l) __raw_writesl((void __iomem *)p, d, l)
    +
    +#define insb(p, d, l) __raw_readsb((void __iomem *)p, d, l)
    +#define insw(p, d, l) __raw_readsw((void __iomem *)p, d, l)
    +#define insl(p, d, l) __raw_readsl((void __iomem *)p, d, l)
    +
    +#include <asm-generic/io.h>
    +
    +/*
    + * __uc32_ioremap and __uc32_ioremap_cached takes CPU physical address.
    + */
    +extern void __iomem *__uc32_ioremap(unsigned long, size_t);
    +extern void __iomem *__uc32_ioremap_cached(unsigned long, size_t);
    +extern void __uc32_iounmap(volatile void __iomem *addr);
    +
    +/*
    + * ioremap and friends.
    + *
    + * ioremap takes a PCI memory address, as specified in
    + * Documentation/IO-mapping.txt.
    + *
    + */
    +#define ioremap(cookie, size) __uc32_ioremap(cookie, size)
    +#define ioremap_cached(cookie, size) __uc32_ioremap_cached(cookie, size)
    +#define iounmap(cookie) __uc32_iounmap(cookie)
    +
    +extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
    +extern void ioport_unmap(void __iomem *addr);
    +
    +/*
    + * Convert a physical pointer to a virtual kernel pointer for /dev/mem
    + * access
    + */
    +#undef xlate_dev_mem_ptr
    +#define xlate_dev_mem_ptr(p) __va(p)
    +
    +#endif /* __KERNEL__ */
    +#endif /* __UNICORE_IO_H__ */
    diff --git a/arch/unicore32/lib/io-readsb.S b/arch/unicore32/lib/io-readsb.S
    new file mode 100644
    index 0000000..ff85be3
    --- /dev/null
    +++ b/arch/unicore32/lib/io-readsb.S
    @@ -0,0 +1,130 @@
    +/*
    + * linux/arch/unicore32/lib/io-readsb.S
    + *
    + * Code specific to PKUnity SoC and UniCore ISA
    + *
    + * Copyright (C) 2001-2010 GUAN Xue-tao
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +#include <linux/linkage.h>
    +#include <asm/assembler.h>
    +
    +.Linsb_align: rsub ip, ip, #4
    + csub.a ip, r2
    + cmovsg ip, r2
    + csub.a ip, #2
    + ldb r3, [r0]
    + stb.w r3, [r1]+, #1
    + bsl 201f
    + ldb r3, [r0]
    + stb.w r3, [r1]+, #1
    + bel 201f
    + ldb r3, [r0]
    + stb.w r3, [r1]+, #1
    +201:
    + sub.a r2, r2, ip
    + bne .Linsb_aligned
    +
    +ENTRY(__raw_readsb)
    + cxor.a r2, #0 @ do we have to check for the zero len?
    + cmoveq pc, lr
    + and.a ip, r1, #3
    + bne .Linsb_align
    +
    +.Linsb_aligned:
    +
    + sub.a r2, r2, #16
    + bfs .Linsb_no_16
    +
    +.Linsb_16_lp: ldb r3, [r0]
    + ldb r4, [r0]
    + ldb r5, [r0]
    + mov r3, r3 put_byte_0
    + ldb r6, [r0]
    + or r3, r3, r4 put_byte_1
    + ldb r4, [r0]
    + or r3, r3, r5 put_byte_2
    + ldb r5, [r0]
    + or r3, r3, r6 put_byte_3
    + ldb r6, [r0]
    + mov r4, r4 put_byte_0
    + ldb ip, [r0]
    + or r4, r4, r5 put_byte_1
    + ldb r5, [r0]
    + or r4, r4, r6 put_byte_2
    + ldb r6, [r0]
    + or r4, r4, ip put_byte_3
    + ldb ip, [r0]
    + mov r5, r5 put_byte_0
    + ldb r15, [r0]
    + or r5, r5, r6 put_byte_1
    + ldb r6, [r0]
    + or r5, r5, ip put_byte_2
    + ldb ip, [r0]
    + or r5, r5, r15 put_byte_3
    + ldb r15, [r0]
    + mov r6, r6 put_byte_0
    + or r6, r6, ip put_byte_1
    + ldb ip, [r0]
    + or r6, r6, r15 put_byte_2
    + or r6, r6, ip put_byte_3
    + stm.w (r3 - r6), [r1]+
    +
    + sub.a r2, r2, #16
    + bns .Linsb_16_lp
    +
    + cand.a r2, #15
    + cmoveq pc, lr
    +
    +.Linsb_no_16: cand.a r2, #8
    + beq .Linsb_no_8
    +
    + ldb r3, [r0]
    + ldb r4, [r0]
    + ldb r5, [r0]
    + mov r3, r3 put_byte_0
    + ldb r6, [r0]
    + or r3, r3, r4 put_byte_1
    + ldb r4, [r0]
    + or r3, r3, r5 put_byte_2
    + ldb r5, [r0]
    + or r3, r3, r6 put_byte_3
    + ldb r6, [r0]
    + mov r4, r4 put_byte_0
    + ldb ip, [r0]
    + or r4, r4, r5 put_byte_1
    + or r4, r4, r6 put_byte_2
    + or r4, r4, ip put_byte_3
    + stm.w (r3, r4), [r1]+
    +
    +.Linsb_no_8: cand.a r2, #4
    + beq .Linsb_no_4
    +
    + ldb r3, [r0]
    + ldb r4, [r0]
    + ldb r5, [r0]
    + ldb r6, [r0]
    + mov r3, r3 put_byte_0
    + or r3, r3, r4 put_byte_1
    + or r3, r3, r5 put_byte_2
    + or r3, r3, r6 put_byte_3
    + stw.w r3, [r1]+, #4
    +
    +.Linsb_no_4: and.a r2, r2, #3
    + cmoveq pc, lr
    +
    + csub.a r2, #2
    + ldb r3, [r0]
    + stb.w r3, [r1]+, #1
    + bsl 201f
    + ldb r3, [r0]
    + stb.w r3, [r1]+, #1
    + bel 201f
    + ldb r3, [r0]
    + stb r3, [r1]
    +201:
    + mov pc, lr
    +ENDPROC(__raw_readsb)
    diff --git a/arch/unicore32/lib/io-readsl.S b/arch/unicore32/lib/io-readsl.S
    new file mode 100644
    index 0000000..980b0fc
    --- /dev/null
    +++ b/arch/unicore32/lib/io-readsl.S
    @@ -0,0 +1,83 @@
    +/*
    + * linux/arch/unicore32/lib/io-readsl.S
    + *
    + * Code specific to PKUnity SoC and UniCore ISA
    + *
    + * Copyright (C) 2001-2010 GUAN Xue-tao
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +#include <linux/linkage.h>
    +#include <asm/assembler.h>
    +
    +ENTRY(__raw_readsl)
    + cxor.a r2, #0 @ do we have to check for the zero len?
    + cmoveq pc, lr
    + and.a ip, r1, #3
    + bne 3f
    +
    + sub.a r2, r2, #4
    + bfs 2f
    +1: ldw r3, [r0+], #0
    + ldw r4, [r0+], #0
    + ldw r14, [r0+], #0
    + ldw r15, [r0+], #0
    + sub.a r2, r2, #4
    + stm.w (r3, r4, r14, r15), [r1]+
    + bns 1b
    +2: mov.a r2, r2 << #31
    + bub 201f
    + ldw r3, [r0+], #0
    + ldw r14, [r0+], #0
    + stm.w (r3, r14), [r1]+
    +201: beq 202f
    + ldw r3, [r0+], #0
    + stw r3, [r1+], #0
    +202:
    + mov pc, lr
    +
    +3: ldw r3, [r0]
    + csub.a ip, #2
    + mov ip, r3 get_byte_0
    + stb.w ip, [r1]+, #1
    + bsg 6f
    + mov ip, r3 get_byte_1
    + stb.w ip, [r1]+, #1
    + beq 5f
    + mov ip, r3 get_byte_2
    + stb.w ip, [r1]+, #1
    +
    +4: sub.a r2, r2, #1
    + mov ip, r3 pull #24
    + beq 8f
    + ldw r3, [r0]
    + or ip, ip, r3 push #8
    + stw.w ip, [r1]+, #4
    + b 4b
    +
    +5: sub.a r2, r2, #1
    + mov ip, r3 pull #16
    + beq 7f
    + ldw r3, [r0]
    + or ip, ip, r3 push #16
    + stw.w ip, [r1]+, #4
    + b 5b
    +
    +6: sub.a r2, r2, #1
    + mov ip, r3 pull #8
    + beq 201f
    + ldw r3, [r0]
    + or ip, ip, r3 push #24
    + stw.w ip, [r1]+, #4
    + b 6b
    +201:
    + mov r3, ip get_byte_2
    + stb r3, [r1+], #2
    +7: mov r3, ip get_byte_1
    + stb r3, [r1+], #1
    +8: mov r3, ip get_byte_0
    + stb r3, [r1+], #0
    + mov pc, lr
    +ENDPROC(__raw_readsl)
    diff --git a/arch/unicore32/lib/io-readsw.S b/arch/unicore32/lib/io-readsw.S
    new file mode 100644
    index 0000000..7d0b49d
    --- /dev/null
    +++ b/arch/unicore32/lib/io-readsw.S
    @@ -0,0 +1,110 @@
    +/*
    + * linux/arch/unicore32/lib/io-readsw.S
    + *
    + * Code specific to PKUnity SoC and UniCore ISA
    + *
    + * Copyright (C) 2001-2010 GUAN Xue-tao
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +#include <linux/linkage.h>
    +#include <asm/assembler.h>
    +
    + .macro pack, rd, hw1, hw2
    + or \rd, \hw1, \hw2 << #16
    + .endm
    +
    +.Linsw_align: mov.a ip, r1 << #31
    + bne .Linsw_noalign
    + ldh ip, [r0]
    + sub r2, r2, #1
    + sth.w ip, [r1]+, #2
    +
    +ENTRY(__raw_readsw)
    + cxor.a r2, #0
    + cmoveq pc, lr
    + cand.a r1, #3
    + bne .Linsw_align
    +
    + sub.a r2, r2, #8
    + bfs .Lno_insw_8
    +
    +.Linsw_8_lp: ldh r3, [r0]
    + ldh r4, [r0]
    + pack r3, r3, r4
    +
    + ldh r4, [r0]
    + ldh r5, [r0]
    + pack r4, r4, r5
    +
    + ldh r5, [r0]
    + ldh ip, [r0]
    + pack r5, r5, ip
    +
    + ldh ip, [r0]
    + ldh r15, [r0]
    + pack ip, ip, r15
    +
    + sub.a r2, r2, #8
    + stm.w (r3 - r5), [r1]+
    + stm.w (ip), [r1]+
    + bns .Linsw_8_lp
    +
    +.Lno_insw_8: cand.a r2, #4
    + beq .Lno_insw_4
    +
    + ldh r3, [r0]
    + ldh r4, [r0]
    + pack r3, r3, r4
    +
    + ldh r4, [r0]
    + ldh ip, [r0]
    + pack r4, r4, ip
    +
    + stm.w (r3, r4), [r1]+
    +
    +.Lno_insw_4: mov.a r2, r2 << #31
    + bub .Lno_insw_2
    +
    + ldh r3, [r0]
    + ldh ip, [r0]
    + pack r3, r3, ip
    + stw.w r3, [r1]+, #4
    +
    +.Lno_insw_2: cmoveq pc, lr
    + ldh r3, [r0]
    + sth r3, [r1]
    + mov pc, lr
    +
    +.Linsw_noalign: bea 201f
    + ldb.w ip, [r1+], #-1
    + b 1f
    +201:
    + ldh ip, [r0]
    + sub r2, r2, #1
    + stb.w ip, [r1]+, #1
    + mov ip, ip >> #8
    +
    +1: sub.a r2, r2, #2
    + bfs 3f
    +
    +2: ldh r3, [r0]
    + ldh r4, [r0]
    + sub.a r2, r2, #2
    + or ip, ip, r3 << #8
    + or ip, ip, r4 << #24
    + stw.w ip, [r1]+, #4
    + mov ip, r4 >> #8
    + bns 2b
    +
    +3: cand.a r2, #1
    + stb.w ip, [r1]+, #1
    + cmoveq pc, lr
    + ldh ip, [r0]
    + stb.w ip, [r1]+, #1
    + mov ip, ip >> #8
    + stb ip, [r1]
    + mov pc, lr
    +ENDPROC(__raw_readsw)
    diff --git a/arch/unicore32/lib/io-writesb.S b/arch/unicore32/lib/io-writesb.S
    new file mode 100644
    index 0000000..bfcb91e
    --- /dev/null
    +++ b/arch/unicore32/lib/io-writesb.S
    @@ -0,0 +1,90 @@
    +/*
    + * linux/arch/unicore32/lib/io-writesb.S
    + *
    + * Code specific to PKUnity SoC and UniCore ISA
    + *
    + * Copyright (C) 2001-2010 GUAN Xue-tao
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +#include <linux/linkage.h>
    +#include <asm/assembler.h>
    +
    + .macro outword, rd
    + stb \rd, [r0]
    + mov \rd, \rd >> #8
    + stb \rd, [r0]
    + mov \rd, \rd >> #8
    + stb \rd, [r0]
    + mov \rd, \rd >> #8
    + stb \rd, [r0]
    + .endm
    +
    +.Loutsb_align: rsub ip, ip, #4
    + csub.a ip, r2
    + cmovsg ip, r2
    + csub.a ip, #2
    + ldb.w r3, [r1]+, #1
    + stb r3, [r0]
    + bsl 201f
    + ldb.w r3, [r1]+, #1
    + stb r3, [r0]
    + bel 201f
    + ldb.w r3, [r1]+, #1
    + stb r3, [r0]
    +201:
    + sub.a r2, r2, ip
    + bne .Loutsb_aligned
    +
    +ENTRY(__raw_writesb)
    + cxor.a r2, #0 @ do we have to check for the zero len?
    + cmoveq pc, lr
    + and.a ip, r1, #3
    + bne .Loutsb_align
    +
    +.Loutsb_aligned:
    +
    + sub.a r2, r2, #16
    + bfs .Loutsb_no_16
    +
    +.Loutsb_16_lp: ldm.w (r3, r4, r5, r14), [r1]+
    + outword r3
    + outword r4
    + outword r5
    + outword r14
    + sub.a r2, r2, #16
    + bns .Loutsb_16_lp
    +
    + cand.a r2, #15
    + cmoveq pc, lr
    +
    +.Loutsb_no_16: cand.a r2, #8
    + beq .Loutsb_no_8
    +
    + ldm.w (r3, r4), [r1]+
    + outword r3
    + outword r4
    +
    +.Loutsb_no_8: cand.a r2, #4
    + beq .Loutsb_no_4
    +
    + ldw.w r3, [r1]+, #4
    + outword r3
    +
    +.Loutsb_no_4: and.a r2, r2, #3
    + cmoveq pc, lr
    +
    + csub.a r2, #2
    + ldb.w r3, [r1]+, #1
    + stb r3, [r0]
    + bsl 201f
    + ldb.w r3, [r1]+, #1
    + stb r3, [r0]
    + bel 201f
    + ldb r3, [r1]
    + stb r3, [r0]
    +201:
    + mov pc, lr
    +ENDPROC(__raw_writesb)
    diff --git a/arch/unicore32/lib/io-writesl.S b/arch/unicore32/lib/io-writesl.S
    new file mode 100644
    index 0000000..a880b47
    --- /dev/null
    +++ b/arch/unicore32/lib/io-writesl.S
    @@ -0,0 +1,69 @@
    +/*
    + * linux/arch/unicore32/lib/io-writesl.S
    + *
    + * Code specific to PKUnity SoC and UniCore ISA
    + *
    + * Copyright (C) 2001-2010 GUAN Xue-tao
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +#include <linux/linkage.h>
    +#include <asm/assembler.h>
    +
    +ENTRY(__raw_writesl)
    + cxor.a r2, #0 @ do we have to check for the zero len?
    + cmoveq pc, lr
    + and.a ip, r1, #3
    + bne 3f
    +
    + sub.a r2, r2, #4
    + bfs 2f
    +1: ldm.w (r3, r4, r14, r15), [r1]+
    + sub.a r2, r2, #4
    + stw r3, [r0+], #0
    + stw r4, [r0+], #0
    + stw r14, [r0+], #0
    + stw r15, [r0+], #0
    + bns 1b
    +2: mov.a r2, r2 << #31
    + bub 201f
    + ldm.w (r3, r14), [r1]+
    + stw r3, [r0+], #0
    + stw r14, [r0+], #0
    +201: cmoveq pc, lr
    + ldw r3, [r1+], #0
    + stw r3, [r0+], #0
    + mov pc, lr
    +
    +3: andn r1, r1, #3
    + ldw.w r3, [r1]+, #4
    + csub.a ip, #2
    + bsl 5f
    + bsg 6f
    +
    +4: mov ip, r3 pull #16
    + ldw.w r3, [r1]+, #4
    + sub.a r2, r2, #1
    + or ip, ip, r3 push #16
    + stw ip, [r0]
    + bne 4b
    + mov pc, lr
    +
    +5: mov ip, r3 pull #8
    + ldw.w r3, [r1]+, #4
    + sub.a r2, r2, #1
    + or ip, ip, r3 push #24
    + stw ip, [r0]
    + bne 5b
    + mov pc, lr
    +
    +6: mov ip, r3 pull #24
    + ldw.w r3, [r1]+, #4
    + sub.a r2, r2, #1
    + or ip, ip, r3 push #8
    + stw ip, [r0]
    + bne 6b
    + mov pc, lr
    +ENDPROC(__raw_writesl)
    diff --git a/arch/unicore32/lib/io-writesw.S b/arch/unicore32/lib/io-writesw.S
    new file mode 100644
    index 0000000..23e1f16
    --- /dev/null
    +++ b/arch/unicore32/lib/io-writesw.S
    @@ -0,0 +1,87 @@
    +/*
    + * linux/arch/unicore32/lib/io-writesw.S
    + *
    + * Code specific to PKUnity SoC and UniCore ISA
    + *
    + * Copyright (C) 2001-2010 GUAN Xue-tao
    + *
    + * This program is free software; you can redistribute it and/or modify
    + * it under the terms of the GNU General Public License version 2 as
    + * published by the Free Software Foundation.
    + */
    +#include <linux/linkage.h>
    +#include <asm/assembler.h>
    +
    + .macro outword, rd
    + sth \rd, [r0]
    + mov \rd, \rd >> #16
    + sth \rd, [r0]
    + .endm
    +
    +.Loutsw_align: mov.a ip, r1 << #31
    + bne .Loutsw_noalign
    +
    + ldh.w r3, [r1]+, #2
    + sub r2, r2, #1
    + sth r3, [r0]
    +
    +ENTRY(__raw_writesw)
    + cxor.a r2, #0
    + cmoveq pc, lr
    + and.a r3, r1, #3
    + bne .Loutsw_align
    +
    + sub.a r2, r2, #8
    + bfs .Lno_outsw_8
    +
    +.Loutsw_8_lp: ldm.w (r3, r4, r5, r14), [r1]+
    + sub.a r2, r2, #8
    + outword r3
    + outword r4
    + outword r5
    + outword r14
    + bns .Loutsw_8_lp
    +
    +.Lno_outsw_8: cand.a r2, #4
    + beq .Lno_outsw_4
    +
    + ldm.w (r3, r14), [r1]+
    + outword r3
    + outword r14
    +
    +.Lno_outsw_4: mov.a r2, r2 << #31
    + bub .Lno_outsw_2
    +
    + ldw.w r3, [r1]+, #4
    + outword r3
    +
    +.Lno_outsw_2: cmoveq pc, lr
    + ldh r3, [r1]
    + sth r3, [r0]
    +
    + mov pc, lr
    +
    +.Loutsw_noalign:
    + ldw.w r3, [r1-], r3
    + bub 201f
    + sub r2, r2, #1
    + b 2f
    +201:
    + sub.a r2, r2, #2
    + bfs 3f
    +
    +1: mov ip, r3 >> #8
    + sth ip, [r0]
    +2: mov ip, r3 >> #24
    + ldw.w r3, [r1+], #4
    + sub.a r2, r2, #2
    + or ip, ip, r3 << #8
    + sth ip, [r0]
    + bns 1b
    +
    + cand.a r2, #1
    +3: cmoveq pc, lr
    + mov ip, r3 >> #8
    + sth ip, [r0]
    + mov pc, lr
    +ENDPROC(__raw_writesw)


    \
     
     \ /
      Last update: 2011-01-03 12:55    [W:3.039 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site