diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..015a664f --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.*.swp +.*.swo +*.i +*.o +*.a +*.bin +pcb/*.b[^r][^d] +pcb/*.p[^c][^b] +rgb-test +am335x/pasm/pasm +.*.d +*~ +*~ +bin/* +*.dtbo +.DS_Store diff --git a/Makefile b/Makefile index 40ca2f9d..27d1dc0e 100755 --- a/Makefile +++ b/Makefile @@ -1,57 +1,25 @@ -#CROSS_COMPILE?=arm-arago-linux-gnueabi- - -LIBDIR_APP_LOADER?=../../app_loader/lib -INCDIR_APP_LOADER?=../../app_loader/include -BINDIR?=. - -CFLAGS += \ - -std=c99 \ - -Wall \ - -I$(INCDIR_APP_LOADER) \ - -D__DEBUG \ - -O2 \ - -mtune=cortex-a8 \ - -march=armv7-a \ - -LDFLAGS += \ - -L$(LIBDIR_APP_LOADER) \ - -lprussdrv \ - -lpthread \ - -PASM := ../../utils/pasm_2 -OBJDIR=obj -TARGET=$(BINDIR)/ws281x - -_DEPS = -DEPS = $(patsubst %,$(INCDIR_APP_LOADER)/%,$(_DEPS)) - -_OBJ = ws281x.o -OBJ = $(patsubst %,$(OBJDIR)/%,$(_OBJ)) - -$(OBJDIR)/%.o: %.c $(DEPS) - @mkdir -p obj - $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $< - -all: $(TARGET) ws281x.bin -$(TARGET): $(OBJ) - $(CROSS_COMPILE)gcc $(CFLAGS) -o $@ $^ $(LDFLAGS) - -ws281x.bin: ws281x.p ws281x.hp - $(CPP) - < $< | grep -v '^#' | sed 's/;/\n/g' > $<.i - $(PASM) -V3 -b $<.i +######### +# +# Top level Makefile. +# Mostly just recurse into subdirectories. + +SUBDIR-y += dts +SUBDIR-y += src/ledscape +SUBDIR-y += src/script +SUBDIR-y += src/ledgames +SUBDIR-y += src/ledgames/rsrc + +all: + for dir in $(SUBDIR-y); do \ + $(MAKE) -C $$dir || exit 1; \ + done +clean: + for dir in $(SUBDIR-y); do \ + $(MAKE) -C $$dir clean; \ + done -.PHONY: clean -clean: - rm -rf $(OBJDIR)/ *~ $(INCDIR_APP_LOADER)/*~ $(TARGET) ../bin/ws281x.bin ws281x.bin +firmware: + echo CAPE-BONE-OCTO > /sys/devices/bone_capemgr.8/slots -SLOT_FILE=/sys/devices/bone_capemgr.8/slots -dts: LEDscape.dts - @SLOT="`grep LEDSCAPE $(SLOT_FILE) | cut -d: -f1`"; \ - if [ ! -z "$$SLOT" ]; then \ - echo "Removing slot $$SLOT"; \ - echo -$$SLOT > $(SLOT_FILE); \ - fi - dtc -O dtb -o /lib/firmware/BB-LEDSCAPE-00A0.dtbo -b 0 -@ LEDscape.dts - echo BB-LEDSCAPE > $(SLOT_FILE) diff --git a/Makefile.common b/Makefile.common new file mode 100644 index 00000000..83de3a50 --- /dev/null +++ b/Makefile.common @@ -0,0 +1,180 @@ +######### +# +# Common build targets +# +# + +TOP ?= ../.. +OBJDIR ?= $(TOP)/obj +LIBDIR ?= $(TOP)/lib +BINDIR ?= $(TOP)/bin + +all: \ + $(TARGETS-y) \ + $(foreach O,$(BIN-y),$(BINDIR)/$O) \ + $(foreach O,$(LIB-y),$(LIBDIR)/$O) \ + +ifeq ($(shell uname -m),armv7l) +# We are on the BeagleBone Black itself; +# do not cross compile. +export CROSS_COMPILE:= + +else +# We are not on the BeagleBone and might be cross compiling. +# If the environment does not set CROSS_COMPILE, set our +# own. Install a cross compiler with something like: +# +# sudo apt-get install gcc-arm-linux-gnueabi +# +export CROSS_COMPILE?=arm-linux-gnueabi- +endif + +GENERIC_CFLAGS += \ + -g \ + -W \ + -Wall \ + -D_BSD_SOURCE \ + -Wp,-MMD,$(dir $@).$(notdir $@).d \ + -Wp,-MT,$@ \ + -I. \ + -I$(TOP)/src/ledscape \ + -O0 \ + -mtune=cortex-a8 \ + -march=armv7-a \ + +CFLAGS += \ + -std=c99 \ + $(GENERIC_CFLAGS) \ + +CPPFLAGS += \ + $(GENERIC_CFLAGS) \ + -std=c++11 + +LDFLAGS += \ + +LDLIBS += \ + -L$(LIBDIR) \ + -lledscape \ + -lpthread \ + -lm \ + -lpng \ + -lSDL \ + -lSDL_mixer + +COMPILE.c-o = $(CROSS_COMPILE)gcc $(CFLAGS) -c -o $@ $< +COMPILE.cc-o = $(CROSS_COMPILE)g++ $(CPPFLAGS) -c -o $@ $< +COMPILE.cpp-o = $(CROSS_COMPILE)g++ $(CPPFLAGS) -c -o $@ $< +COMPILE.a = $(CROSS_COMPILE)ar crv $@ $^ +COMPILE.link = $(CROSS_COMPILE)g++ $(LDFLAGS) -o $@ $^ $(LDLIBS) + +$(OBJDIR)/%.o: %.c + $(COMPILE.c-o) +$(OBJDIR)/%.o: %.cpp + $(COMPILE.cpp-o) +$(OBJDIR)/%.o: %.cc + $(COMPILE.cc-o) + +$(LIBDIR)/%.a: + $(RM) $@ + $(COMPILE.a) + +$(BINDIR)/%: + $(COMPILE.link) + + +##### +# +# The TI "app_loader" is the userspace library for talking to +# the PRU and mapping memory between it and the ARM. +# +APP_LOADER_DIR ?= $(TOP)/am335x/app_loader +APP_LOADER_LIB := $(APP_LOADER_DIR)/lib/libprussdrv.a +CFLAGS += -I$(APP_LOADER_DIR)/include +LDLIBS += $(APP_LOADER_LIB) + + +##### +# +# The TI PRU assembler looks like it has macros and includes, +# but it really doesn't. So instead we use cpp to pre-process the +# file and then strip out all of the directives that it adds. +# PASM also doesn't handle multiple statements per line, so we +# insert hard newline characters for every ; in the file. +# +PASM_DIR ?= $(TOP)/am335x/pasm +PASM := $(PASM_DIR)/pasm + +$(LIBDIR)/%.bin: %.p $(PASM) + $(CPP) - < $< | perl -p -e 's/^#.*//; s/;/\n/g; s/BYTE\((\d+)\)/t\1/g' > /tmp/$(basename $<).i + $(PASM) -V3 -b /tmp/$(basename $<).i $(basename $@) + $(RM) /tmp/$(basename $<).i + +# +# Generate a target for each of the binaries, with dependencies on +# object files for that source. +# +$(foreach O,$(BIN-y),\ + $(eval $(BINDIR)/$O: $(foreach s,$($O.srcs),$(OBJDIR)/$(basename $s).o) $(LIBDIR)/libledscape.a)) + +$(foreach O,$(LIB-y),\ + $(eval $(LIBDIR)/$O: $(foreach s,$($(basename $O).srcs),$(OBJDIR)/$(basename $s).o) $(APP_LOADER_LIB))) + +#$(TARGETS): + #$(COMPILE.link) + + +.PHONY: clean + +# Include all of the generated dependency files +-include $(OBJDIR)/.*.o.d + +clean: + rm -rf \ + $(OBJDIR)/*.o \ + $(LIBDIR)/*.a \ + $(OBJDIR)/.*.o.d \ + $(LIBDIR)/*.bin \ + + +########### +# +# The correct way to reserve the GPIO pins on the BBB is with the +# capemgr and a Device Tree file. But it doesn't work. +# +SLOT_FILE=/sys/devices/bone_capemgr.9/slots +DTS=CAPE-BONE-OCTO +DTB=/lib/firmware/$(DTS)-00A0.dtbo +GPIODTS=GPIO +GPIODTB=/lib/firmware/$(GPIODTS)-00A0.dtbo + +dts: LEDscape.dts + @SLOT="`grep LEDSCAPE $(SLOT_FILE) | cut -d: -f1`"; \ + if [ ! -z "$$SLOT" ]; then \ + echo "Removing slot $$SLOT"; \ + echo -$$SLOT > $(SLOT_FILE); \ + fi + dtc -O dtb -o /lib/firmware/BB-LEDSCAPE-00A0.dtbo -b 0 -@ LEDscape.dts + echo BB-LEDSCAPE > $(SLOT_FILE) + + + +firmware: $(DTB) $(GPIODTB) + +$(DTB): cape-bone-octo.dts FORCE + dtc -O dtb -o $@ -b 0 -@ $< + +$(GPIODTB): gpio.dts FORCE + dtc -O dtb -o $@ -b 0 -@ $< + +FORCE: + +########### +# +# PRU Libraries and PRU assembler are build from their own trees. +# +$(APP_LOADER_LIB): + $(MAKE) -C $(APP_LOADER_DIR)/interface + +$(PASM): + $(MAKE) -C $(PASM_DIR) + diff --git a/README.md b/README.md deleted file mode 100644 index 5a8ab1cc..00000000 --- a/README.md +++ /dev/null @@ -1,102 +0,0 @@ -![Testing LEDscape](http://farm4.staticflickr.com/3834/9378678019_b706c55635_z.jpg) - -DANGER! -======= - -This code works with the PRU units on the Beagle Bone and can easily -cause *hard crashes*. It is still being debugged and developed. - - -Overview -======== - -The WS281x LED chips are built like shift registers and make for very -easy LED strip construction. The signals are duty-cycle modulated, -with a 0 measuring 250 ns long and a 1 being 600 ns long, and 1250 ns -between bits. Since this doesn't map to normal SPI hardware and requires -an 800 KHz bit clock, it is typically handled with a dedicated microcontroller -or DMA hardware on something like the Teensy 3. - -However, the TI OMAP in the BeagleBone Black has two programmable -"microcontrollers" built into the CPU that can handle real time -tasks and also access the ARM's memory. This allows things that -might have been delegated to external devices to be handled without -any additional hardware, and without the overhead of clocking data out -the USB port. - -The frames are stored in memory as a series of 4-byte pixels in the -order GRBA, packed in strip-major order. This means that it looks -like this in RAM: - - S0P0 S1P0 S2P0 ... S31P0 S0P1 S1P1 ... S31P1 S0P2 S1P2 ... S31P2 - -This way length of the strip can be variable, although the memory used -will depend on the length of the longest strip. 4 * 32 * longest strip -bytes are required per frame buffer. - - -API -=== - -There is a command structure shared in PRU DRAM that holds a pointer -to the current frame buffer, the length in pixels, a command byte and -a response byte. - - typedef struct - { - // in the DDR shared with the PRU - const uintptr_t pixels_dma; - - // Length in pixels of the longest LED strip. - unsigned size; - - // write 1 to start, 0xFF to abort. will be cleared when started - volatile unsigned command; - - // will have a non-zero response written when done - volatile unsigned response; - } __attribute__((__packed__)) ws281x_command_t; - -Once the PRU has cleared the command byte you are free to re-write the -dma address or number of pixels. You can double buffer like this: - - unsigned frame_id = 0; - pixel_slice_t * frames[2]; - uintptr_t frames_dma[2]; - - while (1) - { - render(frames[frame_id]); - cmd->pixels_dma = frames_dma[frame_id]; - - // wait for the previous frame to finish display - while(!cmd->reponse) - ; - - // Send the start command and wait for the ack - cmd->command = 1; - while(cmd->command) - ; - - frame_id = (frame_id+1) % 2; - } - -The 24-bit RGB data to be displayed is laid out with BRGA format, -since that is how it will be translated during the clock out from the PRU. - - typedef struct { - uint8_t b; - uint8_t r; - uint8_t g; - uint8_t a; - } __attribute__((__packed__)) pixel_t; - - typedef struct { - pixel_t strip[32]; - } __attribute__((__packed__)) pixel_slice_t; - -LED Strips -========== - -* http://www.adafruit.com/products/1138 -* http://www.adafruit.com/datasheets/WS2811.pdf diff --git a/acrylic/LedBasePlate-X5.cdr b/acrylic/LedBasePlate-X5.cdr new file mode 100755 index 00000000..71a41318 Binary files /dev/null and b/acrylic/LedBasePlate-X5.cdr differ diff --git a/acrylic/LedBasePlate-X7.cdr b/acrylic/LedBasePlate-X7.cdr new file mode 100755 index 00000000..7687d02e Binary files /dev/null and b/acrylic/LedBasePlate-X7.cdr differ diff --git a/acrylic/LedMount-X5.cdr b/acrylic/LedMount-X5.cdr new file mode 100755 index 00000000..07bd77c5 Binary files /dev/null and b/acrylic/LedMount-X5.cdr differ diff --git a/acrylic/LedMount-X7.cdr b/acrylic/LedMount-X7.cdr new file mode 100755 index 00000000..4064982e Binary files /dev/null and b/acrylic/LedMount-X7.cdr differ diff --git a/am335x/app_loader/include/pruss_intc_mapping.h b/am335x/app_loader/include/pruss_intc_mapping.h new file mode 100644 index 00000000..0923008e --- /dev/null +++ b/am335x/app_loader/include/pruss_intc_mapping.h @@ -0,0 +1,104 @@ +/* + * pruss_intc_mapping.h + * + * Example PRUSS INTC mapping for the application + * + * Copyright (C) 2010 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. + * +*/ + +/* + * ============================================================================ + * Copyright (c) Texas Instruments Inc 2010-11 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ +*/ + +#define AM33XX +#ifdef AM33XX +#define PRU0_PRU1_INTERRUPT 17 +#define PRU1_PRU0_INTERRUPT 18 +#define PRU0_ARM_INTERRUPT 19 +#define PRU1_ARM_INTERRUPT 20 +#define ARM_PRU0_INTERRUPT 21 +#define ARM_PRU1_INTERRUPT 22 +#else +#define PRU0_PRU1_INTERRUPT 32 +#define PRU1_PRU0_INTERRUPT 33 +#define PRU0_ARM_INTERRUPT 34 +#define PRU1_ARM_INTERRUPT 35 +#define ARM_PRU0_INTERRUPT 36 +#define ARM_PRU1_INTERRUPT 37 +#endif +#define CHANNEL0 0 +#define CHANNEL1 1 +#define CHANNEL2 2 +#define CHANNEL3 3 +#define CHANNEL4 4 +#define CHANNEL5 5 +#define CHANNEL6 6 +#define CHANNEL7 7 +#define CHANNEL8 8 +#define CHANNEL9 9 + +#define PRU0 0 +#define PRU1 1 +#define PRU_EVTOUT0 2 +#define PRU_EVTOUT1 3 +#define PRU_EVTOUT2 4 +#define PRU_EVTOUT3 5 +#define PRU_EVTOUT4 6 +#define PRU_EVTOUT5 7 +#define PRU_EVTOUT6 8 +#define PRU_EVTOUT7 9 + +#define PRU0_HOSTEN_MASK 0x0001 +#define PRU1_HOSTEN_MASK 0x0002 +#define PRU_EVTOUT0_HOSTEN_MASK 0x0004 +#define PRU_EVTOUT1_HOSTEN_MASK 0x0008 +#define PRU_EVTOUT2_HOSTEN_MASK 0x0010 +#define PRU_EVTOUT3_HOSTEN_MASK 0x0020 +#define PRU_EVTOUT4_HOSTEN_MASK 0x0040 +#define PRU_EVTOUT5_HOSTEN_MASK 0x0080 +#define PRU_EVTOUT6_HOSTEN_MASK 0x0100 +#define PRU_EVTOUT7_HOSTEN_MASK 0x0200 + + +#define PRUSS_INTC_INITDATA { \ +{ PRU0_PRU1_INTERRUPT, PRU1_PRU0_INTERRUPT, PRU0_ARM_INTERRUPT, PRU1_ARM_INTERRUPT, ARM_PRU0_INTERRUPT, ARM_PRU1_INTERRUPT, -1 }, \ +{ {PRU0_PRU1_INTERRUPT,CHANNEL1}, {PRU1_PRU0_INTERRUPT, CHANNEL0}, {PRU0_ARM_INTERRUPT,CHANNEL2}, {PRU1_ARM_INTERRUPT, CHANNEL3}, {ARM_PRU0_INTERRUPT, CHANNEL0}, {ARM_PRU1_INTERRUPT, CHANNEL1}, {-1,-1}}, \ + { {CHANNEL0,PRU0}, {CHANNEL1, PRU1}, {CHANNEL2, PRU_EVTOUT0}, {CHANNEL3, PRU_EVTOUT1}, {-1,-1} }, \ + (PRU0_HOSTEN_MASK | PRU1_HOSTEN_MASK | PRU_EVTOUT0_HOSTEN_MASK | PRU_EVTOUT1_HOSTEN_MASK) /*Enable PRU0, PRU1, PRU_EVTOUT0 */ \ +} \ + diff --git a/am335x/app_loader/include/prussdrv.h b/am335x/app_loader/include/prussdrv.h new file mode 100644 index 00000000..90c489b3 --- /dev/null +++ b/am335x/app_loader/include/prussdrv.h @@ -0,0 +1,160 @@ +/* + * prussdrv.h + * + * Describes PRUSS userspace driver for Industrial Communications + * + * Copyright (C) 2010 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. + * +*/ + +/* + * ============================================================================ + * Copyright (c) Texas Instruments Inc 2010-11 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ +*/ + +#ifndef _PRUSSDRV_H +#define _PRUSSDRV_H + +#include +#include + +#if defined (__cplusplus) +extern "C" { +#endif + +#define NUM_PRU_HOSTIRQS 8 +#define NUM_PRU_HOSTS 10 +#define NUM_PRU_CHANNELS 10 +#define NUM_PRU_SYS_EVTS 64 + +#define PRUSS0_PRU0_DATARAM 0 +#define PRUSS0_PRU1_DATARAM 1 +#define PRUSS0_PRU0_IRAM 2 +#define PRUSS0_PRU1_IRAM 3 + +//Available in AM33xx series - begin +#define PRUSS0_SHARED_DATARAM 4 +#define PRUSS0_CFG 5 +#define PRUSS0_UART 6 +#define PRUSS0_IEP 7 +#define PRUSS0_ECAP 8 +#define PRUSS0_MII_RT 9 +#define PRUSS0_MDIO 10 +//Available in AM33xx series - end + +#define PRU_EVTOUT_0 0 +#define PRU_EVTOUT_1 1 +#define PRU_EVTOUT_2 2 +#define PRU_EVTOUT_3 3 +#define PRU_EVTOUT_4 4 +#define PRU_EVTOUT_5 5 +#define PRU_EVTOUT_6 6 +#define PRU_EVTOUT_7 7 + + typedef void *(*prussdrv_function_handler) (void *); + typedef struct __sysevt_to_channel_map { + short sysevt; + short channel; + } tsysevt_to_channel_map; + typedef struct __channel_to_host_map { + short channel; + short host; + } tchannel_to_host_map; + typedef struct __pruss_intc_initdata { + //Enabled SYSEVTs - Range:0..63 + //{-1} indicates end of list + char sysevts_enabled[NUM_PRU_SYS_EVTS]; + //SysEvt to Channel map. SYSEVTs - Range:0..63 Channels -Range: 0..9 + //{-1, -1} indicates end of list + tsysevt_to_channel_map sysevt_to_channel_map[NUM_PRU_SYS_EVTS]; + //Channel to Host map.Channels -Range: 0..9 HOSTs - Range:0..9 + //{-1, -1} indicates end of list + tchannel_to_host_map channel_to_host_map[NUM_PRU_CHANNELS]; + //10-bit mask - Enable Host0-Host9 {Host0/1:PRU0/1, Host2..9 : PRUEVT_OUT0..7) + unsigned int host_enable_bitmask; + } tpruss_intc_initdata; + + int prussdrv_init(void); + + int prussdrv_open(unsigned int pru_evtout_num); + + int prussdrv_pru_reset(unsigned int prunum); + + int prussdrv_pru_disable(unsigned int prunum); + + int prussdrv_pru_enable(unsigned int prunum); + + int prussdrv_pru_write_memory(unsigned int pru_ram_id, + unsigned int wordoffset, + unsigned int *memarea, + unsigned int bytelength); + + int prussdrv_pruintc_init(tpruss_intc_initdata * prussintc_init_data); + + int prussdrv_map_l3mem(void **address); + + int prussdrv_map_extmem(void **address); + + int prussdrv_map_prumem(unsigned int pru_ram_id, void **address); + + int prussdrv_map_peripheral_io(unsigned int per_id, void **address); + + unsigned int prussdrv_get_phys_addr(void *address); + + void *prussdrv_get_virt_addr(unsigned int phyaddr); + + int prussdrv_pru_wait_event(unsigned int pru_evtout_num); + + int prussdrv_pru_send_event(unsigned int eventnum); + + int prussdrv_pru_clear_event(unsigned int eventnum); + + int prussdrv_pru_send_wait_clear_event(unsigned int send_eventnum, + unsigned int pru_evtout_num, + unsigned int ack_eventnum); + + int prussdrv_exit(void); + + int prussdrv_exec_program(int prunum, char *filename); + + int prussdrv_start_irqthread(unsigned int pru_evtout_num, int priority, + prussdrv_function_handler irqhandler); + + +#if defined (__cplusplus) +} +#endif +#endif diff --git a/am335x/app_loader/interface/Makefile b/am335x/app_loader/interface/Makefile new file mode 100644 index 00000000..4b9324c7 --- /dev/null +++ b/am335x/app_loader/interface/Makefile @@ -0,0 +1,66 @@ +ROOTDIR = .. +TARGET = libprussdrv +CROSS_COMPILE?=arm-linux-gnueabi- + +CC = $(CROSS_COMPILE)gcc +AR = $(CROSS_COMPILE)ar + +INCLUDEDIR = ../include +LIBDIR = ../lib + +C_FLAGS += -I. -Wall -I$(INCLUDEDIR) + +COMPILE.c = $(CC) $(C_FLAGS) $(CPP_FLAGS) -c +AR.c = $(AR) rc + +DBGTARGET = $(LIBDIR)/$(TARGET)d.a +RELTARGET = $(LIBDIR)/$(TARGET).a + +DBGCFLAGS = -g -O0 -D__DEBUG +RELCFLAGS = -O3 -mtune=cortex-a8 -march=armv7-a + +SOURCES = $(wildcard *.c) +HEADERS = $(wildcard *.h) + +TARGETHEADERS = $(addprefix $(INCLUDEDIR)/, $(HEADERS)) + +DBGOBJFILES = $(SOURCES:%.c=debug/%.o) +RELOBJFILES = $(SOURCES:%.c=release/%.o) + +.PHONY: clean debug release install + +all: debug release + +install: + +release: $(RELTARGET) +#release: $(RELTARGET) $(TARGETHEADERS) + +debug: $(DBGTARGET) +#debug: $(DBGTARGET) $(TARGETHEADERS) + + +$(RELTARGET): $(RELOBJFILES) + @mkdir -p $(ROOTDIR)/lib + $(AR.c) $@ $(RELOBJFILES) + +$(DBGTARGET): $(DBGOBJFILES) + @mkdir -p $(ROOTDIR)/lib + $(AR.c) $@ $(DBGOBJFILES) + +$(RELOBJFILES): release/%.o: %.c $(HEADERS) + @mkdir -p release + $(COMPILE.c) $(RELCFLAGS) -o $@ $< + +$(DBGOBJFILES): debug/%.o: %.c $(HEADERS) + @mkdir -p debug + $(COMPILE.c) $(DBGCFLAGS) -o $@ $< + +$(TARGETHEADERS): $(HEADERS) + @echo Installing headers... + @install -d $(INCLUDEDIR) + @install -c $< $@ + +clean: + -rm -rf release debug *~ ../lib/* + diff --git a/am335x/app_loader/interface/__prussdrv.h b/am335x/app_loader/interface/__prussdrv.h new file mode 100644 index 00000000..08d69375 --- /dev/null +++ b/am335x/app_loader/interface/__prussdrv.h @@ -0,0 +1,275 @@ +/* + * __prussdrv.h + * + * + * Copyright (C) 2012 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. + * +*/ + +/* + * ============================================================================ + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#define DISABLE_L3RAM_SUPPORT + +#define PAGE_SIZE 4096 + +#define PRUSS_V1 1 +#define PRUSS_V2 2 + +#define AM33XX_PRUSS_INTC_REV 0x4E82A900 +#define AM18XX_PRUSS_INTC_REV 0x4E825900 + +#define PRUSS_MAX_IRAM_SIZE 8192 + +#define AM33XX_PRUSS_IRAM_SIZE 8192 +#define AM33XX_PRUSS_MMAP_SIZE 0x40000 +#define AM33XX_DATARAM0_PHYS_BASE 0x4a300000 +#define AM33XX_DATARAM1_PHYS_BASE 0x4a302000 +#define AM33XX_INTC_PHYS_BASE 0x4a320000 +#define AM33XX_PRU0CONTROL_PHYS_BASE 0x4a322000 +#define AM33XX_PRU0DEBUG_PHYS_BASE 0x4a322400 +#define AM33XX_PRU1CONTROL_PHYS_BASE 0x4a324000 +#define AM33XX_PRU1DEBUG_PHYS_BASE 0x4a324400 +#define AM33XX_PRU0IRAM_PHYS_BASE 0x4a334000 +#define AM33XX_PRU1IRAM_PHYS_BASE 0x4a338000 +#define AM33XX_PRUSS_SHAREDRAM_BASE 0x4a310000 +#define AM33XX_PRUSS_CFG_BASE 0x4a326000 +#define AM33XX_PRUSS_UART_BASE 0x4a328000 +#define AM33XX_PRUSS_IEP_BASE 0x4a32e000 +#define AM33XX_PRUSS_ECAP_BASE 0x4a330000 +#define AM33XX_PRUSS_MIIRT_BASE 0x4a332000 +#define AM33XX_PRUSS_MDIO_BASE 0x4a332400 + +#define AM18XX_PRUSS_IRAM_SIZE 4096 +#define AM18XX_PRUSS_MMAP_SIZE 0x7C00 +#define AM18XX_DATARAM0_PHYS_BASE 0x01C30000 +#define AM18XX_DATARAM1_PHYS_BASE 0x01C32000 +#define AM18XX_INTC_PHYS_BASE 0x01C34000 +#define AM18XX_PRU0CONTROL_PHYS_BASE 0x01C37000 +#define AM18XX_PRU0DEBUG_PHYS_BASE 0x01C37400 +#define AM18XX_PRU1CONTROL_PHYS_BASE 0x01C37800 +#define AM18XX_PRU1DEBUG_PHYS_BASE 0x01C37C00 +#define AM18XX_PRU0IRAM_PHYS_BASE 0x01C38000 +#define AM18XX_PRU1IRAM_PHYS_BASE 0x01C3C000 + +//PRUSS INTC register offsets +#define PRU_INTC_REVID_REG 0x000 +#define PRU_INTC_CR_REG 0x004 +#define PRU_INTC_HCR_REG 0x00C +#define PRU_INTC_GER_REG 0x010 +#define PRU_INTC_GNLR_REG 0x01C +#define PRU_INTC_SISR_REG 0x020 +#define PRU_INTC_SICR_REG 0x024 +#define PRU_INTC_EISR_REG 0x028 +#define PRU_INTC_EICR_REG 0x02C +#define PRU_INTC_HIEISR_REG 0x034 +#define PRU_INTC_HIDISR_REG 0x038 +#define PRU_INTC_GPIR_REG 0x080 + +#define PRU_INTC_SRSR1_REG 0x200 +#define PRU_INTC_SRSR2_REG 0x204 + +#define PRU_INTC_SECR1_REG 0x280 +#define PRU_INTC_SECR2_REG 0x284 + +#define PRU_INTC_ESR1_REG 0x300 +#define PRU_INTC_ESR2_REG 0x304 + +#define PRU_INTC_ECR1_REG 0x380 +#define PRU_INTC_ECR2_REG 0x384 + +#define PRU_INTC_CMR1_REG 0x400 +#define PRU_INTC_CMR2_REG 0x404 +#define PRU_INTC_CMR3_REG 0x408 +#define PRU_INTC_CMR4_REG 0x40C +#define PRU_INTC_CMR5_REG 0x410 +#define PRU_INTC_CMR6_REG 0x414 +#define PRU_INTC_CMR7_REG 0x418 +#define PRU_INTC_CMR8_REG 0x41C +#define PRU_INTC_CMR9_REG 0x420 +#define PRU_INTC_CMR10_REG 0x424 +#define PRU_INTC_CMR11_REG 0x428 +#define PRU_INTC_CMR12_REG 0x42C +#define PRU_INTC_CMR13_REG 0x430 +#define PRU_INTC_CMR14_REG 0x434 +#define PRU_INTC_CMR15_REG 0x438 +#define PRU_INTC_CMR16_REG 0x43C + +#define PRU_INTC_HMR1_REG 0x800 +#define PRU_INTC_HMR2_REG 0x804 +#define PRU_INTC_HMR3_REG 0x808 + +#define PRU_INTC_SIPR1_REG 0xD00 +#define PRU_INTC_SIPR2_REG 0xD04 + +#define PRU_INTC_SITR1_REG 0xD80 +#define PRU_INTC_SITR2_REG 0xD84 + +#define PRU_INTC_HIER_REG 0x1500 + + +#define MAX_HOSTS_SUPPORTED 10 + +//UIO driver expects user space to map PRUSS_UIO_MAP_OFFSET_XXX to +//access corresponding memory regions - region offset is N*PAGE_SIZE + +#define PRUSS_UIO_MAP_OFFSET_PRUSS 0*PAGE_SIZE +#define PRUSS_UIO_DRV_PRUSS_BASE "/sys/class/uio/uio0/maps/map0/addr" +#define PRUSS_UIO_DRV_PRUSS_SIZE "/sys/class/uio/uio0/maps/map0/size" + +#ifndef DISABLE_L3RAM_SUPPORT + +#define PRUSS_UIO_MAP_OFFSET_L3RAM 1*PAGE_SIZE +#define PRUSS_UIO_DRV_L3RAM_BASE "/sys/class/uio/uio0/maps/map1/addr" +#define PRUSS_UIO_DRV_L3RAM_SIZE "/sys/class/uio/uio0/maps/map1/size" + +#define PRUSS_UIO_MAP_OFFSET_EXTRAM 2*PAGE_SIZE +#define PRUSS_UIO_DRV_EXTRAM_BASE "/sys/class/uio/uio0/maps/map2/addr" +#define PRUSS_UIO_DRV_EXTRAM_SIZE "/sys/class/uio/uio0/maps/map2/size" + +#else + +#define PRUSS_UIO_MAP_OFFSET_EXTRAM 1*PAGE_SIZE +#define PRUSS_UIO_DRV_EXTRAM_BASE "/sys/class/uio/uio0/maps/map1/addr" +#define PRUSS_UIO_DRV_EXTRAM_SIZE "/sys/class/uio/uio0/maps/map1/size" + + +#endif + + +typedef struct __prussdrv { + int version; + int fd[NUM_PRU_HOSTIRQS]; + void *pru0_dataram_base; + void *pru1_dataram_base; + void *intc_base; + void *pru0_control_base; + void *pru0_debug_base; + void *pru1_control_base; + void *pru1_debug_base; + void *pru0_iram_base; + void *pru1_iram_base; + void *l3ram_base; + void *extram_base; + pthread_t irq_thread[NUM_PRU_HOSTIRQS]; + int mmap_fd; + void *pruss_sharedram_base; + void *pruss_cfg_base; + void *pruss_uart_base; + void *pruss_iep_base; + void *pruss_ecap_base; + void *pruss_miirt_base; + void *pruss_mdio_base; + unsigned int pru0_dataram_phy_base; + unsigned int pru1_dataram_phy_base; + unsigned int intc_phy_base; + unsigned int pru0_control_phy_base; + unsigned int pru0_debug_phy_base; + unsigned int pru1_control_phy_base; + unsigned int pru1_debug_phy_base; + unsigned int pru0_iram_phy_base; + unsigned int pru1_iram_phy_base; + unsigned int l3ram_phy_base; + unsigned int extram_phy_base; + unsigned int pruss_sharedram_phy_base; + unsigned int pruss_cfg_phy_base; + unsigned int pruss_uart_phy_base; + unsigned int pruss_iep_phy_base; + unsigned int pruss_ecap_phy_base; + unsigned int pruss_miirt_phy_base; + unsigned int pruss_mdio_phy_base; + unsigned int pruss_phys_base; + unsigned int pruss_map_size; + unsigned int l3ram_phys_base; + unsigned int l3ram_map_size; + unsigned int extram_phys_base; + unsigned int extram_map_size; +} tprussdrv; + + +int __pruss_detect_hw_version(unsigned int *pruss_io) +{ + + if (pruss_io[(AM18XX_INTC_PHYS_BASE - AM18XX_DATARAM0_PHYS_BASE) >> 2] + == AM18XX_PRUSS_INTC_REV) + return PRUSS_V1; + else { + if (pruss_io + [(AM33XX_INTC_PHYS_BASE - AM33XX_DATARAM0_PHYS_BASE) >> 2] == + AM33XX_PRUSS_INTC_REV) + return PRUSS_V2; + else + return -1; + } +} + +void __prussintc_set_cmr(unsigned int *pruintc_io, unsigned short sysevt, + unsigned short channel) +{ + pruintc_io[(PRU_INTC_CMR1_REG + (sysevt & ~(0x3))) >> 2] |= + ((channel & 0xF) << ((sysevt & 0x3) << 3)); + +} + + +void __prussintc_set_hmr(unsigned int *pruintc_io, unsigned short channel, + unsigned short host) +{ + pruintc_io[(PRU_INTC_HMR1_REG + (channel & ~(0x3))) >> 2] = + pruintc_io[(PRU_INTC_HMR1_REG + + (channel & ~(0x3))) >> 2] | (((host) & 0xF) << + (((channel) & 0x3) << 3)); + +} diff --git a/am335x/app_loader/interface/prussdrv.c b/am335x/app_loader/interface/prussdrv.c new file mode 100644 index 00000000..21e4ba4c --- /dev/null +++ b/am335x/app_loader/interface/prussdrv.c @@ -0,0 +1,660 @@ +/* + * prussdrv.c + * + * User space driver for PRUSS + * + * Copyright (C) 2012 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. + * +*/ + + +/* + * ============================================================================ + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + + +#include +#include "__prussdrv.h" +#include + +#define PRUSS_UIO_PRAM_PATH_LEN 128 +#define PRUSS_UIO_PARAM_VAL_LEN 20 +#define HEXA_DECIMAL_BASE 16 + +static tprussdrv prussdrv; + +int __prussdrv_memmap_init(void) +{ + int i, fd; + char hexstring[PRUSS_UIO_PARAM_VAL_LEN]; + + if (prussdrv.mmap_fd == 0) { + for (i = 0; i < NUM_PRU_HOSTIRQS; i++) { + if (prussdrv.fd[i]) + break; + } + if (i == NUM_PRU_HOSTIRQS) + return -1; + else + prussdrv.mmap_fd = prussdrv.fd[i]; + } + fd = open(PRUSS_UIO_DRV_PRUSS_BASE, O_RDONLY); + if (fd >= 0) { + read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); + prussdrv.pruss_phys_base = + strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); + close(fd); + } else + return -1; + fd = open(PRUSS_UIO_DRV_PRUSS_SIZE, O_RDONLY); + if (fd >= 0) { + read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); + prussdrv.pruss_map_size = + strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); + close(fd); + } else + return -1; + + prussdrv.pru0_dataram_base = + mmap(0, prussdrv.pruss_map_size, PROT_READ | PROT_WRITE, + MAP_SHARED, prussdrv.mmap_fd, PRUSS_UIO_MAP_OFFSET_PRUSS); + prussdrv.version = + __pruss_detect_hw_version(prussdrv.pru0_dataram_base); + + switch (prussdrv.version) { + case PRUSS_V1: + { + printf("AM18XX\n"); + prussdrv.pru0_dataram_phy_base = AM18XX_DATARAM0_PHYS_BASE; + prussdrv.pru1_dataram_phy_base = AM18XX_DATARAM1_PHYS_BASE; + prussdrv.intc_phy_base = AM18XX_INTC_PHYS_BASE; + prussdrv.pru0_control_phy_base = AM18XX_PRU0CONTROL_PHYS_BASE; + prussdrv.pru0_debug_phy_base = AM18XX_PRU0DEBUG_PHYS_BASE; + prussdrv.pru1_control_phy_base = AM18XX_PRU1CONTROL_PHYS_BASE; + prussdrv.pru1_debug_phy_base = AM18XX_PRU1DEBUG_PHYS_BASE; + prussdrv.pru0_iram_phy_base = AM18XX_PRU0IRAM_PHYS_BASE; + prussdrv.pru1_iram_phy_base = AM18XX_PRU1IRAM_PHYS_BASE; + } + break; + case PRUSS_V2: + { + printf("AM33XX\n"); + prussdrv.pru0_dataram_phy_base = AM33XX_DATARAM0_PHYS_BASE; + prussdrv.pru1_dataram_phy_base = AM33XX_DATARAM1_PHYS_BASE; + prussdrv.intc_phy_base = AM33XX_INTC_PHYS_BASE; + prussdrv.pru0_control_phy_base = AM33XX_PRU0CONTROL_PHYS_BASE; + prussdrv.pru0_debug_phy_base = AM33XX_PRU0DEBUG_PHYS_BASE; + prussdrv.pru1_control_phy_base = AM33XX_PRU1CONTROL_PHYS_BASE; + prussdrv.pru1_debug_phy_base = AM33XX_PRU1DEBUG_PHYS_BASE; + prussdrv.pru0_iram_phy_base = AM33XX_PRU0IRAM_PHYS_BASE; + prussdrv.pru1_iram_phy_base = AM33XX_PRU1IRAM_PHYS_BASE; + prussdrv.pruss_sharedram_phy_base = + AM33XX_PRUSS_SHAREDRAM_BASE; + prussdrv.pruss_cfg_phy_base = AM33XX_PRUSS_CFG_BASE; + prussdrv.pruss_uart_phy_base = AM33XX_PRUSS_UART_BASE; + prussdrv.pruss_iep_phy_base = AM33XX_PRUSS_IEP_BASE; + prussdrv.pruss_ecap_phy_base = AM33XX_PRUSS_ECAP_BASE; + prussdrv.pruss_miirt_phy_base = AM33XX_PRUSS_MIIRT_BASE; + prussdrv.pruss_mdio_phy_base = AM33XX_PRUSS_MDIO_BASE; + } + break; + default: + printf("UNKNOWN\n"); + } + + prussdrv.pru1_dataram_base = + prussdrv.pru0_dataram_base + prussdrv.pru1_dataram_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.intc_base = + prussdrv.pru0_dataram_base + prussdrv.intc_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pru0_control_base = + prussdrv.pru0_dataram_base + prussdrv.pru0_control_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pru0_debug_base = + prussdrv.pru0_dataram_base + prussdrv.pru0_debug_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pru1_control_base = + prussdrv.pru0_dataram_base + prussdrv.pru1_control_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pru1_debug_base = + prussdrv.pru0_dataram_base + prussdrv.pru1_debug_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pru0_iram_base = + prussdrv.pru0_dataram_base + prussdrv.pru0_iram_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pru1_iram_base = + prussdrv.pru0_dataram_base + prussdrv.pru1_iram_phy_base - + prussdrv.pru0_dataram_phy_base; + if (prussdrv.version == PRUSS_V2) { + prussdrv.pruss_sharedram_base = + prussdrv.pru0_dataram_base + + prussdrv.pruss_sharedram_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pruss_cfg_base = + prussdrv.pru0_dataram_base + prussdrv.pruss_cfg_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pruss_uart_base = + prussdrv.pru0_dataram_base + prussdrv.pruss_uart_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pruss_iep_base = + prussdrv.pru0_dataram_base + prussdrv.pruss_iep_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pruss_ecap_base = + prussdrv.pru0_dataram_base + prussdrv.pruss_ecap_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pruss_miirt_base = + prussdrv.pru0_dataram_base + prussdrv.pruss_miirt_phy_base - + prussdrv.pru0_dataram_phy_base; + prussdrv.pruss_mdio_base = + prussdrv.pru0_dataram_base + prussdrv.pruss_mdio_phy_base - + prussdrv.pru0_dataram_phy_base; + } +#ifndef DISABLE_L3RAM_SUPPORT + fd = open(PRUSS_UIO_DRV_L3RAM_BASE, O_RDONLY); + if (fd >= 0) { + read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); + prussdrv.l3ram_phys_base = + strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); + close(fd); + } else + return -1; + + + fd = open(PRUSS_UIO_DRV_L3RAM_SIZE, O_RDONLY); + if (fd >= 0) { + read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); + prussdrv.l3ram_map_size = + strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); + close(fd); + } else + return -1; + + prussdrv.l3ram_base = + mmap(0, prussdrv.l3ram_map_size, PROT_READ | PROT_WRITE, + MAP_SHARED, prussdrv.mmap_fd, PRUSS_UIO_MAP_OFFSET_L3RAM); +#endif + + fd = open(PRUSS_UIO_DRV_EXTRAM_BASE, O_RDONLY); + if (fd >= 0) { + read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); + prussdrv.extram_phys_base = + strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); + close(fd); + } else + return -1; + + fd = open(PRUSS_UIO_DRV_EXTRAM_SIZE, O_RDONLY); + if (fd >= 0) { + read(fd, hexstring, PRUSS_UIO_PARAM_VAL_LEN); + prussdrv.extram_map_size = + strtoul(hexstring, NULL, HEXA_DECIMAL_BASE); + close(fd); + } else + return -1; + + + prussdrv.extram_base = + mmap(0, prussdrv.extram_map_size, PROT_READ | PROT_WRITE, + MAP_SHARED, prussdrv.mmap_fd, PRUSS_UIO_MAP_OFFSET_EXTRAM); + + return 0; + +} + +int prussdrv_init(void) +{ + memset(&prussdrv, 0, sizeof(prussdrv)); + return 0; + +} + +int prussdrv_open(unsigned int pru_evtout_num) +{ + char name[PRUSS_UIO_PRAM_PATH_LEN]; + if (!prussdrv.fd[pru_evtout_num]) { + sprintf(name, "/dev/uio%d", pru_evtout_num); + prussdrv.fd[pru_evtout_num] = open(name, O_RDWR | O_SYNC); + return __prussdrv_memmap_init(); + } else { + return -1; + + } +} + + + + +int prussdrv_pru_reset(unsigned int prunum) +{ + unsigned int *prucontrolregs; + if (prunum == 0) + prucontrolregs = (unsigned int *) prussdrv.pru0_control_base; + else if (prunum == 1) + prucontrolregs = (unsigned int *) prussdrv.pru1_control_base; + else + return -1; + *prucontrolregs = 0; + return 0; +} + +int prussdrv_pru_enable(unsigned int prunum) +{ + unsigned int *prucontrolregs; + if (prunum == 0) + prucontrolregs = (unsigned int *) prussdrv.pru0_control_base; + else if (prunum == 1) + prucontrolregs = (unsigned int *) prussdrv.pru1_control_base; + else + return -1; + + *prucontrolregs = 2; + return 0; + +} + +int prussdrv_pru_disable(unsigned int prunum) +{ + unsigned int *prucontrolregs; + if (prunum == 0) + prucontrolregs = (unsigned int *) prussdrv.pru0_control_base; + else if (prunum == 1) + prucontrolregs = (unsigned int *) prussdrv.pru1_control_base; + else + return -1; + *prucontrolregs = 1; + return 0; + +} + +int prussdrv_pru_write_memory(unsigned int pru_ram_id, + unsigned int wordoffset, + unsigned int *memarea, + unsigned int bytelength) +{ + unsigned int *pruramarea, i, wordlength; + switch (pru_ram_id) { + case PRUSS0_PRU0_IRAM: + pruramarea = (unsigned int *) prussdrv.pru0_iram_base; + break; + case PRUSS0_PRU1_IRAM: + pruramarea = (unsigned int *) prussdrv.pru1_iram_base; + break; + case PRUSS0_PRU0_DATARAM: + pruramarea = (unsigned int *) prussdrv.pru0_dataram_base; + break; + case PRUSS0_PRU1_DATARAM: + pruramarea = (unsigned int *) prussdrv.pru1_dataram_base; + break; + case PRUSS0_SHARED_DATARAM: + if (prussdrv.version != PRUSS_V2) + return -1; + pruramarea = (unsigned int *) prussdrv.pruss_sharedram_base; + break; + default: + return -1; + } + + + wordlength = (bytelength + 3) >> 2; //Adjust length as multiple of 4 bytes + for (i = 0; i < wordlength; i++) { + *(pruramarea + i + wordoffset) = *(memarea + i); + } + return wordlength; + +} + + +int prussdrv_pruintc_init(tpruss_intc_initdata * prussintc_init_data) +{ + unsigned int *pruintc_io = (unsigned int *) prussdrv.intc_base; + unsigned int i, mask1, mask2; + + pruintc_io[PRU_INTC_SIPR1_REG >> 2] = 0xFFFFFFFF; + pruintc_io[PRU_INTC_SIPR2_REG >> 2] = 0xFFFFFFFF; + + for (i = 0; i < (NUM_PRU_SYS_EVTS + 3) >> 2; i++) + pruintc_io[(PRU_INTC_CMR1_REG >> 2) + i] = 0; + for (i = 0; + ((prussintc_init_data->sysevt_to_channel_map[i].sysevt != -1) + && (prussintc_init_data->sysevt_to_channel_map[i].channel != + -1)); i++) { + __prussintc_set_cmr(pruintc_io, + prussintc_init_data->sysevt_to_channel_map[i]. + sysevt, + prussintc_init_data->sysevt_to_channel_map[i]. + channel); + } + for (i = 0; i < (NUM_PRU_HOSTS + 3) >> 2; i++) + pruintc_io[(PRU_INTC_HMR1_REG >> 2) + i] = 0; + for (i = 0; + ((prussintc_init_data->channel_to_host_map[i].channel != -1) + && (prussintc_init_data->channel_to_host_map[i].host != -1)); + i++) { + + __prussintc_set_hmr(pruintc_io, + prussintc_init_data->channel_to_host_map[i]. + channel, + prussintc_init_data->channel_to_host_map[i]. + host); + } + + pruintc_io[PRU_INTC_SITR1_REG >> 2] = 0x0; + pruintc_io[PRU_INTC_SITR2_REG >> 2] = 0x0; + + + mask1 = mask2 = 0; + for (i = 0; prussintc_init_data->sysevts_enabled[i] != 255; i++) { + if (prussintc_init_data->sysevts_enabled[i] < 32) { + mask1 = + mask1 + (1 << (prussintc_init_data->sysevts_enabled[i])); + } else if (prussintc_init_data->sysevts_enabled[i] < 64) { + mask2 = + mask2 + + (1 << (prussintc_init_data->sysevts_enabled[i] - 32)); + } else { + printf("Error: SYS_EVT%d out of range\n", + prussintc_init_data->sysevts_enabled[i]); + return -1; + } + } + pruintc_io[PRU_INTC_ESR1_REG >> 2] = mask1; + pruintc_io[PRU_INTC_SECR1_REG >> 2] = mask1; + pruintc_io[PRU_INTC_ESR2_REG >> 2] = mask2; + pruintc_io[PRU_INTC_SECR2_REG >> 2] = mask2; + + for (i = 0; i < MAX_HOSTS_SUPPORTED; i++) + if (prussintc_init_data->host_enable_bitmask & (1 << i)) { + pruintc_io[PRU_INTC_HIEISR_REG >> 2] = i; + } + + pruintc_io[PRU_INTC_GER_REG >> 2] = 0x1; + + return 0; +} + + +int prussdrv_pru_send_event(unsigned int eventnum) +{ + unsigned int *pruintc_io = (unsigned int *) prussdrv.intc_base; + if (eventnum < 32) + pruintc_io[PRU_INTC_SRSR1_REG >> 2] = 1 << eventnum; + else + pruintc_io[PRU_INTC_SRSR2_REG >> 2] = 1 << (eventnum - 32); + return 0; +} + +int prussdrv_pru_wait_event(unsigned int pru_evtout_num) +{ + int event_count; + unsigned int *pruintc_io = (unsigned int *) prussdrv.intc_base; + read(prussdrv.fd[pru_evtout_num], &event_count, sizeof(int)); + pruintc_io[PRU_INTC_HIEISR_REG >> 2] = pru_evtout_num+2; + return 0; + +} + +int prussdrv_pru_clear_event(unsigned int eventnum) +{ + unsigned int *pruintc_io = (unsigned int *) prussdrv.intc_base; + if (eventnum < 32) + pruintc_io[PRU_INTC_SECR1_REG >> 2] = 1 << eventnum; + else + pruintc_io[PRU_INTC_SECR2_REG >> 2] = 1 << (eventnum - 32); + return 0; +} + +int prussdrv_pru_send_wait_clear_event(unsigned int send_eventnum, + unsigned int pru_evtout_num, + unsigned int ack_eventnum) +{ + prussdrv_pru_send_event(send_eventnum); + prussdrv_pru_wait_event(pru_evtout_num); + prussdrv_pru_clear_event(ack_eventnum); + return 0; + +} + + +int prussdrv_map_l3mem(void **address) +{ + *address = prussdrv.l3ram_base; + return 0; +} + + + +int prussdrv_map_extmem(void **address) +{ + + *address = prussdrv.extram_base; + return 0; + +} + + +int prussdrv_map_prumem(unsigned int pru_ram_id, void **address) +{ + switch (pru_ram_id) { + case PRUSS0_PRU0_DATARAM: + *address = prussdrv.pru0_dataram_base; + break; + case PRUSS0_PRU1_DATARAM: + *address = prussdrv.pru1_dataram_base; + break; + case PRUSS0_SHARED_DATARAM: + if (prussdrv.version != PRUSS_V2) + return -1; + *address = prussdrv.pruss_sharedram_base; + break; + default: + *address = 0; + return -1; + } + return 0; +} + +int prussdrv_map_peripheral_io(unsigned int per_id, void **address) +{ + if (prussdrv.version != PRUSS_V2) + return -1; + + switch (per_id) { + case PRUSS0_CFG: + *address = prussdrv.pruss_cfg_base; + break; + case PRUSS0_UART: + *address = prussdrv.pruss_uart_base; + break; + case PRUSS0_IEP: + *address = prussdrv.pruss_iep_base; + break; + case PRUSS0_ECAP: + *address = prussdrv.pruss_ecap_base; + break; + case PRUSS0_MII_RT: + *address = prussdrv.pruss_miirt_base; + break; + case PRUSS0_MDIO: + *address = prussdrv.pruss_mdio_base; + break; + default: + *address = 0; + return -1; + } + return 0; +} + +unsigned int prussdrv_get_phys_addr(void *address) +{ + unsigned int retaddr = 0; + if ((address >= prussdrv.pru0_dataram_base) + && (address < + prussdrv.pru0_dataram_base + prussdrv.pruss_map_size)) { + retaddr = + ((unsigned int) (address - prussdrv.pru0_dataram_base) + + prussdrv.pru0_dataram_phy_base); + } else if ((address >= prussdrv.l3ram_base) + && (address < + prussdrv.l3ram_base + prussdrv.l3ram_map_size)) { + retaddr = + ((unsigned int) (address - prussdrv.l3ram_base) + + prussdrv.l3ram_phys_base); + } else if ((address >= prussdrv.extram_base) + && (address < + prussdrv.extram_base + prussdrv.extram_map_size)) { + retaddr = + ((unsigned int) (address - prussdrv.extram_base) + + prussdrv.extram_phys_base); + } + return retaddr; + +} + +void *prussdrv_get_virt_addr(unsigned int phyaddr) +{ + void *address = 0; + if ((phyaddr >= prussdrv.pru0_dataram_phy_base) + && (phyaddr < + prussdrv.pru0_dataram_phy_base + prussdrv.pruss_map_size)) { + address = + (void *) ((unsigned int) prussdrv.pru0_dataram_base + + (phyaddr - prussdrv.pru0_dataram_phy_base)); + } else if ((phyaddr >= prussdrv.l3ram_phys_base) + && (phyaddr < + prussdrv.l3ram_phys_base + prussdrv.l3ram_map_size)) { + address = + (void *) ((unsigned int) prussdrv.l3ram_base + + (phyaddr - prussdrv.l3ram_phys_base)); + } else if ((phyaddr >= prussdrv.extram_phys_base) + && (phyaddr < + prussdrv.extram_phys_base + prussdrv.extram_map_size)) { + address = + (void *) ((unsigned int) prussdrv.extram_base + + (phyaddr - prussdrv.extram_phys_base)); + } + return address; + +} + + +int prussdrv_exit() +{ + int i; + munmap(prussdrv.pru0_dataram_base, prussdrv.pruss_map_size); + munmap(prussdrv.l3ram_base, prussdrv.l3ram_map_size); + munmap(prussdrv.extram_base, prussdrv.extram_map_size); + for (i = 0; i < NUM_PRU_HOSTIRQS; i++) { + if (prussdrv.fd[i]) + close(prussdrv.fd[i]); + if (prussdrv.irq_thread[i]) + pthread_join(prussdrv.irq_thread[i], NULL); + } + return 0; +} + +int prussdrv_exec_program(int prunum, char *filename) +{ + FILE *fPtr; + unsigned char fileDataArray[PRUSS_MAX_IRAM_SIZE]; + int fileSize = 0; + unsigned int pru_ram_id; + + if (prunum == 0) + pru_ram_id = PRUSS0_PRU0_IRAM; + else if (prunum == 1) + pru_ram_id = PRUSS0_PRU1_IRAM; + else + return -1; + + // Open an File from the hard drive + fPtr = fopen(filename, "rb"); + if (fPtr == NULL) { + printf("File %s open failed\n", filename); + } else { + printf("File %s open passed\n", filename); + } + // Read file size + fseek(fPtr, 0, SEEK_END); + fileSize = ftell(fPtr); + + if (fileSize == 0) { + printf("File read failed.. Closing program\n"); + fclose(fPtr); + return -1; + } + + fseek(fPtr, 0, SEEK_SET); + + if (fileSize != + fread((unsigned char *) fileDataArray, 1, fileSize, fPtr)) { + printf("WARNING: File Size mismatch\n"); + } + + fclose(fPtr); + + // Make sure PRU sub system is first disabled/reset + prussdrv_pru_disable(prunum); + prussdrv_pru_write_memory(pru_ram_id, 0, + (unsigned int *) fileDataArray, fileSize); + prussdrv_pru_enable(prunum); + + return 0; +} + +int prussdrv_start_irqthread(unsigned int pru_evtout_num, int priority, + prussdrv_function_handler irqhandler) +{ + pthread_attr_t pthread_attr; + struct sched_param sched_param; + pthread_attr_init(&pthread_attr); + if (priority != 0) { + pthread_attr_setinheritsched(&pthread_attr, + PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(&pthread_attr, SCHED_FIFO); + sched_param.sched_priority = priority; + pthread_attr_setschedparam(&pthread_attr, &sched_param); + } + + pthread_create(&prussdrv.irq_thread[pru_evtout_num], &pthread_attr, + irqhandler, NULL); + + pthread_attr_destroy(&pthread_attr); + + return 0; + +} diff --git a/am335x/pasm/LICENCE.txt b/am335x/pasm/LICENCE.txt new file mode 100644 index 00000000..4295a9e2 --- /dev/null +++ b/am335x/pasm/LICENCE.txt @@ -0,0 +1,39 @@ +/* +* {module name} +* +* {module description} +* +* Copyright (C) {YEAR} 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. +* +*/ + + diff --git a/am335x/pasm/Makefile b/am335x/pasm/Makefile new file mode 100755 index 00000000..6482c98d --- /dev/null +++ b/am335x/pasm/Makefile @@ -0,0 +1,27 @@ +# Builds with whatever the host format is +CC := gcc + +CFLAGS += \ + -O3 \ + -W \ + -Wall \ + -D_UNIX_ \ + +OBJS := \ + pasm.o \ + pasmpp.o \ + pasmexp.o \ + pasmop.o \ + pasmdot.o \ + pasmstruct.o \ + pasmmacro.o \ + +all: pasm + +pasm: $(OBJS) + $(CC) -o $@ $^ + +clean: + $(RM) -f *.o + + diff --git a/am335x/pasm/pasm.c b/am335x/pasm/pasm.c new file mode 100644 index 00000000..380899be --- /dev/null +++ b/am335x/pasm/pasm.c @@ -0,0 +1,1358 @@ +/* + * pasm.c + * + * Copyright (C) 2012 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. + * +*/ + +/*=========================================================================== + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + +/*=========================================================================== +// PASM - PRU Assembler +//--------------------------------------------------------------------------- +// +// File : pasm.c +// +// Description: +// Main assembler control program. +// - Processes command line and flags +// - Runs the main assembler engine (dual pass) +// - Handles error reporting +// - Handles label creation and matching +// - Handle output file generation +// +//--------------------------------------------------------------------------- +// Revision: +// 21-Jun-13: 0.84 - Open source version +============================================================================*/ + +#include +#include +#include +#if !defined(__APPLE__) +#include +#else +#include +#endif +#include +#include "pasm.h" +#include "pasmdbg.h" + +/* +// Multiple Core Revision Support +// ------------------------------ +// +// -V0 PRU Legacy (same as -x) +// -V1 PRU Generation 1 (default) +// Adds [LMBD,SCAN,HALT,ZERO(1),MVI(1),SLP(1)] Removes [LFC,STC] +// -V2 PRU Generation 2 (same as -X) +// Adds [ZERO(2),FILL,XIN,XOUT,XCHG,MVI(2)] Removes [SCAN] +// -V3 PRU Generation 3 +// Adds [SLP(2),LOOP,ILOOP,SXIN,SXOUT,SXCHG,NOPx] +// +// ZERO(1) : Zero is multi-cycle pseudo op encoded via moves +// ZERO(2) : Zero is single-cycle pseudo op encoded via XFR +// +// MVI(1) : Pseudo op forms of MVI only +// MVI(2) : Pseudo op forms of MVI only +// +// SLP(1) : SLP with trailing NOP +// SLP(2) : SLP without trailing NOP +*/ + + +/* ---------- Local Macro Definitions ----------- */ + +#define PROCESSOR_NAME_STRING ("PRU") +#define VERSION_STRING ("0.84") + +#define MAXFILE (256) /* Max file length for output files */ +#define MAX_PROGRAM (16384) /* Max instruction count */ +#define MAX_CMD_EQUATE (8) /* Max equates that can be put on command line */ + +#define RET_ERROR (1) +#define RET_SUCCESS (0) + +/* Big/Little Endian Conversions */ +#define HNC16(a) ((((a)>>8)&0xff)+(((a)<<8)&0xff00)) +#define HNC32(a) ((((a)>>24)&0xff)+(((a)>>8)&0xff00)+(((a)<<8)&0xff0000)+(((a)<<24)&0xff000000)) + +/* User Options */ +unsigned int Options = 0; +unsigned int Core = CORE_NONE; +FILE *ListingFile = 0; + +/* Assembler Engine */ +int Pass; /* Pass 1 or 2 of parser */ +int HaveEntry; /* Entrypont flag (init to 0) */ +int EntryPoint; /* Entrypont (init to -1) */ +int CodeOffset; /* Current instruction "word" offset (zero based) */ +int Errors; /* Total number or errors */ +int FatalError; /* Set on fatal error */ +int Warnings; /* Total number of warnings */ +uint RetRegValue; /* Return register index */ +uint RetRegField; /* Return register field */ + +LABEL *pLabelList=0; /* List of installed labels */ +int LabelCount=0; + +CODEGEN ProgramImage[MAX_PROGRAM]; + +SOURCEFILE cmdLine = { 0, 0, 0, 0, 0, 0, 0, 0, "[CommandLine]", "" }; +char cmdLineName[MAX_CMD_EQUATE][EQUATE_NAME_LEN]; +char cmdLineData[MAX_CMD_EQUATE][EQUATE_DATA_LEN]; +int cmdLineEquates = 0; + +char nameCArray[EQUATE_DATA_LEN]; +int nameCArraySet = 0; + +/* Local Support Funtions */ +static int ValidateOffset( SOURCEFILE *ps ); +static int PrintLine( FILE *pfOut, SOURCEFILE *ps ); +static int GetInfoFromAddr( uint address, uint *pIndex, uint *pLineNo, uint *pCodeWord ); +static int ListFile( FILE *pfOut, SOURCEFILE *ps ); + +/* +// Main Assembler Entry Point +// +*/ +int main(int argc, char *argv[]) +{ + int i,j; + int CodeOffsetPass1 = 0; + char *infile, *outfile, *flags; + SOURCEFILE *mainsource; + char outbase[MAXFILE],outfilename[MAXFILE]; + + printf("\n\n%s Assembler Version %s\n",PROCESSOR_NAME_STRING, VERSION_STRING); + printf("Copyright (C) 2005-2013 by Texas Instruments Inc.\n\n"); + + /* Scan argv[0] to the final '/' in program name */ + i=0; + j=-1; + while( argv[0][i] ) + { + if( argv[0][i] == '/' || argv[0][i] == '\\') + j=i; + i++; + } + argv[0]+=(j+1); + + /* + // Process command line + */ + infile=0; + flags=0; + outfile=0; + + if( argc<2 ) + { +USAGE: + printf("Usage: %s [-V#EBbcmLldz] [-Dname=value] [-Cname] InFile [OutFileBase]\n\n",argv[0]); + printf(" V# - Specify core version (V0,V1,V2,V3). (Default is V1)\n"); + printf(" E - Assemble for big endian core\n"); + printf(" B - Create big endian binary output (*.bib)\n"); + printf(" b - Create little endian binary output (*.bin)\n"); + printf(" c - Create 'C array' binary output (*_bin.h)\n"); + printf(" m - Create 'image' binary output (*.img)\n"); + printf(" L - Create annotated source file style listing (*.txt)\n"); + printf(" l - Create raw listing file (*.lst)\n"); + printf(" d - Create pView debug file (*.dbg)\n"); + printf(" z - Enable debug messages\n"); + printf("\n D - Set equate 'name' to 1 using '-Dname', or to any\n"); + printf(" value using '-Dname=value'\n"); + printf(" C - Name the C array in 'C array' binary output\n"); + printf(" to 'name' using '-Cname'\n"); + printf("\n"); + return(RET_ERROR); + } + + /* Get all non-flag arguments */ + for( i=1; i'3' ) + { + printf("\nExpected a number (0-3) after option 'V'\n\n"); + goto USAGE; + } + if( Core != CORE_NONE ) + { + printf("\nDo not specify more than one core version or use -V with -X or -x\n\n"); + goto USAGE; + } + Core = CORE_V0 + *flags - '0'; + } + else if( *flags == 'x' ) + { + if( Core != CORE_NONE ) + { + printf("\nDo not use -x with -X or -V\n\n"); + goto USAGE; + } + Core = CORE_V0; + } + else if( *flags == 'X' ) + { + if( Core != CORE_NONE ) + { + printf("\nDo not use -X with -x or -V\n\n"); + goto USAGE; + } + Core = CORE_V2; + } + else if( *flags == 'E' ) + Options |= OPTION_BIGENDIAN; + else if( *flags == 'b' ) + Options |= OPTION_BINARY; + else if( *flags == 'B' ) + Options |= OPTION_BINARYBIG; + else if( *flags == 'c' ) + Options |= OPTION_CARRAY; + else if( *flags == 'm' ) + Options |= OPTION_IMGFILE; + else if( *flags == 'l' ) + Options |= OPTION_LISTING; + else if( *flags == 'L' ) + Options |= OPTION_SOURCELISTING; + else if( *flags == 'd' ) + Options |= OPTION_DBGFILE; + else if( *flags == 'z' ) + Options |= OPTION_DEBUG; + else + { + printf("\nUnknown flag '%c'\n\n",*flags); + goto USAGE; + } + flags++; + } + } + } + + if( Core==CORE_NONE ) + Core = CORE_V1; + + /* Check input file */ + if( !infile ) + goto USAGE; + + /* Check output file base - make sure no '.' */ + if( outfile ) + { + if( strlen(outfile) > (MAXFILE-5) ) + { Report(0,REP_ERROR,"Outfile name too long"); return(RET_ERROR); } + i=0; + while( outfile[i] ) + { + if( outfile[i]=='.' ) + { + if( outfile[i+1]=='.' ) + i++; + else + { Report(0,REP_ERROR,"Outfile should be basename only - no '.'"); return(RET_ERROR); } + } + i++; + } + strcpy( outbase, outfile ); + } + + /* Test opening the main source file */ + if( !(mainsource=InitSourceFile(0,infile)) ) + return(RET_ERROR); + + /* Setup outfile base */ + if( !outfile ) + { + for(i=0; mainsource->SourceName[i] && mainsource->SourceName[i]!='.'; i++ ) + outbase[i]=mainsource->SourceName[i]; + outbase[i] = 0; + } + if( Options & OPTION_DEBUG ) + printf("Output base filename: '%s'\n",outbase); + + /* Close the source file for now */ + CloseSourceFile( mainsource ); + + /* If no output specified, default to 'C' array */ + if( !(Options & (OPTION_BINARY|OPTION_CARRAY|OPTION_BINARYBIG|OPTION_IMGFILE|OPTION_DBGFILE)) ) + { + printf("Note: Using default output '-c' (C array *_bin.h)\n\n"); + Options |= OPTION_CARRAY; + } + + /* Open listing file */ + if( Options & OPTION_LISTING ) + { + strcpy( outfilename, outbase ); + strcat( outfilename, ".lst" ); + if (!(ListingFile = fopen(outfilename,"wb"))) + { Report(0,REP_ERROR,"Unable to open output file: %s",outfilename); return(RET_ERROR); } + } + + /* Clear the binary image */ + memset( ProgramImage, 0, sizeof(ProgramImage) ); + + /* Make 2 assembler passes */ + Pass = 0; + Errors = 0; + Warnings = 0; + FatalError = 0; + RetRegValue = DEFAULT_RETREGVAL; + RetRegField = DEFAULT_RETREGFLD; + while( !Errors && Pass<2 ) + { + Pass++; + CodeOffset = -1; + HaveEntry = 0; + EntryPoint = -1; + + /* Initialize the PP and DOT modules */ + for(i=0; iOffset; + strcpy(lbl.Name,pLabel->Name); + if(BigEndian) + lbl.AddrOffset = HNC32(lbl.AddrOffset); + if( fwrite(&lbl,1,sizeof(DBGFILE_LABEL),Outfile) != sizeof(DBGFILE_LABEL) ) + Report(0,REP_ERROR,"File write error"); + pLabel = pLabel->pNext; + } + } + + for(i=0; i<(int)hdr.FileCount; i++) + { + memset( &file, 0, sizeof(DBGFILE_FILE) ); + if( !strcmp( sfArray[i].SourceBaseDir,"./") || + ((strlen(sfArray[i].SourceName)+strlen(sfArray[i].SourceBaseDir)) >= DBGFILE_NAMELEN_SHORT) ) + strcpy(file.SourceName,sfArray[i].SourceName); + else + { + strcpy(file.SourceName,sfArray[i].SourceBaseDir); + strcat(file.SourceName,sfArray[i].SourceName); + } + if( fwrite(&file,1,sizeof(DBGFILE_FILE),Outfile) != sizeof(DBGFILE_FILE) ) + Report(0,REP_ERROR,"File write error"); + } + + for(i=0; i<(int)hdr.CodeCount; i++) + { + memset( &code, 0, sizeof(DBGFILE_CODE) ); + code.Flags = ProgramImage[i].Flags; + code.Resv8 = ProgramImage[i].Resv8; + code.FileIndex = ProgramImage[i].FileIndex; + code.Line = ProgramImage[i].Line; + code.AddrOffset = ProgramImage[i].AddrOffset; + code.CodeWord = ProgramImage[i].CodeWord; + if(BigEndian) + { + code.FileIndex = HNC16(code.FileIndex); + code.Line = HNC32(code.Line); + code.AddrOffset = HNC32(code.AddrOffset); + code.CodeWord = HNC32(code.CodeWord); + } + if( fwrite(&code,1,sizeof(DBGFILE_CODE),Outfile) != sizeof(DBGFILE_CODE) ) + Report(0,REP_ERROR,"File write error"); + } + fclose( Outfile ); + } + } + if( Options & OPTION_SOURCELISTING ) + { + FILE *Outfile; + + strcpy( outfilename, outbase ); + strcat( outfilename, ".txt" ); + if (!(Outfile = fopen(outfilename,"wb"))) + Report(0,REP_ERROR,"Unable to open output file: %s",outfilename); + else + { + char FullPath[SOURCE_BASE_DIR+SOURCE_NAME]; + + for( i=0; i<(int)sfIndex; i++ ) + { + fprintf(Outfile, "Source File %d : '%s' ", i+1, sfArray[i].SourceName); + strcpy(FullPath,sfArray[i].SourceBaseDir); + strcat(FullPath,sfArray[i].SourceName); + sfArray[i].FilePtr=fopen(FullPath,"rb"); + if( sfArray[i].FilePtr!=0 ) + { + sfArray[i].CurrentLine = 1; + sfArray[i].CurrentColumn = 1; + sfArray[i].LastChar = 0; + ListFile(Outfile,&sfArray[i]); + fclose(sfArray[i].FilePtr); + fprintf(Outfile, "\n\n"); + } + else + fprintf(Outfile, "(File Not Found '%s')\n\n",FullPath); + } + + fclose(Outfile); + } + } + if( Options & OPTION_BINARY ) + { + FILE *Outfile; + + strcpy( outfilename, outbase ); + strcat( outfilename, ".bin" ); + if (!(Outfile = fopen(outfilename,"wb"))) + Report(0,REP_ERROR,"Unable to open output file: %s",outfilename); + else + { + unsigned char tmp; + + /* Write out as Little Endian */ + for(i=0;i>8); + fwrite(&tmp,1,1,Outfile); + tmp = (unsigned char)(ProgramImage[i].CodeWord>>16); + fwrite(&tmp,1,1,Outfile); + tmp = (unsigned char)(ProgramImage[i].CodeWord>>24); + fwrite(&tmp,1,1,Outfile); + } + fclose( Outfile ); + } + } + if( Options & OPTION_BINARYBIG ) + { + FILE *Outfile; + + strcpy( outfilename, outbase ); + strcat( outfilename, ".bib" ); + if (!(Outfile = fopen(outfilename,"wb"))) + Report(0,REP_ERROR,"Unable to open output file: %s",outfilename); + else + { + unsigned char tmp; + + /* Write out as Big Endian */ + for(i=0;i>24); + fwrite(&tmp,1,1,Outfile); + tmp = (unsigned char)(ProgramImage[i].CodeWord>>16); + fwrite(&tmp,1,1,Outfile); + tmp = (unsigned char)(ProgramImage[i].CodeWord>>8); + fwrite(&tmp,1,1,Outfile); + tmp = (unsigned char)ProgramImage[i].CodeWord; + fwrite(&tmp,1,1,Outfile); + } + fclose( Outfile ); + } + } + + /* Assember label cleanup */ + while( pLabelList ) + LabelDestroy( pLabelList ); + + if( Errors || CodeOffset<=0 ) + return(RET_ERROR); + return(RET_SUCCESS); +} + + +/* +// ProcessSourceFile +// +// New source file to assemble. +// +// Returns 1 on success, 0 on error +*/ +#define MAX_SOURCE_LINE 256 +int ProcessSourceFile( SOURCEFILE *ps ) +{ + char src[MAX_SOURCE_LINE]; + int i; + + for(;;) + { + /* Abort on a total disaster */ + if( FatalError || Errors >= 25 ) + { printf("Aborting...\n"); return(0); } + + /* Get a line of source code */ + i = GetSourceLine( ps, src, MAX_SOURCE_LINE ); + if( !i ) + return(1); + if( i<0 ) + continue; + + if( !ProcessSourceLine(ps, i, src) && Pass==2 ) + return(0); + } +} + + +/* +// ProcessSourceLine +// +// New source line to assemble. +// +// Returns 1 on success, 0 on error +*/ +int ProcessSourceLine( SOURCEFILE *ps, int length, char *src ) +{ + char *pParams[MAX_TOKENS]; + SRCLINE sl; + int i,rc; + +REPEAT: + if( !ParseSourceLine(ps,length,src,&sl) ) + return(0); + + /* Process Label */ + if( sl.Flags & SRC_FLG_LABEL ) + { + /* Make sure offset is ready */ + if( !ValidateOffset(ps) ) + return(0); + + /* Create Label */ + if( Pass==1 ) + { + LabelCreate(ps, sl.Label, CodeOffset); + } + + /* Note it in listing file */ + if( Pass==2 && (Options & OPTION_LISTING) ) + { + fprintf(ListingFile,"%s(%5d) : 0x%04x = Label : %s:\n", + ps->SourceName,ps->CurrentLine,CodeOffset,sl.Label); + } + } + + /* Process Command/Opcode */ + if( sl.Terms ) + { + /* Get the parameters into a collection of string pointers */ + for(i=0; i<(int)sl.Terms; i++) + pParams[i]=sl.Term[i]; + for( ; iFlags = 0; + pa->Terms = 0; + +PROCESS_LINE: + /* Make sure character 1 is legal */ + c = src[srcIdx++]; + if( !LabelChar(c,1) && c!='.' ) + { + Report(ps,REP_ERROR,"Syntax error in Cmd/Opcode"); + return(0); + } + + /* Get the Opcode or Command */ + wordIdx = 0; + while( LabelChar(c,0) || c=='.' ) + { + if( wordIdx>=(TOKEN_MAX_LEN-1) ) + { Report(ps,REP_ERROR,"Cmd/Opcode too long"); return(0); } + pa->Term[0][wordIdx++] = c; + c = src[srcIdx++]; + } + pa->Term[0][wordIdx]=0; + + /* See if it is a label */ + if( c==':' ) + { + if( pa->Flags & SRC_FLG_LABEL ) + { Report(ps,REP_ERROR,"Two labels found on the same line"); return(0); } + pa->Flags |= SRC_FLG_LABEL; + strcpy(pa->Label,pa->Term[0]); + + /* Process any assembly after the label */ + c = src[srcIdx]; + if( c!=0 ) + { + while( c==' ' || c==0x9 ) + c = src[++srcIdx]; + goto PROCESS_LINE; + } + return(1); + } + + if( c!=' ' && c!=0 && c!=0x9 ) + { + Report(ps,REP_ERROR,"Syntax error in Cmd/Opcode"); + return(0); + } + + /* Get up to "MAX_TOKENS-1" parameters (comma delimited) */ + parmCnt=0; + while(c) + { + wordIdx=0; + parmCnt++; + if( parmCnt==MAX_TOKENS ) + { Report(ps,REP_ERROR,"Too many parameters on line"); return(0); } + + /* Trim off leading white space */ + while( c==' ' || c==0x9 ) + c = src[srcIdx++]; + + if( !LabelChar(c,0) && + c!='.' && c!='#' && c!='-' && c!='(' && c!='"' && c!='&' && c!='*' ) + { Report(ps,REP_ERROR,"Syntax error in parameter %d",parmCnt); return(0); } + + if( parmCnt==1 && c=='.' ) + { + while( c!=0 && c!=',' && c!=' ' && c!=0x9 ) + { + if( wordIdx>=(TOKEN_MAX_LEN-1) ) + { Report(ps,REP_ERROR,"Parameter %d too long",parmCnt); return(0); } + pa->Term[parmCnt][wordIdx++] = c; + c = src[srcIdx++]; + + } + if(c==' ' || c==0x9) + c=','; + + pa->Flags |= SRC_FLG_DOTCMD2; + } + else + { + while( c!=0 && c!=',' ) + { + if( wordIdx>=(TOKEN_MAX_LEN-1) ) + { Report(ps,REP_ERROR,"Parameter %d too long",parmCnt); return(0); } + pa->Term[parmCnt][wordIdx++] = c; + c = src[srcIdx++]; + } + } + pa->Term[parmCnt][wordIdx] = 0; + + /* Trim off trailing white space */ + while( wordIdx && (pa->Term[parmCnt][wordIdx-1]==0x9 || pa->Term[parmCnt][wordIdx-1]==' ') ) + pa->Term[parmCnt][--wordIdx]=0; + + /* This character must be a comma or NULL */ + if( c==',' ) + c = src[srcIdx++]; + else if( c ) + { Report(ps,REP_ERROR,"Syntax error in parameter %d",parmCnt); return(0); } + } + + parmCnt++; + pa->Terms = parmCnt; + + /* If its a dot command, mark it */ + if( pa->Term[0][0]=='.' ) + pa->Flags |= SRC_FLG_DOTCMD1; + + return(1); +} + + +/* +// GenOp +// +// Generate an opcode to the ouput file +// +// ps - Pointer to source file record +// TermCnt - Number of terms (including the command) +// pTerms - Pointer to the terms +// opcode - Generated Opcode +*/ +void GenOp( SOURCEFILE *ps, int TermCnt, char **pTerms, uint opcode ) +{ + int i; + + if( !ValidateOffset(ps) ) + return; + + if( (Options & OPTION_LISTING) && Pass==2 ) + { + fprintf(ListingFile,"%s(%5d) : 0x%04x = 0x%08x : ", + ps->SourceName,ps->CurrentLine,CodeOffset,opcode); + fprintf(ListingFile,"%-8s ",pTerms[0]); + for(i=1; i1 ) + fprintf(ListingFile,", %s",pTerms[i]); + else + fprintf(ListingFile,"%s",pTerms[i]); + } + if( opcode==0xFFFFFFFF ) + fprintf(ListingFile," // *** ERROR ***"); + + fprintf(ListingFile,"\n"); + } + + ProgramImage[CodeOffset].Flags = CODEGEN_FLG_FILEINFO|CODEGEN_FLG_CANMAP; + ProgramImage[CodeOffset].FileIndex = ps->FileIndex; + ProgramImage[CodeOffset].Line = ps->CurrentLine; + ProgramImage[CodeOffset].AddrOffset = CodeOffset; + ProgramImage[CodeOffset++].CodeWord = opcode; +} + + +/* +// Report +// +// Report an abnormal condition +*/ +void Report( SOURCEFILE *ps, int Level, char *fmt, ... ) +{ + va_list arg_ptr; + + if( Pass==1 && Level==REP_WARN2 ) + return; + if( Pass==2 && (Level==REP_INFO || Level==REP_WARN1) ) + return; + + /* Log to stdout */ + if( ps ) + printf("%s(%d) ",ps->SourceName,ps->CurrentLine); + + if( Level == REP_FATAL ) + { + printf("Fatal Error: "); + FatalError=1; + Errors++; + } + else if( Level == REP_ERROR ) + { + printf("Error: "); + Errors++; + } + else if( Level==REP_WARN1 || Level==REP_WARN2 ) + { + printf("Warning: "); + Warnings++; + } + else + printf("Note: "); + + va_start( arg_ptr, fmt ); + vprintf( fmt, arg_ptr ); + va_end( arg_ptr ); + + if( !ps ) + printf("\n"); + printf("\n"); +} + + +/* +// LabelChar +// +// Return whether the character is legal for a label. +// Numbers are not allowed when FlagFirstChar is set. +// +// Returns 1 on success, 0 on error +*/ +int LabelChar( char c, int FlagFirstChar ) +{ + if( FlagFirstChar ) + { + if( (c>='A'&&c<='Z')||(c>='a'&&c<='z')||(c=='_') ) + return(1); + else + return(0); + } + if( (c>='A'&&c<='Z')||(c>='a'&&c<='z')||(c>='0'&&c<='9')||(c=='_')) + return(1); + else + return(0); +} + + +/* +// LabelCreate +// +// Create a label with the supplied offset value +// +// Returns 1 on success, 0 on error +*/ +int LabelCreate( SOURCEFILE *ps, char *label, int value ) +{ + LABEL *pl; + + if( strlen(label) >= LABEL_NAME_LEN ) + { Report(ps,REP_ERROR,"Label too long"); return(0); } + + /* Make sure this name is OK to use */ + if( !CheckName(ps,label) ) + return(0); + + /* Allocate a new record */ + pl = malloc(sizeof(LABEL)); + if( !pl ) + { Report(ps,REP_FATAL,"Memory allocation failed"); return(0); } + + strcpy( pl->Name, label ); + pl->Offset = value; + + /* Put this label in the master list */ + pl->pPrev = 0; + pl->pNext = pLabelList; + if( pLabelList ) + pLabelList->pPrev = pl; + pLabelList = pl; + LabelCount++; + + if( (Options & OPTION_DEBUG) ) + printf("%s(%5d) : LABEL : '%s' = %05d\n", ps->SourceName,ps->CurrentLine,label,value); + + return(1); +} + + +/* +// LabelFind +// +// Searches for an equate by name. If found, returns the record pointer. +// +// Returns LABEL * on success, 0 on error +*/ +LABEL *LabelFind( char *name ) +{ + LABEL *pl; + + pl = pLabelList; + while( pl ) + { + if( !strcmp( name, pl->Name ) ) + break; + pl = pl->pNext; + } + return(pl); +} + + +/* +// LabelDestroy +// +// Frees and label record. +// +// void +*/ +void LabelDestroy( LABEL *pl ) +{ + if( !pl->pPrev ) + pLabelList = pl->pNext; + else + pl->pPrev->pNext = pl->pNext; + + if( pl->pNext ) + pl->pNext->pPrev = pl->pPrev; + + LabelCount--; + + free(pl); +} + + +/* +// Check Name +// +// Returns 1 if the name is free, or 0 if it is in use +*/ +int CheckName( SOURCEFILE *ps, char *name ) +{ + /* Make sure its not a reserved word */ + if( CheckTokenType(name)!=TOKENTYPE_UNRESERVED ) + { Report(ps,REP_ERROR,"Illegal use of reserved word '%s'",name); return(0); } + if( LabelFind(name) ) + { Report(ps,REP_ERROR,"'%s' is already a label",name); return(0); } + if( CheckEquate(name) ) + { Report(ps,REP_ERROR,"'%s' is already an equate",name); return(0); } + if( CheckStruct(name) ) + { Report(ps,REP_ERROR,"'%s' is already a structure or scope",name); return(0); } + if( CheckMacro(name) ) + { Report(ps,REP_ERROR,"'%s' is already a macro",name); return(0); } + return(1); +} + + +/*=================================================================== +// +// Private Functions +// +====================================================================*/ + +/* +// ValidateOffset +// +// Validates that the current offset is ready to be used +// +// Returns 1 on success, 0 on error +*/ +static int ValidateOffset( SOURCEFILE *ps ) +{ + uint opcode; + + if( CodeOffset==-1 ) + { + CodeOffset = 8; + if( EntryPoint<0 ) + EntryPoint = 8; + if( Core != CORE_V0 ) + Report(ps,REP_WARN1,"Using default code origin of 8"); + else + { + opcode = 0x21000900; + + /* Note it in listing file */ + if( Pass==2 && (Options & OPTION_LISTING) ) + { + fprintf(ListingFile, + "%s(%5d) : 0x%04x = 0x%08x : JMP #0x9 // Legacy Mode\n", + ps->SourceName,ps->CurrentLine,CodeOffset,opcode); + } + + ProgramImage[CodeOffset].Flags = CODEGEN_FLG_FILEINFO; + ProgramImage[CodeOffset].FileIndex = ps->FileIndex; + ProgramImage[CodeOffset].Line = ps->CurrentLine; + ProgramImage[CodeOffset].AddrOffset = CodeOffset; + ProgramImage[CodeOffset++].CodeWord = opcode; + } + } + + if( CodeOffset >= MAX_PROGRAM ) + { Report(ps,REP_FATAL,"Max program size exceeded"); return(0); } + + return(1); +} + +/* +// PrintLine +// +// Prints out a line of the source file for source listings +// +// Returns 1 on success, 0 on EOF +*/ +static int PrintLine( FILE *pfOut, SOURCEFILE *ps ) +{ + int i; + char c; + +AGAIN: + i = fread( &c, 1, 1, ps->FilePtr ); + if( i != 1 ) + return(0); + if( c == 0xd ) + goto AGAIN; + if( c == 0xa ) + { + ps->CurrentLine++; + fprintf(pfOut,"\n"); + return(1); + } + fprintf(pfOut,"%c",c); + goto AGAIN; +} + +/* +// GetInfoFromAddr +// +// Returns the SourceFileIndex, Line Number, and CodeWord for a given address offset +// +// Returns 0 on success, -1 on error +*/ +static int GetInfoFromAddr( uint address, uint *pIndex, uint *pLineNo, uint *pCodeWord ) +{ + int i; + + for(i=0; i<(int)CodeOffset; i++) + { + if( ProgramImage[i].AddrOffset == address ) + { + *pIndex = ProgramImage[i].FileIndex; + *pLineNo = ProgramImage[i].Line; + *pCodeWord = ProgramImage[i].CodeWord; + return 0; + } + } + return -1; +} + +/* +// ListFile +// +// Prints out an object code annotated listing of an original source file +// +// Returns 1 on success +*/ +static int ListFile( FILE *pfOut, SOURCEFILE *ps ) +{ + uint addr, index, line, code, count, output, cline; + + count = 0; + for( addr=0; addr<(uint)CodeOffset; addr++ ) + { + if( GetInfoFromAddr( addr, &index, &line, &code ) >= 0 ) + { + if( index == ps->FileIndex ) + count++; + } + } + + if( !count ) + { + // No code section + fprintf(pfOut,"(No Ouput Generated)\n\n"); + + for(;;) + { + fprintf(pfOut,"%5d : : ",ps->CurrentLine ); + if( !PrintLine(pfOut,ps) ) + return(1); + } + } + else + { + fprintf(pfOut,"(%d Instructions Generated)\n\n",count); + + for(;;) + { + output = 0; + cline = ps->CurrentLine; + + for( addr=0; addr<(uint)CodeOffset; addr++ ) + { + if( (GetInfoFromAddr( addr, &index, &line, &code ) < 0) || index!=ps->FileIndex || lineCurrentLine ); + if( !PrintLine(pfOut,ps) ) + return(1); + } + } + } + return(1); +} + + diff --git a/am335x/pasm/pasm.h b/am335x/pasm/pasm.h new file mode 100644 index 00000000..dccbeeed --- /dev/null +++ b/am335x/pasm/pasm.h @@ -0,0 +1,645 @@ +/* + * pasm.h + * + * Copyright (C) 2012 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. + * +*/ + +/*=========================================================================== + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + +/*=========================================================================== +// PASM - PRU Assembler +//--------------------------------------------------------------------------- +// +// File : pasm.h +// +// Description: +// Main include file +// - Global data structures and assembler state +// - Declarations of all public functions +// +//--------------------------------------------------------------------------- +// Revision: +// 21-Jun-13: 0.84 - Open source version +============================================================================*/ +typedef unsigned int uint; + +#include "pru_ins.h" + +#define TOKEN_MAX_LEN 128 + +/* Label Record */ +#define LABEL_NAME_LEN TOKEN_MAX_LEN +typedef struct _LABEL { + struct _LABEL *pPrev; /* Previous in LABEL list */ + struct _LABEL *pNext; /* Next in LABEL list */ + int Offset; /* Offset Value */ + char Name[LABEL_NAME_LEN]; +} LABEL; + +/* Source File Record */ +#define SOURCE_NAME 64 +#define SOURCE_BASE_DIR 256 +typedef struct _SOURCEFILE { + struct _SOURCE *pParent; /* The file that included this file */ + FILE *FilePtr; /* Open file handle */ + unsigned int InUse; /* Set to '1' if file is active */ + unsigned int FileIndex; /* Index of this source file in CODEGEN */ + unsigned int CurrentLine; /* The current line being read */ + unsigned int CurrentColumn; /* The current column being read */ + unsigned int ccDepthIn; /* Original condition code depth */ + char LastChar; /* Last character read from file */ + char SourceName[SOURCE_NAME]; + char SourceBaseDir[SOURCE_BASE_DIR]; +} SOURCEFILE; + +/* Source Line Record */ +#define MAX_TOKENS 12 +#define SRC_FLG_LABEL (1<<0) +#define SRC_FLG_DOTCMD1 (1<<1) +#define SRC_FLG_DOTCMD2 (1<<2) +typedef struct _SRCLINE { + uint Flags; + uint Terms; + char Label[TOKEN_MAX_LEN]; + char Term[MAX_TOKENS][TOKEN_MAX_LEN]; +} SRCLINE; + +/* CodeGen Record */ +typedef struct _CODEGEN { + unsigned char Flags; /* Record flags */ +#define CODEGEN_FLG_FILEINFO 0x01 +#define CODEGEN_FLG_CANMAP 0x02 + unsigned char Resv8; /* Reserved */ + unsigned short FileIndex; /* Source file index */ + unsigned int Line; /* The line number */ + unsigned int AddrOffset; /* Code address offset */ + unsigned int CodeWord; /* Code */ +} CODEGEN; + +/* User Options */ +extern unsigned int Options; +#define OPTION_BINARY (1<<0) +#define OPTION_BINARYBIG (1<<1) +#define OPTION_CARRAY (1<<2) +#define OPTION_IMGFILE (1<<3) +#define OPTION_DBGFILE (1<<4) +#define OPTION_LISTING (1<<5) +#define OPTION_DEBUG (1<<6) +#define OPTION_BIGENDIAN (1<<7) +#define OPTION_RETREGSET (1<<8) +#define OPTION_SOURCELISTING (1<<9) +extern unsigned int Core; +#define CORE_NONE 0 +#define CORE_V0 1 +#define CORE_V1 2 +#define CORE_V2 3 +#define CORE_V3 4 +extern FILE *CArrayFile; +extern FILE *ListingFile; + +/* Assembler Engine */ +extern int Pass; /* Pass 1 or 2 of parser */ +extern int HaveEntry; /* Entrypont flag (init to 0) */ +extern int EntryPoint; /* Entrypont (init to -1) */ +extern int CodeOffset; /* Current instruction "word" offset (zero based) */ +extern int Errors; /* Total number or errors */ +extern int FatalError; /* Set on fatal error */ +extern int Warnings; /* Total number of warnings */ +extern uint RetRegValue; /* Return register index */ +extern uint RetRegField; /* Return register field */ + +#define DEFAULT_RETREGVAL 30 +#define DEFAULT_RETREGFLD FIELDTYPE_15_0 + +#define SOURCEFILE_MAX 64 +extern SOURCEFILE sfArray[SOURCEFILE_MAX]; +extern unsigned int sfIndex; + +/* Use platform appropriate function for case-insensitive string compare */ +#ifdef _MSC_VER + #define stricmp _stricmp +#elif defined(__GNUC__) + #define stricmp strcasecmp +#endif + + +/*===================================================================== +// +// Functions Implemented by the Opcode Module +// +//====================================================================*/ + +/* +// CheckOpcode +// +// Called to see if the supplied token is a reserved word. +// +// Returns index of opcode, 0 if not an opcode +*/ +int CheckOpcode( char *word ); + + +/* +// CheckTokenType +// +// Called to see if the supplied token is reserved word. +// +// Returns token type flags +*/ +uint CheckTokenType( char *word ); +#define TOKENTYPE_UNRESERVED 0 +#define TOKENTYPE_FLG_OPCODE 0x0001 +#define TOKENTYPE_FLG_DIRECTIVE 0x0002 +#define TOKENTYPE_FLG_REG_BASE 0x0004 +#define TOKENTYPE_FLG_REG_ADDR 0x0008 +#define TOKENTYPE_FLG_REG_PTR 0x0010 +#define TOKENTYPE_FLG_REG_POSTINC 0x0020 +#define TOKENTYPE_FLG_REG_PREDEC 0x0040 + +/* +// ProcessOp +// +// Opcode processor +// +// This is the function that assembles opcode statements +// +// ps - Pointer to source file record +// TermCnt - Number of terms (including the command) +// pTerms - Pointer to the terms +// +// Returns: +// 1 : Success +// 0 : Error +*/ +int ProcessOp( SOURCEFILE *ps, int TermCnt, char **pTerms ); + +/* +// GetRegister +// +// Get Register Argument +// +// Parses the source string for a register and field +// +// ps - Pointer to source file record +// num - operand number (1 based) +// src - source string +// pa - Pointer to register structure +// fBitOk - Can accept Rxx.Txx +// termC - Set to non-zero if special terminating character ('+') +// +// Returns: +// 1 : Success +// 0 : Error +*/ +int GetRegister( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa, int fBitOk, char termC ); + + +/*===================================================================== +// +// Functions Implemented by the DotCommand Module +// +//====================================================================*/ + +/* +// CheckDotCommand +// +// Check to see if supplied word is a dot command +// +// Returns 1 if the word is a command, else zero +*/ +int CheckDotCommand( char *word ); + +/* +// DotCommand +// +// Dot command processor +// +// This is the function where users add their assembler commands +// +// ps - Pointer to source file record +// TermCnt - Number of terms (including the command) +// pTerms - Pointer to the terms +// Src - Buffer to write any resulting assembly line +// MaxSrc - Size of assembly line buffer +// +// Returns: +// >=0 : Success - Length of assemby line (0 to MaxSrc) +// <0 : Illegal command +*/ +int DotCommand( SOURCEFILE *ps, int TermCnt, char **pTerms, char *Src, int MaxSrc ); + +/* +// DotInitialize +// +// Open the dot-command environment +// +// void +*/ +void DotInitialize(int pass); + +/* +// DotCleanup +// +// Clean up the dot environment +// +// void +*/ +void DotCleanup(int pass); + + + +/*===================================================================== +// +// Functions Implemented by the Structure/Scope Module +// +//====================================================================*/ + +/* +// ScopeEnter +// +// Returns: +// 0 - Success +// -1 - Error +*/ +int ScopeEnter( SOURCEFILE *ps, char *Name ); + + +/* +// ScopeLeave +// +// Returns: +// 0 - Success +// -1 - Error +*/ +int ScopeLeave( SOURCEFILE *ps, char *Name ); + + +/* +// ScopeUsing +// +// Returns: +// 0 - Success +// -1 - Error +*/ +int ScopeUsing( SOURCEFILE *ps, char *Name ); + + +/* +// StructInit +// +// Returns: void +*/ +void StructInit(); + + +/* +// StructCleanup +// +// Returns: void +*/ +void StructCleanup(); + + +/* +// StructNew +// +// Returns: +// 0 - Success +// -1 - Error +*/ +int StructNew( SOURCEFILE *ps, char *Name ); + + +/* +// StructEnd +// +// Returns: +// 0 - Success +// -1 - Error +*/ +int StructEnd( SOURCEFILE *ps ); + + +/* +// StructAddElement +// +// Create a new structure record +// +// Returns 0 on success, -1 on error +*/ +int StructAddElement( SOURCEFILE *ps, char *Name, uint size ); + + +/* +// StructAssign +// +// Assign a structure to an instance +// +// Returns 0 on success, -1 on error +*/ +int StructAssign( SOURCEFILE *ps, char *structName, char *rsName, + char *reName, char *defName ); + + +/* +// Struct Param Process +// +// Processes the supplied argument for stucture references or SIZE/OFFSET +// operations. When found, the structure definition is used to substitute +// in the proper register or numeric value. +// +// The string 'source' is assumed to be be able to hold a length of +// at least 'TOKEN_MAX_LEN' bytes. +// +// Returns 0 for OK, or -1 for Fatal Error +// +*/ +int StructParamProcess( SOURCEFILE *ps, int ParamIdx, char *source ); + + +/* +// CheckStruct +// +// Searches for struct template or struct by name. +// +// Returns 1 on success, 0 on error +*/ +int CheckStruct( char *name ); + + + +/*===================================================================== +// +// Main Assembler Functions +// +//====================================================================*/ + +/* +// ProcessSourceFile +// +// New source file to assemble. +// +// Returns 1 on success, 0 on error +*/ +int ProcessSourceFile( SOURCEFILE *ps ); + +/* +// ProcessSourceLine +// +// New source line to assemble. +// +// Returns 1 on success, 0 on error +*/ +int ProcessSourceLine( SOURCEFILE *ps, int length, char *src ); + +/* +// ParseSourceLine +// +// New source line to parse. +// +// Returns 1 on success, 0 on error +*/ +int ParseSourceLine( SOURCEFILE *ps, int length, char *src, SRCLINE *pa ); + +/* +// Report +// +// Report an abnormal condition +*/ +#define REP_INFO 0 /* Information only */ +#define REP_WARN1 1 /* Warn on pass1 */ +#define REP_WARN2 2 /* Warn on pass2 */ +#define REP_ERROR 3 +#define REP_FATAL 4 +void Report( SOURCEFILE *ps, int Level, char *fmt, ... ); + +/* +// LabelChar +// +// Return whether the character is legal for a label. +// Numbers are not allowed when FlagFirstChar is set. +// +// Returns 1 on success, 0 on error +*/ +int LabelChar( char c, int FlagFirstChar ); + + +/* +// LabelCreate +// +// Create a label with the supplied offset value +// +// Returns 1 on success, 0 on error +*/ +int LabelCreate( SOURCEFILE *ps, char *label, int value ); + + +/* +// LabelFind +// +// Searches for an equate by name. If found, returns the record pointer. +// +// Returns LABEL * on success, 0 on error +*/ +LABEL *LabelFind( char *name ); + + +/* +// LabelDestroy +// +// Frees and label record. +// +// void +*/ +void LabelDestroy( LABEL *pl ); + + +/* +// GenOp +// +// Generate an opcode to the ouput file +// +// ps - Pointer to source file record +// TermCnt - Number of terms (including the command) +// pTerms - Pointer to the terms +// opcode - Generated Opcode +*/ +void GenOp( SOURCEFILE *ps, int TermCnt, char **pTerms, uint opcode ); + + +/* +// Check Name +// +// Returns 1 if the name is free, or 0 if it is in use +*/ +int CheckName( SOURCEFILE *ps, char *name ); + + +/*======================================================================= +// +// Expression Analyzer +// +=======================================================================*/ + +/* +// Expression - Math Expression Parser +// +// Returns 0 on success, <0 on error +*/ +int Expression( SOURCEFILE *ps, char *s, uint *pResult, int *pIndex ); + + + +/*======================================================================= +// +// Pre-processor Functions +// +=======================================================================*/ + +/* +// InitSourceFile +// +// Initializes all the fields in SOURCEFILE, and attempts to to open the +// file. +// +// Returns 1 on success, 0 on error +*/ +SOURCEFILE *InitSourceFile( SOURCEFILE *pParent, char *filename ); + +/* +// CloseSourceFile +// +// Close the source file and free the block. +// +// void +*/ +void CloseSourceFile( SOURCEFILE *ps ); + +/* +// GetSourceLine +// +// Get a new line of source code. +// +// This module also processes: +// '#' directives +// #define expansion +// Comments +// +// Returns length of line, 0 on EOF, -1 on Error +*/ +int GetSourceLine( SOURCEFILE *ps, char *Dst, int MaxLen ); + +/* +// ppCleanup +// +// Clean up the pre-processor environment +// +// void +*/ +void ppCleanup(); + + +/* +// EquateCreate +// +// Creates an equate record +// +// Returns 0 on success, -1 on error +*/ +#define EQUATE_NAME_LEN TOKEN_MAX_LEN +#define EQUATE_DATA_LEN 256 +int EquateCreate( SOURCEFILE *ps, char *Name, char *Value ); + + +/* +// CheckEquate +// +// Searches for an equate by name. +// +// Returns 1 on success, 0 on error +*/ +int CheckEquate( char *name ); + + +/*======================================================================= +// +// Macro Functions +// +=======================================================================*/ + +/* +// MacroEnter +// Returns: +// 0 - Success +// -1 - Error +*/ +int MacroEnter( SOURCEFILE *ps, char *Name ); + + +/* +// ProcessMacro +// +// ps - Pointer to source file record +// TermCnt - Number of terms (including the command) +// pTerms - Pointer to the terms +// +// Returns: +// 1 : Success +// 0 : Error +*/ +int ProcessMacro( SOURCEFILE *ps, int TermCnt, char **pTerms ); + + +/* +// MacroCleanup +// +// Returns: void +*/ +void MacroCleanup(); + + +/* +// CheckMacro +// +// Searches for an macro by name. +// +// Returns 1 on success, 0 on error +*/ +int CheckMacro( char *name ); + diff --git a/am335x/pasm/pasmdbg.h b/am335x/pasm/pasmdbg.h new file mode 100644 index 00000000..9b2eefee --- /dev/null +++ b/am335x/pasm/pasmdbg.h @@ -0,0 +1,97 @@ +/* + * pasmdbg.h + * + * Copyright (C) 2012 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. + * +*/ + + +/*=========================================================================== + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + + +/*=========================================================================== +// PASM - PRU Assembler +//--------------------------------------------------------------------------- +// +// File : pasmdbg.h +// +// Description: +// File format for pView debugger debug file +// +//--------------------------------------------------------------------------- +// Revision: +// 21-Jun-13: 0.84 - Open source version +============================================================================*/ + +#define DBGFILE_NAMELEN_SHORT 64 + +typedef struct _DBGFILE_HEADER { + unsigned int FileID; +#define DBGFILE_FILEID_VER3 (0x10150000 | 0x03) + unsigned int LabelCount; /* Number of label records */ + unsigned int LabelOffset; /* File offset to label records */ + unsigned int FileCount; /* Number of file records */ + unsigned int FileOffset; /* File offset to file records */ + unsigned int CodeCount; /* Number of code records */ + unsigned int CodeOffset; /* File offset to code records */ + unsigned int EntryPoint; /* Program entrypoint */ + unsigned int Flags; /* File format flags */ +#define DBGHDR_FLAGS_BIGENDIAN 0x00000001 +} DBGFILE_HEADER; + +typedef struct _DBGFILE_LABEL { + unsigned int AddrOffset; + char Name[DBGFILE_NAMELEN_SHORT]; +} DBGFILE_LABEL; + +typedef struct _DBGFILE_FILE { + char SourceName[DBGFILE_NAMELEN_SHORT]; +} DBGFILE_FILE; + +typedef struct _DBGFILE_CODE { + unsigned char Flags; /* Record flags */ +#define DBGFILE_CODE_FLG_FILEINFO 0x01 +#define DBGFILE_CODE_FLG_CANMAP 0x02 + unsigned char Resv8; /* Reserved */ + unsigned short FileIndex; /* Source file index */ + unsigned int Line; /* The line number */ + unsigned int AddrOffset; /* Code address offset */ + unsigned int CodeWord; /* Code */ +} DBGFILE_CODE; + + diff --git a/am335x/pasm/pasmdot.c b/am335x/pasm/pasmdot.c new file mode 100644 index 00000000..1ad4a5b4 --- /dev/null +++ b/am335x/pasm/pasmdot.c @@ -0,0 +1,446 @@ +/* + * pasmdot.c + * + * Copyright (C) 2012 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. + * +*/ + +/*=========================================================================== + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + +/*=========================================================================== +// PASM - PRU Assembler +//--------------------------------------------------------------------------- +// +// File : pasmdot.c +// +// Description: +// Processes the "dot" commands (.ret, .origin, .main, etc.) +// +//--------------------------------------------------------------------------- +// Revision: +// 21-Jun-13: 0.84 - Open source version +============================================================================*/ + +#include +#include +#include +#if !defined(__APPLE__) +#include +#else +#include +#endif +#include +#include "pasm.h" + +#define DOTCMD_MAIN 0 +#define DOTCMD_END 1 +#define DOTCMD_PROC 2 +#define DOTCMD_RET 3 +#define DOTCMD_ORIGIN 4 +#define DOTCMD_ENTRYPOINT 5 +#define DOTCMD_STRUCT 6 +#define DOTCMD_ENDS 7 +#define DOTCMD_U32 8 +#define DOTCMD_U16 9 +#define DOTCMD_U8 10 +#define DOTCMD_ASSIGN 11 +#define DOTCMD_SETCALLREG 12 +#define DOTCMD_ENTER 13 +#define DOTCMD_LEAVE 14 +#define DOTCMD_USING 15 +#define DOTCMD_MACRO 16 +#define DOTCMD_MPARAM 17 +#define DOTCMD_ENDM 18 +#define DOTCMD_CODEWORD 19 +#define DOTCMD_MAX 19 +char *DotCmds[] = { ".main",".end",".proc",".ret",".origin",".entrypoint", + ".struct",".ends",".u32",".u16",".u8",".assign", + ".setcallreg", ".enter", ".leave", ".using", + ".macro", ".mparam", ".endm", ".codeword" }; + +/*=================================================================== +// +// Public Functions +// +====================================================================*/ + +/* +// CheckDotCommand +// +// Check to see if supplied word is a dot command +// +// Returns 1 if the word is a command, else zero +*/ +int CheckDotCommand( char *word ) +{ + int i; + + /* Commands are reserved */ + for(i=0; i<=DOTCMD_MAX; i++) + { + if( !stricmp( word, DotCmds[i] ) ) + return(1); + } + return(0); +} + +/* +// DotCommand +// +// Dot command processor +// +// This is the function where users add their assembler commands +// +// ps - Pointer to source file record +// TermCnt - Number of terms (including the command) +// pTerms - Pointer to the terms +// Src - Buffer to write any resulting assembly line +// MaxSrc - Size of assembly line buffer +// +// Returns: +// >=0 : Success - Length of assemby line (0 to MaxSrc) +// <0 : Illegal command +*/ +int DotCommand( SOURCEFILE *ps, int TermCnt, char **pTerms, char *Src, int MaxSrc ) +{ + int i; + + for(i=0; i<=DOTCMD_MAX; i++) + { + if( !stricmp( pTerms[0], DotCmds[i] ) ) + break; + } + if( i>DOTCMD_MAX ) + { + Report(ps,REP_ERROR,"Unrecognized dot command"); + return(-1); + } + + if( i==DOTCMD_MAIN ) + { + char c,cs; + int quote=0; + int idx=0,nameidx=0; + + /* + // .main command + // + // Just print a warning - its only here for compatibility + */ + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + + /* If the string is in quotes, skip the first charater */ + if( pTerms[1][0]=='"' ) + { + quote++; + idx++; + } + c = pTerms[1][idx++]; + cs = ps->SourceName[nameidx++]; + while( c && c!='"' ) + { + if( toupper(c) != toupper(cs) ) + { +NO_MATCH: + Report(ps,REP_WARN1,".main name '%s' doesn't match '%s'", + pTerms[1],ps->SourceName); + return(0); + } + c = pTerms[1][idx++]; + cs = ps->SourceName[nameidx++]; + } + if( cs && cs!='.' ) + goto NO_MATCH; + if( c=='"' ) + { + quote--; + c = pTerms[1][idx++]; + } + if( c ) + { Report(ps,REP_ERROR,"Trailing characters on name"); return(-1); } + if( quote ) + { Report(ps,REP_ERROR,"Unbalanced quotes on name"); return(-1); } + return(0); + } + else if( i==DOTCMD_END ) + { + /* + // .end command + // + // Do nothing - its only here for compatibility + */ + if( TermCnt != 1 ) + { Report(ps,REP_ERROR,"Expected no operands"); return(-1); } + return(0); + } + else if( i==DOTCMD_PROC ) + { + /* + // .proc command + // + // Create a label from the proc name, with a leading '.' + // (this is for compatibility) + */ + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + sprintf( Src, ".%s:", pTerms[1] ); + return(strlen(Src)); + } + else if( i==DOTCMD_RET ) + { + /* + // .ret command + // + // Generate the line "jmp r30.w0" + // This makes us compatible with "CALL", although inexplicably, + // the CALL command is not a "dot" command. + // + */ + if( TermCnt != 1 ) + { Report(ps,REP_ERROR,"Expected no operands"); return(-1); } + if( Options & OPTION_RETREGSET ) + { Report(ps,REP_ERROR,".ret incompatible with .setcallreg, use ret"); return(-1); } + if( Core > CORE_V1 ) + { Report(ps,REP_ERROR,".ret illegal with specified core version, use ret"); return(-1); } + strcpy( Src, "jmp r30.w0" ); + return(strlen(Src)); + } + else if( i==DOTCMD_ORIGIN ) + { + int val,tmp; + char tstr[TOKEN_MAX_LEN]; + + /* + // .origin command + // + // Alter the origin for writing code + */ + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + + strcpy( tstr, pTerms[1] ); + if( Expression(ps, tstr, (uint *)&val, &tmp)<0 ) + { Report(ps,REP_ERROR,"Error in processing .origin value"); return(-1); } + if( Core == CORE_V0 ) + { Report(ps,REP_ERROR,".origin illegal with specified core version"); return(-1); } + if( val=0 ) + Report(ps,REP_WARN1,"Resetting .origin value after use"); + if( EntryPoint<0 ) + EntryPoint = val; + + CodeOffset = val; + return(0); + } + else if( i==DOTCMD_ENTRYPOINT ) + { + int val,tmp; + char tstr[TOKEN_MAX_LEN]; + + /* + // .entrypoint command + // + // Alter the origin for writing code + */ + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + + strcpy( tstr, pTerms[1] ); + if( Expression(ps, tstr, (uint *)&val, &tmp)<0 ) + { Report(ps,REP_ERROR,"Error in processing .entrypoint value"); return(-1); } + + if( Core == CORE_V0 ) + { Report(ps,REP_ERROR,".entrypoint illegal with specified core version"); return(-1); } + + if( HaveEntry ) + { Report(ps,REP_ERROR,"Multiple .entrypoint declarations"); return(-1); } + + EntryPoint = val; + HaveEntry = 1; + return(0); + } + else if( i==DOTCMD_STRUCT ) + { + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + return( StructNew(ps,pTerms[1]) ); + + } + else if( i==DOTCMD_ENDS ) + { + if( TermCnt != 1 ) + { Report(ps,REP_ERROR,"Expected no operands"); return(-1); } + return( StructEnd(ps) ); + } + else if( i==DOTCMD_U32 ) + { + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + return( StructAddElement( ps, pTerms[1], 4 ) ); + } + else if( i==DOTCMD_U16 ) + { + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + return( StructAddElement( ps, pTerms[1], 2 ) ); + } + else if( i==DOTCMD_U8 ) + { + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + return( StructAddElement( ps, pTerms[1], 1 ) ); + } + else if( i==DOTCMD_ASSIGN ) + { + if( TermCnt != 5 ) + { Report(ps,REP_ERROR,"Expected 4 operands"); return(-1); } + return( StructAssign(ps, pTerms[1], pTerms[2], pTerms[3], pTerms[4]) ); + } + else if( i==DOTCMD_SETCALLREG ) + { + PRU_ARG r; + + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + if( Core == CORE_V0 ) + { Report(ps,REP_ERROR,".setcallreg illegal with specified core version"); return(-1); } + if( Pass==1 && (Options & OPTION_RETREGSET) ) + { Report(ps,REP_ERROR,".setcallreg redefinition"); return(-1); } + if( CodeOffset>=0 ) + { Report(ps,REP_ERROR,"Can not use .setcallreg after code generation"); return(-1); } + if( !GetRegister( ps, 1, pTerms[1], &r, 0, 0 ) ) + return -1; + + switch( r.Field ) + { + case FIELDTYPE_15_0: + case FIELDTYPE_23_8: + case FIELDTYPE_31_16: + if( r.Value<31 ) + { + RetRegValue = r.Value; + RetRegField = r.Field; + Options |= OPTION_RETREGSET; + return 0; + } + } + + Report(ps,REP_ERROR,"Register field must be r0 to r30 and 16 bits wide"); + return(-1); + } + else if( i==DOTCMD_ENTER ) + { + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + return( ScopeEnter(ps, pTerms[1]) ); + } + else if( i==DOTCMD_LEAVE ) + { + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + return( ScopeLeave(ps, pTerms[1]) ); + } + else if( i==DOTCMD_USING ) + { + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + return( ScopeUsing(ps, pTerms[1]) ); + } + else if( i==DOTCMD_MACRO ) + { + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + return( MacroEnter(ps, pTerms[1]) ); + } + else if( i==DOTCMD_MPARAM || i==DOTCMD_ENDM ) + { Report(ps,REP_ERROR,"%s can not be used outside of macro",pTerms[0]); return(-1); } + else if( i==DOTCMD_CODEWORD ) + { + uint opcode; + int tmp; + char tstr[TOKEN_MAX_LEN]; + + /* + // .codeword command + */ + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(-1); } + + strcpy( tstr, pTerms[1] ); + if( Expression(ps, tstr, &opcode, &tmp)<0 ) + { Report(ps,REP_ERROR,"Error in processing .codeword value"); return(-1); } + + GenOp( ps, TermCnt, pTerms, opcode ); + return(0); + } + + Report(ps,REP_ERROR,"Dot command - Internal Error"); + return(-1); +} + + +/* +// DotInitialize +// +// Open the dot-command environment +// +// void +*/ +void DotInitialize(int pass) +{ + StructInit(); +} + + + +/* +// DotCleanup +// +// Clean up the dot-command environment +// +// void +*/ +void DotCleanup(int pass) +{ + StructCleanup(); + MacroCleanup(); +} + + diff --git a/am335x/pasm/pasmexp.c b/am335x/pasm/pasmexp.c new file mode 100644 index 00000000..5b387096 --- /dev/null +++ b/am335x/pasm/pasmexp.c @@ -0,0 +1,585 @@ +/* + * pasmexp.c + * + * Copyright (C) 2012 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. + * +*/ + +/*=========================================================================== + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + +/*=========================================================================== +// PASM - PRU Assembler +//--------------------------------------------------------------------------- +// +// File : pasmexp.c +// +// Description: +// Expression analyzer. This module is a "drop in", and thus does't +// have much knowledge of the rest of the assembler. +// - Handles expression processing +// +// Note that the expression analyzer will only report errors on pass 2 +// +//--------------------------------------------------------------------------- +// Revision: +// 21-Jun-13: 0.84 - Open source version +============================================================================*/ + +#include +#include +#include +#if !defined(__APPLE__) +#include +#else +#include +#endif +#include +#include "pasm.h" + +#define MAXTERM 32 + +#define EOP_MULTIPLY 1 +#define EOP_DIVIDE 2 +#define EOP_MOD 3 +#define EOP_ADD 4 +#define EOP_SUBTRACT 5 +#define EOP_LEFTSHIFT 6 +#define EOP_RIGHTSHIFT 7 +#define EOP_AND 8 +#define EOP_XOR 9 +#define EOP_OR 10 + +uint prec[] = { 999, + 1, /* EOP_MULTIPLY */ + 1, /* EOP_DIVIDE */ + 1, /* EOP_MOD */ + 2, /* EOP_ADD */ + 2, /* EOP_SUBTRACT */ + 3, /* EOP_LEFTSHIFT */ + 3, /* EOP_RIGHTSHIFT */ + 4, /* EOP_AND */ + 5, /* EOP_XOR */ + 6 };/* EOP_OR */ + + +int EXP_getValue( SOURCEFILE *ps, char *s, int *pIdx, uint *pValue ); +int EXP_getOperation( SOURCEFILE *ps, char *s, int *pIdx, uint *pValue ); +static int GetRegisterOffset( char *src, uint *pValue ); + +/* +// Expression - Math Expression Parser +// +// Returns 0 on success, <0 on error +*/ +int Expression( SOURCEFILE *ps, char *s, uint *pResult, int *pIndex ) +{ + uint values[MAXTERM]; + uint ops[MAXTERM]; + int maxprec; + int i; + int validx,opidx,stridx; + + validx=0; + opidx=0; + stridx=0; + + while( validx= validx || !validx ) + return(-1); + + while( opidx ) + { + /* Find the highest prec op */ + maxprec = 0; + for( i=1; i> values[maxprec+1]; + break; + case EOP_AND: + values[maxprec] = values[maxprec] & values[maxprec+1]; + break; + case EOP_XOR: + values[maxprec] = values[maxprec] ^ values[maxprec+1]; + break; + case EOP_OR: + values[maxprec] = values[maxprec] | values[maxprec+1]; + break; + } + + // Remove this op and 2nd value term from the list + i = MAXTERM-2-maxprec; + if( i>0 ) + { + memcpy( &values[maxprec+1], &values[maxprec+2], i*sizeof(uint)); + memcpy( &ops[maxprec], &ops[maxprec+1], i*sizeof(uint)); + } + + opidx--; + validx--; + } + + if( validx != 1 ) + { Report(ps,REP_ERROR,"Exp internal error"); return(-1); } + + *pResult = values[0]; + return(0); +} + + +/* +// EXP_getValue - Get a value from the supplied string +// +// Returns 0 no value, 1 on success, <0 on error +*/ +int EXP_getValue( SOURCEFILE *ps, char *s, int *pIdx, uint *pValue ) +{ + int base = 10,index,i,j,k; + int rc = 1; + uint tval = 0; + char c; + + index = *pIdx; + + c = s[index]; + while( c==' ' || c==9 ) + { + index++; + c = s[index]; + } + + if( !c ) + return(0); + + /* Look for a label */ + if( LabelChar(c,1) || c=='.' || c=='&' ) + { + LABEL *pl; + char lblstr[LABEL_NAME_LEN]; + int lblidx = 0; + + for(;;) + { + lblstr[lblidx++]=c; + index++; + c = s[index]; + if( !LabelChar(c,0) && c!='.' ) + break; + } + lblstr[lblidx]=0; + *pIdx = index; + + if( CheckTokenType(lblstr) & TOKENTYPE_FLG_REG_ADDR ) + { + if( GetRegisterOffset(lblstr+1,&tval) ) + { + *pValue = tval; + return(1); + } + } + pl = LabelFind(lblstr); + if(!pl && Pass==1) + *pValue = 0; + else if( !pl ) + { Report(ps,REP_ERROR,"Not found: '%s'",lblstr); return(0); } + else + *pValue = pl->Offset; + return(1); + } + + if( c=='-' ) + { + index++; + i = EXP_getValue( ps, s, &index, &tval ); + if( i<0 ) + rc = i; + else + tval = (uint)(-(int)tval); + goto EGV_EXIT; + } + if( c=='~' ) + { + index++; + i = EXP_getValue( ps, s, &index, &tval ); + if( i<0 ) + rc = i; + else + tval = ~tval; + goto EGV_EXIT; + } + if( c=='(' ) + { + /* Scan to the far ')' */ + index++; + j = index; + i=1; + for(;;) + { + c = *(s+j); + if( !c ) + { + rc = -1; + goto EGV_EXIT; + } + if( c=='(' ) + i++; + if( c==')' ) + { + i--; + if(!i) + { + /* Terminate the string and eval the () */ + *(s+j) = 0; + i = Expression( 0, s+index, &tval, &k ); + if( i<0 ) + { + index+=k; + rc=i; + } + else + index=j+1; + goto EGV_EXIT; + } + } + j++; + } + } + + /* This character must be a number */ + if( c<'0' || c>'9' ) + { + rc = -1; + goto EGV_EXIT; + } + index++; + tval = c-'0'; + if( tval==0 ) + { + c = s[index]; + if( c=='x' ) + { + base=16; + index++; + } + else if( c=='b' ) + { + base=2; + index++; + } + else + base=8; + } + + for(;;) + { + c = s[index]; + if( c>='0' && c<='9' ) + i = c-'0'; + else if( c>='a' && c<='f' ) + i = c-'a'+10; + else if( c>='A' && c<='F' ) + i = c-'A'+10; + else + break; + + if( i>=base ) + { + rc = -1; + goto EGV_EXIT; + } + tval *= base; + tval += i; + index++; + } + +EGV_EXIT: + *pValue = tval; + *pIdx = index; + return(rc); +} + + +/* +// EXP_getOperation - Get an operation from the supplied string +// +// Returns 0 no value, 1 on success, <0 on error +*/ +int EXP_getOperation( SOURCEFILE *ps, char *s, int *pIdx, uint *pValue ) +{ + int index; + char c; + int rc = 1; + + index = *pIdx; + + c = s[index]; + while( c==' ' || c==9 ) + { + index++; + c = s[index]; + } + + if( !c ) + return(0); + else if( c=='*' ) + *pValue = EOP_MULTIPLY; + else if( c=='/' ) + *pValue = EOP_DIVIDE; + else if( c=='%' ) + *pValue = EOP_MOD; + else if( c=='+' ) + *pValue = EOP_ADD; + else if( c=='-' ) + *pValue = EOP_SUBTRACT; + else if( c=='<' ) + { + index++; + c = s[index]; + if( c != '<' ) + rc=-1; + else + *pValue = EOP_LEFTSHIFT; + } + else if( c=='>' ) + { + index++; + c = s[index]; + if( c != '>' ) + rc=-1; + else + *pValue = EOP_RIGHTSHIFT; + } + else if( c=='&' ) + *pValue = EOP_AND; + else if( c=='^' ) + *pValue = EOP_XOR; + else if( c=='|' ) + *pValue = EOP_OR; + else + rc = -1; + + if( rc == 1) + index++; + + *pIdx = index; + return(rc); +} + + +/* +// GetRegisterOffset +// +// Get Register Offset +// +// Returns: +// 1 : Success +// 0 : Error +*/ +static int GetRegisterOffset( char *src, uint *pValue ) +{ + uint idx; + char c,field; + int val,reg,width,offset; + + if( Core == CORE_V0 ) + return(0); + + /* + // The following register syntaxes are valid: + // Raa aa=(0-31) + // Raa.Wb aa=(0-31) b=(0-2) + // Raa.Bc aa=(0-31) c=(0-3) + // Raa.Tdd aa=(0-31) dd=(0-31) + // Raa.Wb.Be aa=(0-31) b=(0-2) e=(0-1) + */ + + idx=0; + c = src[idx++]; + /* Get initial 'R##' */ + if( toupper(c) != 'R' ) + return(0); + c = src[idx++]; + if( !isdigit(c) ) + return(0); + val = 0; + while( isdigit(c) ) + { + val *= 10; + val += c-'0'; + c = src[idx++]; + } + if( val>31 ) + return(0); + + reg = val; + width = 32; + offset = 0; + + for(;;) + { + /* This char must be '.', or terminator */ + + /* If terminated, we're done */ + if( !c ) + break; + if( c != '.' ) + return(0); + + c = src[idx++]; + + /* This char must be 'W', or 'B' */ + c = toupper(c); + if( c!='W' && c!='B' ) + return(0); + field=c; + c = src[idx++]; + if( !isdigit(c) ) + return(0); + val = 0; + while( isdigit(c) ) + { + val *= 10; + val += c-'0'; + c = src[idx++]; + } + if( field=='W' ) + { + if( ((val*8)+16)>width ) + return(0); + width = 16; + offset += val; + } + if( field=='B' ) + { + if( ((val*8)+8)>width ) + return(0); + width = 8; + offset += val; + } + } + + if( !(Options & OPTION_BIGENDIAN) ) + *pValue = reg * 4 + offset; + else + { + width /= 8; + offset = 4 - offset - width; + *pValue = reg * 4 + offset; + } + + return(1); +} + diff --git a/am335x/pasm/pasmmacro.c b/am335x/pasm/pasmmacro.c new file mode 100644 index 00000000..710a538c --- /dev/null +++ b/am335x/pasm/pasmmacro.c @@ -0,0 +1,560 @@ +/* + * pasmmacro.c + * + * Copyright (C) 2012 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. + * +*/ + +/*=========================================================================== + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + +/*=========================================================================== +// PASM - PRU Assembler +//--------------------------------------------------------------------------- +// +// File : pasmmacro.c +// +// Description: +// Processes the macro commands +// +//--------------------------------------------------------------------------- +// Revision: +// 21-Jun-13: 0.84 - Open source version +============================================================================*/ + +#include +#include +#include +#if !defined(__APPLE__) +#include +#else +#include +#endif +#include +#include "pasm.h" + +/* Local Macro Definitions */ + +#define MACRO_NAME_LEN TOKEN_MAX_LEN +#define MACRO_MAX_ARGS 8 +#define MACRO_MAX_LINES 128 +#define MACRO_LINE_LENGTH 256 +#define MACRO_MAX_LABELS 32 +#define MAX_SOURCE_LINE 256 + +/* Macro Struct Record */ +typedef struct _MACRO { + struct _MACRO *pPrev; /* Previous in MACRO list */ + struct _MACRO *pNext; /* Next in MACRO list */ + char Name[MACRO_NAME_LEN]; + int InUse; /* Macro is in use */ + int Id; /* Macro ID */ + int Arguments; /* Number of arguments */ + int Required; /* Number of required arguments */ + int Labels; /* Number of labels */ + int Expands; /* Number of label expansions */ + int CodeLines; /* Number of code lines */ + char ArgName[MACRO_MAX_ARGS][TOKEN_MAX_LEN]; + char ArgDefault[MACRO_MAX_ARGS][TOKEN_MAX_LEN]; + char LableName[MACRO_MAX_LABELS][TOKEN_MAX_LEN]; + char Code[MACRO_MAX_LINES][MACRO_LINE_LENGTH]; +} MACRO; + + +/* Local Support Funtions */ +static int _strncat( char *dst, int len, char *src ); +static MACRO *MacroFind( char *Name ); +static MACRO *MacroCreate( SOURCEFILE *ps, char *Name ); +int MacroAddArg( SOURCEFILE *ps, MACRO *pm, char *ArgText ); +static void MacroDestroy( MACRO *pm ); + +/* Local macro list */ +int MacroId=0; +MACRO *pMacroList=0; /* List of declared structs */ +MACRO *pMacroCurrent=0; + + +/*=================================================================== +// +// Public Functions +// +====================================================================*/ + +/* +// MacroEnter +// Returns: +// 0 - Success +// -1 - Error +*/ +int MacroEnter( SOURCEFILE *ps, char *Name ) +{ + SRCLINE sl; + MACRO *pm; + char src[MAX_SOURCE_LINE]; + int i; + + if( Core == CORE_V0 ) + { Report(ps,REP_ERROR,".macro illegal with specified core version"); return(-1); } + + /* Create the macro */ + pm = MacroCreate( ps, Name ); + if( !pm ) + return(-1); + + /* Scan source lines until we see .endm */ + for(;;) + { + /* Abort on a total disaster */ + if( FatalError || Errors >= 25 ) + return(-1); + + /* Get a line of source code */ + i = GetSourceLine( ps, src, MAX_SOURCE_LINE ); + if( !i ) + { Report(ps,REP_ERROR,"Missing .endm on macro"); return(-1); } + if( i<0 ) + continue; + + if( !ParseSourceLine(ps,i,src,&sl) ) + continue; + + /* Check for a label */ + if( sl.Flags & SRC_FLG_LABEL ) + { + if( pm->Labels==MACRO_MAX_LABELS ) + Report(ps,REP_ERROR,"Macro contains too many labels"); + else + { + strcpy( pm->LableName[pm->Labels], sl.Label ); + pm->Labels++; + } + } + + /* Check for a macro related dot command */ + if( sl.Terms && (sl.Flags & SRC_FLG_DOTCMD1) ) + { + if( !stricmp( sl.Term[0], ".mparam" ) ) + { + if( sl.Terms==1 ) + { Report(ps,REP_ERROR,"Expected at least 1 parameter on .mparam"); continue; } + for( i=1; i<(int)sl.Terms; i++) + MacroAddArg(ps,pm,sl.Term[i]); + continue; + } + else if( !stricmp( sl.Term[0], ".macro" ) ) + { Report(ps,REP_ERROR,"Macro definitions may not be nested"); continue; } + else if( !stricmp( sl.Term[0], ".endm" ) ) + { + pm->InUse = 0; + return(0); + } + } + /* Else store the line as part of the macro */ + else + { + if( pm->CodeLines == MACRO_MAX_LINES ) + { Report(ps,REP_ERROR,"Macro line count exceeded"); continue; } + strcpy(pm->Code[pm->CodeLines],src); + pm->CodeLines++; + } + } +} + + +/* +// ProcessMacro +// +// ps - Pointer to source file record +// TermCnt - Number of terms (including the command) +// pTerms - Pointer to the terms +// +// Returns: +// 1 : Success +// 0 : Error +*/ +int ProcessMacro( SOURCEFILE *ps, int TermCnt, char **pTerms ) +{ + MACRO *pm; + int cidx,sidx,nidx,i; + char src[MAX_SOURCE_LINE]; + char namebuf[MACRO_NAME_LEN]; + char c; + + pm = MacroFind(pTerms[0]); + if( !pm ) + return(0); + + if( pm->InUse ) + { Report(ps,REP_ERROR,"Illegal recursive use of macro '%s'",pTerms[0]); return(0); } + + if( pm->Required >= TermCnt ) + { Report(ps,REP_ERROR,"Expected at least %d arguments on '%s'",pm->Required,pTerms[0]); return(0); } + + if( pm->Arguments < (TermCnt-1) ) + { Report(ps,REP_ERROR,"Expected no more than %d arguments on '%s'",pm->Arguments,pTerms[0]); return(0); } + + /* Bump expansion count */ + pm->Expands++; + pm->InUse = 1; + + for( cidx=0; cidxCodeLines; cidx++ ) + { + /* Build the assembly statement */ + sidx=0; + nidx=0; + src[0] = 0; + for(;;) + { + c=pm->Code[cidx][sidx++]; + /* Check for start of name */ + if( !nidx ) + { + if(LabelChar(c,1)) + { + namebuf[nidx++]=c; + continue; + } + } + /* Else continue a previously started name */ + else + { + if(LabelChar(c,0)) + { + /* Check for name too long */ + if( nidx==(MACRO_NAME_LEN-1) ) + { Report(ps,REP_ERROR,"Term too long in macro assembly text"); pm->InUse=0; return(0); } + namebuf[nidx++]=c; + continue; + } + + /* This name is done */ + namebuf[nidx]=0; + + /* Look for an argument match */ + for(i=0;iArguments;i++) + { + if(!strcmp(namebuf,pm->ArgName[i])) + { + /* Match! */ + if( (i+1)>=TermCnt ) + _strncat( src, MAX_SOURCE_LINE, pm->ArgDefault[i] ); + else + _strncat( src, MAX_SOURCE_LINE, pTerms[i+1] ); + goto SUBTEXTDONE; + } + } + + /* Look for a label match */ + for(i=0;iLabels;i++) + { + if(!strcmp(namebuf,pm->LableName[i])) + { + char labeltext[TOKEN_MAX_LEN+32]; + + /* Match! */ + sprintf(labeltext,"_%s_%d_%d_", pm->LableName[i],pm->Id,pm->Expands); + _strncat( src, MAX_SOURCE_LINE, labeltext ); + goto SUBTEXTDONE; + } + } + + /* Sub in the original text */ + _strncat( src, MAX_SOURCE_LINE, namebuf ); +SUBTEXTDONE: + nidx = 0; + } + /* Check for text too long */ + i=strlen(src); + if( i==(MAX_SOURCE_LINE-1) ) + { Report(ps,REP_ERROR,"Macro expansion too long"); pm->InUse=0; return(0); } + src[i++]=c; + src[i]=0; + if( !c ) + break; + } + + i=strlen(src); + if(i) + { + if( !ProcessSourceLine(ps, i, src) ) + { + Report(ps,REP_ERROR,"(While expanding code line %d of macro '%s')",(cidx+1),pm->Name); + pm->InUse=0; + return(0); + } + } + } + pm->InUse = 0; + return(1); +} + + +/* +// MacroCleanup +// +// Returns: void +*/ +void MacroCleanup() +{ + while( pMacroList ) + MacroDestroy( pMacroList ); + MacroId = 0; +} + +/* +// CheckMacro +// +// Searches for an macro by name. +// +// Returns 1 on success, 0 on error +*/ +int CheckMacro( char *name ) +{ + if( MacroFind(name) ) + return(1); + return(0); +} + + + +/*=================================================================== +// +// Private Functions +// +====================================================================*/ + +static int _strncat( char *dst, int len, char *src ) +{ + int sidx,didx; + + didx = 0; + while( didx(len-1) ) + return(-1); + sidx = 0; + while( src[sidx] ) + { + if( didx>(len-1) ) + { + dst[didx] = 0; + return(-1); + } + dst[didx++] = src[sidx++]; + } + dst[didx] = 0; + return(didx); +} + + +/* +// MacroFind +// +// Searches for a macro record by name. If found, returns the record pointer. +// +// Returns MACRO * on success, 0 on error +*/ +static MACRO *MacroFind( char *Name ) +{ + MACRO *pm; + + pm = pMacroList; + while( pm ) + { + if( !strcmp( Name, pm->Name ) ) + break; + pm = pm->pNext; + } + return(pm); +} + + +/* +// MacroCreate +// +// Create a new macro record +// +// Returns MACRO * on success, 0 on error +*/ +static MACRO *MacroCreate( SOURCEFILE *ps, char *Name ) +{ + MACRO *pm; + + /* Make sure this name is OK to use */ + if( !CheckName(ps,Name) ) + return(0); + + /* Make sure its not too long */ + if( strlen(Name)>=MACRO_NAME_LEN ) + { Report(ps,REP_ERROR,"Macro name too long"); return(0); } + + /* Allocate a new record */ + pm = malloc(sizeof(MACRO)); + if( !pm ) + { Report(ps,REP_ERROR,"Memory allocation failed"); return(0); } + + strcpy( pm->Name, Name ); + pm->InUse = 1; + pm->Id = MacroId++; + pm->Arguments = 0; + pm->Required = 0; + pm->CodeLines = 0; + pm->Labels = 0; + pm->Expands = 0; + + /* Put this equate in the master list */ + pm->pPrev = 0; + pm->pNext = pMacroList; + pMacroList = pm; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : DOTCMD : Macro '%s' declared\n", + ps->SourceName,ps->CurrentLine,pm->Name); + + return(pm); +} + + +/* +// MacroAddArg +// +// Add an argument to a macro record +// +// Returns 0 on success, -1 on error +*/ +int MacroAddArg( SOURCEFILE *ps, MACRO *pm, char *ArgText ) +{ + int i,sidx; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : DOTCMD : Macro Parameter '%s' declared\n", + ps->SourceName,ps->CurrentLine,ArgText); + + if( pm->Arguments == MACRO_MAX_ARGS ) + { Report(ps,REP_ERROR,"Too many macro arguments"); return(-1); } + + /* Scan in the argument */ + sidx=0; + while( ArgText[sidx]==' ' || ArgText[sidx]==9 ) + sidx++; + i=0; + while( ArgText[sidx]!=' ' && ArgText[sidx]!=9 && ArgText[sidx]!='=' && ArgText[sidx]!=0 ) + { + if(i==TOKEN_MAX_LEN) + { Report(ps,REP_ERROR,"Macro argument name too long"); return(-1); } + if( (i==0 && !LabelChar(ArgText[sidx],1)) || + (i!=0 && !LabelChar(ArgText[sidx],0)) ) + { Report(ps,REP_ERROR,"Illegal character in macro argument name"); return(-1); } + pm->ArgName[pm->Arguments][i++] = ArgText[sidx++]; + } + pm->ArgName[pm->Arguments][i] = 0; + if( !i ) + goto MARG_SYNTAX; + + /* Verify no duplicate naming */ + for(i=0; iArguments; i++) + { + if( !strcmp(pm->ArgName[i],pm->ArgName[pm->Arguments]) ) + { + Report(ps,REP_ERROR,"Duplicate macro argument name '%s'",pm->ArgName[i]); + return(-1); + } + } + + /* Scan in the default value (if any) */ + while( ArgText[sidx]==' ' || ArgText[sidx]==9 ) + sidx++; + + if( ArgText[sidx]=='=' ) + { + sidx++; + while( ArgText[sidx]==' ' || ArgText[sidx]==9 ) + sidx++; + i=0; + while( ArgText[sidx]!=' ' && ArgText[sidx]!=9 && ArgText[sidx]!='=' && ArgText[sidx]!=0 ) + { + if(i==TOKEN_MAX_LEN) + { Report(ps,REP_ERROR,"Macro argument value too long"); return(-1); } + if( !LabelChar(ArgText[sidx],0) && ArgText[sidx]!='.' ) + goto MARG_SYNTAX; + pm->ArgDefault[pm->Arguments][i++] = ArgText[sidx++]; + } + pm->ArgDefault[pm->Arguments][i] = 0; + if( !i ) + goto MARG_SYNTAX; + pm->Arguments++; + } + else + { + pm->ArgDefault[pm->Arguments][0] = 0; + if(pm->Arguments > pm->Required) + { Report(ps,REP_ERROR,"Optional macro arguments must be listed last"); return(-1); } + pm->Arguments++; + pm->Required++; + } + + if( ArgText[sidx]!=0 ) + { +MARG_SYNTAX: + Report(ps,REP_ERROR,"Syntax error in macro argument '%s' around character %d",ArgText,sidx+1); + return(-1); + } + + return(0); +} + + +/* +// MacroDestroy +// +// Frees a macro record. +// +// void +*/ +static void MacroDestroy( MACRO *pm ) +{ + if( !pm->pPrev ) + pMacroList = pm->pNext; + else + pm->pPrev->pNext = pm->pNext; + + if( pm->pNext ) + pm->pNext->pPrev = pm->pPrev; + + free(pm); +} + diff --git a/am335x/pasm/pasmop.c b/am335x/pasm/pasmop.c new file mode 100644 index 00000000..617c37c4 --- /dev/null +++ b/am335x/pasm/pasmop.c @@ -0,0 +1,2132 @@ +/* + * pasmop.c + * + * Copyright (C) 2012 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. + * +*/ + +/*=========================================================================== + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + +/*=========================================================================== +// PASM - PRU Assembler +//--------------------------------------------------------------------------- +// +// File : pasmop.c +// +// Description: +// Handles the processing of PRU opcodes. +// - Provides a function to test for reserved words +// - Processes assembly lines and generates opcodes +// - Contains private functions to process operand fields +// +//--------------------------------------------------------------------------- +// Revision: +// 21-Jun-13: 0.84 - Open source version +============================================================================*/ + +#include +#include +#include +#if !defined(__APPLE__) +#include +#else +#include +#endif +#include +#include "pasm.h" + +char *OpText[] = { + "$ERROR$","ADD","ADC","SUB","SUC","LSL","LSR","RSB","RSC","AND","OR", + "XOR","NOT","MIN","MAX","CLR","SET","LDI","LBBO","LBCO","SBBO", + "SBCO","LFC","STC","JAL","JMP","QBGT","QBLT","QBEQ","QBGE","QBLE", + "QBNE","QBA","QBBS","QBBC","LMBD","CALL","WBC","WBS","MOV","MVIB", + "MVIW","MVID","SCAN","HALT","SLP", "RET", "ZERO", "FILL", "XIN", "XOUT", + "XCHG","SXIN","SXOUT","SXCHG","LOOP","ILOOP","NOP0","NOP1","NOP2","NOP3", + "NOP4","NOP5","NOP6","NOP7","NOP8","NOP9","NOPA","NOPB","NOPC","NOPD", + "NOPE","NOPF"}; + +/* Local Support Funtions */ +static int GetImValue( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa, uint low, uint high ); +static int GetConstant( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa ); +static int GetR0offset( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa ); +static int GetJmpOffset( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa ); +static int GetLoopOffset( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa ); +static int Offset2Reg( SOURCEFILE *ps, int num, PRU_ARG *pa, uint addr, uint size ); + +/* +// CheckOpcode +// +// Called to see if the supplied token is an opcode. +// +// Returns index of opcode, 0 if not an opcode +*/ +int CheckOpcode( char *word ) +{ + int i; + + for(i=1; i<=OP_MAXIDX; i++) + { + if( !stricmp( word, OpText[i] ) ) + return(i); + } + return(0); +} + + +/* +// GetTokenType +// +// Called to see if the supplied token is reserved word. +// +// Returns 1 if reserved, 0 if not +*/ +uint CheckTokenType( char *word ) +{ + int i,parse_state; + uint flags; + char c; + + /* Opcodes are reserved */ + if( CheckOpcode(word) ) + return(TOKENTYPE_FLG_OPCODE); + + /* Check for command */ + if( CheckDotCommand( word ) ) + return(TOKENTYPE_FLG_DIRECTIVE); + + if( !strcmp(word,"SIZE") || !strcmp(word,"OFFSET") ) + return(TOKENTYPE_FLG_DIRECTIVE); + + /* + // [&,*][--](B,C,R,T,W)#[#][.(B,C,R,T,W)#[#]][++ ] is reserved + // + // For example: + // R - not reserved + // R23 - reserved + // R100 - not reserved + // C34.XYZ - not reserved + // C34.T34 - reserved + */ + i=0; + parse_state=0; + + if( word[i]=='*' ) + { + /* Mark as a pointer */ + flags = TOKENTYPE_FLG_REG_PTR; + i++; + + /* Check if its an immediate address */ + if( word[i]=='&' ) + { + flags |= TOKENTYPE_FLG_REG_ADDR; + i++; + } + /* Else its a register base */ + else + { + flags |= TOKENTYPE_FLG_REG_BASE; + + /* Registers can also be pre-dec */ + if( word[i]=='-' ) + { + if( word[i+1]!='-' ) + return(TOKENTYPE_UNRESERVED); + i+=2; + flags |= TOKENTYPE_FLG_REG_PREDEC; + } + } + } + else if( word[i]=='&' ) + { + flags = TOKENTYPE_FLG_REG_ADDR; + i++; + } + else + flags = TOKENTYPE_FLG_REG_BASE; + + for(;;) + { + c = word[i++]; + c = toupper(c); + switch( parse_state ) + { + case 0: + if( c=='B' || c=='C' || c=='R' || c=='T' || c=='W' ) + parse_state=1; + else + return(TOKENTYPE_UNRESERVED); + break; + + case 1: + if( isdigit(c) ) + parse_state=2; + else + return(TOKENTYPE_UNRESERVED); + break; + + case 2: + case 3: + if( isdigit(c) ) + { + parse_state++; + if( parse_state>3 ) + return(TOKENTYPE_UNRESERVED); + } + else if( c=='.' ) + parse_state=0; + else if( !c || c==' ' || c==0x9 ) + return(flags); + else if( c=='+' ) + { + /* Can not be an address or predec */ + if( flags & (TOKENTYPE_FLG_REG_ADDR|TOKENTYPE_FLG_REG_PREDEC) ) + return(TOKENTYPE_UNRESERVED); + + /* Rest of type must match */ + if( word[i]!=c || word[i+1]!=0 ) + return(TOKENTYPE_UNRESERVED); + + flags |= TOKENTYPE_FLG_REG_POSTINC; + return(flags); + } + else + return(TOKENTYPE_UNRESERVED); + break; + } + } +} + +/* +// ProcessOp +// +// Opcode processor +// +// This is the function that assembles opcode statements +// +// ps - Pointer to source file record +// TermCnt - Number of terms (including the command) +// pTerms - Pointer to the terms +// +// Returns: +// 1 : Success +// 0 : Error +*/ +int ProcessOp( SOURCEFILE *ps, int TermCnt, char **pTerms ) +{ + PRU_INST inst; + unsigned int opcode; + unsigned int utmp; + + /* Get opcode */ + inst.Op = CheckOpcode(pTerms[0]); + + if( !inst.Op ) + { Report(ps,REP_ERROR,"Invalid opcode"); return(0); } + + switch( inst.Op ) + { + case OP_NOT: + /* + // Instruction in the form of: + // NOT Rdst, Rsrc, OP(255) + // NOT Rdst, Rsrc + */ + if( TermCnt!=3 && TermCnt!=4 ) + { Report(ps,REP_ERROR,"Expected 2 or 3 operands on NOT"); return(0); } + goto PARSE_ARITHMETIC; + case OP_ADD: + case OP_ADC: + case OP_SUB: + case OP_SUC: + case OP_LSL: + case OP_LSR: + case OP_RSB: + case OP_RSC: + case OP_AND: + case OP_OR: + case OP_XOR: + case OP_MIN: + case OP_MAX: + case OP_LMBD: + case OP_NOP0: + case OP_NOP1: + case OP_NOP2: + case OP_NOP3: + case OP_NOP4: + case OP_NOP5: + case OP_NOP6: + case OP_NOP7: + case OP_NOP8: + case OP_NOP9: + case OP_NOPA: + case OP_NOPB: + case OP_NOPC: + case OP_NOPD: + case OP_NOPE: + case OP_NOPF: + /* + // Instruction in the form of: + // OPCODE Rdst, Rsrc, OP(255) + */ + if( inst.Op==OP_LMBD && Core=OP_NOP0 && inst.Op<=OP_NOPF && Core=OP_NOP0 && inst.Op<=OP_NOPF ) + opcode = (0x50+inst.Op-OP_NOP0) << 25; + else if( inst.Op == OP_LMBD ) + opcode = 0x13 << 25; + else if( inst.Op == OP_SCAN ) + opcode = 0x14 << 25; + else + opcode = (inst.Op-OP_ADD) << 25; + opcode |= inst.Arg[0].Value; + opcode |= inst.Arg[0].Field << 5; + opcode |= inst.Arg[1].Value << 8; + opcode |= inst.Arg[1].Field << 13; + if( inst.Arg[2].Type == ARGTYPE_REGISTER ) + { + opcode |= inst.Arg[2].Value << 16; + opcode |= inst.Arg[2].Field << 21; + } + else + { + opcode |= inst.Arg[2].Value << 16; + opcode |= 1<<24; + } + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + + + case OP_CLR: + case OP_SET: + /* + // Instruction in the form of: + // OPCODE Rdst, Rsrc, OP(255) -or- + // OPCODE Rdst, Rsrc.Tnn -or- + // OPCODE Rdst, OP(255) -or- + // OPCODE Rdst.Tnn + */ + if( TermCnt<2 || TermCnt>4 ) + { Report(ps,REP_ERROR,"Expected 1 to 3 operands"); return(0); } + + /* The 3 argument (4 term) variant can be parsed as arithmetic */ + if( TermCnt==4 ) + goto PARSE_ARITHMETIC; + else if( TermCnt==2 ) + { + /* + // Hande "OPCODE Rdst.Tnn" + */ + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[0]), 1, 0 ) ) + return(0); + if( inst.Arg[0].Type != ARGTYPE_REGISTERBIT ) + { Report(ps,REP_ERROR,"Single operand mode must specify .T field"); return(0); } + /* 2nd arg = 1st arg, move bit# to 3rd arg */ + inst.Arg[0].Type = ARGTYPE_REGISTER; + inst.Arg[1] = inst.Arg[0]; + inst.Arg[2].Type = ARGTYPE_IMMEDIATE; + inst.Arg[2].Value = inst.Arg[0].Bit; + } + else + { + /* + // Handle "OPCODE Rdst, Rsrc.Tnn", and + // "OPCODE Rdst, OP(255)" + */ + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[0]), 0, 0 ) ) + return(0); + if( CheckTokenType(pTerms[2]) & TOKENTYPE_FLG_REG_BASE ) + { + if( !GetRegister( ps, 2, pTerms[2], &(inst.Arg[1]), 1, 0 ) ) + return(0); + } + else + { + if( !GetImValue( ps, 2, pTerms[2], &(inst.Arg[1]), 0, 31 ) ) + return(0); + } + + /* Patch up the args to the standard "arithmetic" form */ + if( inst.Arg[1].Type == ARGTYPE_REGISTERBIT ) + { + /* Here the 2nd arg is Rsrc.Tnn, move bit# to 3rd arg */ + inst.Arg[1].Type = ARGTYPE_REGISTER; + inst.Arg[2].Type = ARGTYPE_IMMEDIATE; + inst.Arg[2].Value = inst.Arg[1].Bit; + } + else + { + /* Here the 2nd arg is OP(255), 3rd arg = 2nd arg, 2nd=1st */ + inst.Arg[2] = inst.Arg[1]; + inst.Arg[1] = inst.Arg[0]; + } + } + goto CODE_ARITHMETIC; + + + case OP_LDI: + /* + // Instruction in the form of: + // LDI Rdst, &Rsrc + // LDI Rdst, #Im65535 + */ + if( TermCnt != 3 ) + { Report(ps,REP_ERROR,"Expected 2 operands"); return(0); } + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[0]), 0, 0 ) ) + { + return(0); + } + if( !GetImValue( ps, 2, pTerms[2], &(inst.Arg[1]), 0, 65535 ) ) + { + return(0); + } + opcode = 0x24 << 24; + opcode |= inst.Arg[0].Value; + opcode |= inst.Arg[0].Field << 5; + opcode |= inst.Arg[1].Value << 8; + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + + + case OP_MOV: + /* + // Instruction in the form of: + // MOV Rdst, Rsrc -or- + // MOV Rdst, &Rsrc -or- + // MOV Rdst, #Imm + */ + if( TermCnt != 3 ) + { Report(ps,REP_ERROR,"Expected 2 operands"); return(0); } + /* If the second term is not reg, treat similar to LDI */ + if( !(CheckTokenType(pTerms[2]) & TOKENTYPE_FLG_REG_BASE) ) + { + // Unlike LDI, we will auto-select the best opcodes to implement the move + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[0]), 0, 0 ) ) + { + return(0); + } + + switch( inst.Arg[0].Field ) + { + case FIELDTYPE_7_0: + case FIELDTYPE_15_8: + case FIELDTYPE_23_16: + case FIELDTYPE_31_24: + if( !GetImValue( ps, 2, pTerms[2], &(inst.Arg[1]), 0, 255 ) ) + return(0); + break; + case FIELDTYPE_15_0: + case FIELDTYPE_23_8: + case FIELDTYPE_31_16: + if( !GetImValue( ps, 2, pTerms[2], &(inst.Arg[1]), 0, 65535 ) ) + return(0); + break; + case FIELDTYPE_31_0: + if( !GetImValue( ps, 2, pTerms[2], &(inst.Arg[1]), 0, 0xFFFFFFFF ) ) + return(0); + // If the value is greater than 0xFFFF, code the upper half here + if( inst.Arg[1].Value > 0xFFFF ) + { + opcode = 0x24 << 24; + opcode |= inst.Arg[0].Value; + opcode |= FIELDTYPE_31_16 << 5; + opcode |= (inst.Arg[1].Value>>16) << 8; + GenOp( ps, TermCnt, pTerms, opcode ); + inst.Arg[0].Field = FIELDTYPE_15_0; + inst.Arg[1].Value &= 0xFFFF; + } + break; + default: + return(0); + } + opcode = 0x24 << 24; + opcode |= inst.Arg[0].Value; + opcode |= inst.Arg[0].Field << 5; + opcode |= inst.Arg[1].Value << 8; + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + } + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[0]), 0, 0 ) ) + return(0); + if( !GetRegister( ps, 2, pTerms[2], &(inst.Arg[1]), 0, 0 ) ) + return(0); + /* Code as an AND */ + inst.Op = OP_AND; + inst.Arg[2] = inst.Arg[1]; + goto CODE_ARITHMETIC; + + + case OP_SCAN: + /* + // Instruction in the form of: + // SCAN Rdst, OP(255) + */ + if( Core!=CORE_V1 ) + { Report(ps,REP_ERROR,"Instruction illegal with specified core version"); return(0); } + if( TermCnt!=3 ) + { Report(ps,REP_ERROR,"Expected 2 operands"); return(0); } + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[0]), 0, 0 ) ) + return(0); + if( inst.Arg[0].Field != FIELDTYPE_31_0 ) + { Report(ps,REP_ERROR,"Register fields not allowed on operand 1"); return(0); } + inst.Arg[1] = inst.Arg[0]; + if( CheckTokenType(pTerms[2]) & TOKENTYPE_FLG_REG_BASE ) + { + if( !GetRegister( ps, 2, pTerms[2], &(inst.Arg[2]), 0, 0 ) ) + return(0); + } + else + { + if( !GetImValue( ps, 2, pTerms[2], &(inst.Arg[2]), 0, 255 ) ) + return(0); + } + goto CODE_ARITHMETIC; + + case OP_MVIB: + /* + // Instruction in the form of: + // MVIB [*][&][--]Rdst[++], [*][&][--]Rsrc[++] [, bn] + */ + utmp = 1; + goto CODE_MVI; + case OP_MVIW: + /* + // Instruction in the form of: + // MVIW [*][&][--]Rdst[++], [*][&][--]Rsrc[++] [, bn] + */ + utmp = 2; + goto CODE_MVI; + case OP_MVID: + /* + // Instruction in the form of: + // MVID [*][&][--]Rdst[++], [*][&][--]Rsrc[++] [, bn] + */ + utmp = 4; +CODE_MVI: + if( Core=4 && (inst.Arg[0].Value!=1 || inst.Arg[0].Field>FIELDTYPE_31_24)) || + (itype%4 && (inst.Arg[1].Value!=1 || inst.Arg[1].Field>FIELDTYPE_31_24)) ) + { Report(ps,REP_ERROR,"RegFile pointers must be R1.b0 through R1.b3"); return(0); } + + if( itype==0 ) + { Report(ps,REP_ERROR,"No indirection specified (use MOV)"); return(0); } + + opcode = 0x16 << 25; + opcode |= itype << 21; + if( TermCnt==4 ) + { + opcode |= 1 << 20; + opcode |= inst.Arg[2].Value << 18; + } + opcode |= (utmp/2) << 16; + opcode |= inst.Arg[0].Value; + opcode |= inst.Arg[0].Field << 5; + opcode |= inst.Arg[1].Value << 8; + opcode |= inst.Arg[1].Field << 13; + } + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + + case OP_HALT: + if( Core>2) & 0x1F; + opcode |= (inst.Arg[0].Value&0x3) << 5; + } + else + { + opcode |= inst.Arg[0].Value; + + if( !(Options & OPTION_BIGENDIAN) ) + { + /* + // ** Little Endian Version ** + */ + switch( inst.Arg[0].Field ) + { + case FIELDTYPE_15_8: + case FIELDTYPE_23_8: + opcode |= 1<<5; + break; + case FIELDTYPE_23_16: + case FIELDTYPE_31_16: + opcode |= 2<<5; + break; + case FIELDTYPE_31_24: + opcode |= 3<<5; + break; + } + } + else + { + /* + // ** Big Endian Version ** + */ + switch( inst.Arg[0].Field ) + { + case FIELDTYPE_23_16: + case FIELDTYPE_23_8: + opcode |= 1<<5; + break; + + case FIELDTYPE_15_0: + case FIELDTYPE_15_8: + opcode |= 2<<5; + break; + + case FIELDTYPE_7_0: + opcode |= 3<<5; + break; + } + } + } + + opcode |= inst.Arg[1].Value << 8; + if( inst.Arg[2].Type == ARGTYPE_REGISTER ) + { + opcode |= inst.Arg[2].Value << 16; + opcode |= inst.Arg[2].Field << 21; + } + else + { + opcode |= inst.Arg[2].Value << 16; + opcode |= 1<<24; + } + if( inst.Arg[3].Type == ARGTYPE_R0BYTE ) + utmp = inst.Arg[3].Value + 124; + else + utmp = inst.Arg[3].Value - 1; + opcode |= (utmp&0x70)<<(25-4); + opcode |= (utmp&0x0E)<<(13-1); + opcode |= (utmp&0x01)<<7; + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + + case OP_SXIN: + opcode = (0x5D << 23) | (1 << 14); + goto CODE_XFR_V3; + + case OP_SXOUT: + opcode = (0x5E << 23) | (1 << 14); + goto CODE_XFR_V3; + + case OP_SXCHG: + opcode = (0x5F << 23) | (1 << 14); + goto CODE_XFR_V3; + + case OP_XIN: + opcode = 0x5D << 23; + goto CODE_XFR; + + case OP_XOUT: + opcode = 0x5E << 23; + goto CODE_XFR; + + case OP_XCHG: + opcode = 0x5F << 23; + goto CODE_XFR; + +CODE_XFR_V3: + if( Core>2) & 0x1F; + opcode |= (inst.Arg[1].Value&0x3) << 5; + } + else + { + opcode |= inst.Arg[1].Value; + + if( !(Options & OPTION_BIGENDIAN) ) + { + /* + // ** Little Endian Version ** + */ + switch( inst.Arg[1].Field ) + { + case FIELDTYPE_15_8: + case FIELDTYPE_23_8: + opcode |= 1<<5; + break; + case FIELDTYPE_23_16: + case FIELDTYPE_31_16: + opcode |= 2<<5; + break; + case FIELDTYPE_31_24: + opcode |= 3<<5; + break; + } + } + else + { + /* + // ** Big Endian Version ** + */ + switch( inst.Arg[1].Field ) + { + case FIELDTYPE_23_16: + case FIELDTYPE_23_8: + opcode |= 1<<5; + break; + + case FIELDTYPE_15_0: + case FIELDTYPE_15_8: + opcode |= 2<<5; + break; + + case FIELDTYPE_7_0: + opcode |= 3<<5; + break; + } + } + } + + opcode |= inst.Arg[0].Value << 15; + if( inst.Arg[2].Type == ARGTYPE_R0BYTE ) + utmp = inst.Arg[2].Value + 124; + else + utmp = inst.Arg[2].Value - 1; + opcode |= utmp<<7; + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + + + case OP_LFC: + /* + // Instruction in the form of: + // LFC Rdst, #Im255 + */ + if( Core!=CORE_V0 ) + { Report(ps,REP_ERROR,"Instruction illegal with specified core version"); return(0); } + if( TermCnt != 3 ) + { Report(ps,REP_ERROR,"Expected 2 operands"); return(0); } + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[0]), 0, 0 ) ) + return(0); + if( !GetImValue( ps, 2, pTerms[2], &(inst.Arg[1]), 0, 255 ) ) + return(0); + + opcode = 0xb << 28; + opcode |= inst.Arg[0].Value; + opcode |= inst.Arg[0].Field << 5; + opcode |= inst.Arg[1].Value << 8; + opcode |= 1 << 24; + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + + + case OP_STC: + /* + // Instruction in the form of: + // STC Rsrc, #Im255 + // STC Rsrc, #Im255, OP(255) + */ + if( Core!=CORE_V0 ) + { Report(ps,REP_ERROR,"Instruction illegal with specified core version"); return(0); } + if( TermCnt!=3 && TermCnt!=4 ) + { Report(ps,REP_ERROR,"Expected 2 or 3 operands"); return(0); } + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[0]), 0, 0 ) ) + return(0); + if( !GetImValue( ps, 2, pTerms[2], &(inst.Arg[1]), 0, 255 ) ) + return(0); + if( TermCnt==4 ) + { + if( CheckTokenType(pTerms[3]) & TOKENTYPE_FLG_REG_BASE ) + { + if( !GetRegister( ps, 3, pTerms[3], &(inst.Arg[2]), 0, 0 ) ) + return(0); + } + else + { + if( !GetImValue( ps, 3, pTerms[3], &(inst.Arg[2]), 0, 255 ) ) + return(0); + } + } + + opcode = 0xa << 28; + opcode |= inst.Arg[0].Value; + opcode |= inst.Arg[0].Field << 5; + opcode |= inst.Arg[1].Value << 8; + if( TermCnt==4 ) + { + if( inst.Arg[2].Type == ARGTYPE_REGISTER ) + { + opcode |= inst.Arg[2].Value << 16; + opcode |= inst.Arg[2].Field << 21; + } + else + { + opcode |= inst.Arg[2].Value << 16; + opcode |= 1<<24; + } + } + else + { + /* When a 32 bit reg is used, we need the 8 MS bits from that reg */ + if( inst.Arg[0].Field==FIELDTYPE_31_0 ) + { + opcode |= inst.Arg[0].Value << 16; + opcode |= FIELDTYPE_31_24 << 21; + } + /* Less than 32 bits were used, so clear the 8 MS bits via #0 */ + else + opcode |= 1<<24; + } + + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + + + case OP_JAL: + /* + // Instruction in the form of: + // JAL Rdst, Rjmp + // JAL Rdst, #Im65535 + */ + if( TermCnt != 3 ) + { Report(ps,REP_ERROR,"Expected 2 operands"); return(0); } + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[0]), 0, 0 ) ) + return(0); + if( CheckTokenType(pTerms[2]) & TOKENTYPE_FLG_REG_BASE ) + { + if( !GetRegister( ps, 2, pTerms[2], &(inst.Arg[1]), 0, 0 ) ) + return(0); + } + else + { + if( !GetImValue( ps, 2, pTerms[2], &(inst.Arg[1]), 0, 65535 ) ) + return(0); + } + +CODE_JAL: + opcode = 0x11 << 25; + opcode |= inst.Arg[0].Value; + opcode |= inst.Arg[0].Field << 5; + if( inst.Arg[1].Type == ARGTYPE_REGISTER ) + { + opcode |= inst.Arg[1].Value << 16; + opcode |= inst.Arg[1].Field << 21; + } + else + { + opcode |= inst.Arg[1].Value << 8; + opcode |= 1<<24; + } + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + + case OP_RET: + if( TermCnt != 1 ) + { Report(ps,REP_ERROR,"Expected no operands"); return(0); } + inst.Arg[1].Type = ARGTYPE_REGISTER; + inst.Arg[1].Value = RetRegValue; + inst.Arg[1].Field = RetRegField; + goto CODE_JMP; + + case OP_JMP: + case OP_CALL: + /* + // Instruction in the form of: + // OPCODE Rjmp + // OPCODE #Im65535 + */ + if( TermCnt != 2 ) + { Report(ps,REP_ERROR,"Expected 1 operand"); return(0); } + if( CheckTokenType(pTerms[1]) & TOKENTYPE_FLG_REG_BASE ) + { + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[1]), 0, 0 ) ) + return(0); + } + else + { + if( !GetImValue( ps, 1, pTerms[1], &(inst.Arg[1]), 0, 65535 ) ) + return(0); + } + + if( inst.Op==OP_CALL ) + { + inst.Arg[0].Type = ARGTYPE_REGISTER; + inst.Arg[0].Value = RetRegValue; + inst.Arg[0].Field = RetRegField; + goto CODE_JAL; + } + +CODE_JMP: + opcode = 0x10 << 25; + if( inst.Arg[1].Type == ARGTYPE_REGISTER ) + { + opcode |= inst.Arg[1].Value << 16; + opcode |= inst.Arg[1].Field << 21; + } + else + { + opcode |= inst.Arg[1].Value << 8; + opcode |= 1<<24; + } + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + + case OP_ILOOP: + opcode = (3<<28) | (1<<15); + goto CODE_LOOP; + + case OP_LOOP: + opcode = (3<<28); +CODE_LOOP: + /* + // Instruction in the form of: + // LOOP LoopDest, OP(255) + */ + if( Core3 ) + { Report(ps,REP_ERROR,"Expected 1 to 2 operands"); return(0); } + + inst.Arg[0].Type = ARGTYPE_OFFSET; + inst.Arg[0].Value = 0; + inst.Arg[0].Field = 0; + + if( !GetRegister( ps, 1, pTerms[1], &(inst.Arg[1]), 1, 0 ) ) + return(0); + if( TermCnt==2 ) + { + /* + // Handle "OPCODE JmpDest, Rtest.Tnn" + */ + if( inst.Arg[1].Type != ARGTYPE_REGISTERBIT ) + { Report(ps,REP_ERROR,"Two operand mode must specify .T field"); return(0); } + /* Move bit# to 3rd arg */ + inst.Arg[1].Type = ARGTYPE_REGISTER; + inst.Arg[2].Type = ARGTYPE_IMMEDIATE; + inst.Arg[2].Value = inst.Arg[1].Bit; + } + else + { + /* + // Handle "OPCODE JmpDest, Rtest, OP(255)" + */ + if( inst.Arg[1].Type != ARGTYPE_REGISTER ) + { Report(ps,REP_ERROR,"Three operand mode may not use .T field"); return(0); } + if( CheckTokenType(pTerms[2]) & TOKENTYPE_FLG_REG_BASE ) + { + if( !GetRegister( ps, 2, pTerms[2], &(inst.Arg[2]), 0, 0 ) ) + return(0); + } + else + { + if( !GetImValue( ps, 2, pTerms[2], &(inst.Arg[2]), 0, 31 ) ) + return(0); + } + } + + goto CODE_QB; + + + case OP_FILL: + /* + // Instruction in the form of: + // FILL &Rdst, #Im124 + // FILL #Im123, #Im124 + */ + if( Core124 ) + { Report(ps,REP_ERROR,"Length exceeds register file length"); return(0); } + if( !inst.Arg[1].Value ) + { Report(ps,REP_ERROR,"Zero length fill"); return(0); } + + /* Implement with XIN */ + opcode = 0x5D << 23; + opcode |= (inst.Arg[0].Value>>2) & 0x1F; + opcode |= (inst.Arg[0].Value&0x3) << 5; + opcode |= 254 << 15; + inst.Arg[1].Value--; + opcode |= inst.Arg[1].Value<<7; + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + + + case OP_ZERO: + /* + // Instruction in the form of: + // ZERO &Rdst, #Im124 + // ZERO #Im123, #Im124 + */ + if( Core124 ) + { Report(ps,REP_ERROR,"Clear length exceeds register file length"); return(0); } + if( !inst.Arg[1].Value ) + { Report(ps,REP_ERROR,"Zero length clear"); return(0); } + + if( Core>=CORE_V2 ) + { + /* Implement with XIN */ + opcode = 0x5D << 23; + opcode |= (inst.Arg[0].Value>>2) & 0x1F; + opcode |= (inst.Arg[0].Value&0x3) << 5; + opcode |= 255 << 15; + inst.Arg[1].Value--; + opcode |= inst.Arg[1].Value<<7; + GenOp( ps, TermCnt, pTerms, opcode ); + return(1); + } + + while( inst.Arg[1].Value ) + { + uint reg,field=0,size=0; + + reg = inst.Arg[0].Value/4; + + if( !(Options & OPTION_BIGENDIAN) ) + { + /* + // Little Endian Version + */ + switch( inst.Arg[0].Value & 0x3 ) + { + case 0: + if( inst.Arg[1].Value >= 4 ) + { + size = 4; + field = FIELDTYPE_31_0; + } + else if( inst.Arg[1].Value >= 2 ) + { + size = 2; + field = FIELDTYPE_15_0; + } + else + { + size = 1; + field = FIELDTYPE_7_0; + } + break; + + case 1: + if( inst.Arg[1].Value >= 2 ) + { + size = 2; + field = FIELDTYPE_23_8; + } + else + { + size = 1; + field = FIELDTYPE_15_8; + } + break; + + case 2: + if( inst.Arg[1].Value >= 2 ) + { + size = 2; + field = FIELDTYPE_31_16; + } + else + { + size = 1; + field = FIELDTYPE_23_16; + } + break; + + case 3: + size = 1; + field = FIELDTYPE_31_24; + break; + } + } + else + { + /* + // Big Endian Version + */ + switch( inst.Arg[0].Value & 0x3 ) + { + case 0: + if( inst.Arg[1].Value >= 4 ) + { + size = 4; + field = FIELDTYPE_31_0; + } + else if( inst.Arg[1].Value >= 2 ) + { + size = 2; + field = FIELDTYPE_31_16; + } + else + { + size = 1; + field = FIELDTYPE_31_24; + } + break; + + case 1: + if( inst.Arg[1].Value >= 2 ) + { + size = 2; + field = FIELDTYPE_23_8; + } + else + { + size = 1; + field = FIELDTYPE_23_16; + } + break; + + case 2: + if( inst.Arg[1].Value >= 2 ) + { + size = 2; + field = FIELDTYPE_15_0; + } + else + { + size = 1; + field = FIELDTYPE_15_8; + } + break; + + case 3: + size = 1; + field = FIELDTYPE_7_0; + break; + } + } + + inst.Arg[0].Value += size; + inst.Arg[1].Value -= size; + + /* LDI */ + opcode = 0x24 << 24; + opcode |= reg; + opcode |= field << 5; + GenOp( ps, TermCnt, pTerms, opcode ); + } + return(1); + } + + Report(ps,REP_ERROR,"Invalid opcode"); + return(0); +} + +/*=================================================================== +// +// Private Functions +// +====================================================================*/ + +/* +// GetRegister +// +// Get Register Argument +// +// Parses the source string for a register and field +// +// ps - Pointer to source file record +// num - operand number (1 based) +// src - source string +// pa - Pointer to register structure +// fBitOk - Can accept Rxx.Txx +// termC - Set to non-zero if special terminating character ('+') +// +// Returns: +// 1 : Success +// 0 : Error +*/ +int GetRegister( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa, int fBitOk, char termC ) +{ + uint idx; + char c,field; + int val,reg,width,offset,bit; + + /* + // The following register syntaxes are valid: + // Raa aa=(0-31) + // Raa.Wb aa=(0-31) b=(0-2) + // Raa.Bc aa=(0-31) c=(0-3) + // Raa.Tdd aa=(0-31) dd=(0-31) + // Raa.Wb.Be aa=(0-31) b=(0-2) e=(0-1) + // Raa.Wb.Tff aa=(0-31) b=(0-2) ff=(0-15) + // Raa.Bc.Tgg aa=(0-31) c=(0-3) gg=(0-7) + // Raa.Wb.Be.Tgg aa=(0-31) b=(0-2) e=(0-1) gg=(0-7) + */ + + idx=0; + c = src[idx++]; + + /* Get initial 'R##' */ + if( toupper(c) != 'R' ) + goto INVALID_REG; + c = src[idx++]; + if( !isdigit(c) ) + goto INVALID_REG; + val = 0; + while( isdigit(c) ) + { + val *= 10; + val += c-'0'; + c = src[idx++]; + } + if( val>31 ) + goto INVALID_REG; + + reg = val; + width = 32; + offset = 0; + bit = -1; + + for(;;) + { + /* This char must be '.', or terminator */ + + /* If terminated, we're done */ + if( c==termC ) + break; + if( c != '.' ) + goto INVALID_REG; + + c = src[idx++]; + + /* This char must be 'W', 'B', or 'T' */ + c = toupper(c); + if( c!='T' && c!='W' && c!='B' ) + goto INVALID_REG; + field=c; + c = src[idx++]; + if( !isdigit(c) ) + goto INVALID_REG; + val = 0; + while( isdigit(c) ) + { + val *= 10; + val += c-'0'; + c = src[idx++]; + } + if( field=='W' ) + { + if( ((val*8)+16)>width ) + goto INVALID_REG; + width = 16; + offset += val; + } + if( field=='B' ) + { + if( ((val*8)+8)>width ) + goto INVALID_REG; + width = 8; + offset += val; + } + if( field=='T' ) + { + if( !fBitOk ) + { Report(ps,REP_ERROR,"Operand %d use of .T field not allowed here",num); return(0); } + if( val>=width ) + goto INVALID_REG; + if(c!=termC) + goto INVALID_REG; + bit = val; + } + + if( c!=termC && (Core==CORE_V0) ) + goto INVALID_REG; + } + + /* Build the record */ + pa->Type = ARGTYPE_REGISTER; + pa->Value = reg; + + if( width==32 ) + pa->Field = FIELDTYPE_31_0; + if( width==16 ) + { + if( !offset ) + pa->Field = FIELDTYPE_15_0; + else if( offset==1 ) + pa->Field = FIELDTYPE_23_8; + else + pa->Field = FIELDTYPE_31_16; + } + if( width==8 ) + { + if( !offset ) + pa->Field = FIELDTYPE_7_0; + else if( offset==1 ) + pa->Field = FIELDTYPE_15_8; + else if( offset==2 ) + pa->Field = FIELDTYPE_23_16; + else + pa->Field = FIELDTYPE_31_24; + } + if( bit>=0 ) + { + pa->Type = ARGTYPE_REGISTERBIT; + pa->Bit = bit; + } + + return(1); + +INVALID_REG: + Report(ps,REP_ERROR,"Operand %d '%s' invalid register or register mode",num,src); + return(0); +} + +/* +// GetImValue +// +// Get Register Argument +// +// Parses the source string for an immediate value +// +// ps - Pointer to source file record +// num - operand number (1 based) +// src - source string +// pa - Pointer to register structure +// min - Lowest legal value +// max - Highest legal value +// +// Returns: +// 1 : Success +// 0 : Error +*/ +static int GetImValue( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa, uint min, uint max ) +{ + char tstr[TOKEN_MAX_LEN]; + uint val; + int idx; + + /* Handler register file offsets as immediates */ + val = CheckTokenType(src); + if( val!=TOKENTYPE_UNRESERVED && !(val&TOKENTYPE_FLG_REG_ADDR) ) + { + Report(ps,REP_ERROR,"Operand %d reserved word '%s' not legal here",num,src); + return(0); + } + + // Get our value from a an expression + if( *src=='#' ) + src++; + strcpy( tstr, src ); + if( Expression(ps, tstr, &val, &idx)<0 ) + { + Report(ps,REP_ERROR,"Operand %d error in expression",num); + return(0); + } + + if( Pass==2 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : EXP : '%s' = %d\n", ps->SourceName,ps->CurrentLine,src,val); + + /* Setup the record */ + pa->Type = ARGTYPE_IMMEDIATE; + pa->Value = val; + pa->Field = 0; + + if( valmax ) + { + Report(ps,REP_ERROR,"Operand %d immediate value out of range (%d-%d)",num,min,max); + return(0); + } + + return(1); +} + +/* +// GetConstant +// +// Get Constant Table Argument +// +// Parses the source string for a constant register +// +// ps - Pointer to source file record +// num - source line number +// src - source string +// pa - Pointer to register structure +// +// Returns: +// 1 : Success +// 0 : Error +*/ +static int GetConstant( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa ) +{ + uint idx; + char c; + int val; + + idx=0; + c = src[idx++]; + + /* Get C## */ + if( toupper(c) != 'C' ) + goto INVALID_CONST; + c = src[idx++]; + if( !isdigit(c) ) + goto INVALID_CONST; + val = 0; + while( isdigit(c) ) + { + val *= 10; + val += c-'0'; + c = src[idx++]; + } + if( c || val>31 ) + goto INVALID_CONST; + + /* Setup the record */ + pa->Type = ARGTYPE_CONSTANT; + pa->Value = val; + pa->Field = 0; + + return(1); + +INVALID_CONST: + Report(ps,REP_ERROR,"Operand %d invalid constant table entry '%s'",num,src); + return(0); +} + + +/* +// GetR0offset +// +// Get "R0-offset" Argument for Burst Opcodes +// +// Parses the source string for a register and field +// +// ps - Pointer to source file record +// num - source line number +// src - source string +// pa - Pointer to register structure +// +// Returns: +// 1 : Success +// 0 : Error +*/ +static int GetR0offset( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa ) +{ + uint idx; + char c; + int val; + + idx=0; + c = src[idx++]; + + /* Get B## */ + if( toupper(c) != 'B' ) + goto INVALID_R0BYTE; + c = src[idx++]; + if( !isdigit(c) ) + goto INVALID_R0BYTE; + val = 0; + while( isdigit(c) ) + { + val *= 10; + val += c-'0'; + c = src[idx++]; + } + if( c || val>3 ) + goto INVALID_R0BYTE; + + /* Setup the record */ + pa->Type = ARGTYPE_R0BYTE; + pa->Value = val; + pa->Field = 0; + + return(1); + +INVALID_R0BYTE: + Report(ps,REP_ERROR,"Operand %d invalid byte count '%s'",num,src); + return(0); +} + + +/* +// GetJmpOffset +// +// Get 10 bit Jump Offset for Quick Branch +// +// Parses the source string for a register and field +// +// ps - Pointer to source file record +// num - source line number +// src - source string +// pa - Pointer to register structure +// +// Returns: +// 1 : Success +// 0 : Error +*/ +static int GetJmpOffset( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa ) +{ + char tstr[TOKEN_MAX_LEN]; + uint val; + int idx; + int jmpoff; + + strcpy( tstr, src ); + if( Expression(ps, tstr, &val, &idx)<0 ) + { + Report(ps,REP_ERROR,"Operand %d error in expression",num); + return(0); + } + + if( Pass==2 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : EXP : '%s' = %d\n", ps->SourceName,ps->CurrentLine,src,val); + + jmpoff = ((int)val) - CodeOffset; + if( Pass==2 && (jmpoff<-512 || jmpoff>511) ) + { Report(ps,REP_ERROR,"Operand %d relative jump out of range",num); return(0); } + + /* Setup the record */ + pa->Type = ARGTYPE_OFFSET; + pa->Value = (uint)jmpoff; + pa->Field = 0; + + return(1); +} + + +/* +// GetLoopOffset +// +// Get 8 bit Loop Offset +// +// Parses the source string for a register and field +// +// ps - Pointer to source file record +// num - source line number +// src - source string +// pa - Pointer to register structure +// +// Returns: +// 1 : Success +// 0 : Error +*/ +static int GetLoopOffset( SOURCEFILE *ps, int num, char *src, PRU_ARG *pa ) +{ + char tstr[TOKEN_MAX_LEN]; + uint val; + int idx; + int jmpoff; + + strcpy( tstr, src ); + if( Expression(ps, tstr, &val, &idx)<0 ) + { + Report(ps,REP_ERROR,"Operand %d error in expression",num); + return(0); + } + + if( Pass==2 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : EXP : '%s' = %d\n", ps->SourceName,ps->CurrentLine,src,val); + + jmpoff = ((int)val) - CodeOffset; + if( Pass==2 && (jmpoff<2 || jmpoff>255) ) + { Report(ps,REP_ERROR,"Operand %d invalid loop termination point",num); return(0); } + + /* Setup the record */ + pa->Type = ARGTYPE_OFFSET; + pa->Value = (uint)jmpoff; + pa->Field = 0; + + return(1); +} + + +/* +// Offset2Reg +// +// Convert Register Offset to Register +// +// ps - Pointer to source file record +// num - operand number (1 based) +// pa - Pointer to register structure +// addr - Field address (0 - 127) +// size - Field size (1, 2, or 4) +// +// Returns: +// 1 : Success +// 0 : Error +*/ +static int Offset2Reg( SOURCEFILE *ps, int num, PRU_ARG *pa, uint addr, uint size ) +{ + uint offset; + + offset = addr&3; + + if( addr+size > 128 ) + { Report(ps,REP_ERROR,"Operand %d, field extends past register file", num); return(0); } + + if( (size==2 && offset==3) || + (size==4 && offset!=0) ) + { Report(ps,REP_ERROR,"Operand %d, this field alignment not supported", num); return(0); } + + /* Build the record */ + pa->Type = ARGTYPE_REGISTER; + pa->Value = addr/4; + + /* Get field type */ + if( !(Options & OPTION_BIGENDIAN) ) + { + /* + // Little Endian Version + */ + if( size==4 ) + pa->Field = FIELDTYPE_31_0; + else if( size==2 ) + { + if( !offset ) + pa->Field = FIELDTYPE_15_0; + else if( offset==1 ) + pa->Field = FIELDTYPE_23_8; + else + pa->Field = FIELDTYPE_31_16; + } + else + { + if( !offset ) + pa->Field = FIELDTYPE_7_0; + else if( offset==1 ) + pa->Field = FIELDTYPE_15_8; + else if( offset==2 ) + pa->Field = FIELDTYPE_23_16; + else + pa->Field = FIELDTYPE_31_24; + } + } + else + { + /* + // Big Endian Version + */ + if( size==4 ) + pa->Field = FIELDTYPE_31_0; + else if( size==2 ) + { + if( !offset ) + pa->Field = FIELDTYPE_31_16; + else if( offset==1 ) + pa->Field = FIELDTYPE_23_8; + else + pa->Field = FIELDTYPE_15_0; + } + else + { + if( !offset ) + pa->Field = FIELDTYPE_31_24; + else if( offset==1 ) + pa->Field = FIELDTYPE_23_16; + else if( offset==2 ) + pa->Field = FIELDTYPE_15_8; + else + pa->Field = FIELDTYPE_7_0; + } + } + + return(1); +} + diff --git a/am335x/pasm/pasmpp.c b/am335x/pasm/pasmpp.c new file mode 100644 index 00000000..20453319 --- /dev/null +++ b/am335x/pasm/pasmpp.c @@ -0,0 +1,1165 @@ +/* + * pasmpp.c + * + * Copyright (C) 2012 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. + * +*/ + +/*=========================================================================== + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + +/*=========================================================================== +// PASM - PRU Assembler +//--------------------------------------------------------------------------- +// +// File : pasmpp.c +// +// Description: +// Assembler pre-processor. This module's operation is independent +// of the rest of the assembler. It contains no PRU specific +// functionality. +// - Preprocessor handles all source file opening and reading +// - Initial source parsing +// - Processes all '#' commands (#include and #define) +// - Handles equate creation, matching, and expansion +// +//--------------------------------------------------------------------------- +// Revision: +// 21-Jun-13: 0.84 - Open source version +============================================================================*/ + +#include +#include +#include +#if !defined(__APPLE__) +#include +#else +#include +#endif +#include +#include "pasm.h" + +/* Local Strcuture Types */ + +/* Equate Record */ +typedef struct _EQUATE { + struct _EQUATE *pPrev; /* Previous in EQUATE list */ + struct _EQUATE *pNext; /* Next in EQUATE list */ + int Busy; /* Is this record busy? */ + char name[EQUATE_NAME_LEN]; + char data[EQUATE_DATA_LEN]; +} EQUATE; + +/* Local Support Funtions */ +static int ReadCharacter( SOURCEFILE *ps ); +static int GetTextLine( SOURCEFILE *ps, char *Dst, int MaxLen, int *pLength, int *pEOF ); +static int ParseSource( SOURCEFILE *ps, char *Src, char *Dst, int *pIdx, int MaxLen ); +static int LoadInclude( SOURCEFILE *ps, char *Src ); +static int EquateProcess( SOURCEFILE *ps, char *Src ); +static int UndefProcess( SOURCEFILE *ps, char *Src ); +static EQUATE *EquateFind( char *name ); +static void EquateDestroy( EQUATE *peq ); + +static int IfDefProcess( SOURCEFILE *ps, char *Src, int fTrue ); +static int ElseProcess( SOURCEFILE *ps, char *Src ); +static int EndifProcess( SOURCEFILE *ps, char *Src ); + +int OpenFiles=0; /* Total number of open files */ +EQUATE *pEqList=0; /* List of installed equates */ + +SOURCEFILE sfArray[SOURCEFILE_MAX]; +unsigned int sfIndex = 0; + +#define CC_MAX_DEPTH 8 +uint ccDepth = 0; +uint ccStateFlags[CC_MAX_DEPTH]; +#define CCSTATEFLG_TRUE 1 // Currently accepting code +#define CCSTATEFLG_ELSE 2 // Else has been used + + +/*=================================================================== +// +// Public Functions +// +====================================================================*/ + +/* +// InitSourceFile +// +// Initializes all the fields in SOURCEFILE, and attempts to to open the +// file. +// +// Returns 1 on success, 0 on error +*/ +SOURCEFILE *InitSourceFile( SOURCEFILE *pParent, char *filename ) +{ + SOURCEFILE *ps; + int i,j,k; + char SourceName[SOURCE_NAME]; + char SourceBaseDir[SOURCE_BASE_DIR]; + + /* Put a reasonable cap on #include depth */ + if( OpenFiles==15 ) + { + Report(pParent,REP_FATAL,"Too many open files"); + return(0); + } + + /* + // Create a base directory for this file + // + // The base directory is used for any #include contained in the source + */ + strcpy( SourceBaseDir, "./" ); + i=0; + j=-1; + k=0; + while( filename[i] ) + { + if( filename[i]==':' ) + { + if(k) + { + Report(pParent,REP_FATAL,"Illegal source file name '%s'",filename); + goto FILEOP_ERROR; + } + j=i; + k=1; + } + if( filename[i]=='/' || filename[i]=='\\' ) + j=i; + i++; + } + if( j>=(SOURCE_BASE_DIR-4) ) + { + Report(pParent,REP_FATAL,"Pathname too long in '%s'",filename); + goto FILEOP_ERROR; + } + if( j>0 ) + { + if(k) + { + memcpy( SourceBaseDir, filename, j+1 ); + SourceBaseDir[j+1]='.'; + SourceBaseDir[j+2]='/'; + SourceBaseDir[j+3]=0; + } + else + { + if((filename[0]=='.' && filename[1]=='/') || filename[0]=='/' || filename[0]=='\\') + { + memcpy( SourceBaseDir, filename, j ); + SourceBaseDir[j]='/'; + SourceBaseDir[j+1]=0; + } + else + { + memcpy( SourceBaseDir+2, filename, j ); + SourceBaseDir[j+2]='/'; + SourceBaseDir[j+3]=0; + } + } + } + if( Options & OPTION_DEBUG ) + printf("Base source directory: '%s'\n",SourceBaseDir); + + /* Create the "friendly" filename for output messages */ + i=strlen(filename)-j; + if( i>SOURCE_NAME ) + { + Report(pParent,REP_FATAL,"Basename too long in '%s'",filename); + goto FILEOP_ERROR; + } + memcpy( SourceName, filename+j+1, i ); + + /* + // See if this file was used before, or allocate a new record + */ + for( i=0; i<(int)sfIndex; i++ ) + { + if( !sfArray[i].InUse && + !strcmp(SourceName, sfArray[i].SourceName) && + !strcmp(SourceBaseDir, sfArray[i].SourceBaseDir) ) + break; + } + + if( i<(int)sfIndex ) + ps = &sfArray[i]; + else + { + /* Allocate a new file */ + if( sfIndex==SOURCEFILE_MAX ) + { Report(pParent,REP_FATAL,"Max source files exceeded"); return(0); } + + ps = &sfArray[sfIndex]; + i = sfIndex++; + } + + /* + // Fill in file record + */ + memset( ps, 0, sizeof(SOURCEFILE) ); + + if( Options & OPTION_DEBUG ) + printf("New source file: '%s'\n",filename); + + /* Init the base fields */ + ps->pParent = 0; + ps->LastChar = 0; + ps->CurrentLine = 1; + ps->CurrentColumn = 1; + ps->ccDepthIn = ccDepth; + ps->InUse = 1; + ps->FileIndex = i; + + strcpy( ps->SourceName, SourceName ); + strcpy( ps->SourceBaseDir, SourceBaseDir ); + + + /* Open the file */ + ps->FilePtr = fopen(filename,"rb"); + if (!ps->FilePtr) + { + Report(pParent,REP_FATAL,"Can't open source file '%s'",filename); + goto FILEOP_ERROR; + } + OpenFiles++; + if( OpenFiles > 10 ) + Report(pParent,REP_WARN1,"%d open files - possible #include recursion",OpenFiles); + return(ps); + +FILEOP_ERROR: + return(0); +} + + +/* +// CloseSourceFile +// +// Close the source file and free the block. +// +// void +*/ +void CloseSourceFile( SOURCEFILE *ps ) +{ + OpenFiles--; + ps->InUse = 0; + fclose( ps->FilePtr ); +} + + +/* +// GetSourceLine +// +// Get a new line of source code. +// +// This module also processes: +// '#' directives +// #define expansion +// Comments +// +// Returns length of line, 0 on EOF, -1 on Error +*/ +#define RAW_SOURCE_MAX 255 +int GetSourceLine( SOURCEFILE *ps, char *Dst, int MaxLen ) +{ + char c,Src[RAW_SOURCE_MAX],word[TOKEN_MAX_LEN]; + int i,idx; + int len,eof; + +NEXT_LINE: + do + { + if( !GetTextLine(ps, Src, RAW_SOURCE_MAX, &len, &eof) ) + return(-1); + } while( !len && !eof ); + + if( !len && eof ) + { + if( ps->ccDepthIn != ccDepth ) + { Report(ps,REP_ERROR,"#endif mismatch in file"); return(0); } + return(0); + } + + /* + // Process any '#' directives + */ + if( Src[0]=='#' ) + { + idx = 1; + c = Src[idx++]; + if( (c<'A'||c>'Z') && (c<'a'||c>'z') ) + { Report(ps,REP_ERROR,"Expected {a-z} after #"); return(-1); } + i=0; + word[i++]=c; + while( i<(TOKEN_MAX_LEN-1) ) + { + c = Src[idx++]; + if( c==' ' || c==0x9 || !c ) + break; + word[i++]=c; + } + word[i]=0; + + /* Make sure the process functions see the final NULL */ + if( !c ) + idx--; + + if( !stricmp( word, "ifdef" ) ) + { + if( !IfDefProcess( ps, Src+idx, 1 ) ) + return(-1); + goto NEXT_LINE; + } + if( !stricmp( word, "ifndef" ) ) + { + if( !IfDefProcess( ps, Src+idx, 0 ) ) + return(-1); + goto NEXT_LINE; + } + if( !stricmp( word, "else" ) ) + { + if( !ElseProcess( ps, Src+idx ) ) + return(-1); + goto NEXT_LINE; + } + if( !stricmp( word, "endif" ) ) + { + if( !EndifProcess( ps, Src+idx ) ) + return(-1); + goto NEXT_LINE; + } + + if( ccDepth && !(ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE) ) + goto NEXT_LINE; + + if( !stricmp( word, "error" ) ) + { + Report(ps,REP_ERROR,"%s",Src+idx); + goto NEXT_LINE; + } + if( !stricmp( word, "warn" ) ) + { + Report(ps,REP_WARN1,"%s",Src+idx); + goto NEXT_LINE; + } + if( !stricmp( word, "note" ) ) + { + Report(ps,REP_INFO,"%s",Src+idx); + goto NEXT_LINE; + } + if( !stricmp( word, "include" ) ) + { + if( !LoadInclude( ps, Src+idx ) ) + return(-1); + goto NEXT_LINE; + } + if( !stricmp( word, "define" ) ) + { + EquateProcess( ps, Src+idx ); + goto NEXT_LINE; + } + if( !stricmp( word, "undef" ) ) + { + UndefProcess( ps, Src+idx ); + goto NEXT_LINE; + } + Report(ps,REP_ERROR,"Unknown # directive"); + return(-1); + } + + /* + // Not '#' directive, process as string + */ + + if( ccDepth && !(ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE) ) + goto NEXT_LINE; + + idx = 0; + if( !ParseSource( ps, Src, Dst, &idx, MaxLen ) ) + return(0); + + Dst[idx] = 0; + return(idx); +} + +/* +// ppCleanup +// +// Clean up the pre-processor environment +// +// void +*/ +void ppCleanup() +{ + ccDepth = 0; + while( pEqList ) + EquateDestroy( pEqList ); +} + + +/* +// EquateCreate +// +// Creates an equate record +// +// Returns 0 on success, -1 on error +*/ +int EquateCreate( SOURCEFILE *ps, char *Name, char *Value ) +{ + EQUATE *pd; + + /* Make sure this name is OK to use */ + if( !CheckName(ps,Name) ) + return(-1); + + /* Make sure its not a too long */ + if( strlen(Name)>=EQUATE_NAME_LEN ) + { Report(ps,REP_ERROR,"Equate name '%s' too long",Name); return(-1); } + if( strlen(Value)>=EQUATE_DATA_LEN ) + { Report(ps,REP_ERROR,"Equate data '%s' too long",Value); return(-1); } + + /* Allocate a new record */ + pd = malloc(sizeof(EQUATE)); + if( !pd ) + { Report(ps,REP_ERROR,"Memory allocation failed"); return(-1); } + + /* Load in the name and data */ + strcpy( pd->name, Name ); + strcpy( pd->data, Value ); + + /* Put this equate in the master list */ + pd->Busy = 0; + pd->pPrev = 0; + pd->pNext = pEqList; + if( pEqList ) + pEqList->pPrev = pd; + pEqList = pd; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : DEFINE : '%s' = '%s'\n", + ps->SourceName,ps->CurrentLine,pd->name,pd->data); + + return(0); +} + + +/* +// CheckEquate +// +// Searches for an equate by name. +// +// Returns 1 on success, 0 on error +*/ +int CheckEquate( char *name ) +{ + if( EquateFind(name) ) + return(1); + return(0); +} + + +/*=================================================================== +// +// Private Functions +// +====================================================================*/ + +/* +// ReadCharacter +// +// Read a charater from the source file and track line and column +// +// Returns character or -1 on error +*/ +static int ReadCharacter( SOURCEFILE *ps ) +{ + int i; + char c; + +AGAIN: + i = fread( &c, 1, 1, ps->FilePtr ); + if( i != 1 ) + return(-1); + if( c == 0xd ) + goto AGAIN; + if( ps->LastChar == 0xa ) + { + ps->CurrentLine++; + ps->CurrentColumn=1; + } + else + ps->CurrentColumn++; + ps->LastChar = c; + + return(c); +} + + +/* +// GetTextLine +// +// Gets a line of text from the source file without # directive +// processing, or processing past a EOL. +// +// Returns 1 on success, 0 on error +*/ +static int GetTextLine( SOURCEFILE *ps, char *Dst, int MaxLen, int *pLength, int *pEOF ) +{ + int c; + int idx; + int commentFlag,quoteFlag; + + /* Remove leading white space */ + do + { + c = ReadCharacter( ps ); + } while( c==' ' || c==0x9 || c==0xa ); + + /* + // Process line watching for comments and quotes + */ + idx=0; + commentFlag=0; + quoteFlag=0; + for(;;) + { + /* Process quotes and comments */ + if( c=='"' ) + quoteFlag^=1; + + if( quoteFlag ) + commentFlag=0; + + if( (commentFlag && c=='/') || (!quoteFlag && c==';') ) + { + if( c=='/' && idx>0 ) + idx--; + while( c!=0 && c!=-1 && c!=0xa ) + c = ReadCharacter( ps ); + break; + } + + if( c=='/' ) + commentFlag=1; + else + commentFlag=0; + + /* If this character terminated the line, break now */ + if( c==0 || c==-1 || c==0xa ) + break; + + /* We didn't consume this charater */ + if( idx<(MaxLen-1) ) + Dst[idx++]=c; + else + { Report(ps,REP_ERROR,"Line too long"); return(0); } + + c = ReadCharacter( ps ); + } + + /* Back off white space */ + while( idx>0 && (Dst[idx-1]==' ' || Dst[idx-1]==0x9) ) + idx--; + + /* Null terminate the output */ + Dst[idx] = 0; + + if( quoteFlag ) + Report(ps,REP_ERROR,"Open Quotes"); + + if( pLength ) + *pLength = idx; + + if( pEOF ) + { + if( idx || c!=-1 ) + *pEOF=0; + else + *pEOF=1; + } + + return(1); +} + + +/* +// ParseSource +// +// Parses the source string, expanding any equates +// +// Returns 1 on success, 0 on error +*/ +#define WF_READY 0 +#define WF_NONLABEL 1 +#define WF_QUOTED 2 +#define WF_LABEL 3 +static int ParseSource( SOURCEFILE *ps, char *Src, char *Dst, int *pIdx, int MaxLen ) +{ + char c,word[TOKEN_MAX_LEN]; + int i,srcIdx,dstIdx,wordIdx; + int wordFlag; + + srcIdx = 0; + dstIdx = *pIdx; + wordIdx = 0; + + wordFlag=WF_READY; + for(;;) + { + c = Src[srcIdx++]; + + /* See if we go into label or non-label mode */ + if( wordFlag==WF_READY ) + { + if( c=='"' ) + wordFlag=WF_QUOTED; + else if( LabelChar(c,1) ) + { + wordFlag=WF_LABEL; + wordIdx=0; + word[wordIdx++]=c; + continue; + } + else if( LabelChar(c,0) ) + wordFlag=WF_NONLABEL; + } + /* See if we fall out of non-label mode */ + else if( wordFlag==WF_NONLABEL ) + { + if( c=='"' ) + wordFlag=WF_QUOTED; + else if( !LabelChar(c,0) ) + wordFlag=WF_READY; + } + /* See if we fall out of label mode */ + else if( wordFlag==WF_LABEL ) + { + if( (wordIdx>=(TOKEN_MAX_LEN-1)) || !LabelChar(c,0) ) + { + /* Here we are teminating the word and checking it */ + EQUATE *peq; + if( c=='"' ) + wordFlag=WF_QUOTED; + else + wordFlag=WF_READY; + word[wordIdx]=0; + peq = EquateFind(word); + /* See if equate exists and is free */ + if( peq && !peq->Busy ) + { + /* Mark as busy, process, then mark as free */ + peq->Busy=1; + i = ParseSource( ps, peq->data, Dst, &dstIdx, MaxLen ); + peq->Busy=0; + + /* If there was an error, return now */ + if( !i ) + return(0); + } + else + { + /* The word is not a EQUATE */ + for(i=0;iSourceBaseDir ); + idx = strlen(NewFileName); + } + else if( c=='<' ) + { + term = '>'; + idx=0; + } + else + { Report(ps,REP_ERROR,"Expected \" or < after #include"); return(0); } + + /* Read in the filename to the terminating character */ + // Check for include paths that start with "/" or "\" + // (assume an absolute path) + if( Src[srcIdx]=='/' || Src[srcIdx]=='\\' ) + idx = 0; + oldidx = idx; + for(;;) + { + c = Src[srcIdx++]; + // Check for include paths that include a ":" + // (assume a driver letter preceeded) + if( c==':' && idx>0 ) + { + NewFileName[0]=NewFileName[idx-1]; + idx = 1; + oldidx = idx; + } + if( c==term ) + break; + if( !c ) + { Report(ps,REP_ERROR,"Bad filename in #include"); return(0); } + if( idx >= (SOURCE_BASE_DIR-1) ) + { Report(ps,REP_ERROR,"Filename too long in #include"); return(0); } + NewFileName[idx++]=c; + } + + /* The line should be done now */ + if( Src[srcIdx] ) + { Report(ps,REP_ERROR,"Expected EOL after '%s'",NewFileName); return(0); } + + /* Null terminate the filename and make sure something got copied */ + NewFileName[idx]=0; + if( idx == oldidx ) + { Report(ps,REP_ERROR,"Null filename in #include"); return(0); } + + /* Open the new file */ + if( !(psNew=InitSourceFile(ps, NewFileName)) ) + return(0); + + /* Process the new file */ + rc = ProcessSourceFile( psNew ); + + /* Free the file block */ + CloseSourceFile( psNew ); + + if( !rc && Pass==2 ) + return(0); + else + return(1); +} + +/* +// EquateProcess +// +// Processes a #define command +// +// Returns 1 on success, 0 on error +*/ +static int EquateProcess( SOURCEFILE *ps, char *Src ) +{ + EQUATE *pd,*pdTmp; + char c; + int idx,srcIdx; + + /* Allocate a new record */ + pd = malloc(sizeof(EQUATE)); + if( !pd ) + { Report(ps,REP_ERROR,"Memory allocation failed"); return(0); } + + srcIdx=0; + + /* Remove leading white space */ + do + { + c = Src[srcIdx++]; + } while( c==' ' || c==0x9 ); + + /* Character must be a legal label */ + if( !LabelChar(c,1) ) + { Report(ps,REP_ERROR,"Illegal label"); free(pd); return(0); } + + /* The name can only be delimited by a white space */ + /* Note: We now allow a NULL for a #define with no value */ + idx=0; + for(;;) + { + pd->name[idx++]=c; + c = Src[srcIdx++]; + if( !c || c==' ' || c==0x9 ) + break; + if( !LabelChar(c,0) ) + { Report(ps,REP_ERROR,"Illegal #define"); free(pd); return(0); } + if( idx >= (EQUATE_NAME_LEN-1) ) + { Report(ps,REP_ERROR,"Label too long"); free(pd); return(0); } + } + pd->name[idx]=0; + + /* Make sure this name is OK to use */ + if( !CheckName(ps,pd->name) ) + { + free(pd); + return(0); + } + + /* Remove leading white space (unless we already hit EOL) */ + if( c ) + do + { + c = Src[srcIdx++]; + } while( c==' ' || c==0x9 ); + + /* Load in the text part of the equate (defaul to "1" if no value) */ + if( !c ) + strcpy( pd->data, "1" ); + else + strcpy( pd->data, Src+srcIdx-1 ); + + /* Check for dedefinition, but ignore exact duplicates */ + if( (pdTmp = EquateFind(pd->name)) != 0 ) + { + idx = strcmp( pd->data, pdTmp->data ); + if( !idx ) + { + free(pd); + return(1); + } + EquateDestroy(pdTmp); + Report(ps,REP_WARN1,"Redefinition of equate '%s'",pd->name); + } + + /* Put this equate in the master list */ + pd->Busy = 0; + pd->pPrev = 0; + pd->pNext = pEqList; + if( pEqList ) + pEqList->pPrev = pd; + pEqList = pd; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : DEFINE : '%s' = '%s'\n", + ps->SourceName,ps->CurrentLine,pd->name,pd->data); + + return(1); +} + + +/* +// UndefProcess +// +// Processes a #undef command +// +// Returns 1 on success, 0 on error +*/ +static int UndefProcess( SOURCEFILE *ps, char *Src ) +{ + EQUATE *pdTmp; + char c,name[EQUATE_NAME_LEN]; + int idx,srcIdx; + + srcIdx=0; + + /* Remove leading white space */ + do + { + c = Src[srcIdx++]; + } while( c==' ' || c==0x9 ); + + /* Character must be a legal label */ + if( !LabelChar(c,1) ) + { Report(ps,REP_ERROR,"Illegal label"); return(0); } + + /* The name is delimited by EOL */ + idx=0; + for(;;) + { + name[idx++]=c; + c = Src[srcIdx++]; + if( !c ) + break; + if( c==' ' || c==0x9 ) + { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); } + if( !LabelChar(c,0) ) + { Report(ps,REP_ERROR,"Illegal name"); return(0); } + if( idx >= (EQUATE_NAME_LEN-1) ) + { Report(ps,REP_ERROR,"Label too long"); return(0); } + } + name[idx]=0; + + /* Check for dedefinition */ + if( !(pdTmp = EquateFind(name)) ) + { Report(ps,REP_WARN1,"Undef attempt on undfined '%s'",name); return(1); } + + EquateDestroy(pdTmp); + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : UNDEF : '%s'\n", + ps->SourceName,ps->CurrentLine,name); + + return(1); +} + + +/* +// EquateFind +// +// Searches for an equate by name. If found, returns the record pointer. +// +// Returns EQUATE * on success, 0 on error +*/ +static EQUATE *EquateFind( char *name ) +{ + EQUATE *peq; + + peq = pEqList; + while( peq ) + { + if( !strcmp( name, peq->name ) ) + break; + peq = peq->pNext; + } + return(peq); +} + + +/* +// EquateDestroy +// +// Frees an equate record. +// +// void +*/ +static void EquateDestroy( EQUATE *peq ) +{ + if( !peq->pPrev ) + pEqList = peq->pNext; + else + peq->pPrev->pNext = peq->pNext; + + if( peq->pNext ) + peq->pNext->pPrev = peq->pPrev; + + free(peq); +} + + +/* +// IfDefProcess +// +// Processes a #ifdef command +// +// Returns 1 on success, 0 on error +*/ +static int IfDefProcess( SOURCEFILE *ps, char *Src, int fTrue ) +{ + char c,name[EQUATE_NAME_LEN]; + int idx,srcIdx; + + /* Check depth */ + if( ccDepth==CC_MAX_DEPTH ) + { Report(ps,REP_ERROR,"Conditional nesting limit exceeded"); return(0); } + + /* If we are already in a false if, just create another false here to track nesting */ + if( ccDepth && !(ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE) ) + { + ccStateFlags[ccDepth++] = 0; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : IFDEF : \n",ps->SourceName,ps->CurrentLine); + + return(1); + } + + srcIdx=0; + + /* Remove leading white space */ + do + { + c = Src[srcIdx++]; + } while( c==' ' || c==0x9 ); + + /* Character must be a legal label */ + if( !LabelChar(c,1) ) + { Report(ps,REP_ERROR,"Illegal label"); return(0); } + + /* The name is delimited by EOL */ + idx=0; + for(;;) + { + name[idx++]=c; + c = Src[srcIdx++]; + if( !c ) + break; + if( c==' ' || c==0x9 ) + { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); } + if( !LabelChar(c,0) ) + { Report(ps,REP_ERROR,"Illegal name"); return(0); } + if( idx >= (EQUATE_NAME_LEN-1) ) + { Report(ps,REP_ERROR,"Label too long"); return(0); } + } + name[idx]=0; + + ccStateFlags[ccDepth] = 0; + + /* Check for dedefinition */ + if( EquateFind(name) ) + ccStateFlags[ccDepth] = CCSTATEFLG_TRUE; + + /* Toggle the state for ifndef */ + if( !fTrue ) + ccStateFlags[ccDepth] ^= CCSTATEFLG_TRUE; + + ccDepth++; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + { + if( fTrue ) + printf("%s(%5d) : IFDEF : '%s' (Result=%d)\n", + ps->SourceName,ps->CurrentLine,name,ccStateFlags[ccDepth-1]); + else + printf("%s(%5d) : IFNDEF : '%s' (Result=%d)\n", + ps->SourceName,ps->CurrentLine,name,ccStateFlags[ccDepth-1]); + } + + return(1); +} + + +/* +// ElseProcess +// +// Processes a #else command +// +// Returns 1 on success, 0 on error +*/ +static int ElseProcess( SOURCEFILE *ps, char *Src ) +{ + int i; + + if( *Src ) + { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); } + + /* Make sure #else is legal here */ + if( !ccDepth || (ccStateFlags[ccDepth-1]&CCSTATEFLG_ELSE) ) + { Report(ps,REP_ERROR,"Multiple #else or use without corresponding #if"); return(0); } + + /* Mark it as used */ + ccStateFlags[ccDepth-1] |= CCSTATEFLG_ELSE; + + /* Toggle the TRUE state */ + ccStateFlags[ccDepth-1] ^= CCSTATEFLG_TRUE; + + /* If we are already in a nested false if, keep expession false */ + for( i=0; i<(int)(ccDepth-1); i++ ) + if( !(ccStateFlags[i]&CCSTATEFLG_TRUE) ) + ccStateFlags[ccDepth-1] &= ~CCSTATEFLG_TRUE; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : ELSE : (Result=%d)\n", + ps->SourceName,ps->CurrentLine,ccStateFlags[ccDepth-1]&CCSTATEFLG_TRUE); + + return(1); +} + + +/* +// EndifProcess +// +// Processes a #endif command +// +// Returns 1 on success, 0 on error +*/ +static int EndifProcess( SOURCEFILE *ps, char *Src ) +{ + if( *Src ) + { Report(ps,REP_ERROR,"Unexpected additional characters on line"); return(0); } + + /* Make sure #else is legal here */ + if( !ccDepth ) + { Report(ps,REP_ERROR,"#endif without corresponding #if"); return(0); } + + ccDepth--; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : ENDIF :\n", + ps->SourceName,ps->CurrentLine); + + return(1); +} + diff --git a/am335x/pasm/pasmstruct.c b/am335x/pasm/pasmstruct.c new file mode 100644 index 00000000..6fc362e3 --- /dev/null +++ b/am335x/pasm/pasmstruct.c @@ -0,0 +1,1251 @@ +/* + * pasmstruct.c + * + * Copyright (C) 2012 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. + * +*/ + +/*=========================================================================== + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + +/*=========================================================================== +// PASM - PRU Assembler +//--------------------------------------------------------------------------- +// +// File : pasmstruct.c +// +// Description: +// Processes the scruct and scope commands +// +//--------------------------------------------------------------------------- +// Revision: +// 21-Jun-13: 0.84 - Open source version +============================================================================*/ + +#include +#include +#include +#if !defined(__APPLE__) +#include +#else +#include +#endif +#include +#include "pasm.h" + +/* Local Strcuture Types */ + +/* Struct Record */ +#define STRUCT_NAME_LEN TOKEN_MAX_LEN +#define STRUCT_MAX_ELEM 64 +typedef struct _STRUCT { + struct _STRUCT *pPrev; /* Previous in STRUCT list */ + struct _STRUCT *pNext; /* Next in STRUCT list */ + char Name[STRUCT_NAME_LEN]; + int Elements; /* Element Count */ + uint TotalSize; /* Total Size */ + uint Offset[STRUCT_MAX_ELEM]; /* Element Offset */ + uint Size[STRUCT_MAX_ELEM]; /* Element Size */ + char ElemName[STRUCT_MAX_ELEM][STRUCT_NAME_LEN]; +} STRUCT; + +/* Assignment Record */ +typedef struct _ASSIGN { + struct _ASSIGN *pPrev; /* Previous in ASSIGN list */ + struct _ASSIGN *pNext; /* Next in ASSIGN list */ + char Name[STRUCT_NAME_LEN]; + char BaseReg[STRUCT_NAME_LEN]; + int Elements; /* Element Count */ + uint TotalSize; /* Total Size */ + char ElemName[STRUCT_MAX_ELEM][STRUCT_NAME_LEN]; + char MappedReg[STRUCT_MAX_ELEM][STRUCT_NAME_LEN]; + uint Offset[STRUCT_MAX_ELEM]; /* Element Offset */ + uint Size[STRUCT_MAX_ELEM]; /* Element Size */ +} ASSIGN; + +/* Scope Record */ +#define SCOPE_NAME_LEN TOKEN_MAX_LEN +typedef struct _SCOPE { + struct _SCOPE *pPrev; /* Previous in SCOPE list */ + struct _SCOPE *pNext; /* Next in SCOPE list */ + uint Flags; +#define SCOPE_FLG_OPEN (1<<0) + char Name[SCOPE_NAME_LEN]; + struct _SCOPE *pParent; /* Current SCOPE when created */ + struct _ASSIGN *pAssignList; /* ASSIGN list */ +} SCOPE; + + +/* Local Support Funtions */ +static STRUCT *StructFind( char *Name ); +static STRUCT *StructCreate( SOURCEFILE *ps, char *Name ); +static void StructDestroy( STRUCT *pst ); +static int GetRegname( SOURCEFILE *ps, uint element, char *str, uint off, uint size ); +static ASSIGN *AssignFind( char *Name ); +static ASSIGN *AssignCreate( SOURCEFILE *ps, ASSIGN **pList, char *Name ); +static void AssignDestroy( ASSIGN **pList, ASSIGN *pas ); +static char *StructNameCheck( char *source ); +static int StructValueOperand( char *source, int CmdType, uint *pValue ); +#define SVO_SIZEOF 0 +#define SVO_OFFSET 1 +static int GetFinalSize( char *ext, uint Size, uint *pValue ); +static int GetFinalOffset( char *ext, uint Size, uint Offset, uint *pValue ); +static SCOPE *ScopeCreate( SOURCEFILE *ps, char *Name ); +static void ScopeDestroy( SCOPE *psc ); +static void ScopeClose( SCOPE *psc ); +static SCOPE *ScopeFind( char *Name ); + + +/* Local structure lists */ +STRUCT *pStructList=0; /* List of declared structs */ +STRUCT *pStructCurrent=0; + +SCOPE *pScopeList=0; /* List of desclared scopes */ +SCOPE *pScopeCurrent=0; + +/*=================================================================== +// +// Public Functions +// +====================================================================*/ + +/* +// ScopeEnter +// +// Returns: +// 0 - Success +// -1 - Error +*/ +int ScopeEnter( SOURCEFILE *ps, char *Name ) +{ + if( Core == CORE_V0 ) + { Report(ps,REP_ERROR,".enter illegal with specified core version"); return(-1); } + if( !ScopeCreate(ps, Name) ) + return(-1); + return(0); +} + + +/* +// ScopeLeave +// +// Returns: +// 0 - Success +// -1 - Error +*/ +int ScopeLeave( SOURCEFILE *ps, char *Name ) +{ + SCOPE *psc; + + psc = ScopeFind(Name); + if( !psc ) + { Report(ps,REP_ERROR,"Scope name undefined"); return(-1); } + if( !(psc->Flags&SCOPE_FLG_OPEN) ) + { Report(ps,REP_ERROR,"Scope is not open"); return(-1); } + ScopeClose(psc); + return(0); +} + + +/* +// ScopeUsing +// +// Returns: +// 0 - Success +// -1 - Error +*/ +int ScopeUsing( SOURCEFILE *ps, char *Name ) +{ + SCOPE *psc; + + psc = ScopeFind(Name); + if( !psc ) + { Report(ps,REP_ERROR,"Scope name undefined"); return(-1); } + if( psc->Flags&SCOPE_FLG_OPEN ) + { Report(ps,REP_ERROR,"Scope is already open"); return(-1); } + psc->Flags |= SCOPE_FLG_OPEN; + pScopeCurrent = psc; + return(0); +} + + +/* +// StructInit +// +// Returns: void +*/ +void StructInit() +{ + ScopeCreate(0,"_ROOT_"); +} + + +/* +// StructCleanup +// +// Returns: void +*/ +void StructCleanup() +{ + while( pScopeList ) + ScopeDestroy( pScopeList ); + while( pStructList ) + StructDestroy( pStructList ); +} + + +/* +// StructNew +// +// Returns: +// 0 - Success +// -1 - Error +*/ +int StructNew( SOURCEFILE *ps, char *Name ) +{ + if( pStructCurrent ) + { Report(ps,REP_ERROR,"Structure can not be nested"); return(-1); } + if( Core == CORE_V0 ) + { Report(ps,REP_ERROR,".struct illegal with specified core version"); return(-1); } + pStructCurrent=StructCreate(ps, Name); + if( !pStructCurrent ) + return(-1); + return(0); +} + + +/* +// StructEnd +// +// Returns: +// 0 - Success +// -1 - Error +*/ +int StructEnd(SOURCEFILE *ps) +{ + if( !pStructCurrent ) + { Report(ps,REP_ERROR,"Structure .struct/.ends mismatch"); return(-1); } + if( !pStructCurrent->Elements ) + { Report(ps,REP_ERROR,"Structure must have at least 1 element"); pStructCurrent=0; return(-1); } + pStructCurrent = 0; + return(0); +} + + +/* +// StructAddElement +// +// Create a new structure record +// +// Returns 0 on success, -1 on error +*/ +int StructAddElement( SOURCEFILE *ps, char *Name, uint size ) +{ + STRUCT *pst = pStructCurrent; + int i; + + if( !pst ) + { Report(ps,REP_ERROR,"Can not add element - missing .struct"); return(-1); } + + /* Make sure its not a too long */ + if( strlen(Name)>=STRUCT_NAME_LEN ) + { Report(ps,REP_ERROR,"Element name too long"); return(-1); } + + /* Make sure its not a reserved word */ + if( CheckTokenType(Name)!=TOKENTYPE_UNRESERVED ) + { Report(ps,REP_ERROR,"Illegal use of reserved word '%s'",Name); return(0); } + + /* Check for too many elements */ + if( pst->Elements==STRUCT_MAX_ELEM ) + { Report(ps,REP_ERROR,"Max element count (%d) exceeded",STRUCT_MAX_ELEM); return(-1); } + + /* Check for duplicate element name */ + for( i=0; iElements; i++ ) + if( !strcmp(Name,pst->ElemName[i]) ) + break; + if( i!= pst->Elements ) + { Report(ps,REP_ERROR,"Duplicate element name"); return(-1); } + + /* Add the element */ + strcpy( pst->ElemName[pst->Elements], Name ); + pst->Offset[pst->Elements] = pst->TotalSize; + pst->Size[pst->Elements] = size; + pst->TotalSize += size; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : DOTCMD : Element '%s' declared, offset=%d, size=%d\n", + ps->SourceName,ps->CurrentLine,pst->ElemName[pst->Elements], + pst->Offset[pst->Elements],pst->Size[pst->Elements]); + + pst->Elements++; + + return(0); +} + + +/* +// StructAssign +// +// Assign a structure to an instance +// +// Returns 0 on success, -1 on error +*/ +int StructAssign( SOURCEFILE *ps, char *structName, char *rsName, + char *reName, char *defName ) +{ + STRUCT *pst; + ASSIGN *pas; + PRU_ARG rs, re; + char tmpData[EQUATE_DATA_LEN]; + uint startOff,endOff,tmp,rangeCheck; + int i; + + if( pStructCurrent ) + { Report(ps,REP_ERROR,"Cannot assign while defining a structure"); return(-1); } + if( !pScopeCurrent ) + { Report(ps,REP_ERROR,"Cannot assign outside of a scope"); return(-1); } + + if( strcmp( reName, "*" ) ) + rangeCheck = 1; + else + rangeCheck = 0; + + /* Get the register parameters */ + if( !GetRegister( ps, 2, rsName, &rs, 0, 0 ) ) + return -1; + if( rangeCheck && !GetRegister( ps, 3, reName, &re, 0, 0 ) ) + return -1; + + /* Set the struct */ + pst = StructFind( structName ); + if( !pst ) + { Report(ps,REP_ERROR,"Structure '%s' not defined",structName); return(-1); } + + + if( !(Options & OPTION_BIGENDIAN) ) + { + /* + // ** Little Endian Version ** + */ + + /* See if the range is ok */ + startOff = rs.Value * 4; + switch( rs.Field ) + { + case FIELDTYPE_15_8: + case FIELDTYPE_23_8: + startOff += 1; + break; + case FIELDTYPE_23_16: + case FIELDTYPE_31_16: + startOff += 2; + break; + case FIELDTYPE_31_24: + startOff += 3; + break; + } + if( rangeCheck ) + { + endOff = re.Value * 4; + switch( re.Field ) + { + case FIELDTYPE_7_0: + endOff += 1; + break; + case FIELDTYPE_15_8: + case FIELDTYPE_15_0: + endOff += 2; + break; + case FIELDTYPE_23_16: + case FIELDTYPE_23_8: + endOff += 3; + break; + case FIELDTYPE_31_24: + case FIELDTYPE_31_16: + case FIELDTYPE_31_0: + endOff += 4; + break; + } + tmp = startOff + pst->TotalSize; + + if( tmp != endOff ) + { + if( !(tmp&3) ) + GetRegname( ps, 0, tmpData, tmp-4, 4 ); + else if( !(tmp&1) ) + GetRegname( ps, 0, tmpData, tmp-2, 2 ); + else + GetRegname( ps, 0, tmpData, tmp-1, 1 ); + Report(ps,REP_ERROR,"Range error, parameter 3 should be '%s'",tmpData); + return -1; + } + } + } + else + { + /* + // ** Big Endian Version ** + */ + + /* See if the range is ok */ + startOff = rs.Value * 4; + switch( rs.Field ) + { + case FIELDTYPE_23_8: + case FIELDTYPE_23_16: + startOff += 1; + break; + case FIELDTYPE_15_8: + case FIELDTYPE_15_0: + startOff += 2; + break; + case FIELDTYPE_7_0: + startOff += 3; + break; + } + if( rangeCheck ) + { + endOff = re.Value * 4; + switch( re.Field ) + { + case FIELDTYPE_31_24: + endOff += 1; + break; + case FIELDTYPE_23_16: + case FIELDTYPE_31_16: + endOff += 2; + break; + case FIELDTYPE_15_8: + case FIELDTYPE_23_8: + endOff += 3; + break; + case FIELDTYPE_7_0: + case FIELDTYPE_15_0: + case FIELDTYPE_31_0: + endOff += 4; + break; + } + tmp = startOff + pst->TotalSize; + + if( tmp != endOff ) + { + if( !(tmp&3) ) + GetRegname( ps, 0, tmpData, tmp-4, 4 ); + else if( !(tmp&1) ) + GetRegname( ps, 0, tmpData, tmp-2, 2 ); + else + GetRegname( ps, 0, tmpData, tmp-1, 1 ); + Report(ps,REP_ERROR,"Range error, parameter 3 should be '%s'",tmpData); + return -1; + } + } + } + + /* Alignment check pass */ + tmp = startOff; + for(i=0; iElements; i++) + { + if( GetRegname( ps, i+1, tmpData, tmp, pst->Size[i] )<0 ) + return(-1); + tmp += pst->Size[i]; + } + + if( !(pas = AssignCreate( ps, &pScopeCurrent->pAssignList, defName )) ) + return(-1); + + pas->Elements = pst->Elements; + pas->TotalSize = pst->TotalSize; + + /* Equate create pass */ + for(i=0; iElements; i++) + { + GetRegname( ps, i+1, tmpData, startOff, pst->Size[i] ); + if( !i ) + { + strcpy(pas->Name,defName); + strcpy(pas->BaseReg,tmpData); + } + pas->Offset[i] = pst->Offset[i]; + pas->Size[i] = pst->Size[i]; + strcpy(pas->ElemName[i],pst->ElemName[i]); + strcpy(pas->MappedReg[i],tmpData); + startOff += pst->Size[i]; + } + + return(0); +} + + +/* +// Struct Param Process +// +// Processes the supplied argument for stucture references or SIZE/OFFSET +// operations. When found, the structure definition is used to substitute +// in the proper register or numeric value. +// +// The string 'source' is assumed to be be able to hold a length of +// at least 'TOKEN_MAX_LEN' bytes. +// +// Returns 0 for OK, or -1 for Fatal Error +// +*/ +int StructParamProcess( SOURCEFILE *ps, int ParamIdx, char *source ) +{ + char substr[TOKEN_MAX_LEN*2]; + int subidx,srcidx; + char tmpname[STRUCT_NAME_LEN],*pNewName; + int i,j,onedot; + + srcidx=0; + subidx=0; + while(source[srcidx]) + { + /* Scan past any number constants */ + if( source[srcidx]>='0' && source[srcidx]<='9' ) + { + do + { + substr[subidx++] = source[srcidx++]; + } while( LabelChar(source[srcidx],0) ); + } + /* Scan past any non-label charaters */ + else if( !LabelChar(source[srcidx],1) ) + substr[subidx++] = source[srcidx++]; + else + { + /* Scan in the candidate name */ + onedot = 0; + tmpname[0] = source[srcidx]; + for(i=1; i= TOKEN_MAX_LEN ) + return -1; + strcpy( source, substr ); + + return(0); +} + + +/* +// CheckStruct +// +// Searches for struct template or struct by name. +// +// Returns 1 on success, 0 on error +*/ +int CheckStruct( char *name ) +{ + if( StructFind(name) || AssignFind(name) || ScopeFind(name) ) + return(1); + return(0); +} + + +/*=================================================================== +// +// Private Functions +// +====================================================================*/ + +/* +// StructFind +// +// Searches for a struct record by name. If found, returns the record pointer. +// +// Returns STRUCT * on success, 0 on error +*/ +static STRUCT *StructFind( char *Name ) +{ + STRUCT *pst; + + pst = pStructList; + while( pst ) + { + if( !strcmp( Name, pst->Name ) ) + break; + pst = pst->pNext; + } + return(pst); +} + + +/* +// StructCreate +// +// Create a new structure record +// +// Returns STRUCT * on success, 0 on error +*/ +static STRUCT *StructCreate( SOURCEFILE *ps, char *Name ) +{ + STRUCT *pst; + + /* Make sure this name is OK to use */ + if( !CheckName(ps,Name) ) + return(0); + + /* Make sure its not too long */ + if( strlen(Name)>=STRUCT_NAME_LEN ) + { Report(ps,REP_ERROR,"Structure name too long"); return(0); } + + /* Allocate a new record */ + pst = malloc(sizeof(STRUCT)); + if( !pst ) + { Report(ps,REP_ERROR,"Memory allocation failed"); return(0); } + + strcpy( pst->Name, Name ); + pst->Elements = 0; + pst->TotalSize = 0; + + /* Put this equate in the master list */ + pst->pPrev = 0; + pst->pNext = pStructList; + pStructList = pst; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : DOTCMD : Structure '%s' declared\n", + ps->SourceName,ps->CurrentLine,pst->Name); + + return(pst); +} + + +/* +// StructDestroy +// +// Frees a structure record. +// +// void +*/ +static void StructDestroy( STRUCT *pst ) +{ + if( !pst->pPrev ) + pStructList = pst->pNext; + else + pst->pPrev->pNext = pst->pNext; + + if( pst->pNext ) + pst->pNext->pPrev = pst->pPrev; + + free(pst); +} + + + +/* +// GetRegname +// +// Checks alignment and returns a string of the proper register +// +// Returns 0 on success, -1 on error +*/ +static int GetRegname( SOURCEFILE *ps, uint element, char *str, uint off, uint size ) +{ + if( ((off%4)+size) > 4 ) + { Report(ps,REP_ERROR,"Register alignment error on element %d",element); return(-1); } + + if( !(Options & OPTION_BIGENDIAN) ) + { + /* + // ** Little Endian Version ** + */ + if( size==4 ) + sprintf( str, "R%d", off/4 ); + else if( size==2 ) + sprintf( str, "R%d.w%d", off/4, off%4 ); + else + sprintf( str, "R%d.b%d", off/4, off%4 ); + } + else + { + /* + // ** Big Endian Version ** + */ + if( size==4 ) + sprintf( str, "R%d", off/4 ); + else if( size==2 ) + sprintf( str, "R%d.w%d", off/4, 2-off%4 ); + else + sprintf( str, "R%d.b%d", off/4, 3-off%4 ); + } + + return(0); +} + +/* +// AssignFind +// +// Searches for an assignment record by name. If found, returns the record pointer. +// +// Returns STRUCT * on success, 0 on error +*/ +static ASSIGN *AssignFind( char *Name ) +{ + SCOPE *psc; + ASSIGN *pas; + + psc = pScopeList; + while( psc ) + { + if( psc->Flags&SCOPE_FLG_OPEN ) + { + pas = psc->pAssignList; + while( pas ) + { + if( !strcmp( Name, pas->Name ) ) + return(pas); + pas = pas->pNext; + } + } + psc = psc->pNext; + } + return(0); +} + + +/* +// AssignCreate +// +// Create a new assignment record +// +// Returns STRUCT * on success, 0 on error +*/ +static ASSIGN *AssignCreate( SOURCEFILE *ps, ASSIGN **pList, char *Name ) +{ + ASSIGN *pas; + + /* Make sure this name is OK to use */ + if( !CheckName(ps,Name) ) + return(0); + + /* Make sure the name is not too long */ + if( strlen(Name)>=STRUCT_NAME_LEN ) + { Report(ps,REP_ERROR,"Structure name too long"); return(0); } + + /* Allocate a new record */ + pas = malloc(sizeof(ASSIGN)); + if( !pas ) + { Report(ps,REP_ERROR,"Memory allocation failed"); return(0); } + + strcpy( pas->Name, Name ); + + /* Put this equate in the master list */ + pas->pPrev = 0; + pas->pNext = *pList; + *pList = pas; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + printf("%s(%5d) : DOTCMD : Assignment '%s' declared\n", + ps->SourceName,ps->CurrentLine,pas->Name); + + return(pas); +} + + +/* +// AssignDestroy +// +// Frees an assignment record. +// +// void +*/ +static void AssignDestroy( ASSIGN **pList, ASSIGN *pas ) +{ + if( !pas->pPrev ) + *pList = pas->pNext; + else + pas->pPrev->pNext = pas->pNext; + + if( pas->pNext ) + pas->pNext->pPrev = pas->pPrev; + + free(pas); +} + + +/* +// Struct Name Check +// +// Returns NULL for not match, or replacement string ptr +// +*/ +static char *StructNameCheck( char *source ) +{ + ASSIGN *pas; + char name[STRUCT_NAME_LEN]; + int i,off,more=0; + + for(i=0; iBaseReg); + + off = i+1; + for(i=0; (i+off)Elements; i++ ) + { + if( !strcmp(name,pas->ElemName[i]) ) + return(pas->MappedReg[i]); + } + return(0); +} + + + +/* +// Struct Value Operand +// +// Returns 0 for OK, or -1 for Fatal Error +*/ +static int StructValueOperand( char *source, int CmdType, uint *pValue ) +{ + ASSIGN *pas; + STRUCT *pst; + char name[STRUCT_NAME_LEN]; + char name2[STRUCT_NAME_LEN]; + char *ext = 0; + int i; + + for(i=0; iTotalSize; + else + *pValue = 0; + return(0); + } + + for( i=0; iElements; i++ ) + { + if( !strcmp(name2,pas->ElemName[i]) ) + break; + } + + if( i==pas->Elements ) + return(-1); + + if( CmdType==SVO_SIZEOF ) + { + if(ext) + return( GetFinalSize( ext, pas->Size[i], pValue ) ); + *pValue = pas->Size[i]; + } + else + { + if(ext) + return( GetFinalOffset( ext, pas->Size[i], pas->Offset[i], pValue ) ); + *pValue = pas->Offset[i]; + } + return(0); + } + + pst = StructFind(name); + if( pst ) + { + if( !strlen(name2) ) + { + if( CmdType==SVO_SIZEOF ) + *pValue = pst->TotalSize; + else + *pValue = 0; + return(0); + } + + for( i=0; iElements; i++ ) + { + if( !strcmp(name2,pst->ElemName[i]) ) + break; + } + + if( i==pst->Elements ) + return(-1); + + if( CmdType==SVO_SIZEOF ) + { + if(ext) + return( GetFinalSize( ext, pst->Size[i], pValue ) ); + *pValue = pst->Size[i]; + } + else + { + if(ext) + return( GetFinalOffset( ext, pst->Size[i], pst->Offset[i], pValue ) ); + *pValue = pst->Offset[i]; + } + return(0); + } + + return -1; +} + + +/* +// GetFinalSize - For subfield on struct operand +// +// Returns 0 for OK, or -1 for Fatal Error +*/ +static int GetFinalSize( char *ext, uint Size, uint *pValue ) +{ + char c; + uint val; + + if( strlen(ext) > 2 ) + return -1; + c = toupper(ext[0]); + val = ext[1] - '0'; + switch(c) + { + case 'B': + if( (val+1)>Size ) + return -1; + *pValue = 1; + return(0); + case 'W': + if( (val+2)>Size ) + return -1; + *pValue = 2; + return(0); + } + return(-1); +} + +/* +// GetFinalOffset - For subfield on struct operand +// +// Returns 0 for OK, or -1 for Fatal Error +*/ +static int GetFinalOffset( char *ext, uint Size, uint Offset, uint *pValue ) +{ + char c; + uint val; + + if( strlen(ext) > 2 ) + return -1; + c = toupper(ext[0]); + val = ext[1] - '0'; + switch(c) + { + case 'B': + if( (val+1)>Size ) + return -1; + if( Options & OPTION_BIGENDIAN ) + val = Size-val-1; + *pValue = Offset+val; + return(0); + case 'W': + if( (val+2)>Size ) + return -1; + if( Options & OPTION_BIGENDIAN ) + val = Size-val-2; + *pValue = Offset+val; + return(0); + } + return(-1); +} + + +/* +// ScopeCreate +// +// Create a new scope record +// +// Returns STRUCT * on success, 0 on error +*/ +static SCOPE *ScopeCreate( SOURCEFILE *ps, char *Name ) +{ + SCOPE *psc; + + /* Make sure this name is OK to use */ + if( !CheckName(ps,Name) ) + return(0); + + /* Make sure its not too long */ + if( strlen(Name)>=SCOPE_NAME_LEN ) + { Report(ps,REP_ERROR,"Scope name too long"); return(0); } + + /* Allocate a new record */ + psc = malloc(sizeof(SCOPE)); + if( !psc ) + { Report(ps,REP_ERROR,"Memory allocation failed"); return(0); } + + strcpy( psc->Name, Name ); + psc->Flags = SCOPE_FLG_OPEN; + psc->pParent = pScopeCurrent; + psc->pAssignList = 0; + + /* Put this equate in the master list */ + psc->pPrev = 0; + psc->pNext = pScopeList; + pScopeList = psc; + pScopeCurrent = psc; + + if( Pass==1 && (Options & OPTION_DEBUG) ) + { + if(ps) + printf("%s(%5d) : ",ps->SourceName,ps->CurrentLine); + printf("DOTCMD : Scope '%s' declared\n",psc->Name); + } + + return(psc); +} + + +/* +// ScopeDestroy +// +// Frees a scope record. +// +// void +*/ +static void ScopeDestroy( SCOPE *psc ) +{ + if( psc->Flags & SCOPE_FLG_OPEN ) + ScopeClose( psc ); + + while( psc->pAssignList ) + AssignDestroy( &psc->pAssignList, psc->pAssignList ); + + if( !psc->pPrev ) + pScopeList = psc->pNext; + else + psc->pPrev->pNext = psc->pNext; + + if( psc->pNext ) + psc->pNext->pPrev = psc->pPrev; + + free(psc); +} + + +/* +// ScopeClose +// +// Closes a scope record. +// +// void +*/ +static void ScopeClose( SCOPE *psc ) +{ + psc->Flags &= ~SCOPE_FLG_OPEN; + + while( pScopeCurrent && !(pScopeCurrent->Flags&SCOPE_FLG_OPEN) ) + pScopeCurrent = pScopeCurrent->pParent; +} + + +/* +// ScopeFind +// +// Finds a scope record. +// +// void +*/ +static SCOPE *ScopeFind( char *Name ) +{ + SCOPE *psc; + + psc = pScopeList; + while( psc ) + { + if( !strcmp( Name, psc->Name ) ) + break; + psc = psc->pNext; + } + return(psc); +} + + diff --git a/am335x/pasm/pru_ins.h b/am335x/pasm/pru_ins.h new file mode 100644 index 00000000..f367b792 --- /dev/null +++ b/am335x/pasm/pru_ins.h @@ -0,0 +1,176 @@ +/* + * pru_ins.h + * + * Copyright (C) 2012 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. + * +*/ + +/*=========================================================================== + * Copyright (c) Texas Instruments Inc 2010-12 + * + * Use of this software is controlled by the terms and conditions found in the + * license agreement under which this software has been supplied or provided. + * ============================================================================ + */ + +/*=========================================================================== +// PASM - PRU Assembler +//--------------------------------------------------------------------------- +// +// File : pru_ins.h +// +// Description: +// Defines a data structre PRU_INST that can completely describe a +// PRU opcode. +// +//--------------------------------------------------------------------------- +// Revision: +// 21-Jun-13: 0.84 - Open source version +============================================================================*/ + +typedef struct _PRU_ARG { + uint Type; + uint Flags; /* Flags for RegisterBit type */ +#define PA_FLG_REGPOINTER 0x0001 +#define PA_FLG_POSTINC 0x0002 +#define PA_FLG_PREDEC 0x0004 + uint Value; /* Reg #, Imm Val, Count Val */ + uint Field; /* Field for Registers */ + uint Bit; /* Bit # for RegisterBit type */ +} PRU_ARG; + +#define ARGTYPE_REGISTER 1 /* Standard register and field */ +#define ARGTYPE_IMMEDIATE 2 /* Immediate value */ +#define ARGTYPE_COUNT 3 /* Count for burst */ +#define ARGTYPE_R0BYTE 4 /* Byte from R0 */ +#define ARGTYPE_CONSTANT 5 /* Constant Table Index */ +#define ARGTYPE_OFFSET 6 /* 10 bit offset for jumps */ +#define ARGTYPE_REGISTERBIT 7 /* Register in Rxx.Txx format Field=bitno */ + +#define FIELDTYPE_7_0 0 /* Bits 7:0 */ +#define FIELDTYPE_15_8 1 /* Bits 15:8 */ +#define FIELDTYPE_23_16 2 /* Bits 23:16 */ +#define FIELDTYPE_31_24 3 /* Bits 31:24 */ +#define FIELDTYPE_15_0 4 /* Bits 15:0 */ +#define FIELDTYPE_23_8 5 /* Bits 23:8 */ +#define FIELDTYPE_31_16 6 /* Bits 31:16 */ +#define FIELDTYPE_31_0 7 /* Bits 31:0 */ + +#define FIELDTYPE_OFF_0 0 /* Offset bit 0 */ +#define FIELDTYPE_OFF_8 1 /* Offset bit 8 */ +#define FIELDTYPE_OFF_16 2 /* Offset bit 16 */ +#define FIELDTYPE_OFF_24 3 /* Offset bit 24 */ + +extern char *FieldText[]; + +typedef struct _PRU_INST { + uint Op; /* Operation */ + uint ArgCnt; /* Argument Count */ + PRU_ARG Arg[4]; /* Arguments */ +} PRU_INST; + +#define OP_ADD 1 +#define OP_ADC 2 +#define OP_SUB 3 +#define OP_SUC 4 +#define OP_LSL 5 +#define OP_LSR 6 +#define OP_RSB 7 +#define OP_RSC 8 +#define OP_AND 9 +#define OP_OR 10 +#define OP_XOR 11 +#define OP_NOT 12 +#define OP_MIN 13 +#define OP_MAX 14 +#define OP_CLR 15 +#define OP_SET 16 +#define OP_LDI 17 +#define OP_LBBO 18 +#define OP_LBCO 19 +#define OP_SBBO 20 +#define OP_SBCO 21 +#define OP_LFC 22 +#define OP_STC 23 +#define OP_JAL 24 +#define OP_JMP 25 +#define OP_QBGT 26 +#define OP_QBLT 27 +#define OP_QBEQ 28 +#define OP_QBGE 29 +#define OP_QBLE 30 +#define OP_QBNE 31 +#define OP_QBA 32 +#define OP_QBBS 33 +#define OP_QBBC 34 +#define OP_LMBD 35 +#define OP_CALL 36 +#define OP_WBC 37 +#define OP_WBS 38 +#define OP_MOV 39 +#define OP_MVIB 40 +#define OP_MVIW 41 +#define OP_MVID 42 +#define OP_SCAN 43 +#define OP_HALT 44 +#define OP_SLP 45 +#define OP_RET 46 +#define OP_ZERO 47 +#define OP_FILL 48 +#define OP_XIN 49 +#define OP_XOUT 50 +#define OP_XCHG 51 +#define OP_SXIN 52 +#define OP_SXOUT 53 +#define OP_SXCHG 54 +#define OP_LOOP 55 +#define OP_ILOOP 56 +#define OP_NOP0 57 +#define OP_NOP1 58 +#define OP_NOP2 59 +#define OP_NOP3 60 +#define OP_NOP4 61 +#define OP_NOP5 62 +#define OP_NOP6 63 +#define OP_NOP7 64 +#define OP_NOP8 65 +#define OP_NOP9 66 +#define OP_NOPA 67 +#define OP_NOPB 68 +#define OP_NOPC 69 +#define OP_NOPD 70 +#define OP_NOPE 71 +#define OP_NOPF 72 +#define OP_MAXIDX 72 + +extern char *OpText[]; + diff --git a/bin/.empty b/bin/.empty new file mode 100644 index 00000000..078f480b --- /dev/null +++ b/bin/.empty @@ -0,0 +1 @@ +git: please make this directory diff --git a/debian/mac80211.conf b/debian/mac80211.conf new file mode 100644 index 00000000..3f4f693e --- /dev/null +++ b/debian/mac80211.conf @@ -0,0 +1,2 @@ +# Disable the wifi power management +options mac80211 max_probe_tries=1 probe_wait_ms=500 diff --git a/LEDscape.dts b/dts/LEDscape.dts similarity index 100% rename from LEDscape.dts rename to dts/LEDscape.dts diff --git a/dts/Makefile b/dts/Makefile new file mode 100644 index 00000000..f8abaf8a --- /dev/null +++ b/dts/Makefile @@ -0,0 +1,3 @@ +include ../Makefile.common + +all: firmware diff --git a/dts/README.md b/dts/README.md new file mode 100644 index 00000000..f73001fa --- /dev/null +++ b/dts/README.md @@ -0,0 +1,18 @@ +Generate DTS from DTB: + + dtc \ + -I dtb \ + -O dts \ + -o ubuntu-`uname -r`.dts \ + /boot/uboot/dtbs/am335x-boneblack.dtb + +Enable the PRU. Change status from "disabled" to "okay" + + +Generate DTB back from DTS: + + dtc \ + -O dtb \ + -I dts \ + -o /boot/uboot/dtbs/am335x-boneblack.dtb \ + ubuntu-`uname -r`.dts diff --git a/dts/angstrom.dtb b/dts/angstrom.dtb new file mode 100644 index 00000000..1cc81659 Binary files /dev/null and b/dts/angstrom.dtb differ diff --git a/dts/angstrom.dts b/dts/angstrom.dts new file mode 100644 index 00000000..f3c6f511 --- /dev/null +++ b/dts/angstrom.dts @@ -0,0 +1,1276 @@ +/dts-v1/; + +/ { + #address-cells = <0x1>; + #size-cells = <0x1>; + compatible = "ti,am335x-bone", "ti,am33xx"; + interrupt-parent = <0x1>; + model = "TI AM335x BeagleBone"; + + chosen { + }; + + aliases { + serial0 = "/ocp/serial@44e09000"; + serial1 = "/ocp/serial@48022000"; + serial2 = "/ocp/serial@48024000"; + serial3 = "/ocp/serial@481a6000"; + serial4 = "/ocp/serial@481a8000"; + serial5 = "/ocp/serial@481aa000"; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x10000000>; + }; + + cpus { + + cpu@0 { + compatible = "arm,cortex-a8"; + operating-points = <0xf4240 0x149970 0xc3500 0x13d620 0x927c0 0x10f7c0 0x493e0 0xec928>; + voltage-tolerance = <0x2>; + clock-latency = <0x493e0>; + cpu0-supply = <0x2>; + linux,phandle = <0x11>; + phandle = <0x11>; + }; + }; + + soc { + compatible = "ti,omap-infra"; + + mpu { + compatible = "ti,omap3-mpu"; + ti,hwmods = "mpu"; + }; + }; + + pinmux@44e10800 { + compatible = "pinctrl-single"; + reg = <0x44e10800 0x238>; + #address-cells = <0x1>; + #size-cells = <0x0>; + pinctrl-single,register-width = <0x20>; + pinctrl-single,function-mask = <0x7f>; + pinctrl-names = "default"; + pinctrl-0 = <0x3>; + linux,phandle = <0x12>; + phandle = <0x12>; + + pinmux_userled_pins { + pinctrl-single,pins = <0x54 0x7 0x58 0x17 0x5c 0x7 0x60 0x17>; + linux,phandle = <0x3>; + phandle = <0x3>; + }; + + pinmux_i2c0_pins { + pinctrl-single,pins = <0x188 0x70 0x18c 0x70>; + linux,phandle = <0x6>; + phandle = <0x6>; + }; + + pinmux_i2c2_pins { + pinctrl-single,pins = <0x178 0x73 0x17c 0x73>; + linux,phandle = <0x7>; + phandle = <0x7>; + }; + + pinmux_rstctl_pins { + pinctrl-single,pins = <0x50 0x17>; + linux,phandle = <0x4>; + phandle = <0x4>; + }; + }; + + ocp { + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + ti,hwmods = "l3_main"; + linux,phandle = <0x13>; + phandle = <0x13>; + + interrupt-controller@48200000 { + compatible = "ti,omap2-intc"; + interrupt-controller; + #interrupt-cells = <0x1>; + ti,intc-size = <0x80>; + reg = <0x48200000 0x1000>; + linux,phandle = <0x1>; + phandle = <0x1>; + }; + + edma@49000000 { + compatible = "ti,edma3"; + ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2"; + reg = <0x49000000 0x10000 0x44e10f90 0x40>; + interrupt-parent = <0x1>; + interrupts = <0xc 0xd 0xe>; + #dma-cells = <0x1>; + dma-channels = <0x40>; + ti,edma-regions = <0x4>; + ti,edma-slots = <0x100>; + ti,edma-queue-tc-map = <0x0 0x0 0x1 0x1 0x2 0x2>; + ti,edma-queue-priority-map = <0x0 0x0 0x1 0x1 0x2 0x2>; + ti,edma-default-queue = <0x1>; + ti,edma-xbar-event-map = <0x20 0xc 0x1e 0x14>; + linux,phandle = <0x8>; + phandle = <0x8>; + }; + + gpio@44e07000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio1"; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x1>; + reg = <0x44e07000 0x1000>; + interrupts = <0x60>; + linux,phandle = <0x14>; + phandle = <0x14>; + }; + + gpio@4804c000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio2"; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x1>; + reg = <0x4804c000 0x1000>; + interrupts = <0x62>; + linux,phandle = <0x5>; + phandle = <0x5>; + }; + + gpio@481ac000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio3"; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x1>; + reg = <0x481ac000 0x1000>; + interrupts = <0x20>; + linux,phandle = <0x15>; + phandle = <0x15>; + }; + + gpio@481ae000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio4"; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x1>; + reg = <0x481ae000 0x1000>; + interrupts = <0x3e>; + linux,phandle = <0x16>; + phandle = <0x16>; + }; + + rstctl@0 { + status = "okay"; + compatible = "gpio-rctrl"; + pinctrl-names = "default"; + pinctrl-0 = <0x4>; + #reset-cells = <0x2>; + gpios = <0x5 0x14 0x0>; + gpio-names = "eMMC_RSTn"; + linux,phandle = <0xa>; + phandle = <0xa>; + }; + + serial@44e09000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart1"; + clock-frequency = <0x2dc6c00>; + reg = <0x44e09000 0x2000>; + interrupts = <0x48>; + status = "okay"; + linux,phandle = <0x17>; + phandle = <0x17>; + }; + + serial@48022000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart2"; + clock-frequency = <0x2dc6c00>; + reg = <0x48022000 0x2000>; + interrupts = <0x49>; + status = "disabled"; + linux,phandle = <0x18>; + phandle = <0x18>; + }; + + serial@48024000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart3"; + clock-frequency = <0x2dc6c00>; + reg = <0x48024000 0x2000>; + interrupts = <0x4a>; + status = "disabled"; + linux,phandle = <0x19>; + phandle = <0x19>; + }; + + serial@481a6000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart4"; + clock-frequency = <0x2dc6c00>; + reg = <0x481a6000 0x2000>; + interrupts = <0x2c>; + status = "disabled"; + linux,phandle = <0x1a>; + phandle = <0x1a>; + }; + + serial@481a8000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart5"; + clock-frequency = <0x2dc6c00>; + reg = <0x481a8000 0x2000>; + interrupts = <0x2d>; + status = "disabled"; + linux,phandle = <0x1b>; + phandle = <0x1b>; + }; + + serial@481aa000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart6"; + clock-frequency = <0x2dc6c00>; + reg = <0x481aa000 0x2000>; + interrupts = <0x2e>; + status = "disabled"; + linux,phandle = <0x1c>; + phandle = <0x1c>; + }; + + i2c@44e0b000 { + compatible = "ti,omap4-i2c"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "i2c1"; + reg = <0x44e0b000 0x1000>; + interrupts = <0x46>; + status = "okay"; + clock-frequency = <0x61a80>; + pinctrl-names = "default"; + pinctrl-0 = <0x6>; + linux,phandle = <0x1d>; + phandle = <0x1d>; + + tps@24 { + reg = <0x24>; + compatible = "ti,tps65217"; + ti,pmic-shutdown-controller; + interrupt-parent = <0x1>; + interrupts = <0x7>; + linux,phandle = <0x1e>; + phandle = <0x1e>; + + regulators { + #address-cells = <0x1>; + #size-cells = <0x0>; + + regulator@0 { + reg = <0x0>; + regulator-compatible = "dcdc1"; + regulator-always-on; + linux,phandle = <0x1f>; + phandle = <0x1f>; + }; + + regulator@1 { + reg = <0x1>; + regulator-compatible = "dcdc2"; + regulator-name = "vdd_mpu"; + regulator-min-microvolt = <0xe1d48>; + regulator-max-microvolt = <0x1437c8>; + regulator-boot-on; + regulator-always-on; + linux,phandle = <0x2>; + phandle = <0x2>; + }; + + regulator@2 { + reg = <0x2>; + regulator-compatible = "dcdc3"; + regulator-name = "vdd_core"; + regulator-min-microvolt = <0xe1d48>; + regulator-max-microvolt = <0x118c30>; + regulator-boot-on; + regulator-always-on; + linux,phandle = <0x20>; + phandle = <0x20>; + }; + + regulator@3 { + reg = <0x3>; + regulator-compatible = "ldo1"; + regulator-always-on; + linux,phandle = <0x21>; + phandle = <0x21>; + }; + + regulator@4 { + reg = <0x4>; + regulator-compatible = "ldo2"; + regulator-always-on; + linux,phandle = <0x22>; + phandle = <0x22>; + }; + + regulator@5 { + reg = <0x5>; + regulator-compatible = "ldo3"; + regulator-min-microvolt = <0x1b7740>; + regulator-max-microvolt = <0x1b7740>; + regulator-always-on; + linux,phandle = <0x23>; + phandle = <0x23>; + }; + + regulator@6 { + reg = <0x6>; + regulator-compatible = "ldo4"; + regulator-always-on; + linux,phandle = <0x24>; + phandle = <0x24>; + }; + }; + }; + + baseboard_eeprom@50 { + compatible = "at,24c256"; + reg = <0x50>; + linux,phandle = <0xc>; + phandle = <0xc>; + }; + }; + + i2c@4802a000 { + compatible = "ti,omap4-i2c"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "i2c2"; + reg = <0x4802a000 0x1000>; + interrupts = <0x47>; + status = "disabled"; + linux,phandle = <0x25>; + phandle = <0x25>; + }; + + i2c@4819c000 { + compatible = "ti,omap4-i2c"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "i2c3"; + reg = <0x4819c000 0x1000>; + interrupts = <0x1e>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <0x7>; + clock-frequency = <0x186a0>; + linux,phandle = <0x26>; + phandle = <0x26>; + + cape_eeprom0@54 { + compatible = "at,24c256"; + reg = <0x54>; + linux,phandle = <0xd>; + phandle = <0xd>; + }; + + cape_eeprom1@55 { + compatible = "at,24c256"; + reg = <0x55>; + linux,phandle = <0xe>; + phandle = <0xe>; + }; + + cape_eeprom2@56 { + compatible = "at,24c256"; + reg = <0x56>; + linux,phandle = <0xf>; + phandle = <0xf>; + }; + + cape_eeprom3@57 { + compatible = "at,24c256"; + reg = <0x57>; + linux,phandle = <0x10>; + phandle = <0x10>; + }; + }; + + mmc@48060000 { + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc1"; + ti,dual-volt; + ti,needs-special-reset; + ti,needs-special-hs-handling; + dmas = <0x8 0x18 0x8 0x19>; + dma-names = "tx", "rx"; + status = "okay"; + vmmc-supply = <0x9>; + ti,vcc-aux-disable-is-sleep; + linux,phandle = <0x27>; + phandle = <0x27>; + }; + + mmc@481d8000 { + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc2"; + ti,needs-special-reset; + ti,needs-special-hs-handling; + dmas = <0x8 0x2 0x8 0x3>; + dma-names = "tx", "rx"; + status = "disabled"; + vmmc-supply = <0x9>; + bus-width = <0x8>; + ti,non-removable; + reset = <0xa 0x0 0x0>; + reset-names = "eMMC_RSTn-CONSUMER"; + linux,phandle = <0x28>; + phandle = <0x28>; + }; + + mmc@47810000 { + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc3"; + ti,needs-special-reset; + ti,needs-special-hs-handling; + status = "disabled"; + linux,phandle = <0x29>; + phandle = <0x29>; + }; + + wdt@44e35000 { + compatible = "ti,omap3-wdt"; + ti,hwmods = "wd_timer2"; + reg = <0x44e35000 0x1000>; + interrupts = <0x5b>; + linux,phandle = <0x2a>; + phandle = <0x2a>; + }; + + d_can@481cc000 { + compatible = "bosch,d_can"; + ti,hwmods = "d_can0"; + reg = <0x481cc000 0x2000>; + interrupts = <0x34>; + status = "disabled"; + linux,phandle = <0x2b>; + phandle = <0x2b>; + }; + + d_can@481d0000 { + compatible = "bosch,d_can"; + ti,hwmods = "d_can1"; + reg = <0x481d0000 0x2000>; + interrupts = <0x37>; + status = "disabled"; + linux,phandle = <0x2c>; + phandle = <0x2c>; + }; + + timer@44e31000 { + compatible = "ti,omap2-timer"; + reg = <0x44e31000 0x400>; + interrupts = <0x43>; + ti,hwmods = "timer1"; + ti,timer-alwon; + linux,phandle = <0x2d>; + phandle = <0x2d>; + }; + + timer@48040000 { + compatible = "ti,omap2-timer"; + reg = <0x48040000 0x400>; + interrupts = <0x44>; + ti,hwmods = "timer2"; + linux,phandle = <0x2e>; + phandle = <0x2e>; + }; + + timer@48042000 { + compatible = "ti,omap2-timer"; + reg = <0x48042000 0x400>; + interrupts = <0x45>; + ti,hwmods = "timer3"; + linux,phandle = <0x2f>; + phandle = <0x2f>; + }; + + timer@48044000 { + compatible = "ti,omap2-timer"; + reg = <0x48044000 0x400>; + interrupts = <0x5c>; + ti,hwmods = "timer4"; + ti,timer-pwm; + linux,phandle = <0x30>; + phandle = <0x30>; + }; + + timer@48046000 { + compatible = "ti,omap2-timer"; + reg = <0x48046000 0x400>; + interrupts = <0x5d>; + ti,hwmods = "timer5"; + ti,timer-pwm; + linux,phandle = <0x31>; + phandle = <0x31>; + }; + + timer@48048000 { + compatible = "ti,omap2-timer"; + reg = <0x48048000 0x400>; + interrupts = <0x5e>; + ti,hwmods = "timer6"; + ti,timer-pwm; + linux,phandle = <0x32>; + phandle = <0x32>; + }; + + timer@4804a000 { + compatible = "ti,omap2-timer"; + reg = <0x4804a000 0x400>; + interrupts = <0x5f>; + ti,hwmods = "timer7"; + ti,timer-pwm; + linux,phandle = <0x33>; + phandle = <0x33>; + }; + + pruss@4a300000 { + compatible = "ti,pruss-v2"; + ti,hwmods = "pruss"; + ti,deassert-hard-reset = "pruss", "pruss"; + reg = <0x4a300000 0x80000>; + ti,pintc-offset = <0x20000>; + interrupt-parent = <0x1>; + status = "okay"; + interrupts = <0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b>; + linux,phandle = <0x34>; + phandle = <0x34>; + }; + + rtc@44e3e000 { + compatible = "ti,da830-rtc"; + reg = <0x44e3e000 0x1000>; + interrupts = <0x4b 0x4c>; + ti,hwmods = "rtc"; + ti,system-power-controller; + }; + + spi@48030000 { + compatible = "ti,omap4-mcspi"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0x48030000 0x400>; + interrupt = <0x41>; + ti,spi-num-cs = <0x2>; + ti,hwmods = "spi0"; + dmas = <0x8 0x10 0x8 0x11 0x8 0x12 0x8 0x13>; + dma-names = "tx0", "rx0", "tx1", "rx1"; + status = "disabled"; + linux,phandle = <0x35>; + phandle = <0x35>; + }; + + spi@481a0000 { + compatible = "ti,omap4-mcspi"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0x481a0000 0x400>; + interrupt = <0x7d>; + ti,spi-num-cs = <0x2>; + ti,hwmods = "spi1"; + dmas = <0x8 0x2a 0x8 0x2b 0x8 0x2c 0x8 0x2d>; + dma-names = "tx0", "rx0", "tx1", "rx1"; + status = "disabled"; + linux,phandle = <0x36>; + phandle = <0x36>; + }; + + gpmc@50000000 { + compatible = "ti,am3352-gpmc"; + ti,hwmods = "gpmc"; + reg = <0x50000000 0x1000000>; + interrupts = <0x64>; + gpmc,num-cs = <0x7>; + gpmc,num-waitpins = <0x2>; + #address-cells = <0x2>; + #size-cells = <0x1>; + status = "disabled"; + linux,phandle = <0x37>; + phandle = <0x37>; + }; + + nop-phy@0 { + compatible = "nop-xceiv-usb"; + }; + + nop-phy@1 { + compatible = "nop-xceiv-usb"; + }; + + usb@47400000 { + compatible = "ti,musb-am33xx"; + reg = <0x47400000 0x1000 0x47401000 0x800 0x47401800 0x800>; + interrupts = <0x11 0x12 0x13>; + multipoint = <0x1>; + num-eps = <0x10>; + ram-bits = <0xc>; + port0-mode = <0x3>; + port1-mode = <0x1>; + power = <0xfa>; + ti,hwmods = "usb_otg_hs"; + status = "okay"; + interface_type = <0x1>; + linux,phandle = <0x38>; + phandle = <0x38>; + }; + + ethernet@4a100000 { + compatible = "ti,cpsw"; + ti,hwmods = "cpgmac0"; + cpdma_channels = <0x8>; + ale_entries = <0x400>; + bd_ram_size = <0x2000>; + no_bd_ram = <0x0>; + rx_descs = <0x40>; + mac_control = <0x20>; + slaves = <0x2>; + cpts_active_slave = <0x0>; + cpts_clock_mult = <0x80000000>; + cpts_clock_shift = <0x1d>; + reg = <0x4a100000 0x800 0x4a101200 0x100>; + #address-cells = <0x1>; + #size-cells = <0x1>; + interrupt-parent = <0x1>; + interrupts = <0x28 0x29 0x2a 0x2b>; + ranges; + disable-napi; + linux,phandle = <0x39>; + phandle = <0x39>; + + mdio@4a101000 { + compatible = "ti,davinci_mdio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "davinci_mdio"; + bus_freq = <0xf4240>; + reg = <0x4a101000 0x100>; + linux,phandle = <0xb>; + phandle = <0xb>; + }; + + slave@4a100200 { + mac-address = [00 00 00 00 00 00]; + phy_id = <0xb 0x0>; + linux,phandle = <0x3a>; + phandle = <0x3a>; + }; + + slave@4a100300 { + mac-address = [00 00 00 00 00 00]; + phy_id = <0xb 0x1>; + linux,phandle = <0x3b>; + phandle = <0x3b>; + }; + }; + + tscadc@44e0d000 { + compatible = "ti,ti-tscadc"; + reg = <0x44e0d000 0x1000>; + interrupt-parent = <0x1>; + interrupts = <0x10>; + ti,hwmods = "adc_tsc"; + status = "disabled"; + linux,phandle = <0x3c>; + phandle = <0x3c>; + }; + + lcdc@4830e000 { + compatible = "ti,am3352-lcdc", "ti,da830-lcdc"; + reg = <0x4830e000 0x1000>; + interrupts = <0x24>; + status = "disabled"; + ti,hwmods = "lcdc"; + linux,phandle = <0x3d>; + phandle = <0x3d>; + }; + + epwmss@48300000 { + compatible = "ti,am33xx-pwmss"; + reg = <0x48300000 0x10>; + ti,hwmods = "epwmss0"; + #address-cells = <0x1>; + #size-cells = <0x1>; + status = "disabled"; + ranges = <0x48300100 0x48300100 0x80 0x48300180 0x48300180 0x80 0x48300200 0x48300200 0x80>; + linux,phandle = <0x3e>; + phandle = <0x3e>; + + ecap@48300100 { + compatible = "ti,am33xx-ecap"; + #pwm-cells = <0x3>; + reg = <0x48300100 0x80>; + ti,hwmods = "ecap0"; + status = "disabled"; + linux,phandle = <0x3f>; + phandle = <0x3f>; + }; + + ehrpwm@48300200 { + compatible = "ti,am33xx-ehrpwm"; + #pwm-cells = <0x3>; + reg = <0x48300200 0x80>; + ti,hwmods = "ehrpwm0"; + status = "disabled"; + linux,phandle = <0x40>; + phandle = <0x40>; + }; + }; + + epwmss@48302000 { + compatible = "ti,am33xx-pwmss"; + reg = <0x48302000 0x10>; + ti,hwmods = "epwmss1"; + #address-cells = <0x1>; + #size-cells = <0x1>; + status = "disabled"; + ranges = <0x48302100 0x48302100 0x80 0x48302180 0x48302180 0x80 0x48302200 0x48302200 0x80>; + linux,phandle = <0x41>; + phandle = <0x41>; + + ecap@48302100 { + compatible = "ti,am33xx-ecap"; + #pwm-cells = <0x3>; + reg = <0x48302100 0x80>; + ti,hwmods = "ecap1"; + status = "disabled"; + linux,phandle = <0x42>; + phandle = <0x42>; + }; + + ehrpwm@48302200 { + compatible = "ti,am33xx-ehrpwm"; + #pwm-cells = <0x3>; + reg = <0x48302200 0x80>; + ti,hwmods = "ehrpwm1"; + status = "disabled"; + linux,phandle = <0x43>; + phandle = <0x43>; + }; + }; + + epwmss@48304000 { + compatible = "ti,am33xx-pwmss"; + reg = <0x48304000 0x10>; + ti,hwmods = "epwmss2"; + #address-cells = <0x1>; + #size-cells = <0x1>; + status = "disabled"; + ranges = <0x48304100 0x48304100 0x80 0x48304180 0x48304180 0x80 0x48304200 0x48304200 0x80>; + linux,phandle = <0x44>; + phandle = <0x44>; + + ecap@48304100 { + compatible = "ti,am33xx-ecap"; + #pwm-cells = <0x3>; + reg = <0x48304100 0x80>; + ti,hwmods = "ecap2"; + status = "disabled"; + linux,phandle = <0x45>; + phandle = <0x45>; + }; + + ehrpwm@48304200 { + compatible = "ti,am33xx-ehrpwm"; + #pwm-cells = <0x3>; + reg = <0x48304200 0x80>; + ti,hwmods = "ehrpwm2"; + status = "disabled"; + linux,phandle = <0x46>; + phandle = <0x46>; + }; + }; + + sham@53100000 { + compatible = "ti,omap4-sham"; + ti,hwmods = "sham"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0x53100000 0x200>; + interrupt-parent = <0x1>; + interrupts = <0x6d>; + dmas = <0x8 0x24>; + dma-names = "rx"; + status = "okay"; + linux,phandle = <0x47>; + phandle = <0x47>; + }; + + aes@53500000 { + compatible = "ti,omap4-aes"; + ti,hwmods = "aes"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0x53500000 0xa0>; + interrupt-parent = <0x1>; + interrupts = <0x66>; + dmas = <0x8 0x6 0x8 0x5>; + dma-names = "tx", "rx"; + status = "okay"; + linux,phandle = <0x48>; + phandle = <0x48>; + }; + + mcasp@48038000 { + compatible = "ti,omap2-mcasp-audio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "mcasp0"; + reg = <0x48038000 0x2000>; + interrupts = <0x50 0x51>; + status = "disabled"; + asp-chan-q = <0x2>; + tx-dma-offset = <0x46000000>; + rx-dma-offset = <0x46000000>; + dmas = <0x8 0x8 0x8 0x9>; + dma-names = "tx", "rx"; + linux,phandle = <0x49>; + phandle = <0x49>; + }; + + mcasp@4803C000 { + compatible = "ti,omap2-mcasp-audio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "mcasp1"; + reg = <0x4803c000 0x2000>; + interrupts = <0x52 0x53>; + status = "disabled"; + asp-chan-q = <0x2>; + tx-dma-offset = <0x46400000>; + rx-dma-offset = <0x46400000>; + dmas = <0x8 0xa 0x8 0xb>; + dma-names = "tx", "rx"; + linux,phandle = <0x4a>; + phandle = <0x4a>; + }; + + gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <0x3>; + + led0 { + label = "beaglebone:green:usr0"; + gpios = <0x5 0x15 0x0>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led1 { + label = "beaglebone:green:usr1"; + gpios = <0x5 0x16 0x0>; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; + + led2 { + label = "beaglebone:green:usr2"; + gpios = <0x5 0x17 0x0>; + linux,default-trigger = "cpu0"; + default-state = "off"; + }; + + led3 { + label = "beaglebone:green:usr3"; + gpios = <0x5 0x18 0x0>; + default-state = "off"; + linux,default-trigger = "mmc1"; + }; + }; + }; + + bone_capemgr { + compatible = "ti,bone-capemgr"; + status = "okay"; + eeprom = <0xc>; + + baseboardmaps { + + board@0 { + board-name = "A335BONE"; + compatible-name = "ti,beaglebone"; + linux,phandle = <0x4b>; + phandle = <0x4b>; + }; + + board@1 { + board-name = "A335BNLT"; + compatible-name = "ti,beaglebone-black"; + linux,phandle = <0x4c>; + phandle = <0x4c>; + }; + }; + + slots { + + slot@0 { + eeprom = <0xd>; + }; + + slot@1 { + eeprom = <0xe>; + }; + + slot@2 { + eeprom = <0xf>; + }; + + slot@3 { + eeprom = <0x10>; + }; + + slot@5 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-Geiger"; + version = "00A0"; + manufacturer = "Geiger Inc."; + part-number = "BB-BONE-GEIGER"; + }; + + slot@7 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-Nixie"; + version = "00A0"; + manufacturer = "Ranostay Industries"; + part-number = "BB-BONE-NIXIE"; + }; + + slot@8 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-TFT"; + version = "00A0"; + manufacturer = "Adafruit"; + part-number = "BB-BONE-TFT-01"; + }; + + slot@9 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-RTC"; + version = "00A0"; + manufacturer = "Adafruit"; + part-number = "BB-BONE-RTC-01"; + }; + + slot@10 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-Hexy"; + version = "00A0"; + manufacturer = "Koen Kooi"; + part-number = "BB-BONE-HEXY-01"; + }; + + slot@11 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-MRF24J40"; + version = "00A0"; + manufacturer = "Signal 11 Software"; + part-number = "BB-BONE-MRF24J40"; + }; + + slot@12 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "BB-BONE-RS232"; + version = "00A0"; + manufacturer = "Adafruit"; + part-number = "BB-BONE-RS232-01"; + }; + + slot@100 { + ti,cape-override; + priority = <0x1>; + compatible = "ti,beaglebone-black"; + board-name = "Bone-LT-eMMC-2G"; + version = "00A0"; + manufacturer = "Texas Instruments"; + part-number = "BB-BONE-EMMC-2G"; + }; + + slot@101 { + ti,cape-override; + priority = <0x1>; + compatible = "ti,beaglebone-black"; + board-name = "Bone-Black-HDMI"; + version = "00A0"; + manufacturer = "Texas Instruments"; + part-number = "BB-BONELT-HDMI"; + }; + + slot@102 { + ti,cape-override; + priority = <0x2>; + compatible = "ti,beaglebone-black"; + board-name = "Bone-Black-HDMIN"; + version = "00A0"; + manufacturer = "Texas Instruments"; + part-number = "BB-BONELT-HDMIN"; + }; + }; + + capemaps { + + cape@0 { + part-number = "BB-BONE-DVID-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-dvi-00A0.dtbo"; + }; + + version@00A1 { + version = "00A1", "01"; + dtbo = "cape-bone-dvi-00A1.dtbo"; + }; + + version@00A2 { + version = "00A2", "A2"; + dtbo = "cape-bone-dvi-00A2.dtbo"; + }; + + version@00A3 { + version = "00A3"; + dtbo = "cape-bone-dvi-00A2.dtbo"; + }; + }; + + cape@1 { + part-number = "BB-BONE-EMMC-2G"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-2g-emmc1.dtbo"; + }; + }; + + cape@2 { + part-number = "BB-BONE-GEIGER"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-geiger-00A0.dtbo"; + }; + }; + + cape@3 { + part-number = "BB-BONE-LCD3-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-lcd3-00A0.dtbo"; + }; + + version@00A2 { + version = "00A2"; + dtbo = "cape-bone-lcd3-00A2.dtbo"; + }; + }; + + cape@4 { + part-number = "BB-BONE-WTHR-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-weather-00A0.dtbo"; + }; + }; + + cape@5 { + part-number = "BB-BONELT-HDMI"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-boneblack-hdmi-00A0.dtbo"; + }; + }; + + cape@6 { + part-number = "BB-BONE-NIXIE"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-nixie-00A0.dtbo"; + }; + }; + + cape@7 { + part-number = "BB-BONE-TFT-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-adafruit-lcd-00A0.dtbo"; + }; + }; + + cape@8 { + part-number = "BB-BONE-RTC-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-adafruit-rtc-00A0.dtbo"; + }; + }; + + cape@9 { + part-number = "BB-BONE-HEXY-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-hexy-00A0.dtbo"; + }; + }; + + cape@10 { + part-number = "BB-BONE-MRF24J40"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-mrf24j40-00A0.dtbo"; + }; + }; + + cape@11 { + part-number = "BB-BONE-EXPTEST"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-exptest-00A0.dtbo"; + }; + }; + + cape@12 { + part-number = "BB-BONE-RS232-01"; + + version@00A0 { + version = "00A0"; + dtbo = "BB-BONE-RS232-00A0.dtbo"; + }; + }; + + cape@13 { + part-number = "BB-BONELT-HDMIN"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-boneblack-hdmin-00A0.dtbo"; + }; + }; + }; + }; + + fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "vmmcsd_fixed"; + regulator-min-microvolt = <0x325aa0>; + regulator-max-microvolt = <0x325aa0>; + linux,phandle = <0x9>; + phandle = <0x9>; + }; + + __symbols__ { + cpu = "/cpus/cpu@0"; + am33xx_pinmux = "/pinmux@44e10800"; + userled_pins = "/pinmux@44e10800/pinmux_userled_pins"; + i2c0_pins = "/pinmux@44e10800/pinmux_i2c0_pins"; + i2c2_pins = "/pinmux@44e10800/pinmux_i2c2_pins"; + rstctl_pins = "/pinmux@44e10800/pinmux_rstctl_pins"; + ocp = "/ocp"; + intc = "/ocp/interrupt-controller@48200000"; + edma = "/ocp/edma@49000000"; + gpio1 = "/ocp/gpio@44e07000"; + gpio2 = "/ocp/gpio@4804c000"; + gpio3 = "/ocp/gpio@481ac000"; + gpio4 = "/ocp/gpio@481ae000"; + rstctl = "/ocp/rstctl@0"; + uart1 = "/ocp/serial@44e09000"; + uart2 = "/ocp/serial@48022000"; + uart3 = "/ocp/serial@48024000"; + uart4 = "/ocp/serial@481a6000"; + uart5 = "/ocp/serial@481a8000"; + uart6 = "/ocp/serial@481aa000"; + i2c0 = "/ocp/i2c@44e0b000"; + tps = "/ocp/i2c@44e0b000/tps@24"; + dcdc1_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@0"; + dcdc2_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@1"; + dcdc3_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@2"; + ldo1_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@3"; + ldo2_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@4"; + ldo3_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@5"; + ldo4_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@6"; + baseboard_eeprom = "/ocp/i2c@44e0b000/baseboard_eeprom@50"; + i2c1 = "/ocp/i2c@4802a000"; + i2c2 = "/ocp/i2c@4819c000"; + cape_eeprom0 = "/ocp/i2c@4819c000/cape_eeprom0@54"; + cape_eeprom1 = "/ocp/i2c@4819c000/cape_eeprom1@55"; + cape_eeprom2 = "/ocp/i2c@4819c000/cape_eeprom2@56"; + cape_eeprom3 = "/ocp/i2c@4819c000/cape_eeprom3@57"; + mmc1 = "/ocp/mmc@48060000"; + mmc2 = "/ocp/mmc@481d8000"; + mmc3 = "/ocp/mmc@47810000"; + wdt2 = "/ocp/wdt@44e35000"; + dcan0 = "/ocp/d_can@481cc000"; + dcan1 = "/ocp/d_can@481d0000"; + timer1 = "/ocp/timer@44e31000"; + timer2 = "/ocp/timer@48040000"; + timer3 = "/ocp/timer@48042000"; + timer4 = "/ocp/timer@48044000"; + timer5 = "/ocp/timer@48046000"; + timer6 = "/ocp/timer@48048000"; + timer7 = "/ocp/timer@4804a000"; + pruss = "/ocp/pruss@4a300000"; + spi0 = "/ocp/spi@48030000"; + spi1 = "/ocp/spi@481a0000"; + gpmc = "/ocp/gpmc@50000000"; + usb_otg_hs = "/ocp/usb@47400000"; + mac = "/ocp/ethernet@4a100000"; + davinci_mdio = "/ocp/ethernet@4a100000/mdio@4a101000"; + cpsw_emac0 = "/ocp/ethernet@4a100000/slave@4a100200"; + cpsw_emac1 = "/ocp/ethernet@4a100000/slave@4a100300"; + tscadc = "/ocp/tscadc@44e0d000"; + lcdc = "/ocp/lcdc@4830e000"; + epwmss0 = "/ocp/epwmss@48300000"; + ecap0 = "/ocp/epwmss@48300000/ecap@48300100"; + ehrpwm0 = "/ocp/epwmss@48300000/ehrpwm@48300200"; + epwmss1 = "/ocp/epwmss@48302000"; + ecap1 = "/ocp/epwmss@48302000/ecap@48302100"; + ehrpwm1 = "/ocp/epwmss@48302000/ehrpwm@48302200"; + epwmss2 = "/ocp/epwmss@48304000"; + ecap2 = "/ocp/epwmss@48304000/ecap@48304100"; + ehrpwm2 = "/ocp/epwmss@48304000/ehrpwm@48304200"; + sham = "/ocp/sham@53100000"; + aes = "/ocp/aes@53500000"; + mcasp0 = "/ocp/mcasp@48038000"; + mcasp1 = "/ocp/mcasp@4803C000"; + baseboard_beaglebone = "/bone_capemgr/baseboardmaps/board@0"; + baseboard_beaglebone_black = "/bone_capemgr/baseboardmaps/board@1"; + vmmcsd_fixed = "/fixedregulator@0"; + }; +}; diff --git a/dts/cape-bone-octo.dts b/dts/cape-bone-octo.dts new file mode 100644 index 00000000..9074163a --- /dev/null +++ b/dts/cape-bone-octo.dts @@ -0,0 +1,134 @@ +/* +* pru dts file BB-BONE-PRU-00A0.dts +* + +*/ +/dts-v1/; +/plugin/; + +/ { + compatible = "ti,beaglebone", "ti,beaglebone-black"; + + /* identification */ + part-number = "BB-BONE-OCTO"; + version = "00A0"; + + exclusive-use = + "P9.12", "P9.16", + + "P8.7", "P8.8", "P8.9", "P8.10", "P8.11", "P8.12", "P8.13", + "P8.14", "P8.15", "P8.16", + + "P8.26", + + "pruss", + "ehrpwm1B"; + + fragment@0 { + target = <&am33xx_pinmux>; + __overlay__ { + mygpio: pinmux_mygpio { + pinctrl-single,pins = < + // p9.11-18 + 0x078 0x7 + 0x04c 0x7 // P9.16 could be PWM for output enable + + // p8.7-19 + 0x090 0x7 + 0x094 0x7 + 0x09c 0x7 + 0x098 0x7 + 0x034 0x7 + 0x030 0x7 + 0x024 0x7 + 0x028 0x7 + 0x03c 0x7 + 0x038 0x7 + + // p8.26-46 + 0x07c 0x7 + >; + }; + }; + }; + + fragment@1 { + target = <&ocp>; + __overlay__ { + test_helper: helper { + compatible = "bone-pinmux-helper"; + pinctrl-names = "default"; + pinctrl-0 = <&mygpio>; + status = "okay"; + }; + }; + }; + + fragment@2{ + target = <&pruss>; + __overlay__ { + status = "okay"; + }; + }; + +/* + // import of am335x_pwm-00A0.dts + // but pru can't write to pwm? + + fragment@3 { + target = <&epwmss0>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@4 { + target = <&ehrpwm0>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@5 { + target = <&ecap0>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@6 { + target = <&epwmss1>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@7 { + target = <&ehrpwm1>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@8 { + target = <&epwmss2>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@9 { + target = <&ehrpwm2>; + __overlay__ { + status = "okay"; + }; + }; + + fragment@10 { + target = <&ecap2>; + __overlay__ { + status = "okay"; + }; + }; +*/ +}; diff --git a/dts/gpio.dts b/dts/gpio.dts new file mode 100644 index 00000000..cd3899a8 --- /dev/null +++ b/dts/gpio.dts @@ -0,0 +1,95 @@ +/dts-v1/; +/plugin/; + +/{ + compatible = "ti,beaglebone", "ti,beaglebone-black"; + board-name = "CustomizeThis"; + part-number = "CustomizeThis"; + version = "00A0"; + + exclusive-use = + "P8.45" /* gpio2_6 */, + "P8.46" /* gpio2_7 */, + "P8.43" /* gpio2_8 */, + "P8.44" /* gpio2_9 */, + "P8.41" /* gpio2_10 */, + "P8.42" /* gpio2_11 */, + "P8.39" /* gpio2_12 */, + "P8.40" /* gpio2_13 */, + "P8.37" /* gpio2_14 */, + "P8.38" /* gpio2_15 */, + "P8.36" /* gpio2_16 */, + "P8.34" /* gpio2_17 */, + "P8.27" /* gpio2_22 */, + "P8.29" /* gpio2_23 */, + "P8.28" /* gpio2_24 */, + "P8.30" /* gpio2_25 */, + "P8.35" /* gpio0_8 */, + "P8.33" /* gpio0_9 */, + "P8.31" /* gpio0_10 */, + "P8.32" /* gpio0_11 */, + "gpio2_6", + "gpio2_7", + "gpio2_8", + "gpio2_9", + "gpio2_10", + "gpio2_11", + "gpio2_12", + "gpio2_13", + "gpio2_14", + "gpio2_15", + "gpio2_16", + "gpio2_17", + "gpio2_22", + "gpio2_23", + "gpio2_24", + "gpio2_25", + "gpio0_8", + "gpio0_9", + "gpio0_10", + "gpio0_11"; + + fragment@0 { + target = <&am33xx_pinmux>; + + __overlay__ { + pinctrl_generated: RNS_Generated_Pins { + pinctrl-single,pins = < + 0x0a0 0x37 /* P8_45 40 GPIO 70 in Mode: 7 */ + 0x0a4 0x37 /* P8_46 41 GPIO 71 in Mode: 7 */ + 0x0a8 0x37 /* P8_43 42 GPIO 72 in Mode: 7 */ + 0x0ac 0x37 /* P8_44 43 GPIO 73 in Mode: 7 */ + 0x0b0 0x37 /* P8_41 44 GPIO 74 in Mode: 7 */ + 0x0b4 0x37 /* P8_42 45 GPIO 75 in Mode: 7 */ + 0x0b8 0x37 /* P8_39 46 GPIO 76 in Mode: 7 */ + 0x0bc 0x37 /* P8_40 47 GPIO 77 in Mode: 7 */ + 0x0c0 0x37 /* P8_37 48 GPIO 78 in Mode: 7 */ + 0x0c4 0x37 /* P8_38 49 GPIO 79 in Mode: 7 */ + 0x0c8 0x37 /* P8_36 50 GPIO 80 in Mode: 7 */ + 0x0cc 0x37 /* P8_34 51 GPIO 81 in Mode: 7 */ + 0x0e0 0x37 /* P8_27 56 GPIO 86 in Mode: 7 */ + 0x0e4 0x37 /* P8_29 57 GPIO 87 in Mode: 7 */ + 0x0e8 0x37 /* P8_28 58 GPIO 88 in Mode: 7 */ + 0x0ec 0x37 /* P8_30 59 GPIO 89 in Mode: 7 */ + 0x0d0 0x37 /* P8_35 52 GPIO 8 in Mode: 7 */ + 0x0d4 0x37 /* P8_33 53 GPIO 9 in Mode: 7 */ + 0x0d8 0x37 /* P8_31 54 GPIO 10 in Mode: 7 */ + 0x0dc 0x37 /* P8_32 55 GPIO 11 in Mode: 7 */ + >; + }; + }; + }; + + fragment@1 { + target = <&ocp>; + __overlay__ { + test_helper: helper { + compatible = "bone-pinmux-helper"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_generated>; + status = "okay"; + }; + }; + }; +}; + diff --git a/dts/ubuntu-3.8.13-bone32.dts b/dts/ubuntu-3.8.13-bone32.dts new file mode 100644 index 00000000..921da884 --- /dev/null +++ b/dts/ubuntu-3.8.13-bone32.dts @@ -0,0 +1,1324 @@ +/dts-v1/; + +/ { + #address-cells = <0x1>; + #size-cells = <0x1>; + compatible = "ti,am335x-bone", "ti,am33xx"; + interrupt-parent = <0x1>; + model = "TI AM335x BeagleBone"; + + chosen { + }; + + aliases { + serial0 = "/ocp/serial@44e09000"; + serial1 = "/ocp/serial@48022000"; + serial2 = "/ocp/serial@48024000"; + serial3 = "/ocp/serial@481a6000"; + serial4 = "/ocp/serial@481a8000"; + serial5 = "/ocp/serial@481aa000"; + }; + + memory { + device_type = "memory"; + reg = <0x80000000 0x10000000>; + }; + + cpus { + + cpu@0 { + compatible = "arm,cortex-a8"; + operating-points = <0xf4240 0x149970 0xc3500 0x13d620 0x927c0 0x10f7c0 0x493e0 0xec928>; + voltage-tolerance = <0x2>; + clock-latency = <0x493e0>; + cpu0-supply = <0x2>; + linux,phandle = <0x13>; + phandle = <0x13>; + }; + }; + + pmu { + compatible = "arm,cortex-a8-pmu"; + interrupts = <0x3>; + }; + + soc { + compatible = "ti,omap-infra"; + + mpu { + compatible = "ti,omap3-mpu"; + ti,hwmods = "mpu"; + }; + }; + + pinmux@44e10800 { + compatible = "pinctrl-single"; + reg = <0x44e10800 0x238>; + #address-cells = <0x1>; + #size-cells = <0x0>; + pinctrl-single,register-width = <0x20>; + pinctrl-single,function-mask = <0x7f>; + pinctrl-names = "default"; + pinctrl-0 = <0x3>; + linux,phandle = <0x14>; + phandle = <0x14>; + + pinmux_userled_pins { + pinctrl-single,pins = <0x54 0x7 0x58 0x17 0x5c 0x7 0x60 0x17>; + linux,phandle = <0x3>; + phandle = <0x3>; + }; + + pinmux_i2c0_pins { + pinctrl-single,pins = <0x188 0x70 0x18c 0x70>; + linux,phandle = <0x6>; + phandle = <0x6>; + }; + + pinmux_i2c2_pins { + pinctrl-single,pins = <0x178 0x73 0x17c 0x73>; + linux,phandle = <0x7>; + phandle = <0x7>; + }; + + pinmux_mmc1_pins { + pinctrl-single,pins = <0x160 0x2f>; + linux,phandle = <0x9>; + phandle = <0x9>; + }; + + pinmux_rstctl_pins { + pinctrl-single,pins = <0x50 0x17>; + linux,phandle = <0x4>; + phandle = <0x4>; + }; + }; + + ocp { + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + ti,hwmods = "l3_main"; + linux,phandle = <0x15>; + phandle = <0x15>; + + interrupt-controller@48200000 { + compatible = "ti,omap2-intc"; + interrupt-controller; + #interrupt-cells = <0x1>; + ti,intc-size = <0x80>; + reg = <0x48200000 0x1000>; + linux,phandle = <0x1>; + phandle = <0x1>; + }; + + edma@49000000 { + compatible = "ti,edma3"; + ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2"; + reg = <0x49000000 0x10000 0x44e10f90 0x40>; + interrupt-parent = <0x1>; + interrupts = <0xc 0xd 0xe>; + #dma-cells = <0x1>; + dma-channels = <0x40>; + ti,edma-regions = <0x4>; + ti,edma-slots = <0x100>; + ti,edma-queue-tc-map = <0x0 0x0 0x1 0x1 0x2 0x2>; + ti,edma-queue-priority-map = <0x0 0x0 0x1 0x1 0x2 0x2>; + ti,edma-default-queue = <0x1>; + ti,edma-xbar-event-map = <0x20 0xc 0x1e 0x14>; + linux,phandle = <0x8>; + phandle = <0x8>; + }; + + gpio@44e07000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio1"; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x1>; + reg = <0x44e07000 0x1000>; + interrupts = <0x60>; + linux,phandle = <0xa>; + phandle = <0xa>; + }; + + gpio@4804c000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio2"; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x1>; + reg = <0x4804c000 0x1000>; + interrupts = <0x62>; + linux,phandle = <0x5>; + phandle = <0x5>; + }; + + gpio@481ac000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio3"; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x1>; + reg = <0x481ac000 0x1000>; + interrupts = <0x20>; + linux,phandle = <0x16>; + phandle = <0x16>; + }; + + gpio@481ae000 { + compatible = "ti,omap4-gpio"; + ti,hwmods = "gpio4"; + gpio-controller; + #gpio-cells = <0x2>; + interrupt-controller; + #interrupt-cells = <0x1>; + reg = <0x481ae000 0x1000>; + interrupts = <0x3e>; + linux,phandle = <0x17>; + phandle = <0x17>; + }; + + rstctl@0 { + status = "okay"; + compatible = "gpio-rctrl"; + pinctrl-names = "default"; + pinctrl-0 = <0x4>; + #reset-cells = <0x2>; + gpios = <0x5 0x14 0x0>; + gpio-names = "eMMC_RSTn"; + linux,phandle = <0xc>; + phandle = <0xc>; + }; + + serial@44e09000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart1"; + clock-frequency = <0x2dc6c00>; + reg = <0x44e09000 0x2000>; + interrupts = <0x48>; + status = "okay"; + linux,phandle = <0x18>; + phandle = <0x18>; + }; + + serial@48022000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart2"; + clock-frequency = <0x2dc6c00>; + reg = <0x48022000 0x2000>; + interrupts = <0x49>; + status = "disabled"; + linux,phandle = <0x19>; + phandle = <0x19>; + }; + + serial@48024000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart3"; + clock-frequency = <0x2dc6c00>; + reg = <0x48024000 0x2000>; + interrupts = <0x4a>; + status = "disabled"; + linux,phandle = <0x1a>; + phandle = <0x1a>; + }; + + serial@481a6000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart4"; + clock-frequency = <0x2dc6c00>; + reg = <0x481a6000 0x2000>; + interrupts = <0x2c>; + status = "disabled"; + linux,phandle = <0x1b>; + phandle = <0x1b>; + }; + + serial@481a8000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart5"; + clock-frequency = <0x2dc6c00>; + reg = <0x481a8000 0x2000>; + interrupts = <0x2d>; + status = "disabled"; + linux,phandle = <0x1c>; + phandle = <0x1c>; + }; + + serial@481aa000 { + compatible = "ti,omap3-uart"; + ti,hwmods = "uart6"; + clock-frequency = <0x2dc6c00>; + reg = <0x481aa000 0x2000>; + interrupts = <0x2e>; + status = "disabled"; + linux,phandle = <0x1d>; + phandle = <0x1d>; + }; + + i2c@44e0b000 { + compatible = "ti,omap4-i2c"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "i2c1"; + reg = <0x44e0b000 0x1000>; + interrupts = <0x46>; + status = "okay"; + clock-frequency = <0x61a80>; + pinctrl-names = "default"; + pinctrl-0 = <0x6>; + linux,phandle = <0x1e>; + phandle = <0x1e>; + + tps@24 { + reg = <0x24>; + compatible = "ti,tps65217"; + ti,pmic-shutdown-controller; + interrupt-parent = <0x1>; + interrupts = <0x7>; + linux,phandle = <0x1f>; + phandle = <0x1f>; + + regulators { + #address-cells = <0x1>; + #size-cells = <0x0>; + + regulator@0 { + reg = <0x0>; + regulator-compatible = "dcdc1"; + regulator-always-on; + linux,phandle = <0x20>; + phandle = <0x20>; + }; + + regulator@1 { + reg = <0x1>; + regulator-compatible = "dcdc2"; + regulator-name = "vdd_mpu"; + regulator-min-microvolt = <0xe1d48>; + regulator-max-microvolt = <0x1437c8>; + regulator-boot-on; + regulator-always-on; + linux,phandle = <0x2>; + phandle = <0x2>; + }; + + regulator@2 { + reg = <0x2>; + regulator-compatible = "dcdc3"; + regulator-name = "vdd_core"; + regulator-min-microvolt = <0xe1d48>; + regulator-max-microvolt = <0x118c30>; + regulator-boot-on; + regulator-always-on; + linux,phandle = <0x21>; + phandle = <0x21>; + }; + + regulator@3 { + reg = <0x3>; + regulator-compatible = "ldo1"; + regulator-always-on; + linux,phandle = <0x22>; + phandle = <0x22>; + }; + + regulator@4 { + reg = <0x4>; + regulator-compatible = "ldo2"; + regulator-always-on; + linux,phandle = <0x23>; + phandle = <0x23>; + }; + + regulator@5 { + reg = <0x5>; + regulator-compatible = "ldo3"; + regulator-min-microvolt = <0x1b7740>; + regulator-max-microvolt = <0x1b7740>; + regulator-always-on; + linux,phandle = <0x24>; + phandle = <0x24>; + }; + + regulator@6 { + reg = <0x6>; + regulator-compatible = "ldo4"; + regulator-always-on; + linux,phandle = <0x25>; + phandle = <0x25>; + }; + }; + }; + + baseboard_eeprom@50 { + compatible = "at,24c256"; + reg = <0x50>; + linux,phandle = <0xe>; + phandle = <0xe>; + }; + }; + + i2c@4802a000 { + compatible = "ti,omap4-i2c"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "i2c2"; + reg = <0x4802a000 0x1000>; + interrupts = <0x47>; + status = "disabled"; + linux,phandle = <0x26>; + phandle = <0x26>; + }; + + i2c@4819c000 { + compatible = "ti,omap4-i2c"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "i2c3"; + reg = <0x4819c000 0x1000>; + interrupts = <0x1e>; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <0x7>; + clock-frequency = <0x186a0>; + linux,phandle = <0x27>; + phandle = <0x27>; + + cape_eeprom0@54 { + compatible = "at,24c256"; + reg = <0x54>; + linux,phandle = <0xf>; + phandle = <0xf>; + }; + + cape_eeprom1@55 { + compatible = "at,24c256"; + reg = <0x55>; + linux,phandle = <0x10>; + phandle = <0x10>; + }; + + cape_eeprom2@56 { + compatible = "at,24c256"; + reg = <0x56>; + linux,phandle = <0x11>; + phandle = <0x11>; + }; + + cape_eeprom3@57 { + compatible = "at,24c256"; + reg = <0x57>; + linux,phandle = <0x12>; + phandle = <0x12>; + }; + }; + + mmc@48060000 { + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc1"; + ti,dual-volt; + ti,needs-special-reset; + ti,needs-special-hs-handling; + dmas = <0x8 0x18 0x8 0x19>; + dma-names = "tx", "rx"; + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <0x9>; + bus-width = <0x4>; + cd-gpios = <0xa 0x6 0x0>; + cd-inverted; + vmmc-supply = <0xb>; + ti,vcc-aux-disable-is-sleep; + linux,phandle = <0x28>; + phandle = <0x28>; + }; + + mmc@481d8000 { + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc2"; + ti,needs-special-reset; + ti,needs-special-hs-handling; + dmas = <0x8 0x2 0x8 0x3>; + dma-names = "tx", "rx"; + status = "disabled"; + vmmc-supply = <0xb>; + bus-width = <0x8>; + ti,non-removable; + reset = <0xc 0x0 0x0>; + reset-names = "eMMC_RSTn-CONSUMER"; + linux,phandle = <0x29>; + phandle = <0x29>; + }; + + mmc@47810000 { + compatible = "ti,omap3-hsmmc"; + ti,hwmods = "mmc3"; + ti,needs-special-reset; + ti,needs-special-hs-handling; + status = "disabled"; + linux,phandle = <0x2a>; + phandle = <0x2a>; + }; + + wdt@44e35000 { + compatible = "ti,omap3-wdt"; + ti,hwmods = "wd_timer2"; + reg = <0x44e35000 0x1000>; + interrupts = <0x5b>; + linux,phandle = <0x2b>; + phandle = <0x2b>; + }; + + d_can@481cc000 { + compatible = "bosch,d_can"; + ti,hwmods = "d_can0"; + reg = <0x481cc000 0x2000>; + interrupts = <0x34>; + status = "disabled"; + linux,phandle = <0x2c>; + phandle = <0x2c>; + }; + + d_can@481d0000 { + compatible = "bosch,d_can"; + ti,hwmods = "d_can1"; + reg = <0x481d0000 0x2000>; + interrupts = <0x37>; + status = "disabled"; + linux,phandle = <0x2d>; + phandle = <0x2d>; + }; + + timer@44e31000 { + compatible = "ti,omap2-timer"; + reg = <0x44e31000 0x400>; + interrupts = <0x43>; + ti,hwmods = "timer1"; + ti,timer-alwon; + linux,phandle = <0x2e>; + phandle = <0x2e>; + }; + + timer@48040000 { + compatible = "ti,omap2-timer"; + reg = <0x48040000 0x400>; + interrupts = <0x44>; + ti,hwmods = "timer2"; + linux,phandle = <0x2f>; + phandle = <0x2f>; + }; + + timer@48042000 { + compatible = "ti,omap2-timer"; + reg = <0x48042000 0x400>; + interrupts = <0x45>; + ti,hwmods = "timer3"; + linux,phandle = <0x30>; + phandle = <0x30>; + }; + + timer@48044000 { + compatible = "ti,omap2-timer"; + reg = <0x48044000 0x400>; + interrupts = <0x5c>; + ti,hwmods = "timer4"; + ti,timer-pwm; + linux,phandle = <0x31>; + phandle = <0x31>; + }; + + timer@48046000 { + compatible = "ti,omap2-timer"; + reg = <0x48046000 0x400>; + interrupts = <0x5d>; + ti,hwmods = "timer5"; + ti,timer-pwm; + linux,phandle = <0x32>; + phandle = <0x32>; + }; + + timer@48048000 { + compatible = "ti,omap2-timer"; + reg = <0x48048000 0x400>; + interrupts = <0x5e>; + ti,hwmods = "timer6"; + ti,timer-pwm; + linux,phandle = <0x33>; + phandle = <0x33>; + }; + + timer@4804a000 { + compatible = "ti,omap2-timer"; + reg = <0x4804a000 0x400>; + interrupts = <0x5f>; + ti,hwmods = "timer7"; + ti,timer-pwm; + linux,phandle = <0x34>; + phandle = <0x34>; + }; + + pruss@4a300000 { + compatible = "ti,pruss-v2"; + ti,hwmods = "pruss"; + ti,deassert-hard-reset = "pruss", "pruss"; + reg = <0x4a300000 0x80000>; + ti,pintc-offset = <0x20000>; + interrupt-parent = <0x1>; + status = "okay"; + interrupts = <0x14 0x15 0x16 0x17 0x18 0x19 0x1a 0x1b>; + linux,phandle = <0x35>; + phandle = <0x35>; + }; + + rtc@44e3e000 { + compatible = "ti,da830-rtc"; + reg = <0x44e3e000 0x1000>; + interrupts = <0x4b 0x4c>; + ti,hwmods = "rtc"; + ti,system-power-controller; + }; + + spi@48030000 { + compatible = "ti,omap4-mcspi"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0x48030000 0x400>; + interrupt = <0x41>; + ti,spi-num-cs = <0x2>; + ti,hwmods = "spi0"; + dmas = <0x8 0x10 0x8 0x11 0x8 0x12 0x8 0x13>; + dma-names = "tx0", "rx0", "tx1", "rx1"; + status = "disabled"; + linux,phandle = <0x36>; + phandle = <0x36>; + }; + + spi@481a0000 { + compatible = "ti,omap4-mcspi"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0x481a0000 0x400>; + interrupt = <0x7d>; + ti,spi-num-cs = <0x2>; + ti,hwmods = "spi1"; + dmas = <0x8 0x2a 0x8 0x2b 0x8 0x2c 0x8 0x2d>; + dma-names = "tx0", "rx0", "tx1", "rx1"; + status = "disabled"; + linux,phandle = <0x37>; + phandle = <0x37>; + }; + + gpmc@50000000 { + compatible = "ti,am3352-gpmc"; + ti,hwmods = "gpmc"; + reg = <0x50000000 0x1000000>; + interrupts = <0x64>; + gpmc,num-cs = <0x7>; + gpmc,num-waitpins = <0x2>; + #address-cells = <0x2>; + #size-cells = <0x1>; + status = "disabled"; + linux,phandle = <0x38>; + phandle = <0x38>; + }; + + nop-phy@0 { + compatible = "nop-xceiv-usb"; + }; + + nop-phy@1 { + compatible = "nop-xceiv-usb"; + }; + + usb@47400000 { + compatible = "ti,musb-am33xx"; + reg = <0x47400000 0x1000 0x47401000 0x800 0x47401800 0x800>; + interrupts = <0x11 0x12 0x13>; + multipoint = <0x1>; + num-eps = <0x10>; + ram-bits = <0xc>; + port0-mode = <0x3>; + port1-mode = <0x1>; + power = <0xfa>; + ti,hwmods = "usb_otg_hs"; + status = "okay"; + interface_type = <0x1>; + linux,phandle = <0x39>; + phandle = <0x39>; + }; + + ethernet@4a100000 { + compatible = "ti,cpsw"; + ti,hwmods = "cpgmac0"; + cpdma_channels = <0x8>; + ale_entries = <0x400>; + bd_ram_size = <0x2000>; + no_bd_ram = <0x0>; + rx_descs = <0x40>; + mac_control = <0x20>; + slaves = <0x2>; + cpts_active_slave = <0x0>; + cpts_clock_mult = <0x80000000>; + cpts_clock_shift = <0x1d>; + reg = <0x4a100000 0x800 0x4a101200 0x100>; + #address-cells = <0x1>; + #size-cells = <0x1>; + interrupt-parent = <0x1>; + interrupts = <0x28 0x29 0x2a 0x2b>; + ranges; + disable-napi; + linux,phandle = <0x3a>; + phandle = <0x3a>; + + mdio@4a101000 { + compatible = "ti,davinci_mdio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "davinci_mdio"; + bus_freq = <0xf4240>; + reg = <0x4a101000 0x100>; + linux,phandle = <0xd>; + phandle = <0xd>; + }; + + slave@4a100200 { + mac-address = [00 00 00 00 00 00]; + phy_id = <0xd 0x0>; + linux,phandle = <0x3b>; + phandle = <0x3b>; + }; + + slave@4a100300 { + mac-address = [00 00 00 00 00 00]; + phy_id = <0xd 0x1>; + linux,phandle = <0x3c>; + phandle = <0x3c>; + }; + }; + + tscadc@44e0d000 { + compatible = "ti,ti-tscadc"; + reg = <0x44e0d000 0x1000>; + interrupt-parent = <0x1>; + interrupts = <0x10>; + ti,hwmods = "adc_tsc"; + status = "disabled"; + linux,phandle = <0x3d>; + phandle = <0x3d>; + }; + + lcdc@4830e000 { + compatible = "ti,am3352-lcdc", "ti,da830-lcdc"; + reg = <0x4830e000 0x1000>; + interrupts = <0x24>; + status = "disabled"; + ti,hwmods = "lcdc"; + linux,phandle = <0x3e>; + phandle = <0x3e>; + }; + + epwmss@48300000 { + compatible = "ti,am33xx-pwmss"; + reg = <0x48300000 0x10>; + ti,hwmods = "epwmss0"; + #address-cells = <0x1>; + #size-cells = <0x1>; + status = "disabled"; + ranges = <0x48300100 0x48300100 0x80 0x48300180 0x48300180 0x80 0x48300200 0x48300200 0x80>; + linux,phandle = <0x3f>; + phandle = <0x3f>; + + ecap@48300100 { + compatible = "ti,am33xx-ecap"; + #pwm-cells = <0x3>; + reg = <0x48300100 0x80>; + ti,hwmods = "ecap0"; + status = "disabled"; + linux,phandle = <0x40>; + phandle = <0x40>; + }; + + ehrpwm@48300200 { + compatible = "ti,am33xx-ehrpwm"; + #pwm-cells = <0x3>; + reg = <0x48300200 0x80>; + ti,hwmods = "ehrpwm0"; + status = "disabled"; + linux,phandle = <0x41>; + phandle = <0x41>; + }; + }; + + epwmss@48302000 { + compatible = "ti,am33xx-pwmss"; + reg = <0x48302000 0x10>; + ti,hwmods = "epwmss1"; + #address-cells = <0x1>; + #size-cells = <0x1>; + status = "disabled"; + ranges = <0x48302100 0x48302100 0x80 0x48302180 0x48302180 0x80 0x48302200 0x48302200 0x80>; + linux,phandle = <0x42>; + phandle = <0x42>; + + ecap@48302100 { + compatible = "ti,am33xx-ecap"; + #pwm-cells = <0x3>; + reg = <0x48302100 0x80>; + ti,hwmods = "ecap1"; + status = "disabled"; + linux,phandle = <0x43>; + phandle = <0x43>; + }; + + ehrpwm@48302200 { + compatible = "ti,am33xx-ehrpwm"; + #pwm-cells = <0x3>; + reg = <0x48302200 0x80>; + ti,hwmods = "ehrpwm1"; + status = "disabled"; + linux,phandle = <0x44>; + phandle = <0x44>; + }; + }; + + epwmss@48304000 { + compatible = "ti,am33xx-pwmss"; + reg = <0x48304000 0x10>; + ti,hwmods = "epwmss2"; + #address-cells = <0x1>; + #size-cells = <0x1>; + status = "disabled"; + ranges = <0x48304100 0x48304100 0x80 0x48304180 0x48304180 0x80 0x48304200 0x48304200 0x80>; + linux,phandle = <0x45>; + phandle = <0x45>; + + ecap@48304100 { + compatible = "ti,am33xx-ecap"; + #pwm-cells = <0x3>; + reg = <0x48304100 0x80>; + ti,hwmods = "ecap2"; + status = "disabled"; + linux,phandle = <0x46>; + phandle = <0x46>; + }; + + ehrpwm@48304200 { + compatible = "ti,am33xx-ehrpwm"; + #pwm-cells = <0x3>; + reg = <0x48304200 0x80>; + ti,hwmods = "ehrpwm2"; + status = "disabled"; + linux,phandle = <0x47>; + phandle = <0x47>; + }; + }; + + sham@53100000 { + compatible = "ti,omap4-sham"; + ti,hwmods = "sham"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0x53100000 0x200>; + interrupt-parent = <0x1>; + interrupts = <0x6d>; + dmas = <0x8 0x24>; + dma-names = "rx"; + status = "okay"; + linux,phandle = <0x48>; + phandle = <0x48>; + }; + + aes@53500000 { + compatible = "ti,omap4-aes"; + ti,hwmods = "aes"; + #address-cells = <0x1>; + #size-cells = <0x0>; + reg = <0x53500000 0xa0>; + interrupt-parent = <0x1>; + interrupts = <0x66>; + dmas = <0x8 0x6 0x8 0x5>; + dma-names = "tx", "rx"; + status = "okay"; + linux,phandle = <0x49>; + phandle = <0x49>; + }; + + mcasp@48038000 { + compatible = "ti,omap2-mcasp-audio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "mcasp0"; + reg = <0x48038000 0x2000>; + interrupts = <0x50 0x51>; + status = "disabled"; + asp-chan-q = <0x2>; + tx-dma-offset = <0x46000000>; + rx-dma-offset = <0x46000000>; + dmas = <0x8 0x8 0x8 0x9>; + dma-names = "tx", "rx"; + linux,phandle = <0x4a>; + phandle = <0x4a>; + }; + + mcasp@4803C000 { + compatible = "ti,omap2-mcasp-audio"; + #address-cells = <0x1>; + #size-cells = <0x0>; + ti,hwmods = "mcasp1"; + reg = <0x4803c000 0x2000>; + interrupts = <0x52 0x53>; + status = "disabled"; + asp-chan-q = <0x2>; + tx-dma-offset = <0x46400000>; + rx-dma-offset = <0x46400000>; + dmas = <0x8 0xa 0x8 0xb>; + dma-names = "tx", "rx"; + linux,phandle = <0x4b>; + phandle = <0x4b>; + }; + + bandgap@44e10448 { + compatible = "ti,am335x-bandgap"; + reg = <0x44e10448 0x8>; + }; + + gpio-leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <0x3>; + + led0 { + label = "beaglebone:green:usr0"; + gpios = <0x5 0x15 0x0>; + linux,default-trigger = "heartbeat"; + default-state = "off"; + }; + + led1 { + label = "beaglebone:green:usr1"; + gpios = <0x5 0x16 0x0>; + linux,default-trigger = "mmc0"; + default-state = "off"; + }; + + led2 { + label = "beaglebone:green:usr2"; + gpios = <0x5 0x17 0x0>; + linux,default-trigger = "cpu0"; + default-state = "off"; + }; + + led3 { + label = "beaglebone:green:usr3"; + gpios = <0x5 0x18 0x0>; + default-state = "off"; + linux,default-trigger = "mmc1"; + }; + }; + }; + + bone_capemgr { + compatible = "ti,bone-capemgr"; + status = "okay"; + eeprom = <0xe>; + + baseboardmaps { + + board@0 { + board-name = "A335BONE"; + compatible-name = "ti,beaglebone"; + linux,phandle = <0x4c>; + phandle = <0x4c>; + }; + + board@1 { + board-name = "A335BNLT"; + compatible-name = "ti,beaglebone-black"; + linux,phandle = <0x4d>; + phandle = <0x4d>; + }; + }; + + slots { + + slot@0 { + eeprom = <0xf>; + }; + + slot@1 { + eeprom = <0x10>; + }; + + slot@2 { + eeprom = <0x11>; + }; + + slot@3 { + eeprom = <0x12>; + }; + + slot@5 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-Geiger"; + version = "00A0"; + manufacturer = "Geiger Inc."; + part-number = "BB-BONE-GEIGER"; + }; + + slot@7 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-Nixie"; + version = "00A0"; + manufacturer = "Ranostay Industries"; + part-number = "BB-BONE-NIXIE"; + }; + + slot@8 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-TFT"; + version = "00A0"; + manufacturer = "Adafruit"; + part-number = "BB-BONE-TFT-01"; + }; + + slot@9 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-RTC"; + version = "00A0"; + manufacturer = "Adafruit"; + part-number = "BB-BONE-RTC-01"; + }; + + slot@10 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-Hexy"; + version = "00A0"; + manufacturer = "Koen Kooi"; + part-number = "BB-BONE-HEXY-01"; + }; + + slot@11 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "Bone-MRF24J40"; + version = "00A0"; + manufacturer = "Signal 11 Software"; + part-number = "BB-BONE-MRF24J40"; + }; + + slot@12 { + ti,cape-override; + compatible = "kernel-command-line", "runtime"; + board-name = "BB-BONE-RS232"; + version = "00A0"; + manufacturer = "Adafruit"; + part-number = "BB-BONE-RS232-01"; + }; + + slot@13 { + compatible = "kernel-command-line", "runtime"; + board-name = "BB-BONE-GPS"; + version = "00A0"; + manufacturer = "Adafruit"; + part-number = "BB-BONE-GPS-01"; + }; + + slot@100 { + ti,cape-override; + priority = <0x1>; + compatible = "ti,beaglebone-black"; + board-name = "Bone-LT-eMMC-2G"; + version = "00A0"; + manufacturer = "Texas Instruments"; + part-number = "BB-BONE-EMMC-2G"; + }; + + slot@101 { + ti,cape-override; + priority = <0x1>; + compatible = "ti,beaglebone-black"; + board-name = "Bone-Black-HDMI"; + version = "00A0"; + manufacturer = "Texas Instruments"; + part-number = "BB-BONELT-HDMI"; + }; + + slot@102 { + ti,cape-override; + priority = <0x2>; + compatible = "ti,beaglebone-black"; + board-name = "Bone-Black-HDMIN"; + version = "00A0"; + manufacturer = "Texas Instruments"; + part-number = "BB-BONELT-HDMIN"; + }; + }; + + capemaps { + + cape@0 { + part-number = "BB-BONE-DVID-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-dvi-00A0.dtbo"; + }; + + version@00A1 { + version = "00A1", "01"; + dtbo = "cape-bone-dvi-00A1.dtbo"; + }; + + version@00A2 { + version = "00A2", "A2"; + dtbo = "cape-bone-dvi-00A2.dtbo"; + }; + + version@00A3 { + version = "00A3"; + dtbo = "cape-bone-dvi-00A2.dtbo"; + }; + }; + + cape@1 { + part-number = "BB-BONE-EMMC-2G"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-2g-emmc1.dtbo"; + }; + }; + + cape@2 { + part-number = "BB-BONE-GEIGER"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-geiger-00A0.dtbo"; + }; + }; + + cape@3 { + part-number = "BB-BONE-LCD3-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-lcd3-00A0.dtbo"; + }; + + version@00A2 { + version = "00A2"; + dtbo = "cape-bone-lcd3-00A2.dtbo"; + }; + }; + + cape@4 { + part-number = "BB-BONE-WTHR-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-weather-00A0.dtbo"; + }; + }; + + cape@5 { + part-number = "BB-BONELT-HDMI"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-boneblack-hdmi-00A0.dtbo"; + }; + }; + + cape@6 { + part-number = "BB-BONE-NIXIE"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-nixie-00A0.dtbo"; + }; + }; + + cape@7 { + part-number = "BB-BONE-TFT-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-adafruit-lcd-00A0.dtbo"; + }; + }; + + cape@8 { + part-number = "BB-BONE-RTC-01"; + + version@00A0 { + version = "00A0"; + dtbo = "BB-BONE-RTC-00A0.dtbo"; + }; + }; + + cape@9 { + part-number = "BB-BONE-HEXY-01"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-hexy-00A0.dtbo"; + }; + }; + + cape@10 { + part-number = "BB-BONE-MRF24J40"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-mrf24j40-00A0.dtbo"; + }; + }; + + cape@11 { + part-number = "BB-BONE-EXPTEST"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-bone-exptest-00A0.dtbo"; + }; + }; + + cape@12 { + part-number = "BB-BONE-RS232-01"; + + version@00A0 { + version = "00A0"; + dtbo = "BB-BONE-RS232-00A0.dtbo"; + }; + }; + + cape@13 { + part-number = "BB-BONE-GPS-01"; + + version@00A0 { + version = "00A0"; + dtbo = "BB-BONE-GPS-00A0.dtbo"; + }; + }; + + cape@14 { + part-number = "BB-BONELT-HDMIN"; + + version@00A0 { + version = "00A0"; + dtbo = "cape-boneblack-hdmin-00A0.dtbo"; + }; + }; + + cape@15 { + part-number = "2191"; + + version@R2 { + version = "R2"; + dtbo = "cape-bebopr-R2.dtbo"; + }; + }; + }; + }; + + fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "vmmcsd_fixed"; + regulator-min-microvolt = <0x325aa0>; + regulator-max-microvolt = <0x325aa0>; + linux,phandle = <0xb>; + phandle = <0xb>; + }; + + __symbols__ { + cpu = "/cpus/cpu@0"; + am33xx_pinmux = "/pinmux@44e10800"; + userled_pins = "/pinmux@44e10800/pinmux_userled_pins"; + i2c0_pins = "/pinmux@44e10800/pinmux_i2c0_pins"; + i2c2_pins = "/pinmux@44e10800/pinmux_i2c2_pins"; + mmc1_pins = "/pinmux@44e10800/pinmux_mmc1_pins"; + rstctl_pins = "/pinmux@44e10800/pinmux_rstctl_pins"; + ocp = "/ocp"; + intc = "/ocp/interrupt-controller@48200000"; + edma = "/ocp/edma@49000000"; + gpio1 = "/ocp/gpio@44e07000"; + gpio2 = "/ocp/gpio@4804c000"; + gpio3 = "/ocp/gpio@481ac000"; + gpio4 = "/ocp/gpio@481ae000"; + rstctl = "/ocp/rstctl@0"; + uart1 = "/ocp/serial@44e09000"; + uart2 = "/ocp/serial@48022000"; + uart3 = "/ocp/serial@48024000"; + uart4 = "/ocp/serial@481a6000"; + uart5 = "/ocp/serial@481a8000"; + uart6 = "/ocp/serial@481aa000"; + i2c0 = "/ocp/i2c@44e0b000"; + tps = "/ocp/i2c@44e0b000/tps@24"; + dcdc1_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@0"; + dcdc2_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@1"; + dcdc3_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@2"; + ldo1_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@3"; + ldo2_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@4"; + ldo3_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@5"; + ldo4_reg = "/ocp/i2c@44e0b000/tps@24/regulators/regulator@6"; + baseboard_eeprom = "/ocp/i2c@44e0b000/baseboard_eeprom@50"; + i2c1 = "/ocp/i2c@4802a000"; + i2c2 = "/ocp/i2c@4819c000"; + cape_eeprom0 = "/ocp/i2c@4819c000/cape_eeprom0@54"; + cape_eeprom1 = "/ocp/i2c@4819c000/cape_eeprom1@55"; + cape_eeprom2 = "/ocp/i2c@4819c000/cape_eeprom2@56"; + cape_eeprom3 = "/ocp/i2c@4819c000/cape_eeprom3@57"; + mmc1 = "/ocp/mmc@48060000"; + mmc2 = "/ocp/mmc@481d8000"; + mmc3 = "/ocp/mmc@47810000"; + wdt2 = "/ocp/wdt@44e35000"; + dcan0 = "/ocp/d_can@481cc000"; + dcan1 = "/ocp/d_can@481d0000"; + timer1 = "/ocp/timer@44e31000"; + timer2 = "/ocp/timer@48040000"; + timer3 = "/ocp/timer@48042000"; + timer4 = "/ocp/timer@48044000"; + timer5 = "/ocp/timer@48046000"; + timer6 = "/ocp/timer@48048000"; + timer7 = "/ocp/timer@4804a000"; + pruss = "/ocp/pruss@4a300000"; + spi0 = "/ocp/spi@48030000"; + spi1 = "/ocp/spi@481a0000"; + gpmc = "/ocp/gpmc@50000000"; + usb_otg_hs = "/ocp/usb@47400000"; + mac = "/ocp/ethernet@4a100000"; + davinci_mdio = "/ocp/ethernet@4a100000/mdio@4a101000"; + cpsw_emac0 = "/ocp/ethernet@4a100000/slave@4a100200"; + cpsw_emac1 = "/ocp/ethernet@4a100000/slave@4a100300"; + tscadc = "/ocp/tscadc@44e0d000"; + lcdc = "/ocp/lcdc@4830e000"; + epwmss0 = "/ocp/epwmss@48300000"; + ecap0 = "/ocp/epwmss@48300000/ecap@48300100"; + ehrpwm0 = "/ocp/epwmss@48300000/ehrpwm@48300200"; + epwmss1 = "/ocp/epwmss@48302000"; + ecap1 = "/ocp/epwmss@48302000/ecap@48302100"; + ehrpwm1 = "/ocp/epwmss@48302000/ehrpwm@48302200"; + epwmss2 = "/ocp/epwmss@48304000"; + ecap2 = "/ocp/epwmss@48304000/ecap@48304100"; + ehrpwm2 = "/ocp/epwmss@48304000/ehrpwm@48304200"; + sham = "/ocp/sham@53100000"; + aes = "/ocp/aes@53500000"; + mcasp0 = "/ocp/mcasp@48038000"; + mcasp1 = "/ocp/mcasp@4803C000"; + baseboard_beaglebone = "/bone_capemgr/baseboardmaps/board@0"; + baseboard_beaglebone_black = "/bone_capemgr/baseboardmaps/board@1"; + vmmcsd_fixed = "/fixedregulator@0"; + }; +}; diff --git a/fonts/json2bmp b/fonts/json2bmp new file mode 100755 index 00000000..a20e7fe0 --- /dev/null +++ b/fonts/json2bmp @@ -0,0 +1,35 @@ +#!/usr/bin/perl +use warnings; +use strict; + +local $/; +local $_ = <>; + +print <<""; +/** \file + * Generated font from json file output by + * http://www.pentacom.jp/pentacom/bitfontmaker2/ + */ +const uint16_t font[][16] = { + +while (m/"(\d+)":\[([\d,]+)\]/msgx) +{ + my $ord = $1; + my @bits = split /,/, $2; + + my $c = chr($ord); + $c = '\\\\' if $c eq '\\'; + printf "['%s'] = {\n", $c; + + for (@bits) + { + printf "\t0x%04x,\n", $_; + } + + print "},\n"; +} + +print <<""; +}; + +__END__ diff --git a/fonts/mta-sign.json b/fonts/mta-sign.json new file mode 100644 index 00000000..bc0c5a3f --- /dev/null +++ b/fonts/mta-sign.json @@ -0,0 +1,77 @@ +{"33":[1920,8160,16368,31992,31864,64764,64764,64764,31992,31992,16368,8160,1920,0,0,0], +"35":[1920,8160,16368,30840,29496,62460,63740,62460,29496,30840,16368,8160,1920,0,0,0], +"36":[1920,8160,16368,31224,30968,63868,63932,61500,31224,31224,16368,8160,1920,0,0,0], +"37":[1920,8160,16368,28728,32568,65340,61500,62460,29496,30840,16368,8160,1920,0,0,0], +"42":[256,896,1984,3168,6960,16184,31804,14648,6448,3168,1984,896,256,0,0,0], +"44":[0,0,0,0,0,0,0,0,0,0,12,12,4,6,0,0], +"45":[0,0,0,0,0,0,0,124,0,0,0,0,0,0,0,0], +"46":[0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0], +"47":[0,0,0,504,496,480,496,440,284,12,0,0,0,0,0,0], +"48":[0,120,204,204,204,204,204,204,204,204,204,120,0,0,0,0], +"49":[0,224,240,216,204,192,192,192,192,192,192,192,0,0,0,0], +"50":[0,120,252,204,192,192,96,112,56,28,252,252,0,0,0,0], +"51":[0,120,252,204,192,112,112,192,192,204,252,120,0,0,0,0], +"52":[0,128,192,224,240,216,204,252,252,192,192,192,0,0,0,0], +"53":[0,252,252,12,12,124,252,192,192,192,252,124,0,0,0,0], +"54":[0,120,252,204,12,124,252,204,204,204,252,120,0,0,0,0], +"55":[0,252,252,192,96,96,48,48,24,24,12,12,0,0,0,0], +"56":[0,120,252,204,204,120,120,204,204,204,252,120,0,0,0,0], +"57":[0,120,252,204,204,204,252,248,192,204,252,120,0,0,0,0], +"58":[0,0,0,0,24,24,0,0,0,0,24,24,0,0,0,0], +"60":[0,0,0,32,48,1016,1020,1016,48,32,0,0,0,0,0,0], +"62":[0,0,0,64,192,508,1020,508,192,64,0,0,0,0,0,0], +"64":[1920,8160,16368,30840,29496,62460,63996,64764,32376,28728,16368,8160,1920,0,0,0], +"65":[0,224,224,224,432,432,432,792,1016,1016,1548,1548,0,0,0,0], +"66":[0,124,252,204,204,124,124,204,204,204,252,124,0,0,0,0], +"67":[0,240,504,920,268,12,12,12,268,920,504,240,0,0,0,0], +"68":[0,124,252,460,396,396,396,396,396,460,252,124,0,0,0,0], +"69":[0,508,508,12,12,508,508,12,12,12,508,508,0,0,0,0], +"70":[0,252,252,12,12,124,124,12,12,12,12,12,0,0,0,0], +"71":[0,240,504,920,268,12,12,972,972,408,504,240,0,0,0,0], +"72":[0,396,396,396,396,508,508,396,396,396,396,396,0,0,0,0], +"73":[0,252,252,48,48,48,48,48,48,48,252,252,0,0,0,0], +"76":[0,12,12,12,12,12,12,12,12,12,1020,1020,0,0,0,0], +"77":[0,1548,1820,1980,2044,1772,1612,1548,1548,1548,1548,1548,0,0,0,1], +"78":[0,396,412,444,508,492,460,396,396,396,396,396,0,0,0,0], +"79":[0,240,504,408,780,780,780,780,780,408,504,240,0,0,0,0], +"80":[0,124,252,204,204,252,124,12,12,12,12,12,0,0,0,0], +"81":[0,248,508,396,396,396,396,396,428,204,508,888,512,0,0,1], +"82":[0,252,508,396,396,508,252,204,396,396,396,396,0,0,0,0], +"83":[0,248,508,396,396,60,248,448,396,396,508,248,0,0,0,0], +"84":[0,1020,1020,96,96,96,96,96,96,96,96,96,0,0,0,0], +"85":[0,792,792,792,792,792,792,792,792,792,1016,496,0,0,0,0], +"86":[0,1548,1548,792,792,792,432,432,432,224,224,224,0,0,0,0], +"87":[0,780,780,780,780,780,780,876,1020,1020,924,780,0,0,0,0], +"88":[0,780,780,408,408,240,96,240,408,408,780,780,0,0,0,1], +"89":[0,780,780,408,408,240,240,96,96,96,96,96,0,0,0,1], +"90":[0,508,508,192,96,96,48,48,24,24,508,508,0,0,0,1], +"92":[0,0,0,252,124,60,124,236,452,384,0,0,0,0,0,0], +"94":[1920,8160,16368,30840,32568,65340,63548,62268,29496,30840,16368,8160,1920,0,0,0], +"97":[0,0,0,0,120,252,204,240,252,204,252,216,0,0,0,0], +"98":[0,12,12,12,124,252,204,204,204,204,252,124,0,0,0,0], +"99":[0,0,0,0,112,248,204,12,12,204,248,112,0,0,0,0], +"100":[0,192,192,192,248,252,204,204,204,204,252,248,0,0,0,0], +"101":[0,0,0,0,120,252,204,252,12,204,252,120,0,0,0,0], +"102":[0,48,56,24,60,60,24,24,24,24,24,24,0,0,0,0], +"103":[0,0,0,0,216,252,204,204,204,204,252,216,192,204,120,0], +"104":[0,12,12,12,108,252,204,204,204,204,204,204,0,0,0,0], +"105":[0,24,24,0,24,24,24,24,24,24,60,60,0,0,0,0], +"107":[0,12,12,12,204,108,60,124,108,108,204,204,0,0,0,0], +"108":[0,12,12,12,12,12,12,12,12,12,12,12,0,0,0,0], +"109":[0,0,0,0,1916,4092,3276,3276,3276,3276,3276,3276,0,0,0,0], +"110":[0,0,0,0,124,252,204,204,204,204,204,204,0,0,0,0], +"111":[0,0,0,0,120,252,204,204,204,204,252,120,0,0,0,0], +"112":[0,0,0,0,60,124,108,108,108,108,124,60,12,12,12,0], +"113":[0,0,0,0,248,252,204,204,204,204,252,248,192,192,192,0], +"114":[0,0,0,0,56,124,12,12,12,12,12,12,0,0,0,0], +"115":[0,0,0,0,120,252,12,124,248,192,252,124,0,0,0,0], +"116":[0,24,24,60,60,24,24,24,24,24,56,56,0,0,0,0], +"117":[0,0,0,0,204,204,204,204,204,204,252,248,0,0,0,0], +"118":[0,0,0,0,780,780,780,408,504,240,96,96,0,0,0,0], +"119":[0,0,0,0,6156,6156,6604,6604,2920,3960,3640,3640,0,0,0,0], +"120":[0,0,0,0,396,396,216,112,112,216,396,396,0,0,0,0], +"121":[0,0,0,0,780,780,408,408,240,240,96,96,120,56,0,0], +"122":[0,0,0,0,252,252,224,112,56,28,252,252,0,0,0,0], +"name":"MTA", +"copy":"TrammellHudson", +"letterspace":"64"} diff --git a/fonts/nycr.png b/fonts/nycr.png new file mode 100644 index 00000000..e05a91cf Binary files /dev/null and b/fonts/nycr.png differ diff --git a/fonts/pf_tempesta_seven.ttf b/fonts/pf_tempesta_seven.ttf new file mode 100644 index 00000000..1a85a620 Binary files /dev/null and b/fonts/pf_tempesta_seven.ttf differ diff --git a/fonts/spincycle.ttf b/fonts/spincycle.ttf new file mode 100644 index 00000000..7f6de674 Binary files /dev/null and b/fonts/spincycle.ttf differ diff --git a/lib/.empty b/lib/.empty new file mode 100644 index 00000000..e69de29b diff --git a/obj/.empty b/obj/.empty new file mode 100644 index 00000000..e69de29b diff --git a/pcb/LEDscape.brd b/pcb/LEDscape.brd deleted file mode 100644 index da1f6c99..00000000 --- a/pcb/LEDscape.brd +++ /dev/null @@ -1,1604 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE ->NAME ->VALUE -P8 -P9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->Name ->Value -+ -- - - - - -<b>Maxim Components</b><p> - -<author>Created by librarian@cadsoft.de</author> - - -<b>Small Outline Package</b> .150 SIOC<p> -Source: http://www.maxim-ic.com/package_drawings/21-0041B.pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>EAGLE Design Rules</b> -<p> -Die Standard-Design-Rules sind so gewählt, dass sie für -die meisten Anwendungen passen. Sollte ihre Platine -besondere Anforderungen haben, treffen Sie die erforderlichen -Einstellungen hier und speichern die Design Rules unter -einem neuen Namen ab. -<b>EAGLE Design Rules</b> -<p> -The default Design Rules have been set to cover -a wide range of applications. Your particular design -may have different requirements, so please make the -necessary adjustments and save your customized -design rules under a new name. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pcb/LEDscape.sch b/pcb/LEDscape.sch deleted file mode 100644 index 52ea8bd7..00000000 --- a/pcb/LEDscape.sch +++ /dev/null @@ -1,2732 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE ->NAME ->VALUE -P8 -P9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -2-Pin JST PH Series Right-Angle Connector (+/- for batteries) - - - - - - - - - - - - - - - - - - - - - ->Name ->Value -+ -- - - -4UCon #01528 -http://www.4uconnector.com/online/object/4udrawing/01528.pdf - - - - - - - - - - ->NAME -+ -- - - -<b>S2B-PH-K-S</b> -<p> -JST PH 2-pin thru-home side entry - - - - - - - - - - - - - - ->NAME -+ -- - - - - - - - - - - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - - ->NAME ->VALUE -P8 -P9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -Should match A3 pinout - but not completely tested - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>JST 2-Pin Connectors of various flavors</b> - -<ul> -<li>SMT-RA (S2B-PH-SM4) 4UConnector #17311</li> -<li>SMT (B2B-PH-SM4)</li> -<li>THM-RA (S2B-PH)</li> -<li>THM (B2B-PH)</li> -</ul> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Maxim Components</b><p> - -<author>Created by librarian@cadsoft.de</author> - - -<b>Thin Shrink Small Outline Plastic 16</b><p> -http://www.maxim-ic.com .. MAX3223-MAX3243.pdf - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - -<b>Small Outline Package</b> .150 SIOC<p> -Source: http://www.maxim-ic.com/package_drawings/21-0041B.pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - - - - - - - - - - - - - -<b>Small Outline Package</b> .300 SIOC<p> -Source: http://www.maxim-ic.com/cgi-bin/packages?pkg=16%2FSOIC%2E300&Type=Max - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -Z -Y -Z -Y -Z -Y -Z -Y - - - - - - - - - - - - - - - - - - - - -<b>±10kV ESD-Protected, Quad 5V RS-485/RS-422 Transmitters</b><p> -Source: www.maxim-ic.com .. MAX3040-MAX3045.pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Supply Symbols</b><p> - GND, VCC, 0V, +5V, -5V, etc.<p> - Please keep in mind, that these devices are necessary for the - automatic wiring of the supply signals.<p> - The pin name defined in the symbol is identical to the net which is to be wired automatically.<p> - In this library the device names are the same as the pin names of the symbols, therefore the correct signal names appear next to the supply symbols in the schematic.<p> - <author>Created by librarian@cadsoft.de</author> - - - - - - ->VALUE - - - - ->VALUE - - - - - -<b>SUPPLY SYMBOL</b> - - - - - - - - - - - - -<b>SUPPLY SYMBOL</b> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pin-setup b/pin-setup deleted file mode 100755 index 1af7c900..00000000 --- a/pin-setup +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -# WTF device tree? So much work, and you still don't set the pin -# direction? - -gpio_output() { - gpio=$1 - n=$2 - pin=`expr 32 \* $gpio + $n` - echo "Exporting GPIO$gpio.$n: pin $pin" - echo $pin > /sys/class/gpio/unexport - echo $pin > /sys/class/gpio/export - echo 0 > /sys/class/gpio/gpio$pin/value - echo out > /sys/class/gpio/gpio$pin/direction -} - -for pin in 2 3 4 5 7 12 13 14 15 20 22 23 26 27 30 31; do - gpio_output 0 $pin -done - -for pin in 12 13 14 15 16 17 18 19 28 29; do - gpio_output 1 $pin -done - -for pin in 1 2 3 4 5; do - gpio_output 2 $pin -done - -for pin in 16 19; do - gpio_output 3 $pin -done diff --git a/src/ledgames/Makefile b/src/ledgames/Makefile new file mode 100755 index 00000000..9e0e9c05 --- /dev/null +++ b/src/ledgames/Makefile @@ -0,0 +1,21 @@ +######### +# +# Build the various demos +# +# +BIN-y += bricks +BIN-y += black +BIN-y += white +BIN-y += paddles +BIN-y += invaders +BIN-y += menu + +bricks.srcs += bricks.cc gpio_pin.cc controls.cc screen.cc sprite.cc ball_sprite.cc +black.srcs += black.c +white.srcs += white.c +paddles.srcs += paddles.cc gpio_pin.cc controls.cc screen.cc sprite.cc ball_sprite.cc +invaders.srcs += invaders.cc gpio_pin.cc controls.cc screen.cc sprite.cc invader_sprite.cc ship_sprite.cc png.cc +menu.srcs += menu.cc gpio_pin.cc controls.cc screen.cc sprite.cc png.cc + +include ../../Makefile.common + diff --git a/src/ledgames/ball_sprite.cc b/src/ledgames/ball_sprite.cc new file mode 100644 index 00000000..476583cc --- /dev/null +++ b/src/ledgames/ball_sprite.cc @@ -0,0 +1,49 @@ +#include "ball_sprite.hh" + +ball_sprite_t::ball_sprite_t() : + sprite_t(), + wall_left_(true), + wall_right_(true), + wall_up_(true), + wall_down_(true) +{ +} + +void ball_sprite_t::move_sprite(void) { + sprite_t::move_sprite(); + + if (wall_left_) { + if ((x_ < 0.0f) && (dx_ < 0)) { + x_ = 0.0f; + dx_ = -dx_; + } + } + + if (wall_right_) { + if ((x_ > 63.0f) && (dx_ > 0)) { + x_ = 63.0f; + dx_ = -dx_; + } + } + + if (wall_up_) { + if ((y_ < 0.0f) && (dy_ < 0)) { + y_ = 0.0f; + dy_ = -dy_; + } + } + + if (wall_down_) { + if ((y_ > 63.0f) && (dy_ > 0)) { + y_ = 63.0f; + dy_ = -dy_; + } + } +} + +void ball_sprite_t::set_walls(bool up, bool down, bool left, bool right) { + wall_left_ = left; + wall_right_ = right; + wall_up_ = up; + wall_down_ = down; +} diff --git a/src/ledgames/ball_sprite.hh b/src/ledgames/ball_sprite.hh new file mode 100644 index 00000000..3cfb0857 --- /dev/null +++ b/src/ledgames/ball_sprite.hh @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#include "sprite.hh" + +class ball_sprite_t : public sprite_t { +public: + ball_sprite_t(); + + virtual void move_sprite(void) override; + void set_walls(bool up, bool down, bool left, bool right); + +private: + bool wall_left_; + bool wall_right_; + bool wall_up_; + bool wall_down_; +}; diff --git a/src/ledgames/black.c b/src/ledgames/black.c new file mode 100644 index 00000000..32546851 --- /dev/null +++ b/src/ledgames/black.c @@ -0,0 +1,82 @@ +/** \file +* Test the matrix LCD PRU firmware with a multi-hue rainbow. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ledscape.h" + +void drawpixel(uint32_t *pixels, uint8_t x, uint8_t y, uint32_t color, uint8_t flip) { + uint32_t pixelnum = ((flip ? (64 - y) : y) * 64) + (flip ? (64 - x ) : x); + pixels[pixelnum] = color; +} + +void render_game(uint32_t *pixels) { + for (int y_clear = 0; y_clear < 64; y_clear++) { + for (int x_clear = 0; x_clear < 64; x_clear++) { + drawpixel(pixels, x_clear, y_clear, 0x00000000, 0); + } + } +} + +int + main( + int argc, +const char ** argv + ) +{ + int width = 64; + int height = 64; + + ledscape_config_t * config = &ledscape_matrix_default; + if (argc > 1) + { + config = ledscape_config(argv[1]); + if (!config) + return EXIT_FAILURE; + } + + if (config->type == LEDSCAPE_MATRIX) + { + config->matrix_config.width = width; + config->matrix_config.height = height; + } + + ledscape_t * const leds = ledscape_init(config, 0); + + printf("init done\n"); + time_t last_time = time(NULL); + unsigned last_i = 0; + + unsigned i = 0; + uint32_t * const p = calloc(width*height,4); + + render_game(p); + + i++; + ledscape_draw(leds, p); + + usleep(20000); + + // wait for the previous frame to finish; + //const uint32_t response = ledscape_wait(leds); + const uint32_t response = 0; + time_t now = time(NULL); + if (now != last_time) + { + printf("%d fps. starting %d previous %"PRIx32"\n", + i - last_i, i, response); + last_i = i; + last_time = now; + } + + printf("init done\n"); + ledscape_close(leds); + + return EXIT_SUCCESS; +} diff --git a/src/ledgames/brick_sprite.hh b/src/ledgames/brick_sprite.hh new file mode 100644 index 00000000..eb8f9c35 --- /dev/null +++ b/src/ledgames/brick_sprite.hh @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#include "sprite.hh" + +class brick_sprite_t : public sprite_t { +public: + uint8_t score (void) { return score_; } + uint8_t tone_number (void) { return tone_number_; } + + void set_score(uint8_t score) { score_ = score; } + void set_tone_number(uint8_t tone_number) { tone_number_ = tone_number; } + +private: + uint8_t tone_number_; + uint8_t score_; + +}; diff --git a/src/ledgames/bricks.cc b/src/ledgames/bricks.cc new file mode 100644 index 00000000..32505d3b --- /dev/null +++ b/src/ledgames/bricks.cc @@ -0,0 +1,331 @@ +/** \file + * Bricks sample game + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "ledscape.h" + +#include "controls.hh" +#include "screen.hh" +#include "sprite.hh" +#include "ball_sprite.hh" +#include "brick_sprite.hh" + +static controls_t *player_controls[3]; +static int player_score[2]; +static int player_lives[2]; +static int number_players; +static int current_player; + +static sprite_t paddle_sprite; +static ball_sprite_t ball_sprite; +static std::vector brick_sprites[2]; + +static Mix_Chunk *startup_bong; +static Mix_Chunk *wall_blip; +static Mix_Chunk *block_blip[3]; +static Mix_Chunk *paddle_blip; + +enum class game_state_t { + Attract, + Serving, + Playing, + Resetting, +}; + +static game_state_t game_state; + +static float ball_horizontal_speeds[] = { + -1.1f, + -0.9f, + -0.7f, + -0.5f, + 0.3f, + 0.5f, + 0.7f, + 0.9f, + 1.1f +}; + +uint32_t ball_data[] = {0x00808000, 0x00808000, 0x00808000, 0x00808000}; +uint32_t paddle_data[] = {0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF}; +uint32_t brick_data[][8] = { + {0x00800000, 0x00800000, 0x00800000, 0x00100000, 0x00800000, 0x00800000, 0x00800000, 0x00100000}, + {0x00008000, 0x00008000, 0x00008000, 0x00001000, 0x00008000, 0x00008000, 0x00008000, 0x00001000}, + {0x00004080, 0x00004080, 0x00004080, 0x00000A10, 0x00004080, 0x00004080, 0x00004080, 0x00000A10}, + {0x00804000, 0x00804000, 0x00804000, 0x00100A00, 0x00804000, 0x00804000, 0x00804000, 0x00100A00}, + {0x00800040, 0x00800040, 0x00800040, 0x0010000A, 0x00800040, 0x00800040, 0x00800040, 0x0010000A}, + {0x00204010, 0x00204010, 0x00204010, 0x0010200A, 0x00204010, 0x00204010, 0x00204010, 0x0010200A}, +}; + +static void reset_bricks(int for_player) { + brick_sprites[for_player].clear(); + for (int row_counter = 0; row_counter < 6; row_counter++) { + for (int column_counter = 0; column_counter < 16; column_counter++) { + brick_sprite_t brick_sprite; + brick_sprite.set_active(true); + brick_sprite.set_position(column_counter * 4, 10 + (row_counter * 2)); + brick_sprite.set_image(4,2, brick_data[row_counter]); + brick_sprite.set_score((6 - row_counter) * 10); + brick_sprite.set_tone_number((5 - row_counter) / 2); + brick_sprites[for_player].push_back(brick_sprite); + } + } +} + +static bool reset_round(void) { + current_player = (current_player + 1) % number_players; + if (player_lives[current_player] == 0) { + return false; + } + + ball_sprite.set_position(32,32); + ball_sprite.set_speed(0.3f, 0.5f); + ball_sprite.set_image(1,1,ball_data); + + game_state = game_state_t::Serving; + + return true; +} + +static void reset_game(int with_number_players) { + paddle_sprite.set_active(true); + paddle_sprite.set_position(28, 60); + paddle_sprite.set_image(8,2,paddle_data); + + reset_bricks(0); + reset_bricks(1); + + player_score[0] = 0; + player_score[1] = 0; + + player_lives[0] = 3; + player_lives[1] = 3; + + number_players = with_number_players; + current_player = 1; + + reset_round(); + + printf("\n\n\nGAME START\n\n\n"); +} + +void init_attract(void) { + paddle_sprite.set_active(false); + + ball_sprite.set_position(32,32); + ball_sprite.set_speed(0.5f, 0.5f); + ball_sprite.set_image(1,1,ball_data); + + current_player = 0; + reset_bricks(0); + + game_state = game_state_t::Attract; +} + +void render_game(Screen *screen) { + if (current_player == 1) { + screen->set_flip(true); + } else { + screen->set_flip(false); + } + screen->set_background_color(0x00000010); + screen->draw_start(); + + paddle_sprite.draw_onto(screen); + ball_sprite.draw_onto(screen); + + for (auto &brick_sprite : brick_sprites[current_player]) { + brick_sprite.draw_onto(screen); + } + + if (game_state == game_state_t::Attract) { + screen->draw_text(32,2,0x00808080,"GAME OVER!"); + screen->draw_text(40,2,0x00808080,"PRESS PLYR"); + screen->draw_text(48,2,0x00808080," 1 OR 2 "); + } else { + char score[7]; + char lives[1]; + sprintf(score, "%06d", player_score[current_player]); + screen->draw_text(0,2,0x00808080,score); + sprintf(lives, "%01d", player_lives[current_player]); + screen->draw_text(0,48,0x00808080,lives); + + } + + screen->draw_end(); + + player_controls[current_player]->refresh_status(); + player_controls[2]->refresh_status(); + + if (game_state == game_state_t::Attract) { + if (player_controls[2]->is_pressed(button_a)) { + reset_game(1); + } else if (player_controls[2]->is_pressed(button_b)) { + reset_game(2); + } + return; + } else { + if (player_controls[current_player]->is_pressed(joystick_left)) { + if (paddle_sprite.x_ > 0) { + paddle_sprite.x_--; + } + } + + if (player_controls[current_player]->is_pressed(joystick_right)) { + if (paddle_sprite.x_ < 56) { + paddle_sprite.x_++; + } + } + if (game_state == game_state_t::Serving) { + if (player_controls[current_player]->is_pressed(button_a)) { + game_state = game_state_t::Playing; + } + } + } + + // Move ball + if (game_state != game_state_t::Serving) { + ball_sprite.move_sprite(); + } + + if (ball_sprite.test_collision(paddle_sprite, true)) { + ball_sprite.y_ = 59.0f; + ball_sprite.dy_ = -ball_sprite.dy_; + ball_sprite.dx_ = ball_horizontal_speeds[(int)(ball_sprite.x_ - (paddle_sprite.x_ - 1))]; + Mix_PlayChannel(-1, paddle_blip, 0); + } + + if (ball_sprite.y_ >= 63.0f) { + if (game_state != game_state_t::Attract) { + player_lives[current_player]--; + if (!reset_round()) { + init_attract(); + } + return; + } else { + ball_sprite.dy_ = -ball_sprite.dy_; + ball_sprite.dx_ = ball_horizontal_speeds[rand()%7]; + } + } + + if (game_state == game_state_t::Playing) { + bool active_bricks = false; + for (auto &brick_sprite : brick_sprites[current_player]) { + active_bricks |= brick_sprite.is_active(); + if (brick_sprite.test_collision(ball_sprite, true)) { + brick_sprite.set_active(false); + game_state = game_state_t::Resetting; + ball_sprite.dy_ = -ball_sprite.dy_; + player_score[current_player] += brick_sprite.score(); + Mix_PlayChannel(-1, block_blip[brick_sprite.tone_number()], 0); + } + } + if (!active_bricks) { + reset_bricks(current_player); + } + } else { + if (game_state != game_state_t::Attract) { + if ((ball_sprite.y_ < 9) || (ball_sprite.y_ > 32)) { + game_state = game_state_t::Playing; + } + } + } +} + +static void init_sdl(void) { + if (SDL_Init(SDL_INIT_AUDIO) != 0) { + fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + + int audio_rate = 44100; + Uint16 audio_format = AUDIO_S16SYS; + int audio_channels = 2; + int audio_buffers = 8192; + + if(Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0) { + fprintf(stderr, "Unable to initialize audio: %s\n", Mix_GetError()); + exit(1); + } + + startup_bong = Mix_LoadWAV("bin/startup.wav"); + if (startup_bong == NULL) { + fprintf(stderr, "Unable to load startup.wav: %s\n", Mix_GetError()); + exit(1); + } + + Mix_PlayChannel(-1, startup_bong, 0); +} + +int +main( + int argc, + const char ** argv + ) +{ + int width = 64; + int height = 64; + + ledscape_config_t * config = &ledscape_matrix_default; + if (argc > 1) + { + config = ledscape_config(argv[1]); + if (!config) + return EXIT_FAILURE; + } + + if (config->type == LEDSCAPE_MATRIX) + { + config->matrix_config.width = width; + config->matrix_config.height = height; + } + + ledscape_t * const leds = ledscape_init(config, 0); + + player_controls[0] = new controls_t(1); + player_controls[1] = new controls_t(2); + player_controls[2] = new controls_t(3); + + init_attract(); + + printf("init done\n"); + uint32_t * const p = (uint32_t*)calloc(width*height,4); + + Screen *screen = new Screen(leds, p); + + init_sdl(); + + wall_blip = Mix_LoadWAV("bin/blip1.wav"); + paddle_blip = Mix_LoadWAV("bin/blip2.wav"); + block_blip[0] = Mix_LoadWAV("bin/blip3.wav"); + block_blip[1] = Mix_LoadWAV("bin/blip4.wav"); + block_blip[2] = Mix_LoadWAV("bin/blip5.wav"); + +try { + while (1) + { + render_game(screen); + + usleep(20000); + + } +} +catch (control_exit_exception* ex) { + delete screen; +} + + return EXIT_SUCCESS; +} diff --git a/src/ledgames/controls.cc b/src/ledgames/controls.cc new file mode 100644 index 00000000..dc0d7504 --- /dev/null +++ b/src/ledgames/controls.cc @@ -0,0 +1,80 @@ +#include + +#include "controls.hh" + +#define BUTTON_PLAYERSTART_P1 70 +#define BUTTON_PLAYERSTART_P2 71 +#define BUTTON_P1_JOYUP 79 +#define BUTTON_P1_JOYDN 73 +#define BUTTON_P1_JOYLEFT 74 +#define BUTTON_P1_JOYRIGHT 89 +#define BUTTON_P1_ACTION_PRI 76 +#define BUTTON_P1_ACTION_SEC 77 +#define BUTTON_P2_JOYUP 8 +#define BUTTON_P2_JOYDN 10 +#define BUTTON_P2_JOYLEFT 9 +#define BUTTON_P2_JOYRIGHT 81 +#define BUTTON_P2_ACTION_PRI 11 +#define BUTTON_P2_ACTION_SEC 80 + +controls_t::controls_t (uint8_t player_number, bool flip_lr) { + player_number_ = player_number; + pin_info_.resize(button_assignments_count); + if (player_number == 1) { + pin_info_[joystick_up] = new gpio_pin_t(BUTTON_P1_JOYUP); + pin_info_[joystick_down] = new gpio_pin_t(BUTTON_P1_JOYDN); + if (flip_lr) { + pin_info_[joystick_left] = new gpio_pin_t(BUTTON_P1_JOYRIGHT); + pin_info_[joystick_right] = new gpio_pin_t(BUTTON_P1_JOYLEFT); + } else { + pin_info_[joystick_left] = new gpio_pin_t(BUTTON_P1_JOYLEFT); + pin_info_[joystick_right] = new gpio_pin_t(BUTTON_P1_JOYRIGHT); + } + pin_info_[button_a] = new gpio_pin_t(BUTTON_P1_ACTION_PRI); + pin_info_[button_b] = new gpio_pin_t(BUTTON_P1_ACTION_SEC); + } else if (player_number == 2) { + pin_info_[joystick_up] = new gpio_pin_t(BUTTON_P2_JOYUP); + pin_info_[joystick_down] = new gpio_pin_t(BUTTON_P2_JOYDN); + if (flip_lr) { + pin_info_[joystick_left] = new gpio_pin_t(BUTTON_P2_JOYRIGHT); + pin_info_[joystick_right] = new gpio_pin_t(BUTTON_P2_JOYLEFT); + } else { + pin_info_[joystick_left] = new gpio_pin_t(BUTTON_P2_JOYLEFT); + pin_info_[joystick_right] = new gpio_pin_t(BUTTON_P2_JOYRIGHT); + } + pin_info_[button_a] = new gpio_pin_t(BUTTON_P2_ACTION_PRI); + pin_info_[button_b] = new gpio_pin_t(BUTTON_P2_ACTION_SEC); + } else if (player_number == 3) { + pin_info_[joystick_up] = new gpio_pin_t(BUTTON_P1_JOYUP); + pin_info_[joystick_down] = new gpio_pin_t(BUTTON_P1_JOYDN); + pin_info_[joystick_left] = new gpio_pin_t(BUTTON_P1_JOYLEFT); + pin_info_[joystick_right] = new gpio_pin_t(BUTTON_P1_JOYRIGHT); + pin_info_[button_a] = new gpio_pin_t(BUTTON_PLAYERSTART_P1); + pin_info_[button_b] = new gpio_pin_t(BUTTON_PLAYERSTART_P2); + } +} + +controls_t::~controls_t () { +} + +void controls_t::refresh_status() { + button_pressed_.clear(); + for (auto pin_info : pin_info_) { + button_pressed_.push_back(pin_info->is_pressed()); + } + if (player_number_ == 3) { + if (button_pressed_[button_a] && button_pressed_[button_b]) { + exit_pressed_frames_ ++; + if (exit_pressed_frames_ >= 60) { + throw new control_exit_exception(); + } + } else { + exit_pressed_frames_ = 0; + } + } +} + +bool controls_t::is_pressed(button_assignments_t button) { + return button_pressed_[button]; +} + diff --git a/src/ledgames/controls.hh b/src/ledgames/controls.hh new file mode 100644 index 00000000..143c59d9 --- /dev/null +++ b/src/ledgames/controls.hh @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#include "gpio_pin.hh" + +class control_exit_exception : public std::exception{ +}; + +enum button_assignments_t { + joystick_up, + joystick_down, + joystick_left, + joystick_right, + button_a, + button_b, + button_assignments_count, +}; + +class controls_t { +public: + controls_t(uint8_t player_number, bool flip_lr = false); + ~controls_t(); + + void refresh_status(); + bool is_pressed(button_assignments_t button); + +private: + std::vector pin_info_; + std::vectorbutton_pressed_; + uint8_t player_number_; + uint32_t exit_pressed_frames_; +}; + diff --git a/src/ledgames/gpio_pin.cc b/src/ledgames/gpio_pin.cc new file mode 100644 index 00000000..d99f12af --- /dev/null +++ b/src/ledgames/gpio_pin.cc @@ -0,0 +1,45 @@ +#include + +#include +#include +#include +#include +#include + +#include "gpio_pin.hh" + +gpio_pin_t::gpio_pin_t (uint8_t button_number) : + button_number_(button_number) +{ + export_gpio(); + + char button_file_name[1024]; + snprintf(button_file_name, 1024, "/sys/class/gpio/gpio%d/value", button_number); + file_descriptor_ = open(button_file_name, O_RDONLY); + if (-1 == file_descriptor_) { + printf("Failed opening button %d\n", button_number); + throw 1; + } +} + +gpio_pin_t::~gpio_pin_t () { + close(file_descriptor_); +} + +void gpio_pin_t::export_gpio (void) { + FILE *exportfile = fopen("/sys/class/gpio/export", "w"); + if (NULL == exportfile) { + printf("Failed opening export device"); + return; + } + + fprintf(exportfile, "%d", button_number_); + fclose(exportfile); +} + +bool gpio_pin_t::is_pressed(void) { + uint8_t button_value; + lseek(file_descriptor_, 0, SEEK_SET); + read(file_descriptor_, &button_value, 1); + return (button_value == '0') ? true : false; +} diff --git a/src/ledgames/gpio_pin.hh b/src/ledgames/gpio_pin.hh new file mode 100644 index 00000000..f06b5398 --- /dev/null +++ b/src/ledgames/gpio_pin.hh @@ -0,0 +1,16 @@ +#include + +class gpio_pin_t { + +public: + gpio_pin_t (uint8_t button_number); + ~gpio_pin_t(); + + bool is_pressed(); + +private: + void export_gpio(); + + uint8_t button_number_; + int file_descriptor_; +}; diff --git a/src/ledgames/invader_sprite.cc b/src/ledgames/invader_sprite.cc new file mode 100644 index 00000000..d19ea0c8 --- /dev/null +++ b/src/ledgames/invader_sprite.cc @@ -0,0 +1,39 @@ +#include "invader_sprite.hh" + +invader_sprite_t::invader_sprite_t(uint32_t score) : +sprite_t(), +frames_in_anim_(0), +score_(score) +{ +} + +void invader_sprite_t::draw_onto(Screen *screen) { + if (frame_ == 2) { + frames_in_anim_++; + if (frames_in_anim_ > 3) { + frames_in_anim_ = 0; + frame_ = 3; + } + } else if (frame_ == 3) { + frames_in_anim_++; + if (frames_in_anim_ > 3) { + frames_in_anim_ = 0; + set_active(false); + } + } + sprite_t::draw_onto(screen); +} + +void invader_sprite_t::move_sprite(void) { + sprite_t::move_sprite(); + + if (frame_ < 2) { + frame_ = (int)x_ & 0x01; + } +} + +uint32_t invader_sprite_t::destroy_sprite(void) { + frame_ = 2; + frames_in_anim_ = 0; + return score_; +} \ No newline at end of file diff --git a/src/ledgames/invader_sprite.hh b/src/ledgames/invader_sprite.hh new file mode 100644 index 00000000..95fec701 --- /dev/null +++ b/src/ledgames/invader_sprite.hh @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include "sprite.hh" + +class invader_sprite_t : public sprite_t { +public: + invader_sprite_t(uint32_t score); + + virtual void draw_onto(Screen *screen) override; + virtual void move_sprite(void) override; + virtual uint32_t destroy_sprite(void); + +private: + uint32_t frames_in_anim_; + uint32_t score_; +}; diff --git a/src/ledgames/invaders.cc b/src/ledgames/invaders.cc new file mode 100644 index 00000000..2430619b --- /dev/null +++ b/src/ledgames/invaders.cc @@ -0,0 +1,436 @@ +/** \file +* Invaders sample game +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "ledscape.h" + +#include "controls.hh" +#include "screen.hh" +#include "sprite.hh" +#include "invader_sprite.hh" +#include "ship_sprite.hh" +#include "png.hh" + +static controls_t *player_controls[3]; +static int player_score[2]; +static int player_lives[2]; +static int number_players; +static int current_player; + +static ship_sprite_t ship_sprite; +static sprite_t ship_missile_sprite; +static std::vector invader_sprites[2]; +static sprite_t invader_missile_sprite; +static int32_t lowest_invaders[6]; + +static Mix_Chunk *startup_bong; +static Mix_Chunk *invader_explosion; +static Mix_Chunk *ship_explosion; +static Mix_Chunk *invader_march[4]; + +static png_t sprite_sheet; + +enum class game_state_t { + Attract, + Serving, + Playing, + Touchdown, + NewShip, +}; + +static game_state_t game_state; +static bool invaders_right; +static bool shot_fired; +static float invader_speed; +static uint32_t frames_in_state; +static uint32_t frames_till_shot; + +static uint32_t invader_march_state; +static uint32_t invader_march_frames; + +static std::default_random_engine generator; +static std::uniform_int_distribution invader_distribution(0,5); +static std::uniform_int_distribution shot_distribution(65,95); + +static void reset_invaders(int for_player) { + invader_sprites[for_player].clear(); + invaders_right = true; + invader_speed = 0.05f; + for (int row_counter = 0; row_counter < 4; row_counter++) { + for (int column_counter = 0; column_counter < 6; column_counter++) { + invader_sprite_t invader_sprite((5 - row_counter) * 100); + invader_sprite.set_active(true); + invader_sprite.set_speed(invader_speed, 0.0); + invader_sprite.set_position(column_counter * 10, 10 + (row_counter * 8)); + invader_sprite.set_image(row_counter * 28,0,7,7,&sprite_sheet, 0); + invader_sprite.set_image((row_counter * 28) + 7,0,7,7,&sprite_sheet, 1); + invader_sprite.set_image((row_counter * 28) + 14,0,7,7,&sprite_sheet, 2); + invader_sprite.set_image((row_counter * 28) + 21,0,7,7,&sprite_sheet, 3); + invader_sprites[for_player].push_back(invader_sprite); + } + } + lowest_invaders[0] = 18; + lowest_invaders[1] = 19; + lowest_invaders[2] = 20; + lowest_invaders[3] = 21; + lowest_invaders[4] = 22; + lowest_invaders[5] = 23; +} + +static bool reset_round(void) { + uint32_t next_player = (current_player + 1) % number_players; + if (player_lives[next_player] > 0) { + current_player = next_player; + } + if ((player_lives[0] == 0) && (player_lives[1] == 0)) { + return false; + } + + shot_fired = false; + ship_missile_sprite.set_active(false); + invader_missile_sprite.set_active(false); + ship_sprite.set_active(true); + game_state = game_state_t::Playing; + + frames_till_shot = 60; + + invader_march_state = 0; + invader_march_frames = 0; + + return true; +} + +static void reset_game(int with_number_players) { + ship_sprite.set_active(true); + ship_sprite.set_position(28, 55); + ship_sprite.set_image(168,0,7,7,&sprite_sheet, 0); + ship_sprite.set_image(168+7,0,7,7,&sprite_sheet, 1); + ship_sprite.set_image(168+14,0,7,7,&sprite_sheet, 2); + ship_sprite.set_image(168+28,0,7,7,&sprite_sheet, 3); + + reset_invaders(0); + reset_invaders(1); + + player_score[0] = 0; + player_score[1] = 0; + + player_lives[0] = 3; + if (with_number_players == 2) { + player_lives[1] = 3; + } else { + player_lives[1] = 0; + } + + number_players = with_number_players; + current_player = 1; + + reset_round(); + + printf("\n\n\nGAME START\n\n\n"); +} + +void init_attract(void) { + ship_sprite.set_active(false); + + current_player = 0; + reset_invaders(0); + + game_state = game_state_t::Attract; +} + +void render_game(Screen *screen) { + if (current_player == 1) { + screen->set_flip(true); + } else { + screen->set_flip(false); + } + screen->set_background_color(0x00000000); + screen->draw_start(); + + ship_sprite.draw_onto(screen); + ship_missile_sprite.draw_onto(screen); + invader_missile_sprite.draw_onto(screen); + ship_missile_sprite.move_sprite(); + invader_missile_sprite.move_sprite(); + if (ship_missile_sprite.get_y_position() < 0.0f) { + ship_missile_sprite.set_active(false); + } + + bool change_direction = false; + bool invader_touchdown = false; + if ((game_state == game_state_t::Attract) || (game_state == game_state_t::Playing)) { + for (auto &invader_sprite : invader_sprites[current_player]) { + invader_sprite.move_sprite(); + if (invader_sprite.is_active()) { + if ((invaders_right && (invader_sprite.get_x_position() > 57.5f)) || (!invaders_right && (invader_sprite.get_x_position() < 0.5f))) { + change_direction = true; + } + if (invader_sprite.get_y_position() > 47) { + invader_touchdown = true; + } + } + } + } + + if (invader_touchdown) { + game_state = game_state_t::Touchdown; + Mix_PlayChannel(-1, ship_explosion, 0); + frames_in_state = 0; + ship_sprite.set_active(false); + player_lives[current_player] = 0; + for (auto &invader_sprite : invader_sprites[current_player]) { + invader_sprite.set_position(invader_sprite.get_x_position(), invader_sprite.get_y_position()+8); + } + } + + if (change_direction) { + invaders_right = !invaders_right; + } + + for (auto &invader_sprite : invader_sprites[current_player]) { + invader_sprite.draw_onto(screen); + } + + frames_till_shot--; + if (frames_till_shot == 0) { + invader_missile_sprite.set_active(true); + int32_t invader_column = -1; + do { + invader_column = lowest_invaders[invader_distribution(generator)]; + } while (invader_column < 0); + sprite_t invader_sprite = invader_sprites[current_player][invader_column]; + invader_missile_sprite.set_position(invader_sprite.get_x_position(), invader_sprite.get_y_position()); + invader_missile_sprite.set_image(196,0,7,7,&sprite_sheet); + invader_missile_sprite.set_speed(0.0f, 0.8f); + frames_till_shot=shot_distribution(generator); + } + + if (game_state == game_state_t::Attract) { + screen->draw_text(0,2,0x00808080,"GAME OVER!"); + screen->draw_text(48,2,0x00808080,"PRESS PLYR"); + screen->draw_text(56,2,0x00808080," 1 OR 2 "); + } else if ((game_state == game_state_t::Playing) || (game_state == game_state_t::NewShip)) { + char score[7]; + char lives[1]; + sprintf(score, "%06d", player_score[current_player]); + screen->draw_text(0,2,0x00808080,score); + sprintf(lives, "%01d", player_lives[current_player]); + screen->draw_text(0,48,0x00808080,lives); + } else if (game_state == game_state_t::Touchdown) { + char score[7]; + char lives[1]; + sprintf(score, "%06d", player_score[current_player]); + screen->draw_text(0,2,0x00808080,score); + sprintf(lives, "%01d", player_lives[current_player]); + screen->draw_text(0,48,0x00808080,lives); + screen->draw_text(32,2,0x00808080,"GAME OVER!"); + } + + screen->draw_end(); + + player_controls[current_player]->refresh_status(); + player_controls[2]->refresh_status(); + + if (game_state == game_state_t::Attract) { + if (player_controls[2]->is_pressed(button_a)) { + reset_game(1); + } else if (player_controls[2]->is_pressed(button_b)) { + reset_game(2); + } + } else if (game_state == game_state_t::Playing) { + if (player_controls[current_player]->is_pressed(joystick_left)) { + if (ship_sprite.x_ > 0) { + ship_sprite.x_--; + } + } + + if (player_controls[current_player]->is_pressed(joystick_right)) { + if (ship_sprite.x_ < 57) { + ship_sprite.x_++; + } + } + + if ((!shot_fired) && (player_controls[current_player]->is_pressed(button_a))) { + ship_missile_sprite.set_active(true); + ship_missile_sprite.set_position(ship_sprite.get_x_position(), 51); + ship_missile_sprite.set_image(196,0,7,7,&sprite_sheet); + ship_missile_sprite.set_speed(0.0f, -2.0f); + shot_fired = true; + } + if (!player_controls[current_player]->is_pressed(button_a)) { + shot_fired = false; + } + + } + + if ((game_state == game_state_t::Attract) || (game_state == game_state_t::Playing)) { + int active_invaders = 0; + int32_t invader_idx = 0; + for (auto &invader_sprite : invader_sprites[current_player]) { + active_invaders += (invader_sprite.is_active() ? 1 : 0); + if (invader_sprite.test_collision(ship_missile_sprite, false)) { + Mix_PlayChannel(-1, invader_explosion, 0); + player_score[current_player] += invader_sprite.destroy_sprite(); + ship_missile_sprite.set_active(false); + for (uint8_t idx_ctr = 0; idx_ctr < 6; idx_ctr++) { + if (lowest_invaders[idx_ctr] == invader_idx) { + // Player just shot the lowest invader in a column. + lowest_invaders[idx_ctr] -= 6; + } + } + } + invader_idx++; + } + invader_speed = 0.06f + ((24 - active_invaders) * 0.05f); + if (active_invaders == 0) { + reset_invaders(current_player); + } + + if (game_state == game_state_t::Playing) { + if (invader_march_frames == 0) { + Mix_PlayChannel(-1, invader_march[invader_march_state], 0); + invader_march_state = (invader_march_state + 1) % 4; + invader_march_frames = 10 + (active_invaders/4); + } else { + invader_march_frames--; + } + } + + if (ship_sprite.test_collision(invader_missile_sprite, false)) { + Mix_PlayChannel(-1, ship_explosion, 0); + game_state = game_state_t::NewShip; + ship_sprite.destroy_sprite(); + player_lives[current_player]--; + frames_in_state = 0; + } + } + + for (auto &invader_sprite : invader_sprites[current_player]) { + invader_sprite.set_speed(invader_speed * (invaders_right ? 1 : -1), 0); + if (change_direction) { + if (game_state == game_state_t::Playing) { + invader_sprite.set_position(invader_sprite.get_x_position(), invader_sprite.get_y_position()+1); + } + } + } + + if (game_state == game_state_t::Touchdown) { + frames_in_state++; + if (frames_in_state == 120) { + if (!reset_round()) { + init_attract(); + } + } + } + + if (game_state == game_state_t::NewShip) { + frames_in_state++; + if (frames_in_state == 120) { + if (!reset_round()) { + init_attract(); + } + } + } +} + +static void init_sdl(void) { + if (SDL_Init(SDL_INIT_AUDIO) != 0) { + fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + + int audio_rate = 44100; + Uint16 audio_format = AUDIO_S16SYS; + int audio_channels = 2; + int audio_buffers = 16384; + + if(Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0) { + fprintf(stderr, "Unable to initialize audio: %s\n", Mix_GetError()); + exit(1); + } + + startup_bong = Mix_LoadWAV("bin/startup.wav"); + if (startup_bong == NULL) { + fprintf(stderr, "Unable to load startup.wav: %s\n", Mix_GetError()); + exit(1); + } + + Mix_PlayChannel(-1, startup_bong, 0); +} + +int + main( + int argc, +const char ** argv + ) +{ + int width = 64; + int height = 64; + + ledscape_config_t * config = &ledscape_matrix_default; + if (argc > 1) + { + config = ledscape_config(argv[1]); + if (!config) + return EXIT_FAILURE; + } + + if (config->type == LEDSCAPE_MATRIX) + { + config->matrix_config.width = width; + config->matrix_config.height = height; + } + + ledscape_t * const leds = ledscape_init(config, 0); + + sprite_sheet.read_file("bin/Invaders.png"); + + player_controls[0] = new controls_t(1); + player_controls[1] = new controls_t(2); + player_controls[2] = new controls_t(3); + + init_attract(); + + printf("init done\n"); + uint32_t * const p = (uint32_t*)calloc(width*height,4); + + Screen *screen = new Screen(leds, p); + + init_sdl(); + + invader_explosion = Mix_LoadWAV("bin/invader_explosion.wav"); + ship_explosion = Mix_LoadWAV("bin/ship_explosion.wav"); + invader_march[0] = Mix_LoadWAV("bin/invader_march1.wav"); + invader_march[1] = Mix_LoadWAV("bin/invader_march2.wav"); + invader_march[2] = Mix_LoadWAV("bin/invader_march3.wav"); + invader_march[3] = Mix_LoadWAV("bin/invader_march4.wav"); + + try { + while (1) + { + render_game(screen); + + usleep(20000); + + } + } + catch (control_exit_exception* ex) { + delete screen; + } + + return EXIT_SUCCESS; +} diff --git a/src/ledgames/menu.cc b/src/ledgames/menu.cc new file mode 100644 index 00000000..3f1c5370 --- /dev/null +++ b/src/ledgames/menu.cc @@ -0,0 +1,283 @@ +/** \file +* Test the matrix LCD PRU firmware with a multi-hue rainbow. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "ledscape.h" + +#include "controls.hh" +#include "screen.hh" +#include "sprite.hh" +#include "png.hh" + +static controls_t *player_controls[2]; + +static Mix_Chunk *startup_bong; +static Mix_Chunk *menu_blip; + +static png_t sprite_sheet; +static std::vector game_sprites; + +static uint32_t current_option; + +static uint32_t marque_position; +static uint32_t text_color; + +enum class game_state_t { + Menu, + Menu_Select, + Service, +}; + +static game_state_t game_state; + +static uint32_t rainbowColors[180]; + +static char marque_text[] = "Welcome to LED Games at MakerFaire Bay Area 2015!"; + +// Borrowed by OctoWS2811 rainbow test +static unsigned int +h2rgb( + unsigned int v1, + unsigned int v2, + unsigned int hue +) +{ + if (hue < 60) + return v1 * 60 + (v2 - v1) * hue; + if (hue < 180) + return v2 * 60; + if (hue < 240) + return v1 * 60 + (v2 - v1) * (240 - hue); + + return v1 * 60; +} + +// Convert HSL (Hue, Saturation, Lightness) to RGB (Red, Green, Blue) +// +// hue: 0 to 359 - position on the color wheel, 0=red, 60=orange, +// 120=yellow, 180=green, 240=blue, 300=violet +// +// saturation: 0 to 100 - how bright or dull the color, 100=full, 0=gray +// +// lightness: 0 to 100 - how light the color is, 100=white, 50=color, 0=black +// +static uint32_t +makeColor( + unsigned int hue, + unsigned int saturation, + unsigned int lightness +) +{ + unsigned int red, green, blue; + unsigned int var1, var2; + + if (hue > 359) + hue = hue % 360; + if (saturation > 100) + saturation = 100; + if (lightness > 100) + lightness = 100; + + // algorithm from: http://www.easyrgb.com/index.php?X=MATH&H=19#text19 + if (saturation == 0) { + red = green = blue = lightness * 255 / 100; + } else { + if (lightness < 50) { + var2 = lightness * (100 + saturation); + } else { + var2 = ((lightness + saturation) * 100) - (saturation * lightness); + } + var1 = lightness * 200 - var2; + red = h2rgb(var1, var2, (hue < 240) ? hue + 120 : hue - 240) * 255 / 600000; + green = h2rgb(var1, var2, hue) * 255 / 600000; + blue = h2rgb(var1, var2, (hue >= 120) ? hue - 120 : hue + 240) * 255 / 600000; + } + return (red << 16) | (green << 8) | blue; +} + +static void reset_menu(void) { + game_state = game_state_t::Menu; + + sprite_t bricks_sprite; + bricks_sprite.set_active(true); + bricks_sprite.set_position(0,0); + bricks_sprite.set_image(0,0,64,32,&sprite_sheet); + + sprite_t paddles_sprite; + paddles_sprite.set_active(false); + paddles_sprite.set_position(0,0); + paddles_sprite.set_image(64,0,64,32,&sprite_sheet); + + sprite_t invaders_sprite; + invaders_sprite.set_active(false); + invaders_sprite.set_position(0,0); + invaders_sprite.set_image(128,0,64,32,&sprite_sheet); + + game_sprites.clear(); + game_sprites.push_back(bricks_sprite); + game_sprites.push_back(paddles_sprite); + game_sprites.push_back(invaders_sprite); + + current_option = 0; + + marque_position = 64; + + // pre-compute the 180 rainbow colors + for (int i=0; i<180; i++) + { + int hue = i * 2; + int saturation = 100; + int lightness = 50; + rainbowColors[i] = makeColor(hue, saturation, lightness); + } + text_color = 0; + + printf("\n\n\nGAME START\n\n\n"); +} + +void render_game(Screen *screen) { + screen->set_background_color(0x00000000); + screen->draw_start(); + + player_controls[0]->refresh_status(); + player_controls[1]->refresh_status(); + + if ((game_state == game_state_t::Menu) || (game_state == game_state_t::Menu_Select)) { + screen->draw_text(32,marque_position,rainbowColors[text_color % 180],marque_text); + screen->draw_text(40,2,rainbowColors[text_color % 180],"Joy. sel."); + screen->draw_text(48,2,rainbowColors[text_color % 180],"Btn. start"); + + for (auto sprite : game_sprites) { + sprite.draw_onto(screen); + } + + marque_position--; + if (marque_position == (0xFFFFFFFF - (5 * sizeof(marque_text)) - 64)) { + marque_position = 64; + } + + text_color++; + } + + screen->draw_end(); + + if (game_state == game_state_t::Menu) { + if (player_controls[0]->is_pressed(button_a)) { + exit(current_option); + } + + if (player_controls[0]->is_pressed(joystick_left)) { + game_sprites[current_option].set_active(false); + current_option = (current_option > 0) ? current_option-1 : 0; + game_sprites[current_option].set_active(true); + game_state = game_state_t::Menu_Select; + } + + if (player_controls[0]->is_pressed(joystick_right)) { + game_sprites[current_option].set_active(false); + current_option = (current_option < game_sprites.size()-1) ? current_option+1 : game_sprites.size()-1; + game_sprites[current_option].set_active(true); + game_state = game_state_t::Menu_Select; + } + } + + if (game_state == game_state_t::Menu_Select) { + if ((!player_controls[0]->is_pressed(joystick_left)) && (!player_controls[0]->is_pressed(joystick_right))) { + game_state = game_state_t::Menu; + } + } +} + +static void init_sdl(void) { + if (SDL_Init(SDL_INIT_AUDIO) != 0) { + fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + + int audio_rate = 44100; + Uint16 audio_format = AUDIO_S16SYS; + int audio_channels = 2; + int audio_buffers = 16384; + + if(Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0) { + fprintf(stderr, "Unable to initialize audio: %s\n", Mix_GetError()); + exit(1); + } + + startup_bong = Mix_LoadWAV("bin/startup.wav"); + if (startup_bong == NULL) { + fprintf(stderr, "Unable to load startup.wav: %s\n", Mix_GetError()); + exit(1); + } + + Mix_PlayChannel(-1, startup_bong, 0); +} + +int + main( + int argc, +const char ** argv + ) +{ + int width = 64; + int height = 64; + + ledscape_config_t * config = &ledscape_matrix_default; + if (argc > 1) + { + config = ledscape_config(argv[1]); + if (!config) + return EXIT_FAILURE; + } + + if (config->type == LEDSCAPE_MATRIX) + { + config->matrix_config.width = width; + config->matrix_config.height = height; + } + + sprite_sheet.read_file("bin/Menus.png"); + + ledscape_t * const leds = ledscape_init(config, 0); + + player_controls[0] = new controls_t(1); + player_controls[1] = new controls_t(3); + + reset_menu(); + + printf("init done\n"); + uint32_t * const p = (uint32_t*)calloc(width*height,4); + + Screen *screen = new Screen(leds, p); + + init_sdl(); + + menu_blip = Mix_LoadWAV("bin/blip3.wav"); + + while (1) + { + try { + render_game(screen); + usleep(20000); + } + catch (control_exit_exception* ex) { + // Ignore the exception, as there is no useful exit program. + } + } + + return EXIT_SUCCESS; +} diff --git a/src/ledgames/paddles.cc b/src/ledgames/paddles.cc new file mode 100644 index 00000000..e55ade72 --- /dev/null +++ b/src/ledgames/paddles.cc @@ -0,0 +1,311 @@ +/** \file + * Paddles sample game + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "ledscape.h" + +#include "controls.hh" +#include "screen.hh" +#include "sprite.hh" +#include "ball_sprite.hh" +#include "brick_sprite.hh" + +static controls_t *player_controls[3]; +static int player_score[2]; +static int number_players; +static int serving_player; + +static sprite_t paddle_sprite[2]; +static ball_sprite_t ball_sprite; + +static Mix_Chunk *startup_bong; +static Mix_Chunk *paddle_blip; + +enum class game_state_t { + Attract, + Serving, + Playing, + Resetting, +}; + +static game_state_t game_state; + +static float ball_horizontal_speeds[] = { + -1.1f, + -0.9f, + -0.7f, + -0.5f, + 0.3f, + 0.5f, + 0.7f, + 0.9f, + 1.1f +}; + +uint32_t ball_data[] = {0x00808000, 0x00808000, 0x00808000, 0x00808000}; +uint32_t paddle_data[] = {0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x0000FFFF}; + +static bool reset_round(void) { + if ((player_score[0] == 7) || (player_score[1] == 7)) { + return false; + } + + if (serving_player == 0) { + ball_sprite.set_position(paddle_sprite[0].x_+4,58); + ball_sprite.set_speed(ball_horizontal_speeds[rand()%7], -0.5f); + } else { + ball_sprite.set_position(paddle_sprite[1].x_+4,6); + ball_sprite.set_speed(ball_horizontal_speeds[rand()%7], 0.5f); + } + ball_sprite.set_image(1,1,ball_data); + + game_state = game_state_t::Serving; + + return true; +} + +static void reset_game(int with_number_players) { + paddle_sprite[0].set_active(true); + paddle_sprite[0].set_position(28, 60); + paddle_sprite[0].set_image(8,3,paddle_data); + + paddle_sprite[1].set_active(true); + paddle_sprite[1].set_position(28, 2); + paddle_sprite[1].set_image(8,3,paddle_data); + + player_score[0] = 0; + player_score[1] = 0; + + serving_player = 0; + + number_players = with_number_players; + + reset_round(); + + printf("\n\n\nGAME START\n\n\n"); +} + +void init_attract(void) { + paddle_sprite[0].set_active(false); + paddle_sprite[1].set_active(false); + + ball_sprite.set_position(32,32); + ball_sprite.set_speed(0.5f, 0.5f); + ball_sprite.set_image(1,1,ball_data); + + game_state = game_state_t::Attract; +} + +void render_game(Screen *screen) { + screen->set_flip(false); + + screen->set_background_color(0x00000010); + screen->draw_start(); + + if (game_state == game_state_t::Attract) { + screen->draw_text(32,2,0x00808080,"GAME OVER!"); + screen->draw_text(40,2,0x00808080,"PRESS PLYR"); + screen->draw_text(48,2,0x00808080," 1 OR 2 "); + } + char score[7]; + sprintf(score, "%1d", player_score[1]); + screen->draw_text(0,59,0x00808080,score,number_players==2); + sprintf(score, "%1d", player_score[0]); + screen->draw_text(57,59,0x00808080,score); + + paddle_sprite[0].draw_onto(screen); + paddle_sprite[1].draw_onto(screen); + ball_sprite.draw_onto(screen); + + screen->draw_end(); + + player_controls[0]->refresh_status(); + player_controls[1]->refresh_status(); + player_controls[2]->refresh_status(); + + if (game_state == game_state_t::Attract) { + if (player_controls[2]->is_pressed(button_a)) { + reset_game(1); + } else if (player_controls[2]->is_pressed(button_b)) { + reset_game(2); + } + return; + } else { + for (int player = 0; player < number_players; player++) { + if (player_controls[player]->is_pressed(joystick_left)) { + if (paddle_sprite[player].x_ > 0) { + paddle_sprite[player].x_--; + } + } + + if (player_controls[player]->is_pressed(joystick_right)) { + if (paddle_sprite[player].x_ < 56) { + paddle_sprite[player].x_++; + } + } + } + if (game_state == game_state_t::Serving) { + ball_sprite.x_ = paddle_sprite[serving_player].x_ + 4; + if (player_controls[serving_player]->is_pressed(button_a)) { + game_state = game_state_t::Playing; + } + } + + if (number_players == 1) { + float computer_paddle_x_target = ball_sprite.x_ - 4; + + if (computer_paddle_x_target > paddle_sprite[1].x_) paddle_sprite[1].x_ += 0.8f; + if (computer_paddle_x_target < paddle_sprite[1].x_) paddle_sprite[1].x_ -= 0.8f; + + if (paddle_sprite[1].x_ < 0) { paddle_sprite[1].x_ = 0; } + if (paddle_sprite[1].x_ > 56) { paddle_sprite[1].x_ = 56; } + } + } + + // Move ball + if (game_state != game_state_t::Serving) { + ball_sprite.move_sprite(); + } + + if (ball_sprite.test_collision(paddle_sprite[0], true)) { + ball_sprite.y_ = 59.0f; + ball_sprite.dy_ = -ball_sprite.dy_ * 1.1f; + if (ball_sprite.dy_ < -2.0f) ball_sprite.dy_ = -2.0f; + ball_sprite.dx_ = ball_horizontal_speeds[(int)(ball_sprite.x_ - (paddle_sprite[0].x_ - 1))]; + Mix_PlayChannel(-1, paddle_blip, 0); + } + + if (ball_sprite.test_collision(paddle_sprite[1], true)) { + ball_sprite.y_ = 5.0f; + ball_sprite.dy_ = -ball_sprite.dy_ * 1.1f; + if (ball_sprite.dy_ > 2.0f) ball_sprite.dy_ = 2.0f; + ball_sprite.dx_ = ball_horizontal_speeds[(int)(ball_sprite.x_ - (paddle_sprite[1].x_ - 1))]; + Mix_PlayChannel(-1, paddle_blip, 0); + } + + if (ball_sprite.y_ >= 63.0f) { + if (game_state != game_state_t::Attract) { + player_score[1]++; + if (number_players == 2) { + serving_player = 1; + } else { + serving_player = 0; + } + if (!reset_round()) { + init_attract(); + } + return; + } else { + ball_sprite.dy_ = -ball_sprite.dy_; + ball_sprite.dx_ = ball_horizontal_speeds[rand()%7]; + } + } + + if (ball_sprite.y_ <= 0.0f) { + if (game_state != game_state_t::Attract) { + player_score[0]++; + serving_player = 0; + if (!reset_round()) { + init_attract(); + } + return; + } else { + ball_sprite.dy_ = -ball_sprite.dy_; + ball_sprite.dx_ = ball_horizontal_speeds[rand()%7]; + } + } +} + +static void init_sdl(void) { + if (SDL_Init(SDL_INIT_AUDIO) != 0) { + fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + + int audio_rate = 44100; + Uint16 audio_format = AUDIO_S16SYS; + int audio_channels = 2; + int audio_buffers = 8192; + + if(Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) != 0) { + fprintf(stderr, "Unable to initialize audio: %s\n", Mix_GetError()); + exit(1); + } + + startup_bong = Mix_LoadWAV("bin/startup.wav"); + if (startup_bong == NULL) { + fprintf(stderr, "Unable to load startup.wav: %s\n", Mix_GetError()); + exit(1); + } + + Mix_PlayChannel(-1, startup_bong, 0); +} + +int +main( + int argc, + const char ** argv + ) +{ + int width = 64; + int height = 64; + + ledscape_config_t * config = &ledscape_matrix_default; + if (argc > 1) + { + config = ledscape_config(argv[1]); + if (!config) + return EXIT_FAILURE; + } + + if (config->type == LEDSCAPE_MATRIX) + { + config->matrix_config.width = width; + config->matrix_config.height = height; + } + + ledscape_t * const leds = ledscape_init(config, 0); + + player_controls[0] = new controls_t(1); + player_controls[1] = new controls_t(2, true); + player_controls[2] = new controls_t(3); + + init_attract(); + + printf("init done\n"); + uint32_t * const p = (uint32_t*)calloc(width*height,4); + + Screen *screen = new Screen(leds, p); + + init_sdl(); + + paddle_blip = Mix_LoadWAV("bin/blip2.wav"); + +try { + while (1) + { + render_game(screen); + + usleep(20000); + + } +} +catch (control_exit_exception* ex) { + delete screen; +} + + return EXIT_SUCCESS; +} diff --git a/src/ledgames/png.cc b/src/ledgames/png.cc new file mode 100644 index 00000000..9324043a --- /dev/null +++ b/src/ledgames/png.cc @@ -0,0 +1,74 @@ +#include "png.hh" + +png_t::png_t() { +} + +png_t::~png_t() { +} + +void abort_(const char * s, ...) +{ + va_list args; + va_start(args, s); + vfprintf(stderr, s, args); + fprintf(stderr, "\n"); + va_end(args); + abort(); +} + +void png_t::read_file(std::string filename) { + unsigned char header[8]; // 8 is the maximum size that can be checked + + /* open file and test for it being a png */ + FILE *fp = fopen(filename.c_str(), "rb"); + if (!fp) + abort_("[read_png_file] File %s could not be opened for reading", filename.c_str()); + fread(header, 1, 8, fp); + if (png_sig_cmp(header, 0, 8)) + abort_("[read_png_file] File %s is not recognized as a PNG file", filename.c_str()); + + + /* initialize stuff */ + png_ptr_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!png_ptr_) + abort_("[read_png_file] png_create_read_struct failed"); + + info_ptr_ = png_create_info_struct(png_ptr_); + if (!info_ptr_) + abort_("[read_png_file] png_create_info_struct failed"); + + if (setjmp(png_jmpbuf(png_ptr_))) + abort_("[read_png_file] Error during init_io"); + + png_init_io(png_ptr_, fp); + png_set_sig_bytes(png_ptr_, 8); + + png_read_info(png_ptr_, info_ptr_); + + width_ = png_get_image_width(png_ptr_, info_ptr_); + height_ = png_get_image_height(png_ptr_, info_ptr_); + color_type_ = png_get_color_type(png_ptr_, info_ptr_); + bit_depth_ = png_get_bit_depth(png_ptr_, info_ptr_); + + number_of_passes_ = png_set_interlace_handling(png_ptr_); + png_read_update_info(png_ptr_, info_ptr_); + + + /* read file */ + if (setjmp(png_jmpbuf(png_ptr_))) + abort_("[read_png_file] Error during read_image"); + + row_pointers_ = (png_bytep*) malloc(sizeof(png_bytep) * height_); + for (int y=0; y +#include +#include + +#include + +class png_t { +public: + png_t(); + ~png_t(); + + virtual void read_file(std::string filename); + virtual png_byte* row(uint16_t row_number); + +private: + int width_, height_; + png_byte color_type_; + png_byte bit_depth_; + + png_structp png_ptr_; + png_infop info_ptr_; + int number_of_passes_; + png_bytep * row_pointers_; + +}; diff --git a/src/ledgames/rsrc/Invaders.png b/src/ledgames/rsrc/Invaders.png new file mode 100644 index 00000000..e33a2c09 Binary files /dev/null and b/src/ledgames/rsrc/Invaders.png differ diff --git a/src/ledgames/rsrc/Makefile b/src/ledgames/rsrc/Makefile new file mode 100644 index 00000000..a8ac78f5 --- /dev/null +++ b/src/ledgames/rsrc/Makefile @@ -0,0 +1,26 @@ +BINDIR = ../../../bin/ + +FILES = blip2.wav \ + blip3.wav \ + blip4.wav \ + blip5.wav \ + startup.wav \ + Invaders.png \ + Menus.png \ + invader_explosion.wav \ + ship_explosion.wav \ + invader_march1.wav \ + invader_march2.wav \ + invader_march3.wav \ + invader_march4.wav + + +all: copy + +copy: + cp -f $(FILES) $(BINDIR) + +clean: + rm -rf $(BINDIR)*.wav + rm -rf $(BINDIR)Invaders.png + diff --git a/src/ledgames/rsrc/Menus.png b/src/ledgames/rsrc/Menus.png new file mode 100644 index 00000000..4ac9b292 Binary files /dev/null and b/src/ledgames/rsrc/Menus.png differ diff --git a/src/ledgames/rsrc/blip2.wav b/src/ledgames/rsrc/blip2.wav new file mode 100644 index 00000000..b6340cf3 Binary files /dev/null and b/src/ledgames/rsrc/blip2.wav differ diff --git a/src/ledgames/rsrc/blip3.wav b/src/ledgames/rsrc/blip3.wav new file mode 100644 index 00000000..e10fa081 Binary files /dev/null and b/src/ledgames/rsrc/blip3.wav differ diff --git a/src/ledgames/rsrc/blip4.wav b/src/ledgames/rsrc/blip4.wav new file mode 100644 index 00000000..999b88ae Binary files /dev/null and b/src/ledgames/rsrc/blip4.wav differ diff --git a/src/ledgames/rsrc/blip5.wav b/src/ledgames/rsrc/blip5.wav new file mode 100644 index 00000000..71c4b1f0 Binary files /dev/null and b/src/ledgames/rsrc/blip5.wav differ diff --git a/src/ledgames/rsrc/invader_explosion.wav b/src/ledgames/rsrc/invader_explosion.wav new file mode 100644 index 00000000..b51cfd01 Binary files /dev/null and b/src/ledgames/rsrc/invader_explosion.wav differ diff --git a/src/ledgames/rsrc/invader_march1.wav b/src/ledgames/rsrc/invader_march1.wav new file mode 100644 index 00000000..b96b6075 Binary files /dev/null and b/src/ledgames/rsrc/invader_march1.wav differ diff --git a/src/ledgames/rsrc/invader_march2.wav b/src/ledgames/rsrc/invader_march2.wav new file mode 100644 index 00000000..86ac5a09 Binary files /dev/null and b/src/ledgames/rsrc/invader_march2.wav differ diff --git a/src/ledgames/rsrc/invader_march3.wav b/src/ledgames/rsrc/invader_march3.wav new file mode 100644 index 00000000..f1c87e3c Binary files /dev/null and b/src/ledgames/rsrc/invader_march3.wav differ diff --git a/src/ledgames/rsrc/invader_march4.wav b/src/ledgames/rsrc/invader_march4.wav new file mode 100644 index 00000000..a0bb3dda Binary files /dev/null and b/src/ledgames/rsrc/invader_march4.wav differ diff --git a/src/ledgames/rsrc/ship_explosion.wav b/src/ledgames/rsrc/ship_explosion.wav new file mode 100644 index 00000000..e57cea9f Binary files /dev/null and b/src/ledgames/rsrc/ship_explosion.wav differ diff --git a/src/ledgames/rsrc/startup.wav b/src/ledgames/rsrc/startup.wav new file mode 100644 index 00000000..1b39a7db Binary files /dev/null and b/src/ledgames/rsrc/startup.wav differ diff --git a/src/ledgames/screen.cc b/src/ledgames/screen.cc new file mode 100644 index 00000000..9a5f7e19 --- /dev/null +++ b/src/ledgames/screen.cc @@ -0,0 +1,87 @@ +#include +#include "screen.hh" + +extern const uint8_t fixed_font[][5]; + +Screen::Screen(ledscape_t * const leds, uint32_t *pixels): +pixels_(pixels), +leds_(leds), +flip_(false) +{ + set_background_color(0x00000000); + draw_start(); + ledscape_printf(&pixels_[9], 64, 0x00401010, "LedGames\n Engine"); + ledscape_printf(&pixels_[64*32 + 17], 64, 0x00101040, "Keith"); + ledscape_printf(&pixels_[64*40 + 2], 64, 0x00101040, "Henrickson"); + draw_end(); + sleep(1); +} + +Screen::~Screen() +{ + set_background_color(0x00000000); + draw_start(); + draw_end(); + sleep(1); +} + +void Screen::drawpixel(uint32_t x, uint32_t y, uint32_t color) { + if ((x > 63) || (y > 63)) { + return; + } + uint32_t pixelnum = ((flip_ ? (63 - y) : y) * 64) + (flip_ ? (63 - x ) : x); + pixels_[pixelnum] = color; +} + +void Screen::set_background_color(uint32_t color) { + background_color_ = color; +} + +void Screen::draw_char(uint32_t row, uint32_t column, const uint32_t color, char c, bool flip) { + if (c < 0x20 || c > 127) + c = '?'; + + const uint8_t* const f = fixed_font[c - 0x20]; + for (int x = 0 ; x < 5 ; x++) { + uint8_t bits = f[x]; + for (int y = 0 ; y < 7 ; y++, bits >>= 1) { + if (flip) { + drawpixel((4-x) + column, (6-y) + row, (bits & 1) ? color : 0); + } else { + drawpixel(x + column, y + row, (bits & 1) ? color : 0); + } + } + } +} + +void Screen::draw_text(uint32_t row, uint32_t column, uint32_t color, std::string output, bool flip) { + if (flip) { + column += (output.length() - 1) * 6; + } + for (unsigned i = 0 ; i < output.length() ; i++) { + char c = output[i]; + if (!c) + break; + + draw_char(row, column, color, c, flip); + if (flip) { + column -= 6; + } else { + column += 6; + } + } +} + +void Screen::draw_start(void) { + for (int counter = 0; counter < (64*64); counter++) { + pixels_[counter] = background_color_; + } +} + +void Screen::draw_end(void) { + ledscape_draw(leds_, pixels_); +} + +void Screen::set_flip(bool do_flip) { + flip_ = do_flip; +} diff --git a/src/ledgames/screen.hh b/src/ledgames/screen.hh new file mode 100644 index 00000000..f5465642 --- /dev/null +++ b/src/ledgames/screen.hh @@ -0,0 +1,27 @@ +#pragma once +#include +#include + +#include "ledscape.h" + +class Screen { +public: + Screen(ledscape_t * const leds, uint32_t *pixels); + ~Screen(); + + void drawpixel(uint32_t x, uint32_t y, uint32_t color); + void set_background_color(uint32_t color); + void draw_start(void); + void draw_end(void); + void draw_text(uint32_t row, uint32_t column, uint32_t color, std::string output, bool flip = false); + void set_flip(bool do_flip); + +private: + void draw_char(uint32_t row, uint32_t column, const uint32_t color, char c, bool flip); + + uint32_t *pixels_; + ledscape_t * const leds_; + bool flip_; + + uint32_t background_color_; +}; diff --git a/src/ledgames/ship_sprite.cc b/src/ledgames/ship_sprite.cc new file mode 100644 index 00000000..1a252eee --- /dev/null +++ b/src/ledgames/ship_sprite.cc @@ -0,0 +1,48 @@ +#include "ship_sprite.hh" + +ship_sprite_t::ship_sprite_t() : +sprite_t(), +frames_in_anim(0) +{ +} + +void ship_sprite_t::draw_onto(Screen *screen) { + if (frame_ == 0) { + frames_in_anim++; + if (frames_in_anim > 3) { + frames_in_anim = 0; + frame_ = 1; + } + } else if (frame_ == 1) { + frames_in_anim++; + if (frames_in_anim > 3) { + frames_in_anim = 0; + frame_ = 0; + } + } else if (frame_ == 2) { + frames_in_anim++; + if (frames_in_anim > 3) { + frames_in_anim = 0; + frame_ = 3; + } + } else if (frame_ == 3) { + frames_in_anim++; + if (frames_in_anim > 3) { + frames_in_anim = 0; + explode_anims++; + if (explode_anims > 10) { + set_active(false); + frame_ = 0; + } else { + frame_ = 2; + } + } + } + sprite_t::draw_onto(screen); +} + +void ship_sprite_t::destroy_sprite(void) { + frame_ = 2; + frames_in_anim = 0; + explode_anims = 0; +} \ No newline at end of file diff --git a/src/ledgames/ship_sprite.hh b/src/ledgames/ship_sprite.hh new file mode 100644 index 00000000..7a5ae358 --- /dev/null +++ b/src/ledgames/ship_sprite.hh @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +#include "sprite.hh" + +class ship_sprite_t : public sprite_t { +public: + ship_sprite_t(); + + virtual void draw_onto(Screen *screen) override; + virtual void destroy_sprite(void); + +private: + uint32_t frames_in_anim; + uint32_t explode_anims; +}; diff --git a/src/ledgames/sprite.cc b/src/ledgames/sprite.cc new file mode 100644 index 00000000..cf9ee7f5 --- /dev/null +++ b/src/ledgames/sprite.cc @@ -0,0 +1,116 @@ +#include "sprite.hh" + +sprite_t::sprite_t() : +x_(0), +y_(0), +dx_(0), +dy_(0), +frame_(0), +active_(true) +{ +} + +sprite_t::~sprite_t() { +} + +bool sprite_t::is_active(void) const { + return active_; +} + +void sprite_t::set_active(bool active) { + active_ = active; +} + +void sprite_t::set_position(float x, float y) { + x_ = x; + y_ = y; +} + +void sprite_t::set_speed(float dx, float dy) { + dx_ = dx; + dy_ = dy; +} + +void sprite_t::move_sprite(void) { + x_ += dx_; + y_ += dy_; +} + +void sprite_t::set_image(uint8_t width, uint8_t height, uint32_t *pixels, uint8_t anim_frame) { + sprite_data_[anim_frame].resize(width * height); + sprite_data_[anim_frame].assign(pixels, pixels+(width * height)); + + width_ = width; + height_ = height; +} + +void sprite_t::set_image(uint16_t x_offset, uint16_t y_offset, uint8_t width, uint8_t height, png_t *png_image, uint8_t anim_frame) { + sprite_data_[anim_frame].resize(width * height); + + width_ = width; + height_ = height; + + for (uint8_t y = 0; y < height; y++) { + png_byte* row = png_image->row(y + y_offset); + for (uint8_t x = 0; x < width; x++) { + uint8_t *sprite_pixel = (uint8_t*)&(sprite_data_[anim_frame][x + (y * width)]); + uint8_t *png_pixel = (uint8_t*)&(row[(x + x_offset) * 4]); + sprite_pixel[0] = png_pixel[2]; + sprite_pixel[1] = png_pixel[1]; + sprite_pixel[2] = png_pixel[0]; + } + } +} + +void sprite_t::draw_onto(Screen *screen) { + if (!active_) return; + + for (uint8_t pixel_y = 0; pixel_y < height_; pixel_y++) { + for (uint8_t pixel_x = 0; pixel_x < width_; pixel_x++) { + uint32_t color_value = sprite_data_[frame_][(pixel_y * width_) + pixel_x]; + if (color_value != 0) { + screen->drawpixel(pixel_x + x_, pixel_y + y_, color_value); + } + } + } +} + +bool sprite_t::test_collision(const sprite_t &other_sprite, bool fast) { + if (!active_) return false; + if (!other_sprite.is_active()) return false; + + if (fast) { + uint8_t visible_x = x_; + uint8_t visible_y = y_; + uint8_t other_visible_x = other_sprite.x_; + uint8_t other_visible_y = other_sprite.y_; + + return !((visible_x + width_ - 1) < other_visible_x || (visible_y + height_ - 1) < (other_visible_y) || + x_ > (other_visible_x + other_sprite.width_ - 1) || + y_ > (other_visible_y + other_sprite.height_ - 1) ); + } + + uint8_t top = std::max(y_, other_sprite.y_); + uint8_t bottom = std::min(y_+height_, other_sprite.y_ + other_sprite.height_); + uint8_t left = std::max(x_, other_sprite.x_); + uint8_t right = std::min(x_+width_, other_sprite.x_ + other_sprite.width_); + + for (uint8_t y = top ; y < bottom; y++) { + for (uint8_t x = left; x < right; x++) { + uint32_t this_color = sprite_data_[frame_][(x - x_) + (y - y_) * width_]; + uint32_t other_color = other_sprite.sprite_data_[other_sprite.frame_][(x - other_sprite.x_) + (y - other_sprite.y_) * other_sprite.width_]; + if ((this_color != 0x00000000) && (other_color != 0x00000000)) { + return true; + } + } + } + return false; +} + +float sprite_t::get_x_position(void) { + return x_; +} + +float sprite_t::get_y_position(void) { + return y_; +} diff --git a/src/ledgames/sprite.hh b/src/ledgames/sprite.hh new file mode 100644 index 00000000..6f921ad1 --- /dev/null +++ b/src/ledgames/sprite.hh @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +#include "screen.hh" +#include "png.hh" + +class sprite_t { +public: + sprite_t(); + ~sprite_t(); + + virtual void set_position(float x, float y); + virtual void set_speed(float dx, float dy); + virtual void move_sprite(void); + virtual void set_image(uint8_t width, uint8_t height, uint32_t *pixels, uint8_t anim_frame = 0); + virtual void set_image(uint16_t x_offset, uint16_t y_offset, uint8_t width, uint8_t height, png_t *png_image, uint8_t anim_frame = 0); + virtual void draw_onto(Screen *screen); + virtual void set_active(bool active); + virtual bool is_active(void) const; + virtual bool test_collision(const sprite_t &other_sprite, bool fast); + virtual float get_x_position(void); + virtual float get_y_position(void); + + float x_; + float y_; + float dx_; + float dy_; + + uint8_t width_; + uint8_t height_; + uint8_t frame_; + + bool active_; + + std::vector sprite_data_[4]; +}; diff --git a/src/ledgames/white.c b/src/ledgames/white.c new file mode 100644 index 00000000..27f0b1c6 --- /dev/null +++ b/src/ledgames/white.c @@ -0,0 +1,82 @@ +/** \file + * Test the matrix LCD PRU firmware with a multi-hue rainbow. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ledscape.h" + +void drawpixel(uint32_t *pixels, uint8_t x, uint8_t y, uint32_t color, uint8_t flip) { + uint32_t pixelnum = ((flip ? (64 - y) : y) * 64) + (flip ? (64 - x ) : x); + pixels[pixelnum] = color; +} + +void render_game(uint32_t *pixels) { + for (int y_clear = 0; y_clear < 64; y_clear++) { + for (int x_clear = 0; x_clear < 64; x_clear++) { + drawpixel(pixels, x_clear, y_clear, 0xffffffff, 0); + } + } +} + +int +main( + int argc, + const char ** argv +) +{ + int width = 64; + int height = 64; + + ledscape_config_t * config = &ledscape_matrix_default; + if (argc > 1) + { + config = ledscape_config(argv[1]); + if (!config) + return EXIT_FAILURE; + } + + if (config->type == LEDSCAPE_MATRIX) + { + config->matrix_config.width = width; + config->matrix_config.height = height; + } + + ledscape_t * const leds = ledscape_init(config, 0); + + printf("init done\n"); + time_t last_time = time(NULL); + unsigned last_i = 0; + + unsigned i = 0; + uint32_t * const p = calloc(width*height,4); + + render_game(p); + + i++; + ledscape_draw(leds, p); + + usleep(20000); + + // wait for the previous frame to finish; + //const uint32_t response = ledscape_wait(leds); + const uint32_t response = 0; + time_t now = time(NULL); + if (now != last_time) + { + printf("%d fps. starting %d previous %"PRIx32"\n", + i - last_i, i, response); + last_i = i; + last_time = now; + } + + + ledscape_close(leds); + + return EXIT_SUCCESS; +} diff --git a/src/ledscape/Makefile b/src/ledscape/Makefile new file mode 100755 index 00000000..b9a7a0b6 --- /dev/null +++ b/src/ledscape/Makefile @@ -0,0 +1,19 @@ +######### +# +# Build the PRU and LEDscape libraries as well as the PRU firmware. +# +# +TARGETS-y += $(LIBDIR)/matrix.bin +TARGETS-y += $(LIBDIR)/ws281x.bin + +LIB-y += libledscape.a + +libledscape.srcs += \ + ledscape.c \ + pru.c \ + util.c \ + config.c \ + fixed-font.c \ + +include ../../Makefile.common + diff --git a/src/ledscape/bitpattern.h b/src/ledscape/bitpattern.h new file mode 100644 index 00000000..b4b9d0d8 --- /dev/null +++ b/src/ledscape/bitpattern.h @@ -0,0 +1,133 @@ +/** \file + * ASCII art for bits. + */ +#pragma once + +#define ________ 0x00 // 0 +#define _______X 0x01 // 1 +#define ______X_ 0x02 // 2 +#define ______XX 0x03 // 3 +#define _____X__ 0x04 // 4 +#define _____X_X 0x05 // 5 +#define _____XX_ 0x06 // 6 +#define _____XXX 0x07 // 7 +#define ____X___ 0x08 // 8 +#define ____X__X 0x09 // 9 +#define ____X_X_ 0x0a // 10 +#define ____X_XX 0x0b // 11 +#define ____XX__ 0x0c // 12 +#define ____XX_X 0x0d // 13 +#define ____XXX_ 0x0e // 14 +#define ____XXXX 0x0f // 15 +#define ___X____ 0x10 // 16 +#define ___X___X 0x11 // 17 +#define ___X__X_ 0x12 // 18 +#define ___X__XX 0x13 // 19 +#define ___X_X__ 0x14 // 20 +#define ___X_X_X 0x15 // 21 +#define ___X_XX_ 0x16 // 22 +#define ___X_XXX 0x17 // 23 +#define ___XX___ 0x18 // 24 +#define ___XX__X 0x19 // 25 +#define ___XX_X_ 0x1a // 26 +#define ___XX_XX 0x1b // 27 +#define ___XXX__ 0x1c // 28 +#define ___XXX_X 0x1d // 29 +#define ___XXXX_ 0x1e // 30 +#define ___XXXXX 0x1f // 31 +#define __X_____ 0x20 // 32 +#define __X____X 0x21 // 33 +#define __X___X_ 0x22 // 34 +#define __X___XX 0x23 // 35 +#define __X__X__ 0x24 // 36 +#define __X__X_X 0x25 // 37 +#define __X__XX_ 0x26 // 38 +#define __X__XXX 0x27 // 39 +#define __X_X___ 0x28 // 40 +#define __X_X__X 0x29 // 41 +#define __X_X_X_ 0x2a // 42 +#define __X_X_XX 0x2b // 43 +#define __X_XX__ 0x2c // 44 +#define __X_XX_X 0x2d // 45 +#define __X_XXX_ 0x2e // 46 +#define __X_XXXX 0x2f // 47 +#define __XX____ 0x30 // 48 +#define __XX___X 0x31 // 49 +#define __XX__X_ 0x32 // 50 +#define __XX__XX 0x33 // 51 +#define __XX_X__ 0x34 // 52 +#define __XX_X_X 0x35 // 53 +#define __XX_XX_ 0x36 // 54 +#define __XX_XXX 0x37 // 55 +#define __XXX___ 0x38 // 56 +#define __XXX__X 0x39 // 57 +#define __XXX_X_ 0x3a // 58 +#define __XXX_XX 0x3b // 59 +#define __XXXX__ 0x3c // 60 +#define __XXXX_X 0x3d // 61 +#define __XXXXX_ 0x3e // 62 +#define __XXXXXX 0x3f // 63 +#define _X______ 0x40 // 64 +#define _X_____X 0x41 // 65 +#define _X____X_ 0x42 // 66 +#define _X____XX 0x43 // 67 +#define _X___X__ 0x44 // 68 +#define _X___X_X 0x45 // 69 +#define _X___XX_ 0x46 // 70 +#define _X___XXX 0x47 // 71 +#define _X__X___ 0x48 // 72 +#define _X__X__X 0x49 // 73 +#define _X__X_X_ 0x4a // 74 +#define _X__X_XX 0x4b // 75 +#define _X__XX__ 0x4c // 76 +#define _X__XX_X 0x4d // 77 +#define _X__XXX_ 0x4e // 78 +#define _X__XXXX 0x4f // 79 +#define _X_X____ 0x50 // 80 +#define _X_X___X 0x51 // 81 +#define _X_X__X_ 0x52 // 82 +#define _X_X__XX 0x53 // 83 +#define _X_X_X__ 0x54 // 84 +#define _X_X_X_X 0x55 // 85 +#define _X_X_XX_ 0x56 // 86 +#define _X_X_XXX 0x57 // 87 +#define _X_XX___ 0x58 // 88 +#define _X_XX__X 0x59 // 89 +#define _X_XX_X_ 0x5a // 90 +#define _X_XX_XX 0x5b // 91 +#define _X_XXX__ 0x5c // 92 +#define _X_XXX_X 0x5d // 93 +#define _X_XXXX_ 0x5e // 94 +#define _X_XXXXX 0x5f // 95 +#define _XX_____ 0x60 // 96 +#define _XX____X 0x61 // 97 +#define _XX___X_ 0x62 // 98 +#define _XX___XX 0x63 // 99 +#define _XX__X__ 0x64 // 100 +#define _XX__X_X 0x65 // 101 +#define _XX__XX_ 0x66 // 102 +#define _XX__XXX 0x67 // 103 +#define _XX_X___ 0x68 // 104 +#define _XX_X__X 0x69 // 105 +#define _XX_X_X_ 0x6a // 106 +#define _XX_X_XX 0x6b // 107 +#define _XX_XX__ 0x6c // 108 +#define _XX_XX_X 0x6d // 109 +#define _XX_XXX_ 0x6e // 110 +#define _XX_XXXX 0x6f // 111 +#define _XXX____ 0x70 // 112 +#define _XXX___X 0x71 // 113 +#define _XXX__X_ 0x72 // 114 +#define _XXX__XX 0x73 // 115 +#define _XXX_X__ 0x74 // 116 +#define _XXX_X_X 0x75 // 117 +#define _XXX_XX_ 0x76 // 118 +#define _XXX_XXX 0x77 // 119 +#define _XXXX___ 0x78 // 120 +#define _XXXX__X 0x79 // 121 +#define _XXXX_X_ 0x7a // 122 +#define _XXXX_XX 0x7b // 123 +#define _XXXXX__ 0x7c // 124 +#define _XXXXX_X 0x7d // 125 +#define _XXXXXX_ 0x7e // 126 +#define _XXXXXXX 0x7f // 127 diff --git a/src/ledscape/config.c b/src/ledscape/config.c new file mode 100644 index 00000000..40bf978a --- /dev/null +++ b/src/ledscape/config.c @@ -0,0 +1,174 @@ +/** \file + * Parse a matrix config file. + */ +#include +#include +#include +#include +#include "ledscape.h" + + +// find the end of the line and strip the whitespace +static ssize_t +readline( + FILE * const file, + char * const buf, + const int max_len +) +{ + if (!fgets(buf, max_len, file)) + return -1; + int len = strlen(buf); + if (len >= max_len) + { + buf[max_len-1] = '\0'; + return max_len; + } + + while (len > 0) + { + const char c = buf[len-1]; + if (!isspace(c)) + break; + // strip the whitespace + buf[--len] = '\0'; + } + + printf("read %d bytes '%s'\n", len, buf); + return len; +} + + +ledscape_config_t * +ledscape_matrix_config( + const char * const filename, + FILE * const file +) +{ + ledscape_config_t * const config_union + = calloc(1, sizeof(*config_union)); + if (!config_union) + return NULL; + ledscape_matrix_config_t * const config = &config_union->matrix_config; + + config->type = LEDSCAPE_MATRIX; + config->panel_width = 32; + config->panel_height = 16; + config->leds_width = 256; + config->leds_height = 128; + + char line[1024]; + int line_num = 1; + + while (1) + { + line_num++; + if (readline(file, line, sizeof(line)) < 0) + break; + + int output, panel, x, y; + char orient; + if (sscanf(line, "%d,%d %c %d,%d", &output, &panel, &orient, &x, &y) != 5) + goto fail; + if (output > LEDSCAPE_MATRIX_OUTPUTS) + goto fail; + if (panel > LEDSCAPE_MATRIX_PANELS) + goto fail; + if (x < 0 || y < 0) + goto fail; + + ledscape_matrix_panel_t * const pconfig + = &config->panels[output][panel]; + + pconfig->x = x; + pconfig->y = y; + + switch (orient) + { + case 'N': pconfig->rot = 0; break; + case 'L': pconfig->rot = 1; break; + case 'R': pconfig->rot = 2; break; + case 'U': pconfig->rot = 3; break; + default: goto fail; + } + } + + fclose(file); + return config_union; + +fail: + fprintf(stderr, "%s: read or parse error on line %d\n", filename, line_num); + fclose(file); + free(config); + return NULL; +} + + +ledscape_config_t * +ledscape_strip_config( + const char * const filename, + FILE * const file +) +{ + ledscape_config_t * const config_union + = calloc(1, sizeof(*config_union)); + if (!config_union) + return NULL; + ledscape_strip_config_t * const config = &config_union->strip_config; + + config->type = LEDSCAPE_STRIP; + + char line[1024]; + int line_num = 2; + + if (readline(file, line, sizeof(line)) < 0) + goto fail; + + // maybe do this better to handle mappings + int width, height; + if (sscanf(line, "%d,%d", &width, &height) != 2) + goto fail; + config->leds_width = width; + config->leds_height = height; + + printf("strips: %d,%d\n", width, height); + return config_union; + +fail: + fprintf(stderr, "%s: line %d: parse error\n", filename, line_num); + free(config_union); + return NULL; +} + + +ledscape_config_t * +ledscape_config( + const char * filename +) +{ + FILE * const file = fopen(filename, "r"); + if (!file) + { + fprintf(stderr, "%s: unable to open\n", filename); + return NULL; + } + + char line[1024]; + + if (readline(file, line, sizeof(line)) < 0) + goto fail; + + if (strcmp(line, "matrix16") == 0) + return ledscape_matrix_config(filename, file); + if (strcmp(line, "ws2812") == 0) + return ledscape_strip_config(filename, file); + + fprintf(stderr, "%s: unknown output type '%s'\n", filename, line); + fclose(file); + return NULL; + +fail: + fclose(file); + return NULL; +} + diff --git a/src/ledscape/fixed-font.c b/src/ledscape/fixed-font.c new file mode 100644 index 00000000..0577a673 --- /dev/null +++ b/src/ledscape/fixed-font.c @@ -0,0 +1,866 @@ +/** \file + * Font is encoded as 5 vertical stripes, 7 bits per stripe. + * Array is in ASCII order, with an offset of 0x20 (' '). + * Look at them sideways. + */ +#include +#include "bitpattern.h" + +const uint8_t fixed_font[][5] = { + // Space + { + ________, + ________, + ________, + ________, + ________, + }, + // ! + { + ________, + ________, + _X_XXXXX, + ________, + ________, + }, + // " + { + ________, + ______XX, + ________, + ______XX, + ________, + }, + // # + { + ___X__X_, + __XXXXXX, + ___X__X_, + __XXXXXX, + ___X__X_, + }, + // $ + { + _____X__, + __X_X_X_, + _XXXXXXX, + __X_X_X_, + ___X____, + }, + // % + { + __X___X_, + ___X_X_X, + __X_X_X_, + _X_X_X__, + __X___X_, + }, + // & + { + __XX_XX_, + _X__X__X, + _X_X___X, + __X___X_, + _X_X____, + }, + // ' + { + ________, + ________, + ______XX, + ________, + ________, + }, + // ( + { + ________, + ___XXX__, + __X___X_, + _X_____X, + ________, + }, + // ( + { + ________, + _X_____X, + __X___X_, + ___XXX__, + ________, + }, + // * + { + _____X__, + ___X_X__, + ____XXXX, + ___X_X__, + _____X__, + }, + // + + { + ____X___, + ____X___, + __XXXXX_, + ____X___, + ____X___, + }, + // ' (not sure) + { + ________, + ________, + ______X_, + _______X, + ________, + }, + // - + { + ____X___, + ____X___, + ____X___, + ____X___, + ____X___, + }, + // . + { + ________, + ________, + _X______, + ________, + ________, + }, + // / + { + __X_____, + ___X____, + ____X___, + _____X__, + ______X_, + }, + + // 0 + { + __XXXXX_, + _X_____X, + _X_____X, + _X_____X, + __XXXXX_, + }, + // 1 + { + ________, + _X____X_, + _XXXXXXX, + _X______, + ________, + }, + // 2 + { + _XX___X_, + _X_X___X, + _X__X__X, + _X__X__X, + _X___XX_, + }, + // 3 + { + __X___X_, + _X_____X, + _X__X__X, + _X__X__X, + __XX_XX_, + }, + // 4 + { + _____XXX, + ____X___, + ____X___, + _XXXXXXX, + ____X___, + }, + // 5 + { + __X_XXXX, + _X__X__X, + _X__X__X, + _X__X__X, + __XX___X, + }, + // 6 + { + __XXXXX_, + _X__X__X, + _X__X__X, + _X__X__X, + __XX__X_, + }, + // 7 + { + _X_____X, + __X____X, + ___X___X, + ____X__X, + _____XXX, + }, + // 8 + { + __XX_XX_, + _X__X__X, + _X__X__X, + _X__X__X, + __XX_XX_, + }, + // 9 + { + _____XX_, + ____X__X, + ____X__X, + ____X__X, + _XXXXXX_, + }, + + // : + { + ________, + ________, + __XX_XX_, + ________, + ________, + }, + // ; + { + ________, + _X______, + __XX_XX_, + ________, + ________, + }, + // < + { + ____X___, + ___X_X__, + __X___X_, + _X_____X, + ________, + }, + // = + { + ___X_X__, + ___X_X__, + ___X_X__, + ___X_X__, + ___X_X__, + }, + // > + { + ________, + _X_____X, + __X___X_, + ___X_X__, + ____X___, + }, + // ? + { + _____XX_, + _______X, + _X_X___X, + ____X__X, + _____XX_, + }, + // @ + { + __XXXXX_, + _X_____X, + _X__X__X, + _X_X_X_X, + ____X_X_, + }, + + // A + { + _XXXXX__, + ____X_X_, + ____X__X, + ____X_X_, + _XXXXX__, + }, + // B + { + _XXXXXXX, + _X__X__X, + _X__X__X, + _X__X__X, + __XX_XX_, + }, + // C + { + __XXXXX_, + _X_____X, + _X_____X, + _X_____X, + __X___X_, + }, + // D + { + _XXXXXXX, + _X_____X, + _X_____X, + _X_____X, + __XXXXX_, + }, + // E + { + _XXXXXXX, + _X__X__X, + _X__X__X, + _X__X__X, + _X_____X, + }, + // F + { + _XXXXXXX, + ____X__X, + ____X__X, + ____X__X, + _______X, + }, + // G + { + __XXXXX_, + _X_____X, + _X__X__X, + _X__X__X, + __XX__X_, + }, + // H + { + _XXXXXXX, + ____X___, + ____X___, + ____X___, + _XXXXXXX, + }, + // I was 65,65,127,65,65, + { + ________, + _X_____X, + _XXXXXXX, + _X_____X, + ________, + }, + // J + { + __X_____, + _X______, + _X_____X, + __XXXXXX, + _______X, + }, + // K + { + _XXXXXXX, + ____X___, + ___X_X__, + __X___X_, + _X_____X, + }, + // L + { + _XXXXXXX, + _X______, + _X______, + _X______, + _X______, + }, + // M + { + _XXXXXXX, + ______X_, + _____X__, + ______X_, + _XXXXXXX, + }, + // N + { + _XXXXXXX, + _____X__, + ____X___, + ___X____, + _XXXXXXX, + }, + // O + { + __XXXXX_, + _X_____X, + _X_____X, + _X_____X, + __XXXXX_, + }, + // P + { + _XXXXXXX, + ____X__X, + ____X__X, + ____X__X, + _____XX_, + }, + // Q + { + __XXXXX_, + _X_____X, + _X_X___X, + __X____X, + _X_XXXX_, + }, + // R + { + _XXXXXXX, + ____X__X, + ___XX__X, + __X_X__X, + _X___XX_, + }, + // S + { + __X__XX_, + _X__X__X, + _X__X__X, + _X__X__X, + __XX__X_, + }, + // T + { + _______X, + _______X, + _XXXXXXX, + _______X, + _______X, + }, + // U + { + __XXXXXX, + _X______, + _X______, + _X______, + __XXXXXX, + }, + // V + { + ___XXXXX, + __X_____, + _X______, + __X_____, + ___XXXXX, + }, + // W + { + __XXXXXX, + _X______, + __XX____, + _X______, + __XXXXXX, + }, + // X + { + _XX___XX, + ___X_X__, + ____X___, + ___X_X__, + _XX___XX, + }, + // Y + { + ______XX, + _____X__, + _XXXX___, + _____X__, + ______XX, + }, + // Z + { + _XX____X, + _X_X___X, + _X__X__X, + _X___X_X, + _X____XX, + }, + + // [ + { + ________, + _XXXXXXX, + _X_____X, + _X_____X, + ________, + }, + // back slash + { + ______X_, + _____X__, + ____X___, + ___X____, + __X_____, + }, + // ] + { + ________, + _X_____X, + _X_____X, + _XXXXXXX, + ________, + }, + // ^ + { + ________, + ______X_, + _______X, + ______X_, + ________, + }, + // _ + { + ____X___, + ____X___, + ____X___, + ____X___, + ____X___, + }, + // ` + { + ________, + ________, + _______X, + ______X_, + ________, + }, + + // a + { + _XXX____, + _X__X___, + _X__X___, + __X_X___, + _XXXX___, + }, + // b + { + _XXXXXX_, + __XX____, + _X__X___, + _X__X___, + __XX____, + }, + // c + { + __XX____, + _X__X___, + _X__X___, + _X__X___, + _X__X___, + }, + // d + { + __XX____, + _X__X___, + _X__X___, + __XX____, + _XXXXXX_, + }, + // e + { + __XXX___, + _X_X_X__, + _X_X_X__, + _X_X_X__, + _X_XX___, + }, + // f + { + ________, + ____X___, + _XXXXX__, + ____X_X_, + ________, + }, + // g + { + __X__X__, + _X__X_X_, + _X__X_X_, + _X__X_X_, + __XXXX__, + }, + // h + { + _XXXXXX_, + ____X___, + ____X___, + ____X___, + _XXX____, + }, + // i + { + ________, + ________, + _XXXX_X_, + ________, + ________, + }, + // j + { + __X_____, + _X______, + _X____X_, + __XXXXX_, + ______X_, + }, + // k + { + _XXXXX__, + ___X____, + ___X____, + __X_X___, + _X___X__, + }, + // l + { + ________, + _XXXXX__, + _X______, + _X______, + ________, + }, + // m + { + _XXXX___, + _____X__, + _XXXX___, + _____X__, + _XXXX___, + }, + // n + { + _XXXXX__, + ____X___, + _____X__, + _____X__, + _XXXX___, + }, + // o + { + __XX____, + _X__X___, + _X__X___, + _X__X___, + __XX____, + }, + // p + { + _XXXXXX_, + ___X__X_, + ___X__X_, + ___X__X_, + ____XX__, + }, + // q + { + ____XX__, + ___X__X_, + ___X__X_, + ___X__X_, + _XXXXX__, + }, + // r + { + _XXXXX__, + ____X___, + _____X__, + _____X__, + ____X___, + }, + // s + { + _X__X___, + _X_X_X__, + _X_X_X__, + _X_X_X__, + __X__X__, + }, + // t + { + _____X__, + _____X__, + _XXXXXX_, + _____X__, + _____X__, + }, + // u + { + __XXXX__, + _X______, + _X______, + _X______, + __XXXX__, + }, + // v + { + ___XXX__, + __X_____, + _X______, + __X_____, + ___XXX__, + }, + // w + { + _XXXXX__, + __X_____, + ___X____, + __X_____, + _XXXXX__, + }, + // x + { + _X___X__, + __X_X___, + ___X____, + __X_X___, + _X___X__, + }, + // y + { + _____X__, + ____X___, + _XXX____, + ____X___, + _____X__, + }, + // z + { + _X___X__, + _XX__X__, + _X_X_X__, + _X__XX__, + _X___X__, + }, + + // { + { + ________, + ____X___, + __XX_XX_, + _X_____X, + ________, + }, + // | + { + ________, + ________, + _XXXXXXX, + ________, + ________, + }, + // } + { + ________, + _X_____X, + __XX_XX_, + ____X___, + ________, + }, + // ~ + { + ___X____, + ____X___, + ___XX___, + ___X____, + ____X___, + }, + + // Small Numbers (for adding colon in clock applications) + // 0 + { + ________, + __XXXXX_, + __X___X_, + __XXXXX_, + ________, + }, + // 1 + { + ________, + ________, + __XXXXX_, + ________, + ________, + }, + // 2 + { + ________, + __XXX_X_, + __X_X_X_, + __X_XXX_, + ________, + }, + // 3 + { + ________, + __X_X_X_, + __X_X_X_, + __XXXXX_, + ________, + }, + // 4 + { + ________, + ____XXX_, + ____X___, + __XXXXX_, + ________, + }, + // 5 + { + ________, + __X_XXX_, + __X_X_X_, + __XXX_X_, + ________, + }, + // 6 + { + ________, + __XXXXX_, + __X_X_X_, + __XXX_X_, + ________, + }, + // 7 + { + ________, + ______X_, + ______X_, + __XXXXX_, + ________, + }, + // 8 + { + ________, + __XXXXX_, + __X_X_X_, + __XXXXX_, + ________, + }, + // 9 + { + ________, + ____XXX_, + ____X_X_, + __XXXXX_, + ________, + }, + // : + { + ________, + ________, + ___X_X__, + ________, + ________, + }, +}; diff --git a/src/ledscape/ledscape.c b/src/ledscape/ledscape.c new file mode 100644 index 00000000..90fec067 --- /dev/null +++ b/src/ledscape/ledscape.c @@ -0,0 +1,675 @@ +/** \file + * Userspace interface to the WS281x LED strip driver. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ledscape.h" +#include "pru.h" + +#define CONFIG_LED_MATRIX + + +/** GPIO pins used by the LEDscape. + * + * The device tree should handle this configuration for us, but it + * seems horribly broken and won't configure these pins as outputs. + * So instead we have to repeat them here as well. + * + * If these are changed, be sure to check the mappings in + * ws281x.p! + * + * The RGB matrix uses a subset of these pins, although with + * the HDMI disabled it might use quite a few more for the four + * output version. + * + * \todo: Find a way to unify this with the defines in the .p file + */ +static const uint8_t gpios_output1[] = { + 2,2,2,3,2,5,0,23,2,4,0,26 +}; + +static const uint8_t gpios_output2[] = { + 0,27,2,1,0,22,2,22,2,23,2,24 +}; + +static const uint8_t gpios_output3[] = { + 0,30,1,18,0,31,1,16,0,3,0,5 +}; + +static const uint8_t gpios_output4[] = { + 0,2,0,15,1,17,3,21,3,19,0,4,1,19 +}; + +static const uint8_t gpios_output5[] = { + 2,25,0,11,0,10,0,9,0,8,2,17 +}; + +static const uint8_t gpios_output6[] = { + 2,16,2,15,2,14,2,13,2,10,2,12 +}; + +static const uint8_t gpios_output7[] = { + 2,11,2,9,2,8,2,6,0,7,2,7 +}; + +static const uint8_t gpios_output8[] = { + 3,17,3,16,3,15,3,14,0,14,0,20 +}; + +static const uint8_t gpios_output_all[] = { + 1,12,1,13,1,14,1,15,1,28,1,29,1,19 +}; + +#define ARRAY_COUNT(a) ((sizeof(a) / sizeof(*a))) + + +/* + * Configure all of our output pins. + * These must have also been set by the device tree overlay. + * If they are not, some things will appear to work, but not + * all the output pins will be correctly configured as outputs. + */ +static void +ledscape_gpio_init(void) +{ + for (unsigned i = 0 ; i < ARRAY_COUNT(gpios_output1) ; i+=2) + pru_gpio(gpios_output1[i], gpios_output1[i+1], 1, 0); +#if LEDSCAPE_MATRIX_OUTPUTS > 1 + for (unsigned i = 0 ; i < ARRAY_COUNT(gpios_output2) ; i+=2) + pru_gpio(gpios_output2[i], gpios_output2[i+1], 1, 0); +#endif +#if LEDSCAPE_MATRIX_OUTPUTS > 2 + for (unsigned i = 0 ; i < ARRAY_COUNT(gpios_output3) ; i+=2) + pru_gpio(gpios_output3[i], gpios_output3[i+1], 1, 0); +#endif +#if LEDSCAPE_MATRIX_OUTPUTS > 3 + for (unsigned i = 0 ; i < ARRAY_COUNT(gpios_output4) ; i+=2) + pru_gpio(gpios_output4[i], gpios_output4[i+1], 1, 0); +#endif +#if LEDSCAPE_MATRIX_OUTPUTS > 4 + for (unsigned i = 0 ; i < ARRAY_COUNT(gpios_output5) ; i+=2) + pru_gpio(gpios_output5[i], gpios_output5[i+1], 1, 0); +#endif +#if LEDSCAPE_MATRIX_OUTPUTS > 5 + for (unsigned i = 0 ; i < ARRAY_COUNT(gpios_output6) ; i+=2) + pru_gpio(gpios_output6[i], gpios_output6[i+1], 1, 0); +#endif +#if LEDSCAPE_MATRIX_OUTPUTS > 6 + for (unsigned i = 0 ; i < ARRAY_COUNT(gpios_output7) ; i+=2) + pru_gpio(gpios_output7[i], gpios_output7[i+1], 1, 0); +#endif +#if LEDSCAPE_MATRIX_OUTPUTS > 7 + for (unsigned i = 0 ; i < ARRAY_COUNT(gpios_output8) ; i+=2) + pru_gpio(gpios_output8[i], gpios_output8[i+1], 1, 0); +#endif + for (unsigned i = 0 ; i < ARRAY_COUNT(gpios_output_all) ; i+=2) + pru_gpio(gpios_output_all[i], gpios_output_all[i+1], 1, 0); +} + + +/** Command structure shared with the PRU. + * + * This is mapped into the PRU data RAM and points to the + * frame buffer in the shared DDR segment. + * + * Changing this requires changes in ws281x.p + */ +typedef struct +{ + // in the DDR shared with the PRU + uintptr_t pixels_dma; + + // Length in pixels of the longest LED strip. + unsigned num_pixels; + + // write 1 to start, 0xFF to abort. will be cleared when started + volatile unsigned command; + + // will have a non-zero response written when done + volatile unsigned response; +} __attribute__((__packed__)) ws281x_command_t; + +#if 0 +typedef struct +{ + uint32_t x_offset; + uint32_t y_offset; +} led_matrix_t; + +#define NUM_MATRIX 16 + +typedef struct +{ + uint32_t matrix_width; // of a full chain + uint32_t matrix_height; // number of rows per-output (8 or 16) + led_matrix_t matrix[NUM_MATRIX]; +} led_matrix_config_t; +#endif + + + +struct ledscape +{ + ws281x_command_t * ws281x; + pru_t * pru; + unsigned width; + unsigned height; + unsigned frame_size; + ledscape_config_t * config; +}; + + +#if 0 +/** Retrieve one of the two frame buffers. */ +ledscape_frame_t * +ledscape_frame( + ledscape_t * const leds, + unsigned int frame +) +{ + if (frame >= 2) + return NULL; + + return (ledscape_frame_t*)((uint8_t*) leds->pru->ddr + leds->frame_size * frame); +} +#endif + + +static uint8_t +bright_map( + uint8_t val +) +{ + return val; +} + + +static uint8_t * +ledscape_remap( + ledscape_t * const leds, + uint8_t * const frame, + unsigned x, + unsigned y +) +{ +#undef CONFIG_ZIGZAG +#ifdef CONFIG_ZIGZAG + (void) leds; + + // each panel is 16x8 + // vertical panel number is y % 8 (which output line) + // horizontal panel number is y % (16*8) + // if y % 2 == 1, map backwards + const unsigned panel_width = 16; + const unsigned panel_height = 8; + unsigned panel_num = x / panel_width; + unsigned output_line = y / panel_height; + unsigned panel_x = x % panel_width; + unsigned panel_y = y % panel_height; + unsigned panel_offset = panel_y * panel_width; + + // the even lines are forwards, the odd lines go backwards + if (panel_y % 2 == 0) + { + panel_offset += panel_x; + } else { + panel_offset += panel_width - panel_x - 1; + } + + return &frame[(panel_num*128 + panel_offset)*48*3 + output_line]; +#else + (void) leds; + return &frame[x*48*3 + y]; +#endif +} + + +/** Copy a 16x32 region from in to a 32x16 region of out. + * If rot == 0, rotate -90, else rotate +90. + */ +static void +ledscape_matrix_panel_copy( + uint8_t * const out, + const uint32_t * const in, + const ledscape_matrix_config_t * const config, + const int rot +) +{ + const size_t row_stride = LEDSCAPE_MATRIX_OUTPUTS*3*2; + const size_t row_len = config->leds_width*row_stride; + + for (int x = 0 ; x < config->panel_width ; x++) + { + for (int y = 0 ; y < config->panel_height ; y++) + { + int ix, iy; + if (rot == 0) + { + // no rotation == (0,0) => (0,0) + ix = x; + iy = y; + } else + if (rot == 1) + { + // rotate +90 (0,0) => (0,15) + ix = config->panel_height-1 - y; + iy = x; + } else + if (rot == 2) + { + // rotate -90 (0,0) => (31,0) + ix = y; + iy = config->panel_width-1 - x; + } else + if (rot == 3) + { + // flip == (0,0) => (31,15) + ix = config->panel_width-1 - x; + iy = config->panel_height-1 - y; + } else + { + // barf + ix = iy = 0; + } + + const uint32_t * const col_ptr = &in[ix + config->width*iy]; + const uint32_t col = *col_ptr; + + // the top half and bottom half of the panels + // are squished together in the output since + // they are drawn simultaneously. + uint8_t * const pix = &out[x*row_stride + (y/(config->panel_height/2))*3 + (y%(config->panel_height/2))*row_len]; + + pix[0] = (col >> 16) & 0xFF; // red +#if LEDSCAPE_MATRIX_GB_INVERT + pix[1] = (col >> 0) & 0xFF; // green + pix[2] = (col >> 8) & 0xFF; // blue +#else + pix[1] = (col >> 8) & 0xFF; // green + pix[2] = (col >> 0) & 0xFF; // blue +#endif + //printf("%d,%d => %p %p %08x\n", x, y, pix, col_ptr, col); + } + } +} + + +static void +ledscape_matrix_draw( + ledscape_t * const leds, + const void * const buffer +) +{ + static unsigned frame = 0; + const uint32_t * const in = buffer; + uint8_t * const out = leds->pru->ddr + leds->frame_size * frame; + + // matrix is re-packed such that a 6-byte read will bring in + // the brightness values for all six outputs of a given panel. + // this means that the rows stride 16 * 3 pixels at a time. + // + // this way the PRU can read all sixteen output pixels in + // one LBBO and clock them out. + // while there are eight output chains, there are two simultaneous + // per output chain. + const ledscape_matrix_config_t * const config + = &leds->config->matrix_config; + + const size_t panel_stride = config->panel_width*2*3*LEDSCAPE_MATRIX_OUTPUTS; + + for (unsigned i = 0 ; i < LEDSCAPE_MATRIX_OUTPUTS ; i++) + { + for (unsigned j = 0 ; j < LEDSCAPE_MATRIX_PANELS ; j++) + { + const ledscape_matrix_panel_t * const panel + = &config->panels[i][j]; + + // the start of the panel in the input + // is defined by the panel's xy coordinate + // and the width of the input image. + const uint32_t * const ip + = &in[panel->x + panel->y*config->width]; + + // the start of the panel's output is defined + // by the current output panel number and the total + // number of panels in the chain. + uint8_t * const op = &out[6*i + j*panel_stride]; + + // copy the top half of this matrix + ledscape_matrix_panel_copy( + op, + ip, + config, + panel->rot + ); + } + } + + leds->ws281x->pixels_dma = leds->pru->ddr_addr + leds->frame_size * frame; + // disable double buffering for now + //frame = (frame + 1) & 1; +} + + +/** Translate the RGBA buffer to the correct output type and + * initiate the transfer of a frame to the LED strips. + * + * Matrix drivers shuffle to have consecutive bits, ws281x do bit slicing. + */ +void +ledscape_strip_draw( + ledscape_t * const leds, + const void * const buffer +) +{ + static unsigned frame = 0; + const uint32_t * const in = buffer; + uint8_t * const out = leds->pru->ddr + leds->frame_size * frame; + + // Translate the RGBA frame into G R B, sliced by color + // only 48 outputs currently supported + const unsigned pru_stride = 48; + for (unsigned y = 0 ; y < leds->height ; y++) + { + const uint32_t * const row_in = &in[y*leds->width]; + for (unsigned x = 0 ; x < leds->width ; x++) + { + uint8_t * const row_out + = ledscape_remap(leds, out, x, y); + uint32_t p = row_in[x]; + row_out[0*pru_stride] = (p >> 8) & 0xFF; // green + row_out[1*pru_stride] = (p >> 16) & 0xFF; // red + row_out[2*pru_stride] = (p >> 0) & 0xFF; // blue + } + } + + // Wait for any current command to have been acknowledged + while (leds->ws281x->command) + ; + + // Update the pixel data and send the start + leds->ws281x->pixels_dma + = leds->pru->ddr_addr + leds->frame_size * frame; +// frame = (frame + 1) & 1; + + // Send the start command + leds->ws281x->command = 1; +} + + +/** Wait for the current frame to finish transfering to the strips. + * \returns a token indicating the response code. + */ +uint32_t +ledscape_wait( + ledscape_t * const leds +) +{ + while (1) + { + uint32_t response = leds->ws281x->response; + if (!response) + continue; + leds->ws281x->response = 0; + return response; + } +} + + +static ledscape_t * +ledscape_matrix_init( + ledscape_config_t * const config_union, + int no_pru_init +) +{ + ledscape_matrix_config_t * const config = &config_union->matrix_config; + pru_t * const pru = pru_init(0); + const size_t frame_size = config->panel_width * config->panel_height * 3 * LEDSCAPE_MATRIX_OUTPUTS * LEDSCAPE_MATRIX_PANELS; + + ledscape_t * const leds = calloc(1, sizeof(*leds)); + + *leds = (ledscape_t) { + .config = config_union, + .pru = pru, + .width = config->leds_width, + .height = config->leds_height, + .ws281x = pru->data_ram, + .frame_size = frame_size, + }; + + *(leds->ws281x) = (ws281x_command_t) { + .pixels_dma = 0, // will be set in draw routine + .num_pixels = (config->leds_width * 3) * (LEDSCAPE_MATRIX_OUTPUTS * 2), + .command = 0, + .response = 0, + }; + + ledscape_gpio_init(); + + // Initiate the PRU program + if (!no_pru_init) + pru_exec(pru, "./lib/matrix.bin"); + + // Watch for a done response that indicates a proper startup + // \todo timeout if it fails + printf("waiting for response\n"); + while (!leds->ws281x->response) + ; + printf("got response\n"); + + return leds; +} + + +static ledscape_t * +ledscape_strip_init( + ledscape_config_t * const config_union, + int no_pru_init +) +{ + ledscape_strip_config_t * const config = &config_union->strip_config; + pru_t * const pru = pru_init(0); + const size_t frame_size = 48 * config->leds_width * 8 * 3; + + printf("frame-size %zu, ddr-size=%zu\n", frame_size, pru->ddr_size); +#if 0 + if (2 *frame_size > pru->ddr_size) + die("Pixel data needs at least 2 * %zu, only %zu in DDR\n", + frame_size, + pru->ddr_size + ); +#endif + + ledscape_t * const leds = calloc(1, sizeof(*leds)); + + *leds = (ledscape_t) { + .config = config_union, + .pru = pru, + .width = config->leds_width, + .height = 48, // only 48 are supported, config->leds_height, + .ws281x = pru->data_ram, + .frame_size = frame_size, + }; + + // LED strips, not matrix output + *(leds->ws281x) = (ws281x_command_t) { + .pixels_dma = 0, // will be set in draw routine + .num_pixels = config->leds_width, // * leds->height, + .command = 0, + .response = 0, + }; + + printf("pixels: %d\n", leds->ws281x->num_pixels); + + ledscape_gpio_init(); + + // Initiate the PRU program + if (!no_pru_init) + pru_exec(pru, "./lib/ws281x.bin"); + + // Watch for a done response that indicates a proper startup + // \todo timeout if it fails + printf("waiting for response\n"); + while (!leds->ws281x->response) + ; + printf("got response\n"); + + return leds; +} + + +ledscape_t * +ledscape_init( + ledscape_config_t * const config, + int no_pru_init +) +{ + switch (config->type) + { + case LEDSCAPE_MATRIX: + return ledscape_matrix_init(config, no_pru_init); + case LEDSCAPE_STRIP: + return ledscape_strip_init(config, no_pru_init); + default: + fprintf(stderr, "unknown config type %d\n", config->type); + return NULL; + } +} + + +void +ledscape_draw( + ledscape_t * const leds, + const void * const buffer +) +{ + switch (leds->config->type) + { + case LEDSCAPE_MATRIX: + ledscape_matrix_draw(leds, buffer); + break; + case LEDSCAPE_STRIP: + ledscape_strip_draw(leds, buffer); + break; + default: + fprintf(stderr, "unknown config type %d\n", leds->config->type); + break; + } +} + + +void +ledscape_close( + ledscape_t * const leds +) +{ + // Signal a halt command + leds->ws281x->command = 0xFF; + pru_close(leds->pru); +} + + +void +ledscape_set_color( + ledscape_frame_t * const frame, + uint8_t strip, + uint8_t pixel, + uint8_t r, + uint8_t g, + uint8_t b +) +{ + ledscape_pixel_t * const p = &frame[pixel].strip[strip]; + p->r = r; + p->g = g; + p->b = b; +} + + + +extern const uint8_t fixed_font[][5]; + +void +ledscape_draw_char( + uint32_t * px, + const size_t width, + const uint32_t color, + char c +) +{ + if (c < 0x20 || c > 127) + c = '?'; + + const uint8_t* const f = fixed_font[c - 0x20]; + for (int i = 0 ; i < 5 ; i++, px++) + { + uint8_t bits = f[i]; + for (int j = 0 ; j < 7 ; j++, bits >>= 1) + px[j*width] = bits & 1 ? color : 0; + } +} + +/** Write with a fixed-width 8px font */ +void +ledscape_printf( + uint32_t * px, + const size_t width, + const uint32_t color, + const char * fmt, + ... +) +{ + char buf[128]; + va_list ap; + va_start(ap, fmt); + int len = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + (void) len; + uint32_t * start = px; + + //printf("%p => '%s'\n", px, buf); + for (unsigned i = 0 ; i < sizeof(buf) ; i++) + { + char c = buf[i]; + if (!c) + break; + if (c == '\n') + { + px = start = start + 8 * width; + continue; + } + + ledscape_draw_char(px, width, color, c); + px += 6; + } +} + +/** Default ledscape config */ +#define DEFAULT_MATRIX(i) { \ + { 0*32, i*32, 0 }, \ + { 1*32, i*32, 0 }, \ + { 0*32, (i+1)*32, 0 }, \ + { 1*32, (i+1)*32, 0 }, \ + } \ + +ledscape_config_t ledscape_matrix_default = { + .matrix_config = { + .type = LEDSCAPE_MATRIX, + .width = 64, + .height = 64, + .panel_width = 32, + .panel_height = 32, + .leds_width = 128, + .leds_height = 32, + .panels = { + DEFAULT_MATRIX(0), + }, + }, +}; diff --git a/src/ledscape/ledscape.h b/src/ledscape/ledscape.h new file mode 100644 index 00000000..843e5f55 --- /dev/null +++ b/src/ledscape/ledscape.h @@ -0,0 +1,160 @@ +/** \file + * LEDscape for the BeagleBone Black. + * + * Drives up to 32 ws281x LED strips using the PRU to have no CPU overhead. + * Allows easy double buffering of frames. + */ + +#ifndef _ledscape_h_ +#define _ledscape_h_ + +#include + +/** The number of strips supported. + * + * Changing this also requires changes in ws281x.p to stride the + * correct number of bytes per row.. + */ +#define LEDSCAPE_NUM_STRIPS 32 + +#define LEDSCAPE_MATRIX 1 +#define LEDSCAPE_STRIP 2 + + +typedef struct { + int x; + int y; + int rot; // 0 == none, 1 == left, 2 == right, 3 == flip +} ledscape_matrix_panel_t; + +#define LEDSCAPE_MATRIX_OUTPUTS 1 // number of outputs on the cape +#define LEDSCAPE_MATRIX_PANELS 4 // number of panels chained per output + +#define LEDSCAPE_MATRIX_GB_INVERT 1 // Flips green and blue colors, as this is different panel to panel + +typedef struct { + int type; + int width; + int height; + int panel_width; + int panel_height; + int leds_width; + int leds_height; + ledscape_matrix_panel_t panels[LEDSCAPE_MATRIX_OUTPUTS][LEDSCAPE_MATRIX_PANELS]; +} ledscape_matrix_config_t; + + +typedef struct { + int type; + int leds_width; // length of the longest strip + int leds_height; // number of output strips +} ledscape_strip_config_t; + + +typedef union { + int type; + ledscape_matrix_config_t matrix_config; + ledscape_strip_config_t strip_config; +} ledscape_config_t; + + +/** LEDscape pixel format is BRGA. + * + * data is laid out with BRGA format, since that is how it will + * be translated during the clock out from the PRU. + */ +typedef struct { + uint8_t b; + uint8_t r; + uint8_t g; + uint8_t a; +} __attribute__((__packed__)) ledscape_pixel_t; + + +/** LEDscape frame buffer is "strip-major". + * + * All 32 strips worth of data for each pixel are stored adjacent. + * This makes it easier to clock out while reading from the DDR + * in a burst mode. + */ +typedef struct { + ledscape_pixel_t strip[LEDSCAPE_NUM_STRIPS]; +} __attribute__((__packed__)) ledscape_frame_t; + + +typedef struct ledscape ledscape_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +extern ledscape_config_t ledscape_matrix_default; + +extern ledscape_t * +ledscape_init( + ledscape_config_t * config, + int no_init_pru +); + + +extern void +ledscape_draw( + ledscape_t * const leds, + const void * const rgb // 4-byte rgb data +); + + +extern void +ledscape_set_color( + ledscape_frame_t * const frame, + uint8_t strip, + uint8_t pixel, + uint8_t r, + uint8_t g, + uint8_t b +); + + +extern uint32_t +ledscape_wait( + ledscape_t * const leds +); + + +extern void +ledscape_close( + ledscape_t * const leds +); + + +/** Flip a rectangular frame buffer to map the LED matrices */ +void +ledscape_matrix_remap( + uint32_t * leds_out, + const uint32_t * fb_in, + const ledscape_matrix_config_t * config +); + + +/** Write with a fixed-width 8px font */ +void +ledscape_printf( + uint32_t * px, + const size_t width, + const uint32_t color, + const char * fmt, + ... +); + +/** Parse a config file */ +ledscape_config_t * +ledscape_config( + const char * filename +); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/src/ledscape/matrix.p b/src/ledscape/matrix.p new file mode 100644 index 00000000..fd5fadc5 --- /dev/null +++ b/src/ledscape/matrix.p @@ -0,0 +1,575 @@ +// \file + /* PRU based 16x32 LED Matrix driver. + * + * Drives up to sixteen 16x32 matrices using the PRU hardware. + * + * Uses sixteen data pins in GPIO0 (one for each data line on each + * matrix) and six control pins in GPIO1 shared between all the matrices. + * + * The ARM writes a 24-bit color 512x16 into the shared RAM, sets the + * frame buffer pointer in the command structure and the PRU clocks it out + * to the sixteen matrices. Since there is no PWM in the matrix hardware, + * the PRU will cycle through various brightness levels. After each PWM + * cycle it rechecks the frame buffer pointer, allowing a glitch-free + * transition to a new frame. + * + * To pause the redraw loop, write a NULL to the buffer pointer. + * To shut down the PRU, write -1 to the buffer pointer. + */ +#if 0 +#define MATRIX_HEIGHT 8 // 32x16 matrices +#else +#define MATRIX_HEIGHT 16 // 32x32 matrices +#endif + +// higher constants == brighter. +// 4 is a ok brightness, 5 is bright, 6 is powerful +#define BRIGHT_SHIFT 3 + +#define NUMBER_OUTPUTS 1 + +#define r11_gpio 2 +#define r11_pin 2 +#define g11_gpio 2 +#define g11_pin 3 +#define b11_gpio 2 +#define b11_pin 5 + +#define r12_gpio 0 +#define r12_pin 23 +#define g12_gpio 2 +#define g12_pin 4 +#define b12_gpio 0 +#define b12_pin 26 + +#if NUMBER_OUTPUTS > 1 +#define r21_gpio 0 +#define r21_pin 27 +#define g21_gpio 2 +#define g21_pin 1 +#define b21_gpio 0 +#define b21_pin 22 + +#define r22_gpio 2 +#define r22_pin 22 +#define g22_gpio 2 +#define g22_pin 23 +#define b22_gpio 2 +#define b22_pin 24 +#endif + +#if NUMBER_OUTPUTS > 2 +#define r31_gpio 0 +#define r31_pin 30 +#define g31_gpio 1 +#define g31_pin 18 +#define b31_gpio 0 +#define b31_pin 31 + +#define r32_gpio 1 +#define r32_pin 16 +#define g32_gpio 0 +#define g32_pin 3 +#define b32_gpio 0 // not working? +#define b32_pin 5 +#endif + +#if NUMBER_OUTPUTS > 3 +#define r41_gpio 0 +#define r41_pin 2 +#define g41_gpio 0 +#define g41_pin 15 +#define b41_gpio 1 +#define b41_pin 17 + +#if 0 +#define r42_gpio 1 // if we want to use PRU r30 output on clock +#define r42_pin 19 +#else +#define r42_gpio 3 // if we use the boards as built +#define r42_pin 21 +#endif +#define g42_gpio 3 +#define g42_pin 19 +#define b42_gpio 0 +#define b42_pin 4 +#endif + +#if NUMBER_OUTPUTS > 4 +#define r51_gpio 2 +#define r51_pin 25 +#define g51_gpio 0 +#define g51_pin 11 +#define b51_gpio 0 +#define b51_pin 10 + +#define r52_gpio 0 +#define r52_pin 9 +#define g52_gpio 0 +#define g52_pin 8 +#define b52_gpio 2 +#define b52_pin 17 +#endif + +#if NUMBER_OUTPUTS > 5 +#define r61_gpio 2 +#define r61_pin 16 +#define g61_gpio 2 +#define g61_pin 15 +#define b61_gpio 2 +#define b61_pin 14 + +#define r62_gpio 2 +#define r62_pin 13 +#define g62_gpio 2 +#define g62_pin 10 +#define b62_gpio 2 +#define b62_pin 12 +#endif + +#if NUMBER_OUTPUTS > 6 +#define r71_gpio 2 +#define r71_pin 11 +#define g71_gpio 2 +#define g71_pin 9 +#define b71_gpio 2 +#define b71_pin 8 + +#define r72_gpio 2 +#define r72_pin 6 +#define g72_gpio 0 +#define g72_pin 7 +#define b72_gpio 2 +#define b72_pin 7 +#endif + +#if NUMBER_OUTPUTS > 7 +#define r81_gpio 3 +#define r81_pin 17 +#define g81_gpio 3 +#define g81_pin 16 +#define b81_gpio 3 +#define b81_pin 15 + +#define r82_gpio 3 +#define r82_pin 14 +#define g82_gpio 0 +#define g82_pin 14 +#define b82_gpio 0 +#define b82_pin 20 +#endif + +#define CAT3(X,Y,Z) X##Y##Z + +// Control pins are all in GPIO1 +#define gpio1_sel0 12 /* must be sequential with sel1 and sel2 */ +#define gpio1_sel1 13 +#define gpio1_sel2 14 +#define gpio1_sel3 15 +#define gpio1_latch 28 +#define gpio1_oe 29 +#define gpio1_clock 19 + +/** Generate a bitmask of which pins in GPIO0-3 are used. + * + * \todo wtf "parameter too long": only 128 chars allowed? + */ + +#define GPIO1_SEL_MASK (0\ +|(1< 1 + SET GPIO_MASK(r21_gpio), r21_pin + SET GPIO_MASK(g21_gpio), g21_pin + SET GPIO_MASK(b21_gpio), b21_pin + SET GPIO_MASK(r22_gpio), r22_pin + SET GPIO_MASK(g22_gpio), g22_pin + SET GPIO_MASK(b22_gpio), b22_pin +#endif + +#if NUMBER_OUTPUTS > 2 + SET GPIO_MASK(r31_gpio), r31_pin + SET GPIO_MASK(g31_gpio), g31_pin + SET GPIO_MASK(b31_gpio), b31_pin + SET GPIO_MASK(r32_gpio), r32_pin + SET GPIO_MASK(g32_gpio), g32_pin + SET GPIO_MASK(b32_gpio), b32_pin +#endif + +#if NUMBER_OUTPUTS > 3 + SET GPIO_MASK(r41_gpio), r41_pin + SET GPIO_MASK(g41_gpio), g41_pin + SET GPIO_MASK(b41_gpio), b41_pin + SET GPIO_MASK(r42_gpio), r42_pin + SET GPIO_MASK(g42_gpio), g42_pin + SET GPIO_MASK(b42_gpio), b42_pin +#endif + +#if NUMBER_OUTPUTS > 4 + SET GPIO_MASK(r51_gpio), r51_pin + SET GPIO_MASK(g51_gpio), g51_pin + SET GPIO_MASK(b51_gpio), b51_pin + SET GPIO_MASK(r52_gpio), r52_pin + SET GPIO_MASK(g52_gpio), g52_pin + SET GPIO_MASK(b52_gpio), b52_pin +#endif + +#if NUMBER_OUTPUTS > 5 + SET GPIO_MASK(r61_gpio), r61_pin + SET GPIO_MASK(g61_gpio), g61_pin + SET GPIO_MASK(b61_gpio), b61_pin + SET GPIO_MASK(r62_gpio), r62_pin + SET GPIO_MASK(g62_gpio), g62_pin + SET GPIO_MASK(b62_gpio), b62_pin +#endif + +#if NUMBER_OUTPUTS > 6 + SET GPIO_MASK(r71_gpio), r71_pin + SET GPIO_MASK(g71_gpio), g71_pin + SET GPIO_MASK(b71_gpio), b71_pin + SET GPIO_MASK(r72_gpio), r72_pin + SET GPIO_MASK(g72_gpio), g72_pin + SET GPIO_MASK(b72_gpio), b72_pin +#endif + +#if NUMBER_OUTPUTS > 7 + SET GPIO_MASK(r81_gpio), r81_pin + SET GPIO_MASK(g81_gpio), g81_pin + SET GPIO_MASK(b81_gpio), b81_pin + SET GPIO_MASK(r82_gpio), r82_pin + SET GPIO_MASK(g82_gpio), g82_pin + SET GPIO_MASK(b82_gpio), b82_pin +#endif + //MOV clock_pin, 1 << gpio1_clock + +READ_LOOP: + // Load the pointer to the buffer from PRU DRAM into r0 and the + // length (in pixels) into r1. + LBCO data_addr, CONST_PRUDRAM, 0, 8 + + // Wait for a non-zero command + QBEQ READ_LOOP, data_addr, #0 + + // Command of 0xFF is the signal to exit + QBEQ EXIT, data_addr, #0xFF + + // scale the width into number of bytes that we will read + // 16 outputs * 3 bytes per output +/******** + ADD offset, width, width + ADD offset, offset, width + LSL width, offset, 4 +*/ + + MOV row, 0 + +NEW_ROW_LOOP: + // Disable output while we set the address + DISPLAY_OFF + + // set address; select pins in gpio1 are sequential + // xor with the select bit mask to set which ones should + LSL out_set, row, gpio1_sel0 + MOV out_clr, GPIO1_SEL_MASK + AND out_set, out_set, out_clr // ensure no extra bits + XOR out_clr, out_clr, out_set // complement the bits into clr + SBBO out_clr, gpio1_base, GPIO_CLRDATAOUT, 8 // set both + + MOV bright, 7 + MOV bright_thresh, 255 + ROW_LOOP: + // Re-start reading at the same row + MOV offset, 0 + + // Reset the latch pin; will be toggled at the end of the row + LATCH_LO + + // compute where we are in the image + PIXEL_LOOP: + // Load the sixteen RGB outputs into + // consecutive registers, starting at pixel_data. + // This takes about 250 ns + LBBO pixel_data, data_addr, offset, 3*16 + + // toggle the clock + CLOCK_HI + + MOV gpio0_set, 0 + MOV gpio1_set, 0 + MOV gpio2_set, 0 + MOV gpio3_set, 0 +#define GPIO(R) CAT3(gpio,R,_set) +#define OUTPUT_ROW(N,reg_r,reg_g,reg_b) \ + QBBC skip_r##N, reg_r, bright; \ + SET GPIO(r##N##_gpio), r##N##_pin; \ + skip_r##N: \ + QBBC skip_g##N, reg_g, bright; \ + SET GPIO(g##N##_gpio), g##N##_pin; \ + skip_g##N: \ + QBBC skip_b##N, reg_b, bright; \ + SET GPIO(b##N##_gpio), b##N##_pin; \ + skip_b##N: \ + + OUTPUT_ROW(11, r18.b0, r18.b1, r18.b2) + OUTPUT_ROW(12, r18.b3, r19.b0, r19.b1) + +#if NUMBER_OUTPUTS > 1 + OUTPUT_ROW(21, r19.b2, r19.b3, r20.b0) + OUTPUT_ROW(22, r20.b1, r20.b2, r20.b3) +#endif + +#if NUMBER_OUTPUTS > 2 + OUTPUT_ROW(31, r21.b0, r21.b1, r21.b2) + OUTPUT_ROW(32, r21.b3, r22.b0, r22.b1) +#endif + +#if NUMBER_OUTPUTS > 3 + OUTPUT_ROW(41, r22.b2, r22.b3, r23.b0) + OUTPUT_ROW(42, r23.b1, r23.b2, r23.b3) +#endif + +#if NUMBER_OUTPUTS > 4 + OUTPUT_ROW(51, r24.b0, r24.b1, r24.b2) + OUTPUT_ROW(52, r24.b3, r25.b0, r25.b1) +#endif + +#if NUMBER_OUTPUTS > 5 + OUTPUT_ROW(61, r25.b2, r25.b3, r26.b0) + OUTPUT_ROW(62, r26.b1, r26.b2, r26.b3) +#endif + +#if NUMBER_OUTPUTS > 6 + OUTPUT_ROW(71, r27.b0, r27.b1, r27.b2) + OUTPUT_ROW(72, r27.b3, r28.b0, r28.b1) +#endif + +#if NUMBER_OUTPUTS > 7 + OUTPUT_ROW(81, r28.b2, r28.b3, r29.b0) + OUTPUT_ROW(82, r29.b1, r29.b2, r29.b3) +#endif + + // reload the gpio*_base registers + // since we have overwritten them with our pixel data + MOV gpio2_base, GPIO2 + MOV gpio3_base, GPIO3 + + // All bits are configured; + // the non-set ones will be cleared + // We write 8 bytes since CLR and DATA are contiguous, + // which will write both the 0 and 1 bits in the + // same instruction. gpio0 and out_set are the same + // register, so they must be done first. + AND out_set, gpio0_set, gpio0_led_mask + XOR out_clr, out_set, gpio0_led_mask + SBBO out_clr, gpio0_base, GPIO_CLRDATAOUT, 8 + + AND out_set, gpio1_set, gpio1_led_mask + XOR out_clr, out_set, gpio1_led_mask + SBBO out_clr, gpio1_base, GPIO_CLRDATAOUT, 8 + + AND out_set, gpio2_set, gpio2_led_mask + XOR out_clr, out_set, gpio2_led_mask + SBBO out_clr, gpio2_base, GPIO_CLRDATAOUT, 8 + + AND out_set, gpio3_set, gpio3_led_mask + XOR out_clr, out_set, gpio3_led_mask + SBBO out_clr, gpio3_base, GPIO_CLRDATAOUT, 8 + + CLOCK_LO +#if 0 + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; + NOP; NOP; NOP; NOP; +#endif + +#if 1 + // If the brightness is less than the pixel, turn off + // but keep in mind that this is the brightness of + // the previous row, not this one. + LSL out_set, offset, 0 + //LSL out_clr, 1, bright + //LSL out_clr, out_clr, 1 + //MOV out_clr, 2048 + + LSL out_clr, bright_thresh, BRIGHT_SHIFT + //LSL out_clr, bright_thresh, 10 + + //QBBS no_blank, out_set, bright + QBGT no_blank, out_set, out_clr + DISPLAY_OFF + no_blank: +#endif + + + ADD offset, offset, 3*(NUMBER_OUTPUTS*2) + QBNE PIXEL_LOOP, offset, width + + // Full data has been clocked out; latch it + LATCH_HI + DISPLAY_ON + + // Update the brightness, and then give the row another scan + SUB bright, bright, 1 + LSR bright_thresh, bright_thresh, 1 + QBLT ROW_LOOP, bright, 0 + + // We have just done all eight brightness levels for this + // row. Time to move to the new row + + // Increment our data_offset to point to the next row + ADD data_addr, data_addr, offset + + ADD row, row, 1 + QBEQ READ_LOOP, row, MATRIX_HEIGHT + + QBA NEW_ROW_LOOP + +EXIT: +#ifdef AM33XX + // Send notification to Host for program completion + MOV R31.b0, PRU0_ARM_INTERRUPT+16 +#else + MOV R31.b0, PRU0_ARM_INTERRUPT +#endif + + HALT diff --git a/src/ledscape/pru.c b/src/ledscape/pru.c new file mode 100644 index 00000000..d76cf7da --- /dev/null +++ b/src/ledscape/pru.c @@ -0,0 +1,190 @@ +/** \file + * Userspace interface to the BeagleBone PRU. + * + * Wraps the prussdrv library in a sane interface. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pru.h" + + +static unsigned int +proc_read( + const char * const fname +) +{ + FILE * const f = fopen(fname, "r"); + if (!f) + die("%s: Unable to open: %s", fname, strerror(errno)); + unsigned int x; + fscanf(f, "%x", &x); + fclose(f); + return x; +} + + +pru_t * +pru_init( + const unsigned short pru_num +) +{ + prussdrv_init(); + + int ret = prussdrv_open(PRU_EVTOUT_0); + if (ret) + die("prussdrv_open open failed\n"); + + tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; + prussdrv_pruintc_init(&pruss_intc_initdata); + + void * pru_data_mem; + prussdrv_map_prumem( + pru_num == 0 ? PRUSS0_PRU0_DATARAM :PRUSS0_PRU1_DATARAM, + &pru_data_mem + ); + + const int mem_fd = open("/dev/mem", O_RDWR); + if (mem_fd < 0) + die("Failed to open /dev/mem: %s\n", strerror(errno)); + + const uintptr_t ddr_addr = proc_read("/sys/class/uio/uio0/maps/map1/addr"); + const uintptr_t ddr_size = proc_read("/sys/class/uio/uio0/maps/map1/size"); + + const uintptr_t ddr_start = 0x10000000; + const uintptr_t ddr_offset = ddr_addr - ddr_start; + const size_t ddr_filelen = ddr_size + ddr_start; + + /* map the memory */ + uint8_t * const ddr_mem = mmap( + 0, + ddr_filelen, + PROT_WRITE | PROT_READ, + MAP_SHARED, + mem_fd, + ddr_offset + ); + if (ddr_mem == MAP_FAILED) + die("Failed to mmap offset %"PRIxPTR" @ %zu bytes: %s\n", + ddr_offset, + ddr_filelen, + strerror(errno) + ); + + close(mem_fd); + + pru_t * const pru = calloc(1, sizeof(*pru)); + if (!pru) + die("calloc failed: %s", strerror(errno)); + + *pru = (pru_t) { + .pru_num = pru_num, + .data_ram = pru_data_mem, + .data_ram_size = 8192, // how to determine? + .ddr_addr = ddr_addr, + .ddr = (void*)(ddr_mem + ddr_start), + .ddr_size = ddr_size, + }; + + fprintf(stderr, + "%s: PRU %d: data %p @ %zu bytes, DMA %p / %"PRIxPTR" @ %zu bytes\n", + __func__, + pru_num, + pru->data_ram, + pru->data_ram_size, + pru->ddr, + pru->ddr_addr, + pru->ddr_size + ); + + return pru; +} + + +void +pru_exec( + pru_t * const pru, + const char * const program +) +{ + char * program_unconst = (char*)(uintptr_t) program; + if (prussdrv_exec_program(pru->pru_num, program_unconst) < 0) + die("%s failed", program); +} + + +void +pru_close( + pru_t * const pru +) +{ + // \todo unmap memory + prussdrv_pru_wait_event(PRU_EVTOUT_0); + prussdrv_pru_clear_event(PRU0_ARM_INTERRUPT); + prussdrv_pru_disable(pru->pru_num); + prussdrv_exit(); +} + + +int +pru_gpio( + const unsigned gpio, + const unsigned pin, + const unsigned direction, + const unsigned initial_value +) +{ + const unsigned pin_num = gpio * 32 + pin; + const char * export_name = "/sys/class/gpio/export"; + FILE * const export = fopen(export_name, "w"); + if (!export) + die("%s: Unable to open? %s\n", + export_name, + strerror(errno) + ); + + fprintf(export, "%d\n", pin_num); + fclose(export); + + char value_name[64]; + snprintf(value_name, sizeof(value_name), + "/sys/class/gpio/gpio%u/value", + pin_num + ); + + FILE * const value = fopen(value_name, "w"); + if (!value) + die("%s: Unable to open? %s\n", + value_name, + strerror(errno) + ); + + fprintf(value, "%d\n", initial_value); + fclose(value); + + char dir_name[64]; + snprintf(dir_name, sizeof(dir_name), + "/sys/class/gpio/gpio%u/direction", + pin_num + ); + + FILE * const dir = fopen(dir_name, "w"); + if (!dir) + die("%s: Unable to open? %s\n", + dir_name, + strerror(errno) + ); + + fprintf(dir, "%s\n", direction ? "out" : "in"); + fclose(dir); + + return 0; +} diff --git a/src/ledscape/pru.h b/src/ledscape/pru.h new file mode 100644 index 00000000..0a471614 --- /dev/null +++ b/src/ledscape/pru.h @@ -0,0 +1,67 @@ +/** \file + * Simplified interface to the ARM PRU. + * + */ +#ifndef _pru_h_ +#define _pru_h_ + +#include +#include +#include "util.h" + + +/** Mapping of the PRU memory spaces. + * + * The PRU has a small, fast local data RAM that is mapped into ARM memory, + * as well as slower access to the DDR RAM of the ARM. + */ +typedef struct +{ + unsigned pru_num; + + void * data_ram; // PRU data ram in ARM space + size_t data_ram_size; // size in bytes of the PRU's data RAM + + void * ddr; // PRU DMA address (in ARM space) + uintptr_t ddr_addr; // PRU DMA address (in PRU space) + size_t ddr_size; // Size in bytes of the shared space +} pru_t; + +extern pru_t * +pru_init( + const unsigned short pru_num +); + + +extern void +pru_exec( + pru_t * const pru, + const char * const program +); + + +extern void +pru_close( + pru_t * const pru +); + + + +/** Configure a GPIO pin. + * + * Since the device tree won't do it for us, we need to do it via + * /sys/class/gpio to set the direction and initial value for + * all of the pins that we use. + * + * Direction 0 == in, 1 == out. + */ +extern int +pru_gpio( + unsigned gpio, + unsigned pin, + unsigned direction, + const unsigned initial_value +); + + +#endif diff --git a/src/ledscape/util.c b/src/ledscape/util.c new file mode 100644 index 00000000..af90c116 --- /dev/null +++ b/src/ledscape/util.c @@ -0,0 +1,92 @@ +/** \file + * Various utility functions + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + +/** Write all the bytes to a fd, even if there is a brief interruption. + * \return number of bytes written or -1 on any fatal error. + */ +ssize_t +write_all( + const int fd, + const void * const buf_ptr, + const size_t len +) +{ + const uint8_t * const buf = buf_ptr; + size_t offset = 0; + + while (offset < len) + { + const ssize_t rc = write(fd, buf + offset, len - offset); + if (rc < 0) + { + if (errno == EAGAIN) + continue; + return -1; + } + + if (rc == 0) + return -1; + + offset += rc; + } + + return len; +} + + +int +serial_open( + const char * const dev +) +{ + const int fd = open(dev, O_RDWR | O_NONBLOCK | O_NOCTTY, 0666); + if (fd < 0) + return -1; + + // Disable modem control signals + struct termios attr; + tcgetattr(fd, &attr); + attr.c_cflag |= CLOCAL | CREAD; + attr.c_oflag &= ~OPOST; + tcsetattr(fd, TCSANOW, &attr); + + return fd; +} + + +void +hexdump( + FILE * const outfile, + const void * const buf, + const size_t len +) +{ + const uint8_t * const p = buf; + + for(size_t i = 0 ; i < len ; i++) + { + if (i % 8 == 0) + fprintf(outfile, "%s%04zu:", i == 0 ? "": "\n", i); + fprintf(outfile, " %02x", p[i]); + } + + fprintf(outfile, "\n"); +} + diff --git a/src/ledscape/util.h b/src/ledscape/util.h new file mode 100644 index 00000000..36c9603f --- /dev/null +++ b/src/ledscape/util.h @@ -0,0 +1,60 @@ +/** \file + * Utility functions. + */ +#ifndef _util_h_ +#define _util_h_ + +#include +#include +#include +#include +#include +#include + +#define warn(fmt, ...) \ + do { \ + fprintf(stderr, "%s:%d: " fmt, \ + __func__, __LINE__, ## __VA_ARGS__); \ + } while (0) + +#define warn_once(fmt, ...) \ + do { \ + static unsigned __warned__; \ + if (__warned__) \ + break; \ + __warned__ = 1; \ + warn(fmt, ## __VA_ARGS__ ); \ + } while (0) + +#define die(fmt, ...) \ + do { \ + warn(fmt, ## __VA_ARGS__ ); \ + exit(EXIT_FAILURE); \ + } while(0) + + +extern void +hexdump( + FILE * const outfile, + const void * const buf, + const size_t len +); + + +extern int +serial_open( + const char * const dev +); + + +/** Write all the bytes to a fd, even if there is a brief interruption. + * \return number of bytes written or -1 on any fatal error. + */ +extern ssize_t +write_all( + const int fd, + const void * const buf_ptr, + const size_t len +); + +#endif diff --git a/ws281x.hp b/src/ledscape/ws281x.hp similarity index 100% rename from ws281x.hp rename to src/ledscape/ws281x.hp diff --git a/src/ledscape/ws281x.p b/src/ledscape/ws281x.p new file mode 100644 index 00000000..da8a48f7 --- /dev/null +++ b/src/ledscape/ws281x.p @@ -0,0 +1,509 @@ +// \file + /* WS281x LED strip driver for the BeagleBone Black. + * + * Drives up to 32 strips using the PRU hardware. The ARM writes + * rendered frames into shared DDR memory and sets a flag to indicate + * how many pixels wide the image is. The PRU then bit bangs the signal + * out the 32 GPIO pins and sets a done flag. + * + * To stop, the ARM can write a 0xFF to the command, which will + * cause the PRU code to exit. + * + * At 800 KHz: + * 0 is 0.25 usec high, 1 usec low + * 1 is 0.60 usec high, 0.65 usec low + * Reset is 50 usec + * + * Pins are not contiguous. + * 18 pins on GPIO0: 2 3 4 5 7 8 9 10 11 14 15 20 22 23 26 27 30 31 + * 3 pins on GPIO01: 16 17 18 + * 21 pins on GPIO02: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 22 23 24 25 + * 6 pins on GPIO03: 14 15 16 17 19 21 + * each pixel is stored in 4 bytes in the order GRBA (4th byte is ignored) + * + */ + +// while len > 0: +// for bit# = 24 down to 0: +// delay 600 ns +// read 16 registers of data, build zero map for gpio0 +// read 10 registers of data, build zero map for gpio1 +// read 5 registers of data, build zero map for gpio3 +// +// Send start pulse on all pins on gpio0, gpio1 and gpio3 +// delay 250 ns +// bring zero pins low +// delay 300 ns +// bring all pins low +// increment address by 32 + + //* + //* So to clock this out: + //* ____ + //* | | |______| + //* 0 250 600 1250 offset + //* 250 350 650 delta + //* + //*/ + +#define r11_gpio 0 +#define r11_pin 27 +#define g11_gpio 2 +#define g11_pin 1 +#define b11_gpio 1 +#define b11_pin 14 + +#define r12_gpio 1 +#define r12_pin 15 +#define g12_gpio 0 +#define g12_pin 23 +#define b12_gpio 0 +#define b12_pin 26 + +#define r21_gpio 1 +#define r21_pin 12 +#define g21_gpio 1 +#define g21_pin 13 +#define b21_gpio 2 +#define b21_pin 5 + +#define r22_gpio 2 +#define r22_pin 4 +#define g22_gpio 2 +#define g22_pin 3 +#define b22_gpio 2 +#define b22_pin 2 + +#define r31_gpio 3 +#define r31_pin 16 +#define g31_gpio 0 +#define g31_pin 20 +#define b31_gpio 0 +#define b31_pin 14 + +#define r32_gpio 3 +#define r32_pin 19 +#define g32_gpio 0 +#define g32_pin 15 +#define b32_gpio 3 +#define b32_pin 21 + +#define r41_gpio 0 +#define r41_pin 2 +#define g41_gpio 1 +#define g41_pin 17 +#define b41_gpio 2 +#define b41_pin 22 + +#define r42_gpio 0 +#define r42_pin 3 +#define g42_gpio 0 +#define g42_pin 4 +#define b42_gpio 2 +#define b42_pin 24 + +#define r51_gpio 1 +#define r51_pin 19 +#define g51_gpio 0 +#define g51_pin 5 +#define b51_gpio 1 +#define b51_pin 18 + +#define r52_gpio 1 +#define r52_pin 16 +#define g52_gpio 1 +#define g52_pin 28 +#define b52_gpio 0 +#define b52_pin 31 + +#define r61_gpio 1 +#define r61_pin 29 +#define g61_gpio 0 +#define g61_pin 30 + +// Note: From here down, these are garbage, we only have 32 outputs. +#define b61_gpio 0 +#define b61_pin 1 + +#define r62_gpio 0 +#define r62_pin 1 +#define g62_gpio 0 +#define g62_pin 1 +#define b62_gpio 0 +#define b62_pin 1 + +#define r71_gpio 0 +#define r71_pin 1 +#define g71_gpio 0 +#define g71_pin 1 +#define b71_gpio 0 +#define b71_pin 1 + +#define r72_gpio 0 +#define r72_pin 1 +#define g72_gpio 0 +#define g72_pin 1 +#define b72_gpio 0 +#define b72_pin 1 + +#define r81_gpio 0 +#define r81_pin 1 +#define g81_gpio 0 +#define g81_pin 1 +#define b81_gpio 0 +#define b81_pin 1 + +#define r82_gpio 0 +#define r82_pin 1 +#define g82_gpio 0 +#define g82_pin 1 +#define b82_gpio 0 +#define b82_pin 1 + + +.origin 0 +.entrypoint START + +#include "ws281x.hp" + +/** Mappings of the GPIO devices */ +#define GPIO0 0x44E07000 +#define GPIO1 0x4804c000 +#define GPIO2 0x481AC000 +#define GPIO3 0x481AE000 + +/** Offsets for the clear and set registers in the devices */ +#define GPIO_CLEARDATAOUT 0x190 +#define GPIO_SETDATAOUT 0x194 + +/** Register map */ +#define data_addr r0 +#define data_len r1 +#define gpio0_zeros r2 +#define gpio1_zeros r3 +#define gpio2_zeros r4 +#define gpio3_zeros r5 +#define bit_num r6 +#define sleep_counter r7 +// r10 - r22 are used for temp storage and bitmap processing +#define gpio0_led_mask r26 +#define gpio1_led_mask r27 +#define gpio2_led_mask r28 +#define gpio3_led_mask r29 + + +/** Sleep a given number of nanoseconds with 10 ns resolution. + * + * This busy waits for a given number of cycles. Not for use + * with things that must happen on a tight schedule. + */ +.macro SLEEPNS +.mparam ns,inst,lab +#ifdef CONFIG_WS2812 + MOV sleep_counter, (ns/5)-1-inst // ws2812 -- low speed +#else + MOV sleep_counter, (ns/10)-1-inst // ws2811 -- high speed +#endif +lab: + SUB sleep_counter, sleep_counter, 1 + QBNE lab, sleep_counter, 0 +.endm + + +/** Wait for the cycle counter to reach a given value */ +.macro WAITNS +.mparam ns,lab + MOV r8, 0x22000 // control register +lab: + LBBO r9, r8, 0xC, 4 // read the cycle counter + SUB r9, r9, sleep_counter +#ifdef CONFIG_WS2812 + QBGT lab, r9, 2*(ns)/5 +#else + QBGT lab, r9, (ns)/5 +#endif +.endm + +///** Macro to generate the mask of which bits are zero. +// * For each of these registers, set the +// * corresponding bit in the gpio0_zeros register if +// * the current bit is set in the strided register. +// */ +//#define TEST_BIT(regN,gpioN,bitN) \ +// QBBS gpioN##_##regN##_skip, regN, bit_num; \ +// SET gpioN##_zeros, gpioN##_zeros, gpioN##_##bitN ; \ +// gpioN##_##regN##_skip: ; \ + +#define CAT3(X,Y,Z) X##Y##Z + +#define GPIO_MASK(X) CAT3(gpio,X,_led_mask) + +#define GPIO(R) CAT3(gpio,R,_zeros) + +// Output the current bit for three LED strip outputs +// Note that this nomenclature was ported from the matrix code, and is +// mostly nonsense when applied to the strip code. +// Parameters: +// N: Output group to consider (11, 12, 21, ... 82) +// reg_r: register byte to read first strip data from (ex: r10.b0) +// reg_g: register byte to read second strip data from (ex: r10.b1) +// reg_b: register byte to read third strip data from (ex: r10.b2) +// +// Parameters from the environment: +// bit_num: current bit we're reading from +#define OUTPUT_ROW(N,reg_r,reg_g,reg_b) \ + QBBS skip_r##N, reg_r, bit_num; \ + SET GPIO(r##N##_gpio), r##N##_pin; \ + skip_r##N: \ + QBBS skip_g##N, reg_g, bit_num; \ + SET GPIO(g##N##_gpio), g##N##_pin; \ + skip_g##N: \ + QBBS skip_b##N, reg_b, bit_num; \ + SET GPIO(b##N##_gpio), b##N##_pin; \ + skip_b##N: \ + +START: + // Enable OCP master port + // clear the STANDBY_INIT bit in the SYSCFG register, + // otherwise the PRU will not be able to write outside the + // PRU memory space and to the BeagleBon's pins. + LBCO r0, C4, 4, 4 + CLR r0, r0, 4 + SBCO r0, C4, 4, 4 + + // Configure the programmable pointer register for PRU0 by setting + // c28_pointer[15:0] field to 0x0120. This will make C28 point to + // 0x00012000 (PRU shared RAM). + MOV r0, 0x00000120 + MOV r1, CTPPR_0 + ST32 r0, r1 + + // Configure the programmable pointer register for PRU0 by setting + // c31_pointer[15:0] field to 0x0010. This will make C31 point to + // 0x80001000 (DDR memory). + MOV r0, 0x00100000 + MOV r1, CTPPR_1 + ST32 r0, r1 + + // Write a 0x1 into the response field so that they know we have started + MOV r2, #0x1 + SBCO r2, CONST_PRUDRAM, 12, 4 + + SET GPIO_MASK(r11_gpio), r11_pin + SET GPIO_MASK(g11_gpio), g11_pin + SET GPIO_MASK(b11_gpio), b11_pin + SET GPIO_MASK(r12_gpio), r12_pin + SET GPIO_MASK(g12_gpio), g12_pin + SET GPIO_MASK(b12_gpio), b12_pin + + SET GPIO_MASK(r21_gpio), r21_pin + SET GPIO_MASK(g21_gpio), g21_pin + SET GPIO_MASK(b21_gpio), b21_pin + SET GPIO_MASK(r22_gpio), r22_pin + SET GPIO_MASK(g22_gpio), g22_pin + SET GPIO_MASK(b22_gpio), b22_pin + + SET GPIO_MASK(r31_gpio), r31_pin + SET GPIO_MASK(g31_gpio), g31_pin + SET GPIO_MASK(b31_gpio), b31_pin + SET GPIO_MASK(r32_gpio), r32_pin + SET GPIO_MASK(g32_gpio), g32_pin + SET GPIO_MASK(b32_gpio), b32_pin + + SET GPIO_MASK(r41_gpio), r41_pin + SET GPIO_MASK(g41_gpio), g41_pin + SET GPIO_MASK(b41_gpio), b41_pin + SET GPIO_MASK(r42_gpio), r42_pin + SET GPIO_MASK(g42_gpio), g42_pin + SET GPIO_MASK(b42_gpio), b42_pin + + SET GPIO_MASK(r51_gpio), r51_pin + SET GPIO_MASK(g51_gpio), g51_pin + SET GPIO_MASK(b51_gpio), b51_pin + SET GPIO_MASK(r52_gpio), r52_pin + SET GPIO_MASK(g52_gpio), g52_pin + SET GPIO_MASK(b52_gpio), b52_pin + + SET GPIO_MASK(r61_gpio), r61_pin + SET GPIO_MASK(g61_gpio), g61_pin + SET GPIO_MASK(b61_gpio), b61_pin + SET GPIO_MASK(r62_gpio), r62_pin + SET GPIO_MASK(g62_gpio), g62_pin + SET GPIO_MASK(b62_gpio), b62_pin + + SET GPIO_MASK(r71_gpio), r71_pin + SET GPIO_MASK(g71_gpio), g71_pin + SET GPIO_MASK(b71_gpio), b71_pin + SET GPIO_MASK(r72_gpio), r72_pin + SET GPIO_MASK(g72_gpio), g72_pin + SET GPIO_MASK(b72_gpio), b72_pin + + SET GPIO_MASK(r81_gpio), r81_pin + SET GPIO_MASK(g81_gpio), g81_pin + SET GPIO_MASK(b81_gpio), b81_pin + SET GPIO_MASK(r82_gpio), r82_pin + SET GPIO_MASK(g82_gpio), g82_pin + SET GPIO_MASK(b82_gpio), b82_pin + + // Wait for the start condition from the main program to indicate + // that we have a rendered frame ready to clock out. This also + // handles the exit case if an invalid value is written to the start + // start position. +_LOOP: + // Load the pointer to the buffer from PRU DRAM into r0 and the + // length (in bytes-bit words) into r1. + // start command into r2 + LBCO data_addr, CONST_PRUDRAM, 0, 12 + + // Wait for a non-zero command + QBEQ _LOOP, r2, #0 + + // Zero out the start command so that they know we have received it + // This allows maximum speed frame drawing since they know that they + // can now swap the frame buffer pointer and write a new start command. + MOV r3, 0 + SBCO r3, CONST_PRUDRAM, 8, 4 + + // Command of 0xFF is the signal to exit + QBEQ EXIT, r2, #0xFF + + // The data len is in pixels; convert it to 3 channels * pixels + ADD r2, data_len, data_len + ADD data_len, data_len, r2 + + WORD_LOOP: + // for bit in 8 to 0; one color at a time + MOV bit_num, 8 + + BIT_LOOP: + SUB bit_num, bit_num, 1 + // The idle period is 650 ns, but this is where + // we do all of our work to read the RGB data and + // repack it into bit slices. Read the current counter + // and then wait until 650 ns have passed once we complete + // our work. + // Disable the counter and clear it, then re-enable it + MOV r8, 0x22000 // control register + LBBO r9, r8, 0, 4 + CLR r9, r9, 3 // disable counter bit + SBBO r9, r8, 0, 4 // write it back + + MOV r10, 0 + SBBO r10, r8, 0xC, 4 // clear the timer + + SET r9, r9, 3 // enable counter bit + SBBO r9, r8, 0, 4 // write it back + + // Read the current counter value + // Should be zero. + LBBO sleep_counter, r8, 0xC, 4 + + + // Load 48 bytes of data, starting at r10 + // one byte for each of the outputs + LBBO r10, r0, 0, 48 + MOV gpio0_zeros, 0 + MOV gpio1_zeros, 0 + MOV gpio2_zeros, 0 + MOV gpio3_zeros, 0 + + OUTPUT_ROW(11, r10.b0, r10.b1, r10.b2) + OUTPUT_ROW(12, r10.b3, r11.b0, r11.b1) + OUTPUT_ROW(21, r11.b2, r11.b3, r12.b0) + OUTPUT_ROW(22, r12.b1, r12.b2, r12.b3) + + OUTPUT_ROW(31, r13.b0, r13.b1, r13.b2) + OUTPUT_ROW(32, r13.b3, r14.b0, r14.b1) + OUTPUT_ROW(41, r14.b2, r14.b3, r15.b0) + OUTPUT_ROW(42, r15.b1, r15.b2, r15.b3) + + OUTPUT_ROW(51, r16.b0, r16.b1, r16.b2) + OUTPUT_ROW(52, r16.b3, r17.b0, r17.b1) + OUTPUT_ROW(61, r17.b2, r17.b3, r18.b0) + OUTPUT_ROW(62, r18.b1, r18.b2, r18.b3) + + OUTPUT_ROW(71, r19.b0, r19.b1, r19.b2) + OUTPUT_ROW(72, r19.b3, r20.b0, r20.b1) + OUTPUT_ROW(81, r20.b2, r20.b3, r21.b0) + OUTPUT_ROW(82, r21.b1, r21.b2, r21.b3) + + // Now that we have read all of the data, + // we can reuse the registers for the set/clear addresses + // and the masks of which pins are mapped to which LEDs. + MOV r10, GPIO0 | GPIO_SETDATAOUT + MOV r11, GPIO1 | GPIO_SETDATAOUT + MOV r12, GPIO2 | GPIO_SETDATAOUT + MOV r13, GPIO3 | GPIO_SETDATAOUT + + // Wait for 650 ns to have passed + WAITNS 650, wait_start_time + + // Send all the start bits + SBBO gpio0_led_mask, r10, 0, 4 + SBBO gpio1_led_mask, r11, 0, 4 + SBBO gpio2_led_mask, r12, 0, 4 + SBBO gpio3_led_mask, r13, 0, 4 + + // Reconfigure r10-13 for clearing the bits + MOV r10, GPIO0 | GPIO_CLEARDATAOUT + MOV r11, GPIO1 | GPIO_CLEARDATAOUT + MOV r12, GPIO2 | GPIO_CLEARDATAOUT + MOV r13, GPIO3 | GPIO_CLEARDATAOUT + + // wait for the length of the zero bits (250 ns) + WAITNS 650+250, wait_zero_time + //SLEEPNS 250, 1, wait_zero_time + + // turn off all the zero bits + SBBO gpio0_zeros, r10, 0, 4 + SBBO gpio1_zeros, r11, 0, 4 + SBBO gpio2_zeros, r12, 0, 4 + SBBO gpio3_zeros, r13, 0, 4 + + // Wait until the length of the one bits + // TODO: Fix WAITNS so it can incorporate both delays? + WAITNS 650+600, wait_one_time + SLEEPNS 500, 1, sleep_one_time // Wait a little longer to fix the timing + + // Turn all the bits off + SBBO gpio0_led_mask, r10, 0, 4 + SBBO gpio1_led_mask, r11, 0, 4 + SBBO gpio2_led_mask, r12, 0, 4 + SBBO gpio3_led_mask, r13, 0, 4 + + QBNE BIT_LOOP, bit_num, 0 + + // The 48 RGB streams have been clocked out + // Move to the next color component for each pixel + ADD data_addr, data_addr, 48 + SUB data_len, data_len, 1 + QBNE WORD_LOOP, data_len, #0 + + // Delay at least 50 usec; this is the required reset + // time for the LED strip to update with the new pixels. + SLEEPNS 50000, 1, reset_time + + // Write out that we are done! + // Store a non-zero response in the buffer so that they know that we are done + // aso a quick hack, we write the counter so that we know how + // long it took to write out. + MOV r8, 0x22000 // control register + LBBO r2, r8, 0xC, 4 + SBCO r2, CONST_PRUDRAM, 12, 4 + + // Go back to waiting for the next frame buffer + QBA _LOOP + +EXIT: + // Write a 0xFF into the response field so that they know we're done + MOV r2, #0xFF + SBCO r2, CONST_PRUDRAM, 12, 4 + +#ifdef AM33XX + // Send notification to Host for program completion + MOV R31.b0, PRU0_ARM_INTERRUPT+16 +#else + MOV R31.b0, PRU0_ARM_INTERRUPT +#endif + + HALT diff --git a/src/script/Makefile b/src/script/Makefile new file mode 100644 index 00000000..20a6664b --- /dev/null +++ b/src/script/Makefile @@ -0,0 +1,19 @@ + +BINDIR = ../../bin/ + +FILES = bbb-network-setup \ + find-serial \ + install \ + ledscape.service \ + python-test \ + run-ledscape \ + run-videoplayer \ + twitter-scroller \ + videoplayer \ + videoplayer.service \ + run-menu + +all: copy + +copy: + cp -f $(FILES) $(BINDIR) diff --git a/src/script/bbb-network-setup b/src/script/bbb-network-setup new file mode 100755 index 00000000..2a0a64ac --- /dev/null +++ b/src/script/bbb-network-setup @@ -0,0 +1,12 @@ +#!/bin/sh +DIR="`dirname $0`" +cd "$DIR" + +route add default gw 192.168.7.1 +echo 'nameserver 8.8.8.8' > /etc/resolv.conf +echo >&2 "setting date" +ntpdate -s pool.ntp.org +date + +echo >&2 "probing serial ports" +./find-serial diff --git a/src/script/find-serial b/src/script/find-serial new file mode 100755 index 00000000..8259ad11 --- /dev/null +++ b/src/script/find-serial @@ -0,0 +1,12 @@ +#!/bin/sh +# Locate the serial ports and their serial numbers. +# This can then be used to map devices to positions in the matrix. + +lsusb -v > /dev/null + +for dev in `find /sys/devices/ -name '*ACM*' `;do + DIR=`dirname $dev` + TTY=`basename $dev` + SERIAL=`cat $DIR/../../serial` + echo "/dev/$TTY: $SERIAL" +done diff --git a/src/script/install b/src/script/install new file mode 100755 index 00000000..750a440e --- /dev/null +++ b/src/script/install @@ -0,0 +1,41 @@ +#!/bin/sh -x +# +# Install the device tree fragment, the angstrom service file, +# and make it runable. +# + +DIRNAME="`dirname $0`" +cd "$DIRNAME/.." + +die() { + echo >&2 "$*" + exit 1 +} + +cp dts/CAPE-BONE-OCTO-00A0.dtbo /lib/firmware + +if [ ! -d /etc/systemd ]; then + die "/etc/systemd does not exist? Is this not angstrom?" +fi + +BOOT=/media/BEAGLEBONE +UENV="$BOOT/uEnv.txt" + +if ! mount | grep -q "$BOOT"; then + mkdir "$BOOT" + mount -t vfat /dev/mmcblk0p1 "$BOOT" || die "Failed to mount $BOOT" +fi + +cp "$UENV" "$UENV.backup" + +cat < "$UENV" +optargs=quiet capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN +END + +sync +umount "$BOOT" + +cp bin/ledscape.service /etc/systemd/system/ +systemctl enable ledscape.service +systemctl status ledscape.service + diff --git a/src/script/ledscape.service b/src/script/ledscape.service new file mode 100755 index 00000000..d7144fba --- /dev/null +++ b/src/script/ledscape.service @@ -0,0 +1,16 @@ +# +# Copy this file to /etc/systemd/system/ and run: +# systemctl enable ledscape.service +# to enable LEDscape to start on each boot. +# + +[Unit] +Description=BeagleBone LED matrix driver + +[Service] +WorkingDirectory=/opt/LEDscape/ +ExecStart=/opt/LEDscape/bin/run-ledscape +KillMode=process + +[Install] +WantedBy=multi-user.target diff --git a/src/script/python-test b/src/script/python-test new file mode 100755 index 00000000..8ee2ccf5 --- /dev/null +++ b/src/script/python-test @@ -0,0 +1,79 @@ +#!/usr/bin/python +# Draw images with PIL and send them to the display. +# Dual scrolling example with fixed time on each side and +# the date scrolling around. +# +import Image, ImageFont, ImageDraw +import socket +import time, datetime +from colorsys import hsv_to_rgb + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +dest = ("localhost", 9999) + +#print im.format, im.size, im.mode +# use a truetype font +font = ImageFont.truetype("fonts/spincycle.ttf", 32) +font_sm = ImageFont.truetype("fonts/spincycle.ttf", 24) +#font_sm = ImageFont.truetype("fonts/pf_tempesta_seven.ttf", 8) +logo = Image.open("fonts/nycr.png") +#logo.resize((64,64)) + +i = 0 +width = 512 +height = 64 +disp = Image.new("RGB", (width,height), "black") +im = Image.new("RGB", (width,height), "black") +im_draw = ImageDraw.Draw(im) +disp_draw = ImageDraw.Draw(disp) + +def rainbow(i): + rgb = [int(x*256) for x in hsv_to_rgb(i/256.0,0.8,0.8)] + return (rgb[0],rgb[1],rgb[2]) + +def internet_time(): + "Swatch Internet Time. Biel meridian." + "More granular Swatch time. Courtesy https://github.com/gcohen55/pebble-beapoch" + return (((time.time() + 3600) % 86400) * 1000) / 86400 + #h, m, s = time.gmtime()[3:6] + #h += 1 # Biel time zone: UTC+1 + #seconds = s + (60.0*m) + (60.0*60.0*h) + #beats = seconds * 1000.0 / (60.0*60.0*24.0) + #beats = beats % 1000.0 + #return beats + + + +while True: + im.paste("black", (0,0,width,height)) + now = datetime.datetime.now() + d = now.strftime("%a %d %b") + t1 = now.strftime("%H:%M:%S") + t2 = "%07.3f" % (internet_time()) + + # Draw the date + im_draw.text((60, 4), d, font=font, fill=rainbow(i)) + im_draw.text((90, 32), t1, font=font_sm, fill=rainbow(i)) + im_draw.text((256+60, 4), d, font=font, fill=rainbow(i)) + im_draw.text((256+80, 32), t2, font=font_sm, fill=rainbow(i)) + im_draw.text((256+180, 32), ".beats", font=font_sm, fill=rainbow(i)) + + im.paste(logo, (0,8)) + im.paste(logo, (256,8)) + + # Make it scroll + disp.paste(im.crop((0,0,i,height)), (width-i,0)) + disp.paste(im.crop((i+1,0,width-1,height)), (0,0)) + + # draw the time on each face + #for x in range(0,7): + #disp_draw.text((4+x*32, 8-3), t, font=font_sm) + + # Split it into two pieces and send it to the drawing server + s = disp.tostring() + s1 = s[:(width*height*3/2)] + s2 = s[(width*height*3/2):] + sock.sendto(chr(0) + s1, dest) + sock.sendto(chr(1) + s2, dest) + i = (i+1) % width + time.sleep(0.025) diff --git a/src/script/run-ledscape b/src/script/run-ledscape new file mode 100755 index 00000000..45db587a --- /dev/null +++ b/src/script/run-ledscape @@ -0,0 +1,26 @@ +#!/bin/bash +DIRNAME="`dirname "$0"`" +cd "$DIRNAME/.." + +# Enable the octoscroller overlay +# Note that we can't do this at boot because it won't load then, for some reason +echo GPIO > /sys/devices/bone_capemgr*/slots +echo CAPE-BONE-OCTO > /sys/devices/bone_capemgr*/slots + +amixer sset PCM 100 +aplay /root/bach.wav & + +# Wait for unknown and unimaginable things to happen +sleep 10 + +CONFIGFILE="$DIRNAME/strips.config" +USBMOUNT="/media/usb0" + +# If a USB stick is mounted, try to load the config file from it +if [ -e "$USBMOUNT/ledscape.config" ] +then + CONFIGFILE="$USBMOUNT/ledscape.config" +fi + +exec ./bin/run-menu > /dev/null +#exec ./bin/matrix-udp-rx -m "Starting LEDscape" -c "$CONFIGFILE" >/dev/null diff --git a/src/script/run-menu b/src/script/run-menu new file mode 100755 index 00000000..a78c1b0c --- /dev/null +++ b/src/script/run-menu @@ -0,0 +1,24 @@ +#!/bin/bash + +function runmenu { + bin/menu + local status=$? + + if [ $status -eq 0 ]; then + bin/bricks + fi + + if [ $status -eq 1 ]; then + bin/paddles + fi + + if [ $status -eq 2 ]; then + bin/invaders + fi +} + +while true +do + runmenu +done + diff --git a/src/script/run-videoplayer b/src/script/run-videoplayer new file mode 100755 index 00000000..b5292d92 --- /dev/null +++ b/src/script/run-videoplayer @@ -0,0 +1,28 @@ +#!/bin/bash +DIRNAME="`dirname "$0"`" +cd "$DIRNAME" + +USBMOUNT="/media/usb0" + +# Wait for a USB drive to be inserted +while true +do + grep -qs $USBMOUNT /proc/mounts + if [ $? -eq 0 ]; then + echo "Mount success!" + break + fi + + sleep 1 +done + + +# Turn on extended filename globbing +shopt -s extglob + +# Play the first video we find, on a loop. +for video in "$USBMOUNT/"*+(.mp4|.MP4|.avi|.AVI) +do + exec ./video_player.py -l -w 112 "$video" + break +done diff --git a/src/script/twitter-scroller b/src/script/twitter-scroller new file mode 100755 index 00000000..a2003d99 --- /dev/null +++ b/src/script/twitter-scroller @@ -0,0 +1,101 @@ +#!/usr/bin/python +import Image, ImageFont, ImageDraw +import socket +import time, datetime +import pickle +import tweepy +import time +import thread +from botomatic import TBot +from colorsys import hsv_to_rgb + +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +dest = ("localhost", 9999) + +#print im.format, im.size, im.mode +# use a truetype font +font = ImageFont.truetype("fonts/spincycle.ttf", 32) +font_sm = ImageFont.truetype("fonts/spincycle.ttf", 24) + +i = 0 +width = 512 +height = 64 +disp = Image.new("RGB", (width,height), "black") +im = Image.new("RGB", (width,height), "black") +im_draw = ImageDraw.Draw(im) +disp_draw = ImageDraw.Draw(disp) + +tweets = [] +seen = {} + + +class Searcher(TBot): + debug_mode = True + + def __init__(self): + handle = "searcher" + super(Searcher, self).__init__(handle) + + def run(self): + while True: + results = self.search('"I"') + for result in results: + if result.id in seen: + continue + tweets.append(str(result.text)) + seen[result.id] = 1 + + #print "-----\n" + str(result.text) + "\n" + #try: + #result.retweet() + #except tweepy.error.TweepError: # private status update? + #continue + time.sleep(10) + + + self.wrap_up() + +def start_bot(): + p = Searcher() + +thread.start_new_thread(start_bot, ()) + + +while True: + if len(tweets) == 0: + time.sleep(1) + continue + tweet = tweets.pop() + print "---\n" + tweet + "\n" + continue + + im.paste("black", (0,0,width,height)) + now = datetime.datetime.now() + d = now.strftime("%a %d %b") + t = now.strftime("%H:%M:%S") + + # Draw the date + im_draw.text((60, 4), d, font=font, fill=rainbow(i)) + im_draw.text((90, 32), t, font=font_sm, fill=rainbow(i)) + im_draw.text((256+60, 4), d, font=font, fill=rainbow(i)) + im_draw.text((256+90, 32), t, font=font_sm, fill=rainbow(i)) + + im.paste(logo, (0,8)) + im.paste(logo, (256,8)) + + # Make it scroll + disp.paste(im.crop((0,0,i,height)), (width-i,0)) + disp.paste(im.crop((i+1,0,width-1,height)), (0,0)) + + # draw the time on each face + #for x in range(0,7): + #disp_draw.text((4+x*32, 8-3), t, font=font_sm) + + # Split it into two pieces and send it to the drawing server + s = disp.tostring() + s1 = s[:(width*height*3/2)] + s2 = s[(width*height*3/2):] + sock.sendto(chr(0) + s1, dest) + sock.sendto(chr(1) + s2, dest) + i = (i+1) % width + time.sleep(0.025) diff --git a/src/script/videoplayer b/src/script/videoplayer new file mode 100755 index 00000000..7db21f4d --- /dev/null +++ b/src/script/videoplayer @@ -0,0 +1,148 @@ +#!/usr/bin/python +# Play a video onto the screen + +import cv2, cv +import socket +import numpy +import datetime +import time +import argparse + +parser = argparse.ArgumentParser( + description="Display a video on the LEDscape screen" + ) +parser.add_argument( + "-s", "--screenGeometry", + dest="screenGeometry", + help="LEDscape screen size (ex: 256x128)", + default="256x128", + ) +parser.add_argument( + "-w", "--scaleWidth", + dest="scaleWidth", + help="Width to scale video to during playback (ex: 256)", + default="256", + type=int, + ) +parser.add_argument( + "-a", "--address", + dest="address", + help="TCP address to connect to (ex: localhost)", + default="localhost", + ) +parser.add_argument( + "-p", "--port", + dest="port", + help="TCP port to send data to (ex: 9999)", + default=9999, + type=int, + ) +parser.add_argument( + "-l", "--loop", + action="store_true", + dest="loop", + help="Loop the video continuously", + default=False, + ) +parser.add_argument( + dest="filename", + help="Filename to load", + ) + +config = parser.parse_args() + +# LEDscape screen geometry +screenWidth = int(config.screenGeometry.split('x')[0]) +screenHeight = int(config.screenGeometry.split('x')[1]) + +# If the screen height is not a divisor of 2, then the subframe scheme won't work. +if screenHeight % 2: + print "Error, screen height must be a multiple of 2!" + exit(1) + +# LEDscape packet geometry +# Note: SubframeCount *must* be an integer divider of screenHeight!! +# Note: This is designed for large screen support, a la the megasidescroller +# Small screens only need one frame to transmit, so set subFrameCount to 1. +subFrameCount = 2 +subFrameHeight = screenHeight / subFrameCount +subFrameSize = 1 + subFrameHeight*screenWidth*3 + +# LEDscape message setup +message = numpy.zeros(subFrameSize*subFrameCount, numpy.uint8); +for subFrame in range(0, subFrameCount): + message[subFrame*subFrameSize] = subFrame + +# Socket to send to +sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +sock.setsockopt(socket.SOL_SOCKET,socket.SO_SNDBUF,int(subFrameSize)) + +# Test if the frame size is acceptable +# TODO: Fix this +if sock.getsockopt(socket.SOL_SOCKET,socket.SO_SNDBUF) < subFrameSize: + print "Error configuring TCP socket: buffer too big (reduce LEDscape image size?)" + exit(1) + +# Open the video for playback +cap = cv2.VideoCapture(config.filename) + + +# Test that the video was loaded +if not cap.isOpened(): + print "Error opening video: Check that the file exists and the format is correct" + exit(1) + +fps = cap.get(cv.CV_CAP_PROP_FPS) +frameDelay = 1.0/fps + +nextTime = time.time() + frameDelay + +while cap.isOpened(): + # Get the video frame + ret, frame = cap.read() + + # If we've reached the end, reset the position to the beginning + if not ret: + if config.loop: + cap.set(cv.CV_CAP_PROP_POS_MSEC, 0) + ret, frame = cap.read() + else: + exit(0) + + # Resize the video to be the width that we actually want + originalHeight = frame.shape[0] + originalWidth = frame.shape[1] + originalAspect = float(originalWidth)/originalHeight + + scaleWidth = config.scaleWidth + scaleHeight = int(scaleWidth/originalAspect) + + smaller = cv2.resize(frame,(scaleWidth, scaleHeight)) + frame = smaller + + # Copy the image data into the LEDscape format + frameHeight = frame.shape[0] + frameWidth = frame.shape[1] + + flattenedFrame = frame.reshape(frameHeight, frameWidth*3) + + copyWidth = min(screenWidth, frameWidth) + copyHeight = min(screenHeight, frameHeight) + + copyLength = copyWidth*3 + + for row in range(0, copyHeight): + offset = 1 + (row / subFrameHeight) + messageOffset = (row*screenWidth)*3 + offset + + message[messageOffset:messageOffset+copyLength] = flattenedFrame[row, 0:copyLength] + + # Send the data to the LEDscape host + for subFrame in range(0, subFrameCount): + sock.sendto(message[subFrame*subFrameSize:(subFrame+1)*subFrameSize], (config.address, config.port)) + + # Delay until it's time to show the next frame. + while time.time() < nextTime: + pass + + nextTime += frameDelay diff --git a/src/script/videoplayer.service b/src/script/videoplayer.service new file mode 100755 index 00000000..7e258cd3 --- /dev/null +++ b/src/script/videoplayer.service @@ -0,0 +1,18 @@ +# +# Copy this file to /etc/systemd/system/ and run: +# systemctl enable videoplayer.service +# to enable videoplayer to start on each boot. +# + +[Unit] +Description=LEDscape video player +Requires=ledscape +After=ledscape + +[Service] +WorkingDirectory=/opt/LEDscape/bin +ExecStart=/opt/LEDscape/bin/run-videoplayer +KillMode=process + +[Install] +WantedBy=multi-user.target diff --git a/ubuntu/ledscape.conf b/ubuntu/ledscape.conf new file mode 100644 index 00000000..e0d0e89a --- /dev/null +++ b/ubuntu/ledscape.conf @@ -0,0 +1,9 @@ +# +# This task runs at boot to start the LEDscape service + +description "start LEDscape udp-rx receiver" + +start on startup + +task +exec /opt/LEDscape/bin/run-ledscape diff --git a/ws281x.c b/ws281x.c deleted file mode 100644 index 36e598ea..00000000 --- a/ws281x.c +++ /dev/null @@ -1,239 +0,0 @@ -/** \file - * Userspace interface to the WS281x LED strip driver. - * - * \todo Package this into a library, possible a Python module. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PRU_NUM (0) - -#define die(fmt, ...) \ - do { \ - fprintf(stderr, fmt, ## __VA_ARGS__); \ - exit(EXIT_FAILURE); \ - } while (0) - -/** Command structure shared with the PRU. - * - * This is mapped into the PRU data RAM and points to the - * frame buffer in the shared DDR segment. - */ -typedef struct -{ - // in the DDR shared with the PRU - uintptr_t pixels_dma; - - // Length in pixels of the longest LED strip. - unsigned size; - - // write 1 to start, 0xFF to abort. will be cleared when started - volatile unsigned command; - - // will have a non-zero response written when done - volatile unsigned response; -} __attribute__((__packed__)) ws281x_command_t; - -// data is laid out with BRGA format, since that is how it will -// be translated during the clock out from the PRU. -typedef struct { - uint8_t b; - uint8_t r; - uint8_t g; - uint8_t a; -} __attribute__((__packed__)) pixel_t; - -// All 32 strips worth of data for each pixel are stored adjacent -// This makes it easier to clock out while reading from the DDR -// in a burst mode.. -typedef struct { - pixel_t strip[32]; -} __attribute__((__packed__)) pixel_slice_t; - -// mapped to the L3 shared with the PRU -static pixel_slice_t * pixels; - -static unsigned int -proc_read( - const char * const fname -) -{ - FILE * const f = fopen(fname, "r"); - if (!f) - die("%s: Unable to open: %s", fname, strerror(errno)); - unsigned int x; - fscanf(f, "%x", &x); - fclose(f); - return x; -} - - -static ws281x_command_t * -ws281_init( - const unsigned short pruNum, - const unsigned num_pixels -) -{ - void * pruDataMem; - prussdrv_map_prumem( - pruNum == 0 ? PRUSS0_PRU0_DATARAM :PRUSS0_PRU1_DATARAM, - &pruDataMem - ); - - const int mem_fd = open("/dev/mem", O_RDWR); - if (mem_fd < 0) - die("Failed to open /dev/mem: %s\n", strerror(errno)); - - const uintptr_t ddr_addr = proc_read("/sys/class/uio/uio0/maps/map1/addr"); - const uintptr_t ddr_size = proc_read("/sys/class/uio/uio0/maps/map1/size"); - - const uintptr_t ddr_start = 0x10000000; - const uintptr_t ddr_offset = ddr_addr - ddr_start; - const size_t ddr_filelen = ddr_size + ddr_start; - - /* map the memory */ - uint8_t * const ddr_mem = mmap( - 0, - ddr_filelen, - PROT_WRITE | PROT_READ, - MAP_SHARED, - mem_fd, - ddr_offset - ); - if (ddr_mem == MAP_FAILED) - die("Failed to mmap offset %"PRIxPTR" @ %zu bytes: %s\n", - ddr_offset, - ddr_filelen, - strerror(errno) - ); - - ws281x_command_t * const cmd = (void*) pruDataMem; - cmd->pixels_dma = ddr_addr; - cmd->size = num_pixels; - cmd->command = 0; - cmd->response = 0; - - const size_t pixel_size = num_pixels * 32 * 4; - - if (pixel_size > ddr_size) - die("Pixel data needs at least %zu, only %zu in DDR\n", - pixel_size, - ddr_size - ); - -#if 0 - prussdrv_map_l3mem (&l3mem); - pixels = l3mem; -#else - pixels = (void*)(ddr_mem + ddr_start); -#endif - - // Store values into source - printf("data ram %p l3 ram %p: setting %zu bytes\n", - cmd, - pixels, - pixel_size - ); - - - return cmd; -} - - -static void -set_color( - uint8_t strip, - uint8_t pixel, - uint8_t r, - uint8_t g, - uint8_t b -) -{ - pixel_t * const p = &pixels[pixel].strip[strip]; - p->r = r; - p->g = g; - p->b = b; -} - - -static void -fill_color( - int num_pixels, - uint8_t r, - uint8_t g, - uint8_t b -) -{ - size_t i; - for(i=0 ; i < num_pixels ; i++) - { - int strip; - for(strip=0 ; strip < 32; strip++) - { - set_color(strip, i, r, g, b); - } - } -} - - -int main (void) -{ - prussdrv_init(); - - int ret = prussdrv_open(PRU_EVTOUT_0); - if (ret) - die("prussdrv_open open failed\n"); - - tpruss_intc_initdata pruss_intc_initdata = PRUSS_INTC_INITDATA; - prussdrv_pruintc_init(&pruss_intc_initdata); - - const int num_pixels = 256; - ws281x_command_t * cmd = ws281_init(PRU_NUM, num_pixels); - - prussdrv_exec_program (PRU_NUM, "./ws281x.bin"); - - unsigned i = 0; - while (1) - { - printf(" starting %d!\n", ++i); - uint8_t val = i >> 1; - fill_color(num_pixels, val, 0, val); - for (int strip = 0 ; strip < 32 ; strip++) - { - //uint8_t r = ((strip >> 2) & 0x3) * 64; - //uint8_t g = ((strip >> 0) & 0x3) * 64; - //uint8_t b = ((strip >> 4) & 0x3) * 64; - set_color(strip, 0, val, 0, 0); - set_color(strip, 1, 0, val + 80, 0); - set_color(strip, 2, 0, 0, val + 160); - } - - cmd->response = 0; - cmd->command = 1; - while (!cmd->response) - ; - const uint32_t * next = (uint32_t*)(cmd + 1); - printf("done! %08x %08x", cmd->response, *next); - //if (cmd->response > 0x2900) break; - } - - // Signal a halt command - cmd->command = 0xFF; - - prussdrv_pru_wait_event(PRU_EVTOUT_0); - prussdrv_pru_clear_event(PRU0_ARM_INTERRUPT); - prussdrv_pru_disable(PRU_NUM); - prussdrv_exit(); - - return EXIT_SUCCESS; -} - diff --git a/ws281x.p b/ws281x.p deleted file mode 100644 index aa139052..00000000 --- a/ws281x.p +++ /dev/null @@ -1,418 +0,0 @@ -// \file - //* WS281x LED strip driver for the BeagleBone Black. - //* - //* Drives up to 32 strips using the PRU hardware. The ARM writes - //* rendered frames into shared DDR memory and sets a flag to indicate - //* how many pixels wide the image is. The PRU then bit bangs the signal - //* out the 32 GPIO pins and sets a done flag. - //* - //* To stop, the ARM can write a 0xFF to the command, which will - //* cause the PRU code to exit. - //* - //* At 800 KHz: - //* 0 is 0.25 usec high, 1 usec low - //* 1 is 0.60 usec high, 0.65 usec low - //* Reset is 50 usec - // - // Pins are not contiguous. - // 16 pins on GPIO0: 2 3 4 5 7 12 13 14 15 20 22 23 26 27 30 31 - // 10 pins on GPIO1: 12 13 14 15 16 17 18 19 28 29 - // 5 pins on GPIO2: 1 2 3 4 5 - // 8 pins on GPIO3: 14 15 16 17 18 19 20 21 - // - // each pixel is stored in 4 bytes in the order GRBA (4th byte is ignored) - // - // while len > 0: - // for bit# = 24 down to 0: - // delay 600 ns - // read 16 registers of data, build zero map for gpio0 - // read 10 registers of data, build zero map for gpio1 - // read 5 registers of data, build zero map for gpio3 - // - // Send start pulse on all pins on gpio0, gpio1 and gpio3 - // delay 250 ns - // bring zero pins low - // delay 300 ns - // bring all pins low - // increment address by 32 - - //* - //* So to clock this out: - //* ____ - //* | | |______| - //* 0 250 600 1250 offset - //* 250 350 650 delta - //* - //*/ - -// Pins available in GPIO0 -#define gpio0_bit0 2 -#define gpio0_bit1 3 -#define gpio0_bit2 4 -#define gpio0_bit3 5 -#define gpio0_bit4 7 -#define gpio0_bit5 12 -#define gpio0_bit6 13 -#define gpio0_bit7 14 -#define gpio0_bit8 15 -#define gpio0_bit9 20 -#define gpio0_bit10 22 -#define gpio0_bit11 23 -#define gpio0_bit12 26 -#define gpio0_bit13 27 -#define gpio0_bit14 30 -#define gpio0_bit15 31 - -// Pins available in GPIO1 -#define gpio1_bit0 12 -#define gpio1_bit1 13 -#define gpio1_bit2 14 -#define gpio1_bit3 15 -#define gpio1_bit4 16 -#define gpio1_bit5 17 -#define gpio1_bit6 18 -#define gpio1_bit7 19 -#define gpio1_bit8 28 -#define gpio1_bit9 29 - -// Pins in GPIO2 -#define gpio2_bit0 1 -#define gpio2_bit1 2 -#define gpio2_bit2 3 -#define gpio2_bit3 4 -#define gpio2_bit4 5 - -// And the paltry pins in GPIO3 to give us 32 -#define gpio3_bit0 16 -#define gpio3_bit1 19 - -/** Generate a bitmask of which pins in GPIO0-3 are used. - * - * This is used to bring all the pins up for the start of - * the bit, and then back down at the end of the 1 bits. - * - * \todo wtf "parameter too long": only 128 chars allowed? - */ -#define GPIO0_LED_MASK (0\ -|(1<