Skip to content

Commit

Permalink
Add inline assembly example using pru-gcc
Browse files Browse the repository at this point in the history
The assembly example uses the GAS syntax for inline asm. The no of times
the LED has to blink is specified by writing to the rpmsg channel and
the LED is blinked the appropriate no of times in assembly.
  • Loading branch information
MuneebMohammed committed Jun 20, 2018
1 parent 6260772 commit 252d826
Show file tree
Hide file tree
Showing 4 changed files with 467 additions and 0 deletions.
86 changes: 86 additions & 0 deletions examples/firmware_examples/inline_asm/AM335x_PRU.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/****************************************************************************/

This comment has been minimized.

Copy link
@dinuxbg

dinuxbg Jun 20, 2018

The TI linker file could be removed. I don't see rules to build with TI CGT, and pru-gcc has its own linker configuration files.

/* AM335x_PRU.cmd */
/* Copyright (c) 2015 Texas Instruments Incorporated */
/* */
/* Description: This file is a linker command file that can be used for */
/* linking PRU programs built with the C compiler and */
/* the resulting .out file on an AM335x device. */
/****************************************************************************/

-cr /* Link using C conventions */

/* Specify the System Memory Map */
MEMORY
{
PAGE 0:
PRU_IMEM : org = 0x00000000 len = 0x00002000 /* 8kB PRU0 Instruction RAM */

PAGE 1:

/* RAM */

PRU_DMEM_0_1 : org = 0x00000000 len = 0x00002000 CREGISTER=24 /* 8kB PRU Data RAM 0_1 */
PRU_DMEM_1_0 : org = 0x00002000 len = 0x00002000 CREGISTER=25 /* 8kB PRU Data RAM 1_0 */

PAGE 2:
PRU_SHAREDMEM : org = 0x00010000 len = 0x00003000 CREGISTER=28 /* 12kB Shared RAM */

DDR : org = 0x80000000 len = 0x00000100 CREGISTER=31
L3OCMC : org = 0x40000000 len = 0x00010000 CREGISTER=30


/* Peripherals */

PRU_CFG : org = 0x00026000 len = 0x00000044 CREGISTER=4
PRU_ECAP : org = 0x00030000 len = 0x00000060 CREGISTER=3
PRU_IEP : org = 0x0002E000 len = 0x0000031C CREGISTER=26
PRU_INTC : org = 0x00020000 len = 0x00001504 CREGISTER=0
PRU_UART : org = 0x00028000 len = 0x00000038 CREGISTER=7

DCAN0 : org = 0x481CC000 len = 0x000001E8 CREGISTER=14
DCAN1 : org = 0x481D0000 len = 0x000001E8 CREGISTER=15
DMTIMER2 : org = 0x48040000 len = 0x0000005C CREGISTER=1
PWMSS0 : org = 0x48300000 len = 0x000002C4 CREGISTER=18
PWMSS1 : org = 0x48302000 len = 0x000002C4 CREGISTER=19
PWMSS2 : org = 0x48304000 len = 0x000002C4 CREGISTER=20
GEMAC : org = 0x4A100000 len = 0x0000128C CREGISTER=9
I2C1 : org = 0x4802A000 len = 0x000000D8 CREGISTER=2
I2C2 : org = 0x4819C000 len = 0x000000D8 CREGISTER=17
MBX0 : org = 0x480C8000 len = 0x00000140 CREGISTER=22
MCASP0_DMA : org = 0x46000000 len = 0x00000100 CREGISTER=8
MCSPI0 : org = 0x48030000 len = 0x000001A4 CREGISTER=6
MCSPI1 : org = 0x481A0000 len = 0x000001A4 CREGISTER=16
MMCHS0 : org = 0x48060000 len = 0x00000300 CREGISTER=5
SPINLOCK : org = 0x480CA000 len = 0x00000880 CREGISTER=23
TPCC : org = 0x49000000 len = 0x00001098 CREGISTER=29
UART1 : org = 0x48022000 len = 0x00000088 CREGISTER=11
UART2 : org = 0x48024000 len = 0x00000088 CREGISTER=12

RSVD10 : org = 0x48318000 len = 0x00000100 CREGISTER=10
RSVD13 : org = 0x48310000 len = 0x00000100 CREGISTER=13
RSVD21 : org = 0x00032400 len = 0x00000100 CREGISTER=21
RSVD27 : org = 0x00032000 len = 0x00000100 CREGISTER=27

}

/* Specify the sections allocation into memory */
SECTIONS {
/* Forces _c_int00 to the start of PRU IRAM. Not necessary when loading
an ELF file, but useful when loading a binary */
.text:_c_int00* > 0x0, PAGE 0

.text > PRU_IMEM, PAGE 0
.stack > PRU_DMEM_0_1, PAGE 1
.bss > PRU_DMEM_0_1, PAGE 1
.cio > PRU_DMEM_0_1, PAGE 1
.data > PRU_DMEM_0_1, PAGE 1
.switch > PRU_DMEM_0_1, PAGE 1
.sysmem > PRU_DMEM_0_1, PAGE 1
.cinit > PRU_DMEM_0_1, PAGE 1
.rodata > PRU_DMEM_0_1, PAGE 1
.rofardata > PRU_DMEM_0_1, PAGE 1
.farbss > PRU_DMEM_0_1, PAGE 1
.fardata > PRU_DMEM_0_1, PAGE 1

.resource_table > PRU_DMEM_0_1, PAGE 1
}
86 changes: 86 additions & 0 deletions examples/firmware_examples/inline_asm/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Copyright (c) 2015, Dimitar Dimitrov
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of the copyright holders nor the names of
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

# Very simple makefile to cross-compile for PRU


# Common flags
CROSS_COMPILE ?= pru-
CFLAGS += -g -Os
CFLAGS += -Wall -Wextra

# Headers needed by the TI rpmsg library.
CFLAGS += -I../../include -I../../include/am335x

# Define this to squeeze code size by removing atexit, exit, constructors
# and destructors from CRT.
CFLAGS += -minrt

# Per-PRU core flags. The -mmcu option will select the correct linker
# script and will predefine mcu-specific macros.
CFLAGS0 += -mmcu=am335x.pru0
CFLAGS1 += -mmcu=am335x.pru1

# List of source files to compile for each PRU core.
SRC0 := main.c ../../lib/src/pru_rpmsg.c ../../lib/src/pru_virtqueue.c
SRC1 :=

# GCC's -MMD does not yield the needed C dependencies when compiling all
# C source files at once. So manually list headers here.
HEADERS := $(wildcard *.h) $(wildcard include/*.h include/*/*.h)

# Where to output compiled objects
OUT := gen

# Final ELF image file names
ELF0 := $(OUT)/inline_asm.elf
ELF1 :=

# ============================ DO NOT TOUCH BELOW ============================
all: $(ELF0) $(ELF1)
@echo Success: $^

%.s : %.elf
$(CROSS_COMPILE)objdump -S -d $< > $@

$(OUT):
mkdir $(OUT)

$(ELF0): $(SRC0) $(HEADERS) | $(OUT)
$(CROSS_COMPILE)gcc $(CFLAGS) $(CFLAGS0) $(SRC0) $(LDFLAGS) -o $@

$(ELF1): $(SRC1) $(HEADERS) | $(OUT)
$(CROSS_COMPILE)gcc $(CFLAGS) $(CFLAGS1) $(SRC1) $(LDFLAGS) -o $@

clean:
$(RM) -fr $(ELF0) $(ELF1) $(OUT)

cscope:
cscope -bRk

.PHONY: all clean cscope
148 changes: 148 additions & 0 deletions examples/firmware_examples/inline_asm/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
/*
* Source Modified by Mohammed Muneeb
*
* Source Modified by Zubeen Tolani < ZeekHuge - zeekhuge@gmail.com >
* Based on the examples distributed by TI
*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdint.h>
#include <stdio.h>
#include <pru_cfg.h>
#include <pru_intc.h>
#include <rsc_types.h>
#include <pru_virtqueue.h>
#include <pru_rpmsg.h>
#include "resource_table_1.h"

#include <pru/io.h>

/* Host-1 Interrupt sets bit 31 in register R31 */
#define HOST_INT ((uint32_t) 1 << 31)

/* The PRU-ICSS system events used for RPMsg are defined in the Linux device tree
* PRU0 uses system event 16 (To ARM) and 17 (From ARM)
* PRU1 uses system event 18 (To ARM) and 19 (From ARM)
*/
#define TO_ARM_HOST 18
#define FROM_ARM_HOST 19

/*
* Using the name 'rpmsg-pru' will probe the rpmsg_pru driver found
* at linux-x.y.z/drivers/rpmsg/rpmsg_pru.c
*/
#define CHAN_NAME "rpmsg-pru"
#define CHAN_DESC "Channel 31"
#define CHAN_PORT 31

/*
* Used to make sure the Linux drivers are ready for RPMsg communication
* Found at linux-x.y.z/include/uapi/linux/virtio_config.h
*/
#define VIRTIO_CONFIG_S_DRIVER_OK 4


/*
* Used to check the state of 0 bit of the r31 ie
* the state of pr1_pru1_pru_r31_0. This gpio can be
* muxed to P8_45.
*/
#define CHECK_BIT 0x0001



uint8_t payload[RPMSG_BUF_SIZE];

/*
* main.c
*/
int main(void)
{
struct pru_rpmsg_transport transport;
uint16_t src, dst, len, num;
volatile uint8_t *status;

/* allow OCP master port access by the PRU so the PRU can read external memories */
CT_CFG.SYSCFG_bit.STANDBY_INIT = 0;

/* clear the status of the PRU-ICSS system event that the ARM will use to 'kick' us */
CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;

/* Make sure the Linux drivers are ready for RPMsg communication */
status = &resourceTable.rpmsg_vdev.status;
while (!(*status & VIRTIO_CONFIG_S_DRIVER_OK));

/* Initialize pru_virtqueue corresponding to vring0 (PRU to ARM Host direction) */
pru_virtqueue_init(&transport.virtqueue0, &resourceTable.rpmsg_vring0, TO_ARM_HOST, FROM_ARM_HOST);

/* Initialize pru_virtqueue corresponding to vring1 (ARM Host to PRU direction) */
pru_virtqueue_init(&transport.virtqueue1, &resourceTable.rpmsg_vring1, TO_ARM_HOST, FROM_ARM_HOST);

/* Create the RPMsg channel between the PRU and ARM user space using the transport structure. */
while (pru_rpmsg_channel(RPMSG_NS_CREATE, &transport, CHAN_NAME, CHAN_DESC, CHAN_PORT) != PRU_RPMSG_SUCCESS);
while (1) {
/* Check bit 30 of register R31 to see if the ARM has kicked us */
if (read_r31() & HOST_INT) {
/* Clear the event status */
CT_INTC.SICR_bit.STS_CLR_IDX = FROM_ARM_HOST;
/* Receive all available messages, multiple messages can be sent per kick */
while (pru_rpmsg_receive(&transport, &src, &dst, payload, &len) == PRU_RPMSG_SUCCESS) {
num = payload[0] - '0';
asm volatile(
"ldi r0, 0 \n\t"

This comment has been minimized.

Copy link
@dinuxbg

dinuxbg Jun 20, 2018

Any register you write needs to be either and output operand or a clobber for the ASM statement. The C compiler might be using it, while you overwrite it with a value. See https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html

"ldi r1, 0x000f \n\t"
"mov r2, %[count] \n\t"
"main_loop: \n\t"
"ldi32 r14, 50000000 \n\t"
"call delay_n2 \n\t"
"mov r30, r1 \n\t"
"ldi32 r14, 50000000 \n\t"
"call delay_n2 \n\t"
"mov r30, r0 \n\t"
"sub r2, r2, 1 \n\t"
"qbne main_loop, r2, 0 \n\t"
"jmp end \n\t"
"delay_n2: \n\t"
"sub r14, r14, 1 \n\t"
"qbne delay_n2, r14, 0 \n\t"
"ret \n\t"
"end: \n\t"
: : [count]"r"(num));

This comment has been minimized.

Copy link
@dinuxbg

dinuxbg Jun 20, 2018

As noted, you must add the clobbers:

: : [count]"r"(num) : "r0", "r1", "r2", "r14", "r3.w0");

Note that you need to clobber "r3.w0" because you use "call" inside the statement.

This comment has been minimized.

Copy link
@MuneebMohammed

MuneebMohammed Jun 20, 2018

Author Owner

@dinuxbg Thanks for commenting. I tried putting "r0", "r1", "r2" and "r14" before, but the LED's won't stop blinking after the count. It is working fine with just "r0", "r1" and "r2". Also, adding "r3.w0" throws an unknown register name error while compiling.

This comment has been minimized.

Copy link
@dinuxbg

dinuxbg Jun 21, 2018

Which version are you using?
$ pru-gcc --version $ apt show gcc-pru

This comment has been minimized.

Copy link
@MuneebMohammed

MuneebMohammed Jun 21, 2018

Author Owner

pru-gcc : 8.0.0 20170530
gcc-pru package : 8.0.1.20180310-0rcnee1~stretch+20180425

This comment has been minimized.

Copy link
@dinuxbg

dinuxbg Jun 21, 2018

Have you built pru-gcc yourself? Check with which pru-gcc . Please remove your local copy and use RCN's 8.0.1.20180310.

This comment has been minimized.

Copy link
@dinuxbg

dinuxbg Jun 21, 2018

If for some reason you want to stay with the old 8.0.0.20170530 version, please clobber "r3" instead of "r3.w0"

In any case you need to clobber "r14".

This comment has been minimized.

Copy link
@MuneebMohammed

MuneebMohammed Jun 21, 2018

Author Owner

I have updated to the latest version. After adding all the clobbers, the LED's blink correctly but now the asm code doesn't return, i.e. the message is not sent back 😅

This comment has been minimized.

Copy link
@dinuxbg

dinuxbg Jun 21, 2018

Looks like r2 (stack pointer) is special and the clobber is not honored by the compiler. Could you replace r2 in your statement with some other register (e.g. r15 or r20)?

This comment has been minimized.

Copy link
@MuneebMohammed

MuneebMohammed Jun 21, 2018

Author Owner

@dinuxbg Thanks a lot! It works now. Also, could you point me to the place where you made changes for pru-as. I will look into it in somewhat detail and document it properly.


pru_rpmsg_send(&transport, dst, src, "BLINKED\n", sizeof("BLINKED\n"));
}
}
}
}


Loading

0 comments on commit 252d826

Please sign in to comment.