From 7c5351b9c33bb768cb4a5cba2d8af76a5278b9c0 Mon Sep 17 00:00:00 2001 From: Joppe Blondel Date: Thu, 8 Sep 2022 13:29:11 +0200 Subject: [PATCH] Added test firmware for zynq Signed-off-by: Joppe Blondel --- examples/zynq7000/SW/.gitignore | 2 + examples/zynq7000/SW/Makefile | 67 +++++ examples/zynq7000/SW/linker.ld | 89 ++++++ examples/zynq7000/SW/src/boot.S | 87 ++++++ examples/zynq7000/SW/src/main.c | 15 + examples/zynq7000/SW/src/printf.c | 452 ++++++++++++++++++++++++++++++ examples/zynq7000/SW/src/printf.h | 11 + examples/zynq7000/SW/src/uart.c | 105 +++++++ examples/zynq7000/SW/src/uart.h | 11 + examples/zynq7000/SW/src/xil_io.h | 0 examples/zynq7000/SW/src/zynq.h | 33 +++ 11 files changed, 872 insertions(+) create mode 100644 examples/zynq7000/SW/.gitignore create mode 100644 examples/zynq7000/SW/Makefile create mode 100644 examples/zynq7000/SW/linker.ld create mode 100644 examples/zynq7000/SW/src/boot.S create mode 100644 examples/zynq7000/SW/src/main.c create mode 100644 examples/zynq7000/SW/src/printf.c create mode 100644 examples/zynq7000/SW/src/printf.h create mode 100644 examples/zynq7000/SW/src/uart.c create mode 100644 examples/zynq7000/SW/src/uart.h create mode 100644 examples/zynq7000/SW/src/xil_io.h create mode 100644 examples/zynq7000/SW/src/zynq.h diff --git a/examples/zynq7000/SW/.gitignore b/examples/zynq7000/SW/.gitignore new file mode 100644 index 0000000..71ede9b --- /dev/null +++ b/examples/zynq7000/SW/.gitignore @@ -0,0 +1,2 @@ +build +DISASS \ No newline at end of file diff --git a/examples/zynq7000/SW/Makefile b/examples/zynq7000/SW/Makefile new file mode 100644 index 0000000..7b50bf5 --- /dev/null +++ b/examples/zynq7000/SW/Makefile @@ -0,0 +1,67 @@ +.SILENT: + +TARGET := app.elf + +BUILDDIR := build + +SRCDIRS := src +SRCFILESC := $(shell find $(SRCDIRS) -type f -name "*.c") +OBJFILESC := $(SRCFILESC:%.c=$(BUILDDIR)/%.c.o) $(BUILDDIR)/src/ps7_init.o +DEPFILESC := $(SRCFILESC:%.c=$(BUILDDIR)/%.c.d) +SRCFILESA := $(shell find $(SRCDIRS) -type f -name "*.S") +OBJFILESA := $(SRCFILESA:%.S=$(BUILDDIR)/%.S.o) +DEPFILESA := $(SRCFILESA:%.S=$(BUILDDIR)/%.S.d) +SRCFILES := $(SRCFILESC) $(SRCFILESA) +OBJFILES := $(OBJFILESA) $(OBJFILESC) +DEPFILES := $(DEPFILESC) $(DEPFILESA) + +FILESTOCLEAN := $(OBJFILES) $(DEPFILES) $(BUILDDIR)/$(TARGET) + +CROSS_COMPILE ?= arm-none-eabi- +CC := $(CROSS_COMPILE)gcc +AS := $(CROSS_COMPILE)as +LD := $(CROSS_COMPILE)gcc + +CC_WARNING := -Wall -Wextra +CC_LIBS := -lgcc +CC_FLAGS := -nostdlib -fno-builtin -g -mcpu=cortex-a9 +CC_INCLUDES := -I src -I ../OUT/ip/zynqps +LD_FLAGS := -Wl,-Tlinker.ld + +.PHONY: $(TARGET) all clean +all: $(TARGET) + +# PHONY RULES +# ----------- + +$(TARGET): $(BUILDDIR)/$(TARGET) + +clean: + echo CLEAN FILES FOR $(TARGET) + -rm -r $(FILESTOCLEAN) + +# SPECIFIC BUILD RULES +# -------------------- + +$(BUILDDIR)/$(TARGET): $(OBJFILES) + echo 'LD ' $@ + $(LD) $(CC_FLAGS) $(LD_FLAGS) -o $(BUILDDIR)/$(TARGET) $(OBJFILES) $(CC_LIBS) + $(XILINX_BASE)/bin/$(CROSS_COMPILE)objdump -D $(BUILDDIR)/$(TARGET) > DISASS + +$(BUILDDIR)/src/ps7_init.o : ../OUT/ip/zynqps/ps7_init.c ../OUT/ip/zynqps/ps7_init.h + echo 'CC ' $@ + -mkdir -p $(shell dirname $@) + $(CC) $(CC_FLAGS) $(CC_WARNING) $(CC_INCLUDES) -MD -o $(BUILDDIR)/src/ps7_init.o -c ../OUT/ip/zynqps/ps7_init.c + +$(OBJFILES): $(BUILDDIR)/%.c.o: %.c + echo 'CC ' $@ + -mkdir -p $(shell dirname $@) + $(CC) $(CC_FLAGS) $(CC_WARNING) $(CC_INCLUDES) -MD -o $@ -c $< + +$(OBJFILESA): $(BUILDDIR)/%.S.o: %.S + echo 'AS ' $@ + -mkdir -p $(shell dirname $@) + $(CC) $(CC_FLAGS) $(CC_WARNING) $(CC_INCLUDES) -MD -o $@ -c $< + +# Add DEPFILE dependencies +-include $(DEPFILES) \ No newline at end of file diff --git a/examples/zynq7000/SW/linker.ld b/examples/zynq7000/SW/linker.ld new file mode 100644 index 0000000..87089ad --- /dev/null +++ b/examples/zynq7000/SW/linker.ld @@ -0,0 +1,89 @@ +OUTPUT_FORMAT ("elf32-littlearm") + +MEMORY +{ + SRAM_0 : ORIGIN = 0x00000000, LENGTH = 0x00030000 /* 192k */ + SRAM_1 : ORIGIN = 0xFFFF0000, LENGTH = 0x00010000 /* 64k */ + DDR_PS : ORIGIN = 0x00100000, LENGTH = 0x0FF00000 /* 256M */ +} + +EXTERN(__stack_size); +ASSERT(__stack_size, "Must provide a non-zero stack size"); + +EXTERN(_start); + +SECTIONS +{ + + .text : + { + __stext = .; + *(.vectortable) /* Vector table */ + *(.text .text.*) /* Standard Code */ + *(.rodata .rodata.*) /* Constants, strings, ... */ + *(.glue_7) /* Glue ARM to thumb code */ + *(.glue_7t) /* Glue thumb to ARM code */ + __etext = .; + } >DDR_PS + + .data : + { + . = ALIGN(4); + __sdata = .; + *(.data .data.*) + __edata = .; + + } >DDR_PS + + .bss (NOLOAD) : + { + . = ALIGN(4); + __bss_start__ = .; /* Used for zeroing bss on startup */ + *(.bss .bss.*) + __bss_end__ = .; + } >DDR_PS + + . = ALIGN(4); + end = .; + + /* Place all stacks in SRAM_1 - need to avoid filling addresses */ + /* 0xfffffe00 to 0xfffffff0 - proc1 is halted running code in this range */ + /* TODO: assert stacks do not step on proc1's code out of reset */ + .stack (NOLOAD) : + { + . += __stack_size; + __proc0_irq_stack = .; + . += __stack_size; + __proc0_fiq_stack = .; + . += __stack_size; + __proc0_svc_stack = .; + . += __stack_size; + __proc0_abt_stack = .; + . += __stack_size; + __proc0_und_stack = .; + . += __stack_size; + __proc0_sys_stack = .; + . += __stack_size; + __proc1_irq_stack = .; + . += __stack_size; + __proc1_fiq_stack = .; + . += __stack_size; + __proc1_svc_stack = .; + . += __stack_size; + __proc1_abt_stack = .; + . += __stack_size; + __proc1_und_stack = .; + . += __stack_size; + __proc1_sys_stack = .; + . += __stack_size; + } >SRAM_1 + + .data.ddr : + { + *(.data_in_ddr) + } >DDR_PS + + .note.gnu.build-id : { + KEEP (*(.note.gnu.build-id)) + } >DDR_PS +} \ No newline at end of file diff --git a/examples/zynq7000/SW/src/boot.S b/examples/zynq7000/SW/src/boot.S new file mode 100644 index 0000000..919c999 --- /dev/null +++ b/examples/zynq7000/SW/src/boot.S @@ -0,0 +1,87 @@ + .syntax unified /* Use the unified instruction syntax */ + .arm /* Assemble ARM instruction set, not thumb */ + + .equ PROC1_RESET_VECTOR_TABLE, 0xFFFFFFF0 + + .equ CPSR_MODE_USER, 0x10 + .equ CPSR_MODE_FIQ, 0x11 + .equ CPSR_MODE_IRQ, 0x12 + .equ CPSR_MODE_SVC, 0x13 + .equ CPSR_MODE_ABORT, 0x17 + .equ CPSR_MODE_UNDEFINED, 0x8B + .equ CPSR_MODE_SYSTEM, 0x1F + + .equ CPSR_IRQ, 0x80 /* disable IRQ interrupts */ + .equ CPSR_FIQ, 0x40 /* disable FIQ interrupts */ + + .global __stack_size + .equ __stack_size, 0x1000 + +// ------------------ +.section .vectortable +// ------------------ +.global vectortable +vectortable: + /* Exception Processor Mode Event Return Sequence */ + b reset_handler /* MODE_SVC System Reset n/a */ + b undef_handler /* MODE_UNDEFINED Undefined Instruction MOVS PC, LR (if emulating) */ + b SVC_handler /* MODE_SVC SVC instruction MOVS PC, LR */ + b prefetch_abort_handler /* MODE_ABORT Invalid inst. address SUBS PC, LR, #4 */ + b data_abort_handler /* MODE_ABORT R/W to invalid address SUBS PC, LR, #8 (to retry) */ + b hypervisor_handler /* MODE_HYP Hypervisor entry ERET */ + b IRQ_handler /* MODE_IRQ IRQ Input Asserted SUBS PC, LR, #4 */ + b FIQ_handler /* MODE_FIQ FIQ Input Asserted SUBS PC, LR, #4 */ + +reset_handler: + b _start + +undef_handler: + b . + +SVC_handler: + b . + +prefetch_abort_handler: + b . + +data_abort_handler: + b . + +hypervisor_handler: + b . + +IRQ_handler: + b . + +FIQ_handler: + b . + +// ----------- +.section .text +// ----------- +.global _start +_start: + msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_IRQ) /* switch to MODE_IRQ */ + ldr sp, =__proc0_irq_stack /* load IRQ mode stack pointer */ + msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_FIQ) /* switch to MODE_FIQ */ + ldr sp, =__proc0_fiq_stack /* load FIQ mode stack pointer */ + msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_ABORT) /* switch to MODE_ABT */ + ldr sp, =__proc0_abt_stack /* load ABT mode stack pointer */ + msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_UNDEFINED) /* switch to MODE_UND */ + ldr sp, =__proc0_und_stack /* load UND mode stack pointer */ + msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_SYSTEM) /* switch to MODE_SYS */ + ldr sp, =__proc0_sys_stack /* load SYS mode stack pointer */ + msr CPSR, #(CPSR_IRQ | CPSR_FIQ | CPSR_MODE_SVC) /* switch to MODE_SVC */ + ldr sp, =__proc0_svc_stack /* load SVC mode stack pointer */ + /* We are now in SVC mode */ + + /* Set vector table base address */ + ldr r0, =vectortable + mcr p15, #0, r0, c12, c0, #0 + + b main + +_hang: + b _hang + +.end \ No newline at end of file diff --git a/examples/zynq7000/SW/src/main.c b/examples/zynq7000/SW/src/main.c new file mode 100644 index 0000000..0f36916 --- /dev/null +++ b/examples/zynq7000/SW/src/main.c @@ -0,0 +1,15 @@ +#include "ps7_init.h" +#include "zynq.h" +#include "uart.h" +#include "printf.h" + +void main(){ + cpu_disable_interrups(); + // Initialize ZYNQ Processing System + ps7_init(); + // Start UART + uart_setup(); + + printf("Hello World!\n"); + +} \ No newline at end of file diff --git a/examples/zynq7000/SW/src/printf.c b/examples/zynq7000/SW/src/printf.c new file mode 100644 index 0000000..2656a13 --- /dev/null +++ b/examples/zynq7000/SW/src/printf.c @@ -0,0 +1,452 @@ +#include "printf.h" +#include "uart.h" + +#define NULL 0 + +extern int putchar(int c); +static void print_double_float(double val, unsigned int precision); + +static void simple_outputchar(char **str, char c) +{ + if (str) { + **str = c; + ++(*str); + } else { + uart_send(c); + } +} + +enum flags { + PAD_ZERO = 1, + PAD_RIGHT = 2, +}; + +static int prints(char **out, const char *string, int width, int flags) +{ + int pc = 0, padchar = ' '; + + if (width > 0) { + int len = 0; + const char *ptr; + for (ptr = string; *ptr; ++ptr) ++len; + if (len >= width) width = 0; + else width -= len; + if (flags & PAD_ZERO) + padchar = '0'; + } + if (!(flags & PAD_RIGHT)) { + for ( ; width > 0; --width) { + simple_outputchar(out, padchar); + ++pc; + } + } + for ( ; *string ; ++string) { + simple_outputchar(out, *string); + ++pc; + } + for ( ; width > 0; --width) { + simple_outputchar(out, padchar); + ++pc; + } + + return pc; +} + +#define PRINT_BUF_LEN 64 + +static int simple_outputi(char **out, long long i, int base, int sign, int width, int flags, int letbase) +{ + char print_buf[PRINT_BUF_LEN]; + char *s; + int t, neg = 0, pc = 0; + unsigned long long u = i; + + if (i == 0) { + print_buf[0] = '0'; + print_buf[1] = '\0'; + return prints(out, print_buf, width, flags); + } + + if (sign && base == 10 && i < 0) { + neg = 1; + u = -i; + } + + s = print_buf + PRINT_BUF_LEN-1; + *s = '\0'; + + while (u) { + t = u % base; + if( t >= 10 ) + t += letbase - '0' - 10; + *--s = t + '0'; + u /= base; + } + + if (neg) { + if( width && (flags & PAD_ZERO) ) { + simple_outputchar (out, '-'); + ++pc; + --width; + } + else { + *--s = '-'; + } + } + + return pc + prints (out, s, width, flags); +} + + +static int simple_vsprintf(char **out, char *format, va_list ap) +{ + int width, flags; + int pc = 0; + char scr[2]; + union { + char c; + char *s; + int i; + unsigned int u; + long li; + unsigned long lu; + long long lli; + unsigned long long llu; + short hi; + unsigned short hu; + signed char hhi; + unsigned char hhu; + void *p; + double d; + } u; + + for (; *format != 0; ++format) { + if (*format == '%') { + ++format; + width = flags = 0; + if (*format == '\0') + break; + if (*format == '%') + goto out; + if (*format == '-') { + ++format; + flags = PAD_RIGHT; + } + while (*format == '0') { + ++format; + flags |= PAD_ZERO; + } + if (*format == '*') { + width = va_arg(ap, int); + format++; + } else { + for ( ; *format >= '0' && *format <= '9'; ++format) { + width *= 10; + width += *format - '0'; + } + } + switch (*format) { + case('d'): + u.i = va_arg(ap, int); + pc += simple_outputi(out, u.i, 10, 1, width, flags, 'a'); + break; + + case('u'): + u.u = va_arg(ap, unsigned int); + pc += simple_outputi(out, u.u, 10, 0, width, flags, 'a'); + break; + + case('x'): + u.u = va_arg(ap, unsigned int); + pc += simple_outputi(out, u.u, 16, 0, width, flags, 'a'); + break; + + case('X'): + u.u = va_arg(ap, unsigned int); + pc += simple_outputi(out, u.u, 16, 0, width, flags, 'A'); + break; + + case('c'): + u.c = va_arg(ap, int); + scr[0] = u.c; + scr[1] = '\0'; + pc += prints(out, scr, width, flags); + break; + + case('f'): + u.d = va_arg(ap, double); + print_double_float(u.d, width); + break; + + case('s'): + u.s = va_arg(ap, char *); + pc += prints(out, u.s ? u.s : "(null)", width, flags); + break; + case('l'): + ++format; + switch (*format) { + case('d'): + u.li = va_arg(ap, long); + pc += simple_outputi(out, u.li, 10, 1, width, flags, 'a'); + break; + + case('u'): + u.lu = va_arg(ap, unsigned long); + pc += simple_outputi(out, u.lu, 10, 0, width, flags, 'a'); + break; + + case('x'): + u.lu = va_arg(ap, unsigned long); + pc += simple_outputi(out, u.lu, 16, 0, width, flags, 'a'); + break; + + case('X'): + u.lu = va_arg(ap, unsigned long); + pc += simple_outputi(out, u.lu, 16, 0, width, flags, 'A'); + break; + + case('l'): + ++format; + switch (*format) { + case('d'): + u.lli = va_arg(ap, long long); + pc += simple_outputi(out, u.lli, 10, 1, width, flags, 'a'); + break; + + case('u'): + u.llu = va_arg(ap, unsigned long long); + pc += simple_outputi(out, u.llu, 10, 0, width, flags, 'a'); + break; + + case('x'): + u.llu = va_arg(ap, unsigned long long); + pc += simple_outputi(out, u.llu, 16, 0, width, flags, 'a'); + break; + + case('X'): + u.llu = va_arg(ap, unsigned long long); + pc += simple_outputi(out, u.llu, 16, 0, width, flags, 'A'); + break; + + default: + break; + } + break; + default: + break; + } + break; + case('h'): + ++format; + switch (*format) { + case('d'): + u.hi = va_arg(ap, int); + pc += simple_outputi(out, u.hi, 10, 1, width, flags, 'a'); + break; + + case('u'): + u.hu = va_arg(ap, unsigned int); + pc += simple_outputi(out, u.lli, 10, 0, width, flags, 'a'); + break; + + case('x'): + u.hu = va_arg(ap, unsigned int); + pc += simple_outputi(out, u.lli, 16, 0, width, flags, 'a'); + break; + + case('X'): + u.hu = va_arg(ap, unsigned int); + pc += simple_outputi(out, u.lli, 16, 0, width, flags, 'A'); + break; + + case('h'): + ++format; + switch (*format) { + case('d'): + u.hhi = va_arg(ap, int); + pc += simple_outputi(out, u.hhi, 10, 1, width, flags, 'a'); + break; + + case('u'): + u.hhu = va_arg(ap, unsigned int); + pc += simple_outputi(out, u.lli, 10, 0, width, flags, 'a'); + break; + + case('x'): + u.hhu = va_arg(ap, unsigned int); + pc += simple_outputi(out, u.lli, 16, 0, width, flags, 'a'); + break; + + case('X'): + u.hhu = va_arg(ap, unsigned int); + pc += simple_outputi(out, u.lli, 16, 0, width, flags, 'A'); + break; + + default: + break; + } + break; + default: + break; + } + break; + default: + break; + } + } + else { +out: + simple_outputchar (out, *format); + ++pc; + } + } + if (out) **out = '\0'; + return pc; +} + +int printf(char *fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = simple_vsprintf(NULL, fmt, ap); + va_end(ap); + + return r; +} + +int sprintf(char *buf, char *fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = simple_vsprintf(&buf, fmt, ap); + va_end(ap); + + return r; +} + +void hexDump (const char * desc, const void * addr, const int len) { + int i; + unsigned char buff[17]; + const unsigned char * pc = (const unsigned char *)addr; + + // Output description if given. + + if (desc != NULL) + printf ("%s:\n", desc); + + // Length checks. + + if (len == 0) { + printf(" ZERO LENGTH\n"); + return; + } + else if (len < 0) { + printf(" NEGATIVE LENGTH: %d\n", len); + return; + } + + // Process every byte in the data. + + for (i = 0; i < len; i++) { + // Multiple of 16 means new line (with line offset). + + if ((i % 16) == 0) { + // Don't print ASCII buffer for the "zeroth" line. + + if (i != 0) + printf (" %s\n", buff); + + // Output the offset. + + printf (" %04x ", i); + } + + // Now the hex code for the specific character. + printf (" %02x", pc[i]); + + // And buffer a printable ASCII character for later. + + if ((pc[i] < 0x20) || (pc[i] > 0x7e)) // isprint() may be better. + buff[i % 16] = '.'; + else + buff[i % 16] = pc[i]; + buff[(i % 16) + 1] = '\0'; + } + + // Pad out last line if not exactly 16 characters. + + while ((i % 16) != 0) { + printf (" "); + i++; + } + + // And print the final ASCII buffer. + + printf (" %s\n", buff); +} + +#define MAX_PRECISION 50 + +#define IsNaN(n) (n != n) + +// %f: double/single precision support (double or promoted float, 64-bits) +static void print_double_float(double val, unsigned int precision) +{ + unsigned int cur_prec = 1; + if(precision==0) + precision = MAX_PRECISION; + + // if the user-defined precision is out-of-bounds, normalize it + if(precision > MAX_PRECISION) + precision = MAX_PRECISION; + + // if it's negative, show it! + if(val < 0) + { + printf("-"); + + // change to a positive value + val = -val; + } + + // check to see if it is Not-a-Number + if(IsNaN(val)) + { + printf("NaN"); + return; + } + + // print the integer part of the floating point + printf("%d", (int)val); + + // if precision == 0, only print the integer part + if(!precision) + return; + + // now on to the decimal potion + printf("."); + + // remove the integer part + val -= (double)((int)val); + + /* on every iteration, make sure there are still decimal places left that are non-zero, + and make sure we're still within the user-defined precision range. */ + while(val > (double)((int)val) && cur_prec++ < precision+1) + { + // move the next decimal into the integer portion and print it + val *= 10; + printf("%d", (int)val); + + /* if the value is == the floored value (integer portion), + then there are no more decimal places that are non-zero. */ + if(val == (double)((int)val)) + return; + + // subtract the integer portion + val -= (double)((int)val); + } +} \ No newline at end of file diff --git a/examples/zynq7000/SW/src/printf.h b/examples/zynq7000/SW/src/printf.h new file mode 100644 index 0000000..486fd7c --- /dev/null +++ b/examples/zynq7000/SW/src/printf.h @@ -0,0 +1,11 @@ +#ifndef __H_KPRINTF +#define __H_KPRINTF 1 + +#include + +int printf(char * fmt, ...); +int sprintf(char * buf, char * fmt, ...); + +void hexDump (const char * desc, const void * addr, const int len); + +#endif \ No newline at end of file diff --git a/examples/zynq7000/SW/src/uart.c b/examples/zynq7000/SW/src/uart.c new file mode 100644 index 0000000..cf4f583 --- /dev/null +++ b/examples/zynq7000/SW/src/uart.c @@ -0,0 +1,105 @@ +#include "uart.h" +#include "stdint.h" + +#define XUARTPS_CR_TXRST 0x00000002U /**< TX logic reset */ +#define XUARTPS_CR_RXRST 0x00000001U /**< RX logic reset */ + +#define XUARTPS_CR_OFFSET 0x0000U /**< Control Register [8:0] */ +#define XUARTPS_MR_OFFSET 0x0004U /**< Mode Register [9:0] */ +#define XUARTPS_BAUDGEN_OFFSET 0x0018U /**< Baud Rate Generator [15:0] */ +#define XUARTPS_BAUDDIV_OFFSET 0x0034U /**< Baud Rate Divider [7:0] */ +#define XUARTPS_FIFO_OFFSET 0x0030U /**< FIFO [7:0] */ +#define XUARTPS_SR_OFFSET 0x002CU /**< Channel Status [14:0] */ +#define XPS_UART1_BASEADDR 0xE0001000U + +#define XUARTPS_MR_CHMODE_NORM 0x00000000U /**< Normal mode */ +#define XUARTPS_MR_STOPMODE_1_BIT 0x00000000U /**< 1 stop bit */ +#define XUARTPS_MR_PARITY_NONE 0x00000020U /**< No parity mode */ +#define XUARTPS_MR_CHARLEN_8_BIT 0x00000000U /**< 8 bits data */ +#define XUARTPS_MR_CLKSEL 0x00000001U /**< Input clock selection */ + +#define XUARTPS_SR_TNFUL 0x00004000U /**< TX FIFO Nearly Full Status */ +#define XUARTPS_SR_TACTIVE 0x00000800U /**< TX active */ +#define XUARTPS_SR_RXEMPTY 0x00000002U /**< RX FIFO empty */ + +#define XUARTPS_CR_TX_DIS 0x00000020U /**< TX disabled. */ +#define XUARTPS_CR_TX_EN 0x00000010U /**< TX enabled */ +#define XUARTPS_CR_RX_DIS 0x00000008U /**< RX disabled. */ +#define XUARTPS_CR_RX_EN 0x00000004U /**< RX enabled */ + +#define POINTER_TO_REGISTER(REG) ( *((volatile uint32_t*)(REG))) + +#define UART_BASE XPS_UART1_BASEADDR +#define UART_CTRL POINTER_TO_REGISTER(UART_BASE + XUARTPS_CR_OFFSET) // Control Register +#define UART_MODE POINTER_TO_REGISTER(UART_BASE + XUARTPS_MR_OFFSET) // Mode Register + +#define UART_BAUD_GEN POINTER_TO_REGISTER(UART_BASE + XUARTPS_BAUDGEN_OFFSET) // Baud Rate Generator "CD" +#define UART_BAUD_DIV POINTER_TO_REGISTER(UART_BASE + XUARTPS_BAUDDIV_OFFSET) // Baud Rate Divider "BDIV" +#define UART_FIFO POINTER_TO_REGISTER(UART_BASE + XUARTPS_FIFO_OFFSET) // FIFO +#define UART_STATUS POINTER_TO_REGISTER(UART_BASE + XUARTPS_SR_OFFSET) // Channel Status + +#define BUFLEN 127 + +static uint16_t end_ndx; +static char buf[BUFLEN+1]; +#define buf_len ((end_ndx - start_ndx) % BUFLEN) +static inline int inc_ndx(int n) { return ((n + 1) % BUFLEN); } +static inline int dec_ndx(int n) { return (((n + BUFLEN) - 1) % BUFLEN); } + +void uart_send(char c) { + while (UART_STATUS & XUARTPS_SR_TNFUL); + UART_FIFO = c; + while (UART_STATUS & XUARTPS_SR_TACTIVE); +} + +char uart_recv() { + if ((UART_STATUS & XUARTPS_SR_RXEMPTY) == XUARTPS_SR_RXEMPTY) + return 0; + + return UART_FIFO; +} + +char uart_recv_blocking() { + while ((UART_STATUS & XUARTPS_SR_RXEMPTY) == XUARTPS_SR_RXEMPTY); + return UART_FIFO; +} + +void uart_setup(void) { + uint32_t r = 0; // Temporary value variable + r = UART_CTRL; + r &= ~(XUARTPS_CR_TX_EN | XUARTPS_CR_RX_EN); // Clear Tx & Rx Enable + r |= XUARTPS_CR_RX_DIS | XUARTPS_CR_TX_DIS; // Tx & Rx Disable + UART_CTRL = r; + + UART_MODE = 0; + UART_MODE &= ~XUARTPS_MR_CLKSEL; // Clear "Input clock selection" - 0: clock source is uart_ref_clk + UART_MODE |= XUARTPS_MR_CHARLEN_8_BIT; // Set "8 bits data" + UART_MODE |= XUARTPS_MR_PARITY_NONE; // Set "No parity mode" + UART_MODE |= XUARTPS_MR_STOPMODE_1_BIT; // Set "1 stop bit" + UART_MODE |= XUARTPS_MR_CHMODE_NORM; // Set "Normal mode" + + // baud_rate = sel_clk / (CD * (BDIV + 1) (ref: UG585 - TRM - Ch. 19 UART) + UART_BAUD_DIV = 6; // ("BDIV") + UART_BAUD_GEN = 124; // ("CD") + // Baud Rate = 100Mhz / (124 * (6 + 1)) = 115200 bps + + UART_CTRL |= (XUARTPS_CR_TXRST | XUARTPS_CR_RXRST); // TX & RX logic reset + + r = UART_CTRL; + r |= XUARTPS_CR_RX_EN | XUARTPS_CR_TX_EN; // Set TX & RX enabled + r &= ~(XUARTPS_CR_RX_DIS | XUARTPS_CR_TX_DIS); // Clear TX & RX disabled + UART_CTRL = r; +} + +void uart_back_up(void){ + end_ndx = dec_ndx(end_ndx); + uart_send('\010'); + uart_send(' '); + uart_send('\010'); +} + +void uart_puts(char * s){ + while(*s){ + uart_send(*(s++)); + } +} \ No newline at end of file diff --git a/examples/zynq7000/SW/src/uart.h b/examples/zynq7000/SW/src/uart.h new file mode 100644 index 0000000..7455956 --- /dev/null +++ b/examples/zynq7000/SW/src/uart.h @@ -0,0 +1,11 @@ +#ifndef __H_UART +#define __H_UART 1 + +void uart_send(char c); +char uart_recv(); +char uart_recv_blocking(); +void uart_setup(void); +void uart_back_up(void); +void uart_puts(char * s); + +#endif \ No newline at end of file diff --git a/examples/zynq7000/SW/src/xil_io.h b/examples/zynq7000/SW/src/xil_io.h new file mode 100644 index 0000000..e69de29 diff --git a/examples/zynq7000/SW/src/zynq.h b/examples/zynq7000/SW/src/zynq.h new file mode 100644 index 0000000..263eeb2 --- /dev/null +++ b/examples/zynq7000/SW/src/zynq.h @@ -0,0 +1,33 @@ +#ifndef __H_ZYNQ +#define __H_ZYNQ 1 + +#define ZYNQ_PERIPH_PHY_BASE 0xF8000000 + +#define ZYNQ_PERIPH_TTC0_BASE (ZYNQ_PERIPH_PHY_BASE + 0x1000) + +#define ZYNQ_PRI_PERIPH_PHYS_BASE 0xF8F00000 +#define ZYNQ_PERIPH_SIZE 0x2000 + +#define ZYNQ_SCU_PHYS_BASE (ZYNQ_PRI_PERIPH_PHYS_BASE + 0) +#define ZYNQ_SCU_SIZE 0x0100 + +#define ZYNQ_GIC_CPU_PHYS_BASE (ZYNQ_PRI_PERIPH_PHYS_BASE + 0x100) +#define ZYNQ_GIC_CPU_SIZE 0x0100 + +#define ZYNQ_GTIMER_PHYS_BASE (ZYNQ_PRI_PERIPH_PHYS_BASE + 0x200) +#define ZYNQ_GTIMER_SIZE 0x0100 + +#define ZYNQ_PTIMER_WDT_PHYS_BASE (ZYNQ_PRI_PERIPH_PHYS_BASE + 0x600) +#define ZYNQ_PTIMER_WDT_SIZE 0x0100 + +#define ZYNQ_GIC_DIST_PHYS_BASE (ZYNQ_PRI_PERIPH_PHYS_BASE + 0x1000) +#define ZYNQ_GIC_DIST_SIZE 0x1000 + +#define WRITE32(_reg, _val) (*(volatile uint32_t*)&_reg = _val) +#define WRITE16(_reg, _val) (*(volatile uint16_t*)&_reg = _val) +#define WRITE8(_reg, _val) (*(volatile uint8_t*)&_reg = _val) + +#define cpu_disable_interrups() asm ("cpsid if") +#define cpu_enable_interrups() asm ("cpsie if") + +#endif \ No newline at end of file