Commit 3a06e007 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

added hello world & UART bootloader

parent 8680d785
/*
* DSI Shield
*
* Copyright (C) 2013-2014 twl
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* board.h - system/hardware definitions */
#ifndef __BOARD_H
#define __BOARD_H
#include <stdint.h>
#define BASE_CLOCK 62500000 // Xtal frequency
#define BASE_UART 0x20000
#define BASE_GPIO 0x21000
#define UART_BAUDRATE 115200
static inline void writel ( uint32_t reg, uint32_t val)
{
*(volatile uint32_t *)(reg) = val;
}
static inline uint32_t readl ( uint32_t reg )
{
return *(volatile uint32_t *)(reg);
}
#endif
.section .boot, "ax", @progbits
.global _start
_start:
la gp, _gp # Initialize global pointer
la sp, _fstack
# clear the bss segment
la t0, _fbss
la t1, _end
1:
#ifdef __riscv64
sd zero,0(t0)
addi t0, t0, 8
#else
sw zero,0(t0)
addi t0, t0, 4
#endif
bltu t0, t1, 1b
call main
\ No newline at end of file
/*
Register definitions for slave core: Simple Wishbone UART
* File : ../../../../software/include/hw/wb_uart.h
* Author : auto-generated by wbgen2 from uart.wb
* Created : Mon Feb 21 22:25:02 2011
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE uart.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_UART_WB
#define __WBGEN2_REGDEFS_UART_WB
#include <inttypes.h>
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Status Register */
/* definitions for field: TX busy in reg: Status Register */
#define UART_SR_TX_BUSY WBGEN2_GEN_MASK(0, 1)
/* definitions for field: RX ready in reg: Status Register */
#define UART_SR_RX_RDY WBGEN2_GEN_MASK(1, 1)
/* definitions for register: Baudrate control register */
/* definitions for register: Transmit data regsiter */
/* definitions for field: Transmit data in reg: Transmit data regsiter */
#define UART_TDR_TX_DATA_MASK WBGEN2_GEN_MASK(0, 8)
#define UART_TDR_TX_DATA_SHIFT 0
#define UART_TDR_TX_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define UART_TDR_TX_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* definitions for register: Receive data regsiter */
/* definitions for field: Received data in reg: Receive data regsiter */
#define UART_RDR_RX_DATA_MASK WBGEN2_GEN_MASK(0, 8)
#define UART_RDR_RX_DATA_SHIFT 0
#define UART_RDR_RX_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 8)
#define UART_RDR_RX_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 8)
/* [0x0]: REG Status Register */
#define UART_REG_SR 0x00000000
/* [0x4]: REG Baudrate control register */
#define UART_REG_BCR 0x00000004
/* [0x8]: REG Transmit data regsiter */
#define UART_REG_TDR 0x00000008
/* [0xc]: REG Receive data regsiter */
#define UART_REG_RDR 0x0000000c
PACKED struct UART_WB {
/* [0x0]: REG Status Register */
uint32_t SR;
/* [0x4]: REG Baudrate control register */
uint32_t BCR;
/* [0x8]: REG Transmit data regsiter */
uint32_t TDR;
/* [0xc]: REG Receive data regsiter */
uint32_t RDR;
};
#endif
OUTPUT_FORMAT("elf32-littleriscv")
ENTRY(_start)
SECTIONS
{
/*--------------------------------------------------------------------*/
/* Code and read-only segment */
/*--------------------------------------------------------------------*/
/* Begining of code and text segment */
. = 0x00000000;
_ftext = .;
PROVIDE( eprol = . );
/* text: Program code section */
.text :
{
*(.boot)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
}
/* init: Code to execute before main (called by crt0.S) */
.init :
{
KEEP( *(.init) )
}
/* fini: Code to execute after main (called by crt0.S) */
.fini :
{
KEEP( *(.fini) )
}
/* rodata: Read-only data */
.rodata :
{
*(.rdata)
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
}
/* End of code and read-only segment */
PROVIDE( etext = . );
_etext = .;
/*--------------------------------------------------------------------*/
/* Global constructor/destructor segement */
/*--------------------------------------------------------------------*/
/* The .ctors/.dtors sections are special sections which contain a
list of constructor/destructor function pointers. crtbegin.o
includes code in a .init section which goes through the .ctors list
and calls each constuctor. crtend.o includes code in a .fini
section which goes through the .dtors list and calls each
destructor. crtbegin.o includes a special null pointer in its own
.ctors/.dtors sections which acts as a start indicator for those
lists. crtend.o also includes a special null pointer in its own
.ctors/.dtors sections which acts as an end indictor. The linker
commands below are setup so that crtbegin.o's .ctors/.dtors
sections are always first and crtend.o's .ctors/.dtors sections are
always last. This is the only way the list of functions will have
the begin and end indicators in the right place. */
/* ctors : Array of global constructor function pointers */
/*--------------------------------------------------------------------*/
/* Initialized data segment */
/*--------------------------------------------------------------------*/
/* Start of initialized data segment */
. = ALIGN(16);
_fdata = .;
/* data: Writable data */
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
}
/* End of initialized data segment */
PROVIDE( edata = . );
_edata = .;
/* Have _gp point to middle of sdata/sbss to maximize displacement range */
. = ALIGN(16);
_gp = . + 0x800;
/* Writable small data segment */
.sdata :
{
*(.sdata)
*(.sdata.*)
*(.srodata.*)
*(.gnu.linkonce.s.*)
}
/*--------------------------------------------------------------------*/
/* Uninitialized data segment */
/*--------------------------------------------------------------------*/
/* Start of uninitialized data segment */
. = ALIGN(8);
_fbss = .;
/* Writable uninitialized small data segment */
.sbss :
{
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
}
/* bss: Uninitialized writeable data section */
. = .;
_bss_start = .;
.bss :
{
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
}
/* End of uninitialized data segment (used by syscalls.c for heap) */
PROVIDE( end = . );
_end = ALIGN(8);
PROVIDE( _fstack = 0xfffc );
}
/*
* DSI Shield
*
* Copyright (C) 2013-2014 twl
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* uart.c - simple UART driver */
#include <stdint.h>
#include "uart.h"
#include "board.h"
#include <hw/wb_uart.h>
#define CALC_BAUD(baudrate) \
( ((( (unsigned int)baudrate << 12)) + \
(BASE_CLOCK >> 8)) / (BASE_CLOCK >> 7) )
volatile struct UART_WB *uart;
void uart_init_hw()
{
uart = (volatile struct UART_WB *)BASE_UART;
#ifndef SIMULATION
uart->BCR = CALC_BAUD(UART_BAUDRATE);
#else
uart->BCR = CALC_BAUD((CPU_CLOCK/10));
#endif
}
void uart_write_byte(int b)
{
if (b == '\n')
uart_write_byte('\r');
while (uart->SR & UART_SR_TX_BUSY)
;
uart->TDR = b;
}
int uart_poll()
{
return uart->SR & UART_SR_RX_RDY;
}
int uart_read_byte()
{
if (!uart_poll())
return -1;
return uart->RDR & 0xff;
}
int puts(const char *s)
{
char c;
while(c=*s++)
uart_write_byte(c);
}
/*
* DSI Shield
*
* Copyright (C) 2013-2014 twl
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __UART_H
#define __UART_H
void uart_init_sw(void);
void uart_init_hw(void);
void uart_write_byte(int b);
int uart_write_string(const char *s);
int puts(const char *s);
int uart_read_byte(void);
/* uart-sw is used by ppsi (but may be wrapped to normal uart) */
int uart_sw_write_string(const char *s);
#endif
......@@ -20,14 +20,28 @@ int main(int argc, char *argv[])
int i = 0;
int n = atoi(argv[2]);
while (!feof(f)) {
int base = 0;
int file_pos = 0;
if(argc >= 5)
{
file_pos = atoi(argv[3]);
base = atoi(argv[4]);
}
fseek(f, file_pos, SEEK_SET);
while (!feof(f) && (n == 0 || (i < n))) {
fread(x, 1, 4, f);
printf("write %x %02X%02X%02X%02X\n", i++, x[3], x[2], x[1],
printf("write %x %02X%02X%02X%02X\n", base + i, x[3], x[2], x[1],
x[0]);
i++;
}
for (; i < n;) {
printf("write %x %02X%02X%02X%02X\n", i++, 0, 0, 0, 0);
printf("write %x %02X%02X%02X%02X\n", base + i, 0, 0, 0, 0);
i++;
}
fclose(f);
return 0;
......
# and don't touch the rest unless you know what you're doing.
CROSS_COMPILE ?= /opt/gcc-riscv/bin/riscv64-unknown-elf-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
CFLAGS = -g -m32 -msoft-float -march=RV32I -I. -I../common
OBJS = ../common/crt0.o main.o ../common/uart.o
LDS = ../common/ram2.ld
OUTPUT=hello
$(OUTPUT): $(LDS) $(OBJS)
${CC} -g -m32 -msoft-float -march=RV32I -o $(OUTPUT).elf -nostartfiles $(OBJS) -lm -T $(LDS)
${OBJCOPY} -O binary $(OUTPUT).elf $(OUTPUT).bin
${OBJDUMP} -D $(OUTPUT).elf > disasm.S
# ../genraminit $(OUTPUT).bin 1024 0 0 > uart-bootloader.ram
$(SIZE) $(OUTPUT).elf
clean:
rm -f $(OUTPUT).elf $(OUTPUT).bin $(OBJS)
%.o: %.S
${CC} -c -m32 $^ -o $@
\ No newline at end of file
#include "board.h"
#include "uart.h"
#define GPIO_CODR 0x0
#define GPIO_SODR 0x4
void gpio_set(int pin, int value)
{
if(value)
*(volatile uint32_t *) ( BASE_GPIO + GPIO_SODR ) = (1<<pin);
else
*(volatile uint32_t *) ( BASE_GPIO + GPIO_CODR ) = (1<<pin);
}
void delay(int v)
{
volatile int i;
for(i=0;i<v;i++);
}
main()
{
uart_init_hw();
for(;;)
{
puts("Hello, world!\n\r");
gpio_set(0, 1);
gpio_set(1, 1);
gpio_set(2, 1);
gpio_set(3, 1);
delay(1000000);
gpio_set(0, 0);
gpio_set(1, 0);
gpio_set(2, 0);
gpio_set(3, 0);
delay(1000000);
}
}
#!/usr/bin/python
our_port="/dev/ttyUSB0"
import sys
import time
import serial
ser = serial.Serial(port=our_port,baudrate=115200,timeout=1,rtscts=False)
fw = open(sys.argv[1], "rb").read()
while(ser.read(1) != 'B'):
pass
while(ser.read(1) != 'o'):
pass
while(ser.read(1) != 'o'):
pass
while(ser.read(1) != 't'):
pass
while(ser.read(1) != '?'):
pass
time.sleep(0.01)
ser.write('Y')
while(ser.read(1) != 'O'):
pass
while(ser.read(1) != 'K'):
pass
time.sleep(10e-6);
l = len(fw)
print("Bootloader OK, writing %d bytes." % l)
ser.write(chr((l >> 24) & 0xff));
time.sleep(100e-6);
ser.write(chr((l >> 16) & 0xff));
time.sleep(100e-6);
ser.write(chr((l >> 8) & 0xff));
time.sleep(100e-6);
ser.write(chr((l >> 0) & 0xff));
n=0
for b in fw:
n+=1
ser.write(b)
time.sleep(100e-6)
if n % 10000 == 0:
print("%d/%d bytes programmed." % (n,len(fw)))
while(ser.read(1) != 'G'):
time.sleep(100e-6)
print("Programming done!")
# and don't touch the rest unless you know what you're doing.
CROSS_COMPILE ?= /opt/gcc-riscv/bin/riscv64-unknown-elf-
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
OBJDUMP = $(CROSS_COMPILE)objdump
OBJCOPY = $(CROSS_COMPILE)objcopy
SIZE = $(CROSS_COMPILE)size
CFLAGS = -g -m32 -msoft-float -march=RV32I -O2 -I. -I../common
OBJS = ../common/crt0.o boot.o ../common/uart.o
LDS = boot.ld
OUTPUT=uart-bootloader
$(OUTPUT): $(LDS) $(OBJS)
${CC} -g -m32 -msoft-float -march=RV32I -o $(OUTPUT).elf -nostartfiles $(OBJS) -lm -T $(LDS)
${OBJCOPY} -O binary $(OUTPUT).elf $(OUTPUT).bin
${OBJDUMP} -D $(OUTPUT).elf > disasm.S
$(SIZE) $(OUTPUT).elf
../genraminit $(OUTPUT).bin 32 0 0 > uart-bootloader.ram
../genraminit $(OUTPUT).bin 512 63488 15872 >> uart-bootloader.ram
clean:
rm -f $(OUTPUT).elf $(OUTPUT).bin $(OBJS)
%.o: %.S
${CC} -c -m32 $^ -o $@
\ No newline at end of file
/* boot.c - a trivial serial port bootloader for LM32.
Public domain.
Awful code below. Be warned. */
#include <stdint.h>
#include "board.h"
#include "uart.h"
#define USER_START 0x0
const char hexchars[] = "0123456789abcdef";
void dump_int(uint32_t v)
{
int i;
for(i=7;i>=0;i--)
{
uart_write_byte(hexchars[(v>>(i*4)) & 0xf]);
}
uart_write_byte('\n');
uart_write_byte('\r');
}
int read_blocking(uint8_t *what)
{
int cnt = 500000;
int b;
while(cnt--)
{
b=uart_read_byte();
if(b >= 0)
break;
}
if(cnt)
{
*what = b;
return 0;
}else
return -1;
}
main()
{
int i;
int len, boot_active = 0;
uint8_t *ptr;
uart_init_hw();
again:
len = 0;
boot_active = 0;
ptr = (uint8_t*)USER_START;
uart_write_byte('B');
uart_write_byte('o');
uart_write_byte('o');
uart_write_byte('t');
uart_write_byte('?');
for(i=0;i<500000;i++)
if(uart_read_byte () == 'Y')
{
boot_active = 1;
break;
}
if(boot_active)
{
uint8_t b;
uart_write_byte('O');
uart_write_byte('K');
if(read_blocking(&b) < 0) goto again;
len = (uint32_t)b;
len <<=8;
if(read_blocking(&b) < 0) goto again;
len |= (uint32_t)b;
len <<=8;
if(read_blocking(&b) < 0) goto again;
len |= (uint32_t)b;
len <<=8;
if(read_blocking(&b) < 0) goto again;
len |= (uint32_t)b;
for(i=0;i<len;i++)
{
if(read_blocking(ptr) < 0)
goto again;
ptr++;
}
uart_write_byte('G');
uart_write_byte('o');
uart_write_byte('!');
void (*f)() = USER_START;
f();
} else {
uart_write_byte('T');
uart_write_byte('o');
uart_write_byte('u');
uart_write_byte('t');
void (*f)() = USER_START;
f();
// goto again;
}
}
OUTPUT_FORMAT("elf32-littleriscv")
ENTRY(_start)
SECTIONS
{
/*--------------------------------------------------------------------*/
/* Code and read-only segment */
/*--------------------------------------------------------------------*/
/* Begining of code and text segment */
. = 0x00000000;
.boot : { *(.boot) }
. = 0x0000f800;
_ftext = .;
PROVIDE( eprol = . );
/* text: Program code section */
.text :
{
*(.boot)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
}
/* init: Code to execute before main (called by crt0.S) */
.init :
{
KEEP( *(.init) )
}
/* fini: Code to execute after main (called by crt0.S) */
.fini :
{
KEEP( *(.fini) )
}
/* rodata: Read-only data */
.rodata :
{
*(.rdata)
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
}
/* End of code and read-only segment */
PROVIDE( etext = . );
_etext = .;
/*--------------------------------------------------------------------*/
/* Global constructor/destructor segement */
/*--------------------------------------------------------------------*/
/* The .ctors/.dtors sections are special sections which contain a
list of constructor/destructor function pointers. crtbegin.o
includes code in a .init section which goes through the .ctors list
and calls each constuctor. crtend.o includes code in a .fini
section which goes through the .dtors list and calls each
destructor. crtbegin.o includes a special null pointer in its own
.ctors/.dtors sections which acts as a start indicator for those
lists. crtend.o also includes a special null pointer in its own
.ctors/.dtors sections which acts as an end indictor. The linker
commands below are setup so that crtbegin.o's .ctors/.dtors
sections are always first and crtend.o's .ctors/.dtors sections are
always last. This is the only way the list of functions will have
the begin and end indicators in the right place. */
/* ctors : Array of global constructor function pointers */
/*--------------------------------------------------------------------*/
/* Initialized data segment */
/*--------------------------------------------------------------------*/
/* Start of initialized data segment */
. = ALIGN(16);
_fdata = .;
/* data: Writable data */
.data :
{
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
}
/* End of initialized data segment */
PROVIDE( edata = . );
_edata = .;
/* Have _gp point to middle of sdata/sbss to maximize displacement range */
. = ALIGN(16);
_gp = . + 0x800;
/* Writable small data segment */
.sdata :
{
*(.sdata)
*(.sdata.*)
*(.srodata.*)
*(.gnu.linkonce.s.*)
}
/*--------------------------------------------------------------------*/
/* Uninitialized data segment */
/*--------------------------------------------------------------------*/
/* Start of uninitialized data segment */
. = ALIGN(8);
_fbss = .;
/* Writable uninitialized small data segment */
.sbss :
{
*(.sbss)
*(.sbss.*)
*(.gnu.linkonce.sb.*)
}
/* bss: Uninitialized writeable data section */
. = .;
_bss_start = .;
.bss :
{
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
*(COMMON)
}
/* End of uninitialized data segment (used by syscalls.c for heap) */
PROVIDE( end = . );
_end = ALIGN(8);
PROVIDE( _fstack = 0xfffc );
}
.section .boot, "ax", @progbits
.global _start
_start:
la gp, _gp # Initialize global pointer
la sp, _fstack
# clear the bss segment
la t0, _fbss
la t1, _end
1:
#ifdef __riscv64
sd zero,0(t0)
addi t0, t0, 8
#else
sw zero,0(t0)
addi t0, t0, 4
#endif
bltu t0, t1, 1b
call main
\ No newline at end of file
/*
* DSI Shield
*
* Copyright (C) 2013-2014 twl
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* uart.c - simple UART driver */
#include <stdint.h>
#include "uart.h"
#include "board.h"
#include <hw/wb_uart.h>
#define CALC_BAUD(baudrate) \
( ((( (unsigned int)baudrate << 12)) + \
(BASE_CLOCK >> 8)) / (BASE_CLOCK >> 7) )
volatile struct UART_WB *uart;
void uart_init_hw()
{
uart = (volatile struct UART_WB *)BASE_UART;
#ifndef SIMULATION
uart->BCR = CALC_BAUD(UART_BAUDRATE);
#else
uart->BCR = CALC_BAUD((CPU_CLOCK/10));
#endif
}
void uart_write_byte(int b)
{
if (b == '\n')
uart_write_byte('\r');
while (uart->SR & UART_SR_TX_BUSY)
;
uart->TDR = b;
}
int uart_poll()
{
return uart->SR & UART_SR_RX_RDY;
}
int uart_read_byte()
{
if (!uart_poll())
return -1;
return uart->RDR & 0xff;
}
int puts(const char *s)
{
char c;
while(c=*s++)
uart_write_byte(c);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment