OpenCores
URL https://opencores.org/ocsvn/openarty/openarty/trunk

Subversion Repositories openarty

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /openarty
    from Rev 51 to Rev 52
    Reverse comparison

Rev 51 → Rev 52

/trunk/sw/board/Makefile
11,7 → 11,7
##
################################################################################
##
## Copyright (C) 2015, Gisselquist Technology, LLC
## Copyright (C) 2016-2017, Gisselquist Technology, LLC
##
## This program is free software (firmware): you can redistribute it and/or
## modify it under the terms of the GNU General Public License as published
23,8 → 23,13
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
## for more details.
##
## You should have received a copy of the GNU General Public License along
## with this program. (It's in the $(ROOT)/doc directory, run make with no
## target there if the PDF file isn't present.) If not, see
## <http://www.gnu.org/licenses/> for a copy.
##
## License: GPL, v3, as defined and found on www.gnu.org,
## http:##www.gnu.org/licenses/gpl.html
## http://www.gnu.org/licenses/gpl.html
##
##
################################################################################
31,7 → 36,7
##
##
.PHONY: all
PROGRAMS := exstartup oledtest gpsdump exmulti cputest # hello
PROGRAMS := exstartup oledtest gpsdump exmulti cputest cputestcis hello gettysburg # simple_ping
all: $(PROGRAMS)
OBJDIR := obj-zip
NM := zip-nm
38,10 → 43,12
RDELF := zip-readelf
CC := zip-gcc
OBJDUMP := zip-objdump
SOURCES := exstartup.c bootloader.c gpsdump.c oledtest.c exmulti.c # hello.c
HEADERS := artyboard.h zipsys.h
SOURCES := exstartup.c gpsdump.c oledtest.c exmulti.c simple_ping.c ipcksum.c cputest.c hello.c gettysburg.c # ntpserver.c
HEADERS :=
DUMPRTL := -fdump-rtl-all
DUMPTREE:= -fdump-tree-all
LFLAGS := -T arty.ld -L../zlib -Wl,--start-group -larty
CFLAGS := -O3 -I../zlib
#
# For source analysis, the following macros are defined:
 
49,9 → 56,13
 
%.o: $(OBJDIR)/%.o
$(OBJDIR)/%.o: %.c
$(CC) -O3 -c -fno-builtin $< -o $@
$(CC) $(CFLAGS) -c $< -o $@
$(OBJDIR)/hello.o: hello.c
$(CC) -O3 -c $< -o $@
$(OBJDIR)/gettysburg.o: gettysburg.c
$(CC) -O3 -c $< -o $@
$(OBJDIR)/%.s: %.c
$(CC) -O3 -S -fno-builtin $< -o $@
$(CC) $(CFLAGS) -fdump-rtl-all -S $< -o $@
$(OBJDIR)/%.txt: $(OBJDIR)/%.o
bash -c "$(RDELF) -a $^ ; $(OBJDUMP) -S -D $^ " | tee $@
%.txt: %
58,30 → 69,61
$(OBJDUMP) -S -D $^ > $@
 
 
#
# The CPUTest program here is special--it doesn't use the C library. Hence,
# it must have the -fno-builtin flag in order to build, and the -Tartyram.ld
# linker script to build something that doesn't go into flash but directly into
# RAM instead.
#
$(OBJDIR)/cputest.o: cputest.c
$(CC) $(CFLAGS) -c -Wa,-nocis -fno-builtin $< -o $@
$(OBJDIR)/cputestcis.o: cputest.c
$(CC) $(CFLAGS) -c -Wa,-cis -fno-builtin $< -o $@
$(OBJDIR)/cputest.s: cputest.c
$(CC) $(CFLAGS) -S -Wa,-cis -fno-builtin $< -o $@
 
exstartup: $(OBJDIR)/exstartup.o $(OBJDIR)/bootloader.o arty.ld
$(CC) -O3 -T arty.ld -fno-builtin -Wl,-Map=exstartup.map $(OBJDIR)/exstartup.o $(OBJDIR)/bootloader.o -o exstartup
$(OBJDIR)/cmptst.o: cmptst.c
$(CC) $(CFLAGS) -c $< -o $@
 
exmulti: $(OBJDIR)/exmulti.o $(OBJDIR)/bootloader.o arty.ld
$(CC) -O3 -T arty.ld -fno-builtin -Wl,-Map=exmulti.map $(OBJDIR)/exmulti.o $(OBJDIR)/bootloader.o -o $@
cputest: $(OBJDIR)/cputest.o artyram.ld
$(CC) $(CFLAGS) -T artyram.ld -fno-builtin -Wl,-Map=$(OBJDIR)/cputest.map $(OBJDIR)/cputest.o -o $@
cputestcis: $(OBJDIR)/cputestcis.o artyram.ld
$(CC) $(CFLAGS) -T artyram.ld -fno-builtin -Wl,-Map=$(OBJDIR)/cputestcis.map $(OBJDIR)/cputestcis.o -o $@
 
gpsdump: $(OBJDIR)/gpsdump.o $(OBJDIR)/bootloader.o arty.ld
$(CC) -O3 -T arty.ld -fno-builtin -Wl,-Map=gpsdump.map $(OBJDIR)/bootloader.o $(OBJDIR)/gpsdump.o -o $@
 
hello: $(OBJDIR)/hello.o $(OBJDIR)/bootloader.o arty.ld
$(CC) -O3 -T arty.ld -fno-builtin -Wl,-Map=hello.map $(OBJDIR)/bootloader.o $(OBJDIR)/hello.o -o $@
#
# Other programs are much simpler
exstartup: $(OBJDIR)/exstartup.o arty.ld
$(CC) $(CFLAGS) $(LFLAGS) $(OBJDIR)/exstartup.o -o $@
 
oledtest: $(OBJDIR)/oledtest.o $(OBJDIR)/bootloader.o $(OBJDIR)/splash.o $(OBJDIR)/mug.o arty.ld
$(CC) -O3 -T arty.ld -fno-builtin -Wl,-Map=oledtest.map $(OBJDIR)/oledtest.o $(OBJDIR)/bootloader.o $(OBJDIR)/splash.o $(OBJDIR)/mug.o -o $@
exmulti: $(OBJDIR)/exmulti.o arty.ld
$(CC) $(CFLAGS) $(LFLAGS) $(OBJDIR)/exmulti.o -o $@
 
cputest: $(OBJDIR)/cputest.o artyram.ld
$(CC) -O3 -T artyram.ld -fno-builtin -Wl,-Map=cputest.map $(OBJDIR)/cputest.o -o $@
gpsdump: $(OBJDIR)/gpsdump.o arty.ld
$(CC) $(CFLAGS) $(LFLAGS) $(OBJDIR)/gpsdump.o -o $@
 
hello: $(OBJDIR)/hello.o arty.ld
$(CC) $(CFLAGS) $(LFLAGS) $(OBJDIR)/hello.o -o $@
 
gettysburg: $(OBJDIR)/gettysburg.o arty.ld
$(CC) $(CFLAGS) $(LFLAGS) $(OBJDIR)/gettysburg.o -o $@
 
oledtest: $(OBJDIR)/oledtest.o $(OBJDIR)/splash.o $(OBJDIR)/mug.o
$(CC) $(CFLAGS) $(LFLAGS) $^ -o $@
 
simple_ping: $(OBJDIR)/simple_ping.o
simple_ping: $(OBJDIR)/arp.o $(OBJDIR)/ipcksum.o $(OBJDIR)/ipcksum.o arty.ld
$(CC) $(CFLAGS) $(LFLAGS) $^ -o simple_ping
 
cmptst: $(OBJDIR)/cmptst.o
$(CC) $(CFLAGS) $(LFLAGS) $(OBJDIR)/cmptst.o -o $@
 
exstartup.txt: exstartup
$(OBJDUMP) -S -D $^ > $@
 
clean:
rm -rf $(PROGRAMS) $(addsuffix .map,$(PROGRAMS)) $(addsuffix .txt,$(PROGRAMS))
rm -rf $(PROGRAMS) $(addsuffix .map,$(PROGRAMS))
rm -rf $(addsuffix .txt,$(PROGRAMS))
rm -rf $(OBJDIR)/
 
define build-depends
/trunk/sw/board/arp.c
0,0 → 1,201
////////////////////////////////////////////////////////////////////////////////
//
// Filename: arp.c
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: To encapsulate common functions associated with the ARP protocol
// and hardware (ethernet MAC) address resolution.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include "zipcpu.h"
#include "zipsys.h"
#define KTRAPID_SENDPKT 0
#include "artyboard.h"
#include "etcnet.h"
#include "protoconst.h"
#include "ipcksum.h"
 
///////////
//
//
// Simplified ARP table and ARP requester
//
//
///////////
 
typedef struct {
int valid;
unsigned age, ipaddr;
unsigned long mac;
} ARP_TABLE_ENTRY;
 
#define NUM_ARP_ENTRIES 8
ARP_TABLE_ENTRY arp_table[NUM_ARP_ENTRIES];
 
void init_arp_table(void) {
for(int k=0; k<NUM_ARP_ENTRIES; k++)
arp_table[k].valid = 0;
}
 
int get_next_arp_index(void) {
int eid, eldest = 0, unused_id = -1, oldage = 0, found=-1;
for(eid=0; eid<NUM_ARP_ENTRIES; eid++) {
if (!arp_table[eid].valid) {
unused_id = eid;
break;
} else if (arp_table[eid].age > oldage) {
oldage = arp_table[eid].age;
eldest = eid;
}
}
 
if (unused_id >= 0)
return unused_id;
return eldest;
}
 
void send_arp_request(int ipaddr) {
unsigned pkt[9];
 
pkt[0] = 0xffffffff;
pkt[1] = 0xffff0000 | ETHERTYPE_ARP;
pkt[2] = 0x010800; // hardware type (enet), proto type (inet)
pkt[3] = 0x06040001; // 6 octets in enet addr, 4 in inet addr,request
pkt[4] = (unsigned)(my_mac_addr>>16);
pkt[5] = ((unsigned)(my_mac_addr<<16))|(my_ip_addr>>16);
pkt[6] = (my_ip_addr<<16);
pkt[7] = 0;
pkt[8] = ipaddr;
 
// Send our packet
syscall(KTRAPID_SENDPKT,0,(unsigned)pkt, 9*4);
}
 
int arp_lookup(unsigned ipaddr, unsigned long *mac) {
int eid, eldest = 0, unused_id = -1, oldage = 0, found=-1;
 
if (((((ipaddr ^ my_ip_addr) & my_ip_mask) != 0)
|| (ipaddr == my_ip_router))
&&(router_mac_addr)) {
*mac = router_mac_addr;
return 0;
}
 
for(eid=0; eid<NUM_ARP_ENTRIES; eid++) {
if (arp_table[eid].valid) {
if (arp_table[eid].ipaddr == ipaddr) {
arp_table[eid].age = 0;
*mac = arp_table[eid].mac;
return 0;
} else if (arp_table[eid].age > oldage) {
oldage = arp_table[eid].age++;
eldest = eid;
if (oldage >= 0x010000)
arp_table[eid].valid = 0;
} else
arp_table[eid].age++;
}
}
 
send_arp_request(ipaddr);
return 1;
}
 
typedef struct {
unsigned ipaddr;
unsigned long mac;
} ARP_TABLE_LOG_ENTRY;
 
int arp_logid = 0;
ARP_TABLE_LOG_ENTRY arp_table_log[32];
 
void arp_table_add(unsigned ipaddr, unsigned long mac) {
unsigned long lclmac;
int eid;
 
arp_table_log[arp_logid].ipaddr = ipaddr;
arp_table_log[arp_logid].mac = mac;
arp_logid++;
arp_logid&= 31;
 
if (ipaddr == my_ip_addr)
return;
// Missing the 'if'??
else if (ipaddr == my_ip_router) {
router_mac_addr = mac;
} else if (arp_lookup(ipaddr, &lclmac)==0) {
if (mac != lclmac) {
for(eid=0; eid<NUM_ARP_ENTRIES; eid++) {
if ((arp_table[eid].valid)&&
(arp_table[eid].ipaddr == ipaddr)) {
volatile int *ev = &arp_table[eid].valid;
// Prevent anyone from using an invalid
// entry while we are updating it
*ev = 0;
arp_table[eid].age = 0;
arp_table[eid].mac = mac;
*ev = 1;
break;
}
}
}
} else {
volatile int *ev = &arp_table[eid].valid;
eid = get_next_arp_index();
 
// Prevent anyone from using an invalid entry while we are
// updating it
*ev = 0;
arp_table[eid].age = 0;
arp_table[eid].ipaddr = ipaddr;
arp_table[eid].mac = mac;
*ev = 1;
}
}
 
void send_arp_reply(unsigned machi, unsigned maclo, unsigned ipaddr) {
unsigned pkt[9];
pkt[0] = (machi<<16)|(maclo>>16);
pkt[1] = (maclo<<16)|ETHERTYPE_ARP;
pkt[2] = 0x010800; // hardware type (enet), proto type (inet)
pkt[3] = 0x06040002;
pkt[4] = (unsigned)(my_mac_addr>>16);
pkt[5] = ((unsigned)(my_mac_addr<<16))|(my_ip_addr>>16);
pkt[6] = (my_ip_addr<<16)|(machi);
pkt[7] = maclo;
pkt[8] = ipaddr;
 
syscall(KTRAPID_SENDPKT, 0, (int)pkt, 9*4);
}
 
/trunk/sw/board/arp.h
0,0 → 1,48
////////////////////////////////////////////////////////////////////////////////
//
// Filename: arp.h
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: To encapsulate common functions associated with the ARP protocol
// and hardware (ethernet MAC) address resolution.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef ARP_H
#define ARP_H
 
extern void init_arp_table(void);
extern int arp_lookup(unsigned ipaddr, unsigned long *mac);
extern void arp_table_add(unsigned ipaddr, unsigned long mac);
extern void send_arp_reply(unsigned machi, unsigned maclo, unsigned ipaddr);
 
#endif
/trunk/sw/board/arty.ld
13,7 → 13,7
*
********************************************************************************
*
* Copyright (C) 2016, Gisselquist Technology, LLC
* Copyright (C) 2016-2017, Gisselquist Technology, LLC
*
* This program is free software (firmware): you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
25,6 → 25,11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. (It's in the $(ROOT)/doc directory. Run make with no
* target there if the PDF file isn't present.) If not, see
* <http://www.gnu.org/licenses/> for a copy.
*
* License: GPL, v3, as defined and found on www.gnu.org,
* http://www.gnu.org/licenses/gpl.html
*
35,22 → 40,21
 
MEMORY
{
blkram (wx) : ORIGIN = 0x0008000, LENGTH = 0x0008000
flash (rx) : ORIGIN = 0x0400000, LENGTH = 0x0400000
sdram (wx) : ORIGIN = 0x4000000, LENGTH = 0x4000000
blkram (wx) : ORIGIN = 0x00020000, LENGTH = 0x00020000
flash (rx) : ORIGIN = 0x01000000, LENGTH = 0x01000000 /* 2^24 = 16MB */
sdram (wx) : ORIGIN = 0x10000000, LENGTH = 0x10000000
}
 
_flash = ORIGIN(flash);
_blkram = ORIGIN(blkram);
_sdram = ORIGIN(sdram);
_top_of_stack = ORIGIN(blkram) + LENGTH(blkram) - 1;
_top_of_stack = ORIGIN(blkram) + LENGTH(blkram) - 4;
 
SECTIONS
{
.rocode 0x4e0000 : {
.rocode 0x1380000 : {
_boot_address = .;
*(.start) *(.boot)
*(.text.startup)
} > flash
_kernel_image_start = . ;
.fastcode : {
60,7 → 64,7
_sdram_image_start = . ;
.ramcode : {
*(.text.startup)
*(.text)
*(.text*)
*(.rodata*) *(.strings)
*(.data) *(COMMON)
}> sdram AT> flash
/trunk/sw/board/artyram.ld
6,7 → 6,7
*
* Purpose: This script provides a description of the memory on the Arty,
* for the purposes of where to place programs in memory during
* linking.
* linking.
*
* Creator: Dan Gisselquist, Ph.D.
* Gisselquist Technology, LLC
13,7 → 13,7
*
********************************************************************************
*
* Copyright (C) 2016, Gisselquist Technology, LLC
* Copyright (C) 2016-2017, Gisselquist Technology, LLC
*
* This program is free software (firmware): you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
35,15 → 35,15
 
MEMORY
{
blkram (wx) : ORIGIN = 0x0008000, LENGTH = 0x0008000
flash (rx) : ORIGIN = 0x0400000, LENGTH = 0x0400000
sdram (wx) : ORIGIN = 0x4000000, LENGTH = 0x4000000
blkram (wx) : ORIGIN = 0x00020000, LENGTH = 0x00020000
flash (rx) : ORIGIN = 0x01000000, LENGTH = 0x01000000
sdram (wx) : ORIGIN = 0x10000000, LENGTH = 0x10000000
}
 
_flash = ORIGIN(flash);
_blkram = ORIGIN(blkram);
_sdram = ORIGIN(sdram);
_top_of_stack = ORIGIN(blkram) + LENGTH(blkram) - 1;
_top_of_stack = ORIGIN(blkram) + LENGTH(blkram) - 4;
 
SECTIONS
{
53,7 → 53,7
_kernel_image_start = . ;
*(.kernel)
*(.text.startup)
*(.text)
*(.text*)
*(.rodata*) *(.strings)
*(.data) *(COMMON) *(.bss)
}> blkram
/trunk/sw/board/cputest.c
33,25 → 33,25
///////////////////////////////////////////////////////////////////////////////
//
//
#include "artyboard.h"
#include "zipcpu.h"
#include "zipsys.h"
#include "artyboard.h"
 
#ifndef NULL
#define NULL (void *)0
#endif
 
static volatile int *const UARTTX = &((IOSPACE *)0x0100)->io_uart_tx,
*const UART_CTRL = &((IOSPACE *)0x0100)->io_auxsetup;
static volatile int * const PIC = (volatile int *)0xff000000;
static const int INT_UARTTX = SYSINT_UARTTX; // 0x2000;
static volatile int *const COUNTER = &((ZIPSYS *)ZIPSYS_ADDR)->z_m.ac_ck;
#define UARTTX _uart->u_tx
#define UART_CTRL _uart->u_setup
#define PIC SYSPIC
#define TIMER SYSTIMER
#define COUNTER zip->z_m.ac_ck
 
#define HAVE_COUNTER
// #define HAVE_COUNTER
#define HAVE_SCOPE
#define SCOPEc sys->io_scope[0].s_ctrl
#define SCOPEc _sys->io_scope[0].s_ctrl
#define SCOPE_DELAY 4
#define TRIGGER_SCOPE_NOW (SCOPE_TRIGGER|SCOPE_DELAY)
#define TRIGGER_SCOPE_NOW (WBSCOPE_TRIGGER|SCOPE_DELAY)
#define PREPARE_SCOPE SCOPE_DELAY
 
unsigned zip_ucc(void);
91,13 → 91,13
"\tBUSY\n"
"\t.section\t.text");
 
#ifdef HAVE_COUNTER
#define MARKSTART start_time = *COUNTER
#define MARKSTOP stop_time = *COUNTER
#ifdef COUNTER
#define MARKSTART start_time = COUNTER
#define MARKSTOP stop_time = COUNTER
#else
#ifdef HAVE_TIMER
#define MARKSTART start_time = *TIMER
#define MARKSTOP stop_time = *TIMER
#ifdef TIMER
#define MARKSTART start_time = TIMER
#define MARKSTOP stop_time = TIMER
#else
#define MARKSTART
#define MARKSTOP
339,15 → 339,7
// How about a reverse do{} while loop? These are usually cheaper than for()
// loops.
"\tLDI\t0,R2\n"
"\tLDI\t5,R3\n"
"bgt_loop_test:\n"
"\tADD\t1,R2\n"
"\tSUB\t1,R3\n"
"\tBGT\tbgt_loop_test\n"
"\tCMP\t5,R2\n"
"\tOR.NZ\t2,R1\n"
// What if we use >=?
"\tLDI\t0,R2\n"
"\tLDI\t5,R3\n"
"bge_loop_test:\n"
"\tADD\t1,R2\n"
357,20 → 349,20
"\tOR.NZ\t4,R1\n"
// Once more with the reverse loop, this time storing the loop variable in
// memory
"\tSUB\t1,SP\n"
"\tSUB\t4,SP\n"
"\tLDI\t0,R2\n"
"\tLDI\t5,R3\n"
"\tSTO\tR3,(SP)\n"
"\tLDI\t4,R3\n"
"\tSW\tR3,(SP)\n"
"mem_loop_test:\n"
"\tADD\t1,R2\n"
"\tADD\t1,R2\n" // Keep track of the number of times loop is executed
"\tADD\t14,R3\n"
"\tLOD\t(SP),R3\n"
"\tLW\t(SP),R3\n"
"\tSUB\t1,R3\n"
"\tSTO\tR3,(SP)\n"
"\tBGT\tmem_loop_test\n"
"\tSW\tR3,(SP)\n"
"\tBGE\tmem_loop_test\n"
"\tCMP\t5,R2\n"
"\tOR.NZ\t8,R1\n"
"\tADD\t1,SP\n"
"\tADD\t4,SP\n"
//
"\tJMP\tR0\n");
 
380,9 → 372,10
asm("\t.text\n\t.global\tshift_test\n"
"\t.type\tshift_test,@function\n"
"shift_test:\n"
"\tLDI\t0,R1\n"
"\tLDI\t0,R3\n"
"\tLDI\t0,R4\n"
"\tLDI\t0,R1\n" // Bit-field of tests that have failed
"\tLDI\t0,R3\n" // Bit-field of tests that have worked
"\tLDI\t0,R4\n" // Upper 16-bits of the same bit field
"\tLDI\t0,R5\n" // Upper 16-bits of tests that have failed
// Does shifting right by 32 result in a zero?
"\tLDI\t-1,R2\n"
"\tLSR\t32,R2\n"
427,12 → 420,14
"\tOR.Z\t1,R4\n"
//
"\tLSR\t0,R2\n"
"\tOR.C\t131072,R1\n"
"\tLDI\t131072,R5\n"
"\tOR.C\tR5,R1\n"
"\tCMP\t-1,R2\n"
"\tOR.Z\t2,R4\n"
//
"\tLSL\t0,R2\n"
"\tOR.C\t524288,R1\n"
"\tLDI\t524288,R5\n"
"\tOR.C\tR5,R1\n"
"\tCMP\t-1,R2\n"
"\tOR.Z\t4,R4\n"
// Tally up our results and return
447,9 → 442,9
asm("\t.text\n\t.global\tsw_brev\n"
"\t.type\tsw_brev,@function\n"
"sw_brev:\n"
"\tSUB\t2,SP\n"
"\tSTO\tR2,(SP)\n"
"\tSTO\tR3,1(SP)\n"
"\tSUB\t8,SP\n"
"\tSW\tR2,(SP)\n"
"\tSW\tR3,4(SP)\n"
"\tLDI\t-1,R2\n"
"\tCLR\tR3\n"
"sw_brev_loop:\n"
461,9 → 456,9
"\tBRA\tsw_brev_loop\n"
"sw_brev_endloop:\n"
"\tMOV\tR3,R1\n"
"\tLOD\t(SP),R2\n"
"\tLOD\t1(SP),R3\n"
"\tADD\t2,SP\n"
"\tLW\t(SP),R2\n"
"\tLW\t4(SP),R3\n"
"\tADD\t8,SP\n"
"\tJMP\tR0");
 
void pipeline_stack_test(void);
470,8 → 465,8
asm("\t.text\n\t.global\tpipeline_stack_test\n"
"\t.type\tpipeline_stack_test,@function\n"
"pipeline_stack_test:\n"
"\tSUB\t1,SP\n"
"\tSTO\tR0,(SP)\n"
"\tSUB\t4,SP\n"
"\tSW\tR0,(SP)\n"
"\tLDI\t0,R0\n"
"\tMOV\t1(R0),R1\n"
"\tMOV\t1(R1),R2\n"
503,8 → 498,8
"\tCMP.Z\t11,R11\n"
"\tCMP.Z\t12,R12\n"
"\tBREV.NZ\t-1,R1\n"
"\tLOD\t(SP),R0\n"
"\tADD\t1,SP\n"
"\tLW\t(SP),R0\n"
"\tADD\t4,SP\n"
"\tJMP\tR0\n"
);
 
512,20 → 507,20
asm("\t.text\n\t.global\tpipeline_stack_test_component\n"
"\t.type\tpipeline_stack_test_component,@function\n"
"pipeline_stack_test_component:\n"
"\tSUB\t13,SP\n"
"\tSTO\tR0,(SP)\n"
"\tSTO\tR1,1(SP)\n"
"\tSTO\tR2,2(SP)\n"
"\tSTO\tR3,3(SP)\n"
"\tSTO\tR4,4(SP)\n"
"\tSTO\tR5,5(SP)\n"
"\tSTO\tR6,6(SP)\n"
"\tSTO\tR7,7(SP)\n"
"\tSTO\tR8,8(SP)\n"
"\tSTO\tR9,9(SP)\n"
"\tSTO\tR10,10(SP)\n"
"\tSTO\tR11,11(SP)\n"
"\tSTO\tR12,12(SP)\n"
"\tSUB\t52,SP\n"
"\tSW\tR0,(SP)\n"
"\tSW\tR1,4(SP)\n"
"\tSW\tR2,8(SP)\n"
"\tSW\tR3,12(SP)\n"
"\tSW\tR4,16(SP)\n"
"\tSW\tR5,20(SP)\n"
"\tSW\tR6,24(SP)\n"
"\tSW\tR7,28(SP)\n"
"\tSW\tR8,32(SP)\n"
"\tSW\tR9,36(SP)\n"
"\tSW\tR10,40(SP)\n"
"\tSW\tR11,44(SP)\n"
"\tSW\tR12,48(SP)\n"
"\tXOR\t-1,R0\n"
"\tXOR\t-1,R1\n"
"\tXOR\t-1,R2\n"
539,20 → 534,20
"\tXOR\t-1,R10\n"
"\tXOR\t-1,R11\n"
"\tXOR\t-1,R12\n"
"\tLOD\t(SP),R0\n"
"\tLOD\t1(SP),R1\n"
"\tLOD\t2(SP),R2\n"
"\tLOD\t3(SP),R3\n"
"\tLOD\t4(SP),R4\n"
"\tLOD\t5(SP),R5\n"
"\tLOD\t6(SP),R6\n"
"\tLOD\t7(SP),R7\n"
"\tLOD\t8(SP),R8\n"
"\tLOD\t9(SP),R9\n"
"\tLOD\t10(SP),R10\n"
"\tLOD\t11(SP),R11\n"
"\tLOD\t12(SP),R12\n"
"\tADD\t13,SP\n"
"\tLW\t(SP),R0\n"
"\tLW\t4(SP),R1\n"
"\tLW\t8(SP),R2\n"
"\tLW\t12(SP),R3\n"
"\tLW\t16(SP),R4\n"
"\tLW\t20(SP),R5\n"
"\tLW\t24(SP),R6\n"
"\tLW\t28(SP),R7\n"
"\tLW\t32(SP),R8\n"
"\tLW\t36(SP),R9\n"
"\tLW\t40(SP),R10\n"
"\tLW\t44(SP),R11\n"
"\tLW\t48(SP),R12\n"
"\tADD\t52,SP\n"
"\tJMP\tR0\n");
 
//mpy_test
596,8 → 591,6
asm("\t.text\n\t.global\thard_mpyuhi\n"
"\t.type\thard_mpyuhi,@function\n"
"hard_mpyuhi:\n"
"\tNOOP\n"
"\tNOOP\n"
"\tMPYUHI\tR2,R1\n"
"\tRETN\n");
 
655,13 → 648,11
}
 
unsigned soft_mpyuhi(unsigned a, unsigned b) {
unsigned alo, ahi, blo, bhi;
unsigned alo, ahi;
unsigned rhi, rlhi, rllo;
 
alo = (a & 0x0ffff);
ahi = (a>>16)& 0x0ffff;
blo = (b & 0x0ffff);
bhi = (b>>16)& 0x0ffff;
 
rhi = 0;
rlhi = 0;
732,6 → 723,23
return r;
}
 
int div_test(void);
asm("\t.text\n\t.global\tdiv_test\n"
"\t.type\tdiv_test,@function\n"
"div_test:\n"
"\tLDI\t0x4881a7,R4\n"
"\tLDI\t0x2d5108b,R2\n"
"\tLDI\t10,R3\n"
"\tDIVU\tR3,R2\n"
"\tCMP\tR4,R2\n"
"\tLDILO.NZ\t1,R1\n"
"\tRETN.NZ\n"
"\tLDI\t0x2d5108b,R2\n"
"\tDIVU\t10,R2\n"
"\tCMP\tR4,R2\n"
"\tLDILO.NZ\t1,R1\n"
"\tRETN\n");
 
//brev_test
//pipeline_test -- used to be called pipeline memory race conditions
void pipeline_test(void);
738,29 → 746,29
asm("\t.text\n\t.global\tpipeline_test\n"
"\t.type\tpipeline_test,@function\n"
"pipeline_test:\n"
"\tSUB\t2,SP\n"
"\tSUB\t12,SP\n"
// Test setup
"\tLDI\t275,R2\n"
"\tSTO\tR2,1(SP)\n"
"\tMOV\t1(SP),R2\n"
"\tSTO\tR2,(SP)\n"
"\tSW\tR2,4(SP)\n"
"\tMOV\t4(SP),R2\n"
"\tSW\tR2,(SP)\n"
"\tCLR\tR2\n"
//
"\tMOV\tSP,R2\n"
"\tLOD\t(R2),R2\n"
"\tLOD\t(R2),R2\n"
"\tLW\t(R2),R2\n"
"\tLW\t(R2),R2\n"
"\tCMP\t275,R2\n"
"\tOR.NZ\t1,R1\n"
//
"\tMOV\tSP,R2\n"
// Here's the test sequence
"\tLOD\t(R2),R3\n"
"\tLOD\t1(R2),R4\n"
"\tSTO\tR4,1(R3)\n"
"\tLW\t(R2),R3\n"
"\tLW\t4(R2),R4\n"
"\tSW\tR4,4(R3)\n"
// Make sure we clear the load pipeline
"\tLOD\t(R2),R3\n"
"\tLW\t(R2),R3\n"
// Load our written value
"\tLOD\t2(R2),R4\n"
"\tLW\t8(R2),R4\n"
"\tCMP\t275,R4\n"
"\tOR.NZ\t2,R1\n"
//
769,18 → 777,18
// LOD -x(R12),R0
// LOD y(R0),R0
"\tMOV\tSP,R2\n"
"\tMOV\t1(R2),R3\n"
"\tSTO\tR3,1(R2)\n"
"\tMOV\t4(R2),R3\n"
"\tSW\tR3,4(R2)\n"
"\tLDI\t3588,R4\n" // Just some random value
"\tSTO\tR4,2(R2)\n"
"\tSW\tR4,8(R2)\n"
"\tMOV\tR2,R3\n"
// Here's the test sequence
"\tLOD\t(R2),R3\n"
"\tLOD\t1(R3),R3\n"
"\tLW\t(R2),R3\n"
"\tLW\t4(R3),R3\n"
"\tCMP\tR4,R3\n"
"\tOR.NZ\t4,R1\n"
//
"\tADD\t2,SP\n"
"\tADD\t12,SP\n"
"\tJMP\tR0\n");
 
//mempipe_test
788,14 → 796,14
asm("\t.text\n\t.global\tmempipe_test\n"
"\t.type\tmempipe_test,@function\n"
"mempipe_test:\n"
"\tSUB\t4,SP\n"
"\tSTO\tR0,(SP)\n"
"\tSUB\t16,SP\n"
"\tSW\tR0,(SP)\n"
"\tLDI\t0x1000,R11\n"
// Test #1 ... Let's start by writing a value to memory
"\tLDI\t-1,R2\n"
"\tCLR\tR3\n"
"\tSTO\tR2,2(SP)\n"
"\tLOD\t2(SP),R3\n"
"\tSW\tR2,8(SP)\n"
"\tLW\t8(SP),R3\n"
"\tCMP\tR3,R2\n"
"\tOR.NZ\t1,R1\n"
// Test #2, reading and then writing a value from memory
803,21 → 811,21
"\tNOOP\n"
"\tCLR\tR2\n"
"\tCLR\tR3\n"
"\tLOD\t2(SP),R2\n" // This should load back up our -1 value
"\tSTO\tR2,3(SP)\n"
"\tLW\t8(SP),R2\n" // This should load back up our -1 value
"\tSW\tR2,12(SP)\n"
// Insist that the pipeline clear
"\tLOD\t2(SP),R2\n"
"\tLW\t8(SP),R2\n"
// Now let's try loading into R3
"\tNOOP\n"
"\tNOOP\n"
"\tNOOP\n"
"\tNOOP\n"
"\tLOD\t3(SP),R3\n"
"\tLW\t12(SP),R3\n"
"\tCMP\tR3,R2\n"
"\tOR.NZ\t2,R1\n"
//
"\tLOD\t(SP),R0\n"
"\tADD\t4,SP\n"
"\tLW\t(SP),R0\n"
"\tADD\t16,SP\n"
"\tJMP\tR0\n");
 
//cexec_test
825,8 → 833,8
asm("\t.text\n\t.global\tcexec_test\n"
"\t.type\tcexec_test,@function\n"
"cexec_test:\n"
"\tSUB\t1,SP\n"
"\tSTO\tR0,(SP)\n"
"\tSUB\t4,SP\n"
"\tSW\tR0,(SP)\n"
//
"\tXOR\tR2,R2\n"
"\tADD.Z\t1,R2\n"
834,8 → 842,8
"\tCMP.Z\t0,R2\n"
"\tOR.Z\t2,R1\n"
//
"\tLOD\t(SP),R0\n"
"\tADD\t1,SP\n"
"\tLW\t(SP),R0\n"
"\tADD\t4,SP\n"
"\tJMP\tR0\n");
 
// Pipeline stalls have been hideous problems for me. The CPU has been modified
849,7 → 857,7
asm("\t.text\n\t.global\tnowaitpipe_test\n"
"\t.type\tnowaitpipe_test,@function\n"
"nowaitpipe_test:\n"
"\tSUB\t2,SP\n"
"\tSUB\t8,SP\n"
//
// Let's start with ALU-ALU testing
// AA: result->input A
892,16 → 900,16
// Then we need to do the ALU-MEM input testing
//
"\tCLR\tR2\n"
"\tSTO\tR2,1(SP)\n"
"\tSW\tR2,4(SP)\n"
"\tLDI\t8352,R2\n"
"\tLOD\t1(SP),R2\n"
"\tLW\t4(SP),R2\n"
"\tTST\t-1,R2\n"
"\tOR.NZ\t64,R1\n"
// Let's try again, this time with something that's not zero
"\tLDI\t937,R2\n"
"\tSTO\tR2,1(SP)\n"
"\tSW\tR2,4(SP)\n"
"\tNOOP\n"
"\tLOD\t1(SP),R2\n"
"\tLW\t4(SP),R2\n"
"\tCMP\t938,R2\n"
"\tOR.GE\t128,R1\n"
"\tCMP\t936,R2\n"
910,13 → 918,13
// Okay, we just did that as part of our last test
// Mem output->mem input testing
"\tLDI\t5328,R2\n"
"\tLOD\t1(SP),R2\n"
"\tSTO\tR2,1(SP)\n"
"\tLOD\t1(SP),R3\n"
"\tLW\t4(SP),R2\n"
"\tSW\tR2,4(SP)\n"
"\tLW\t4(SP),R3\n"
"\tCMP\t937,R3\n"
"\tOR.NZ\t512,R1\n"
//
"\tADD\t2,SP\n"
"\tADD\t8,SP\n"
"\tJMP\tR0\n");
 
//bcmem_test
924,32 → 932,32
asm("\t.text\n.global\tbcmem_test\n"
"\t.type\tbcmem_test,@function\n"
"bcmem_test:\n"
"\tSUB\t1,SP\n"
"\tSUB\t4,SP\n"
"\tCLR\tR1\n"
"\tCLR\tR2\n"
"\tLDI\t-1,R3\n"
"\tLDI\t0x13000,R4\n"
"\tSTO\tR2,(SP)\n"
"\tLOD\t(SP),R3\n"
"\tSW\tR2,(SP)\n"
"\tLW\t(SP),R3\n"
"\tCMP\tR2,R3\n"
"\tOR.NZ\t1,R1\n"
"\tCMP\t0x13000,R4\n"
"\tBZ\tbcmem_test_cmploc_1\n"
"\tSTO\tR4,(SP)\n"
"\tSW\tR4,(SP)\n"
"bcmem_test_cmploc_1:\n"
"\tLOD\t(SP),R2\n"
"\tLW\t(SP),R2\n"
"\tCMP\tR2,R4\n"
"\tOR.Z\t2,R1\n"
"\tCLR\tR2\n"
"\tCMP\tR2,R4\n"
"\tBZ\tbcmem_test_cmploc_2\n"
"\tSTO.NZ\tR4,(SP)\n"
"\tSW.NZ\tR4,(SP)\n"
"bcmem_test_cmploc_2:\n"
"\tLOD\t(SP),R2\n"
"\tLW\t(SP),R2\n"
"\tCMP\tR2,R4\n"
"\tOR.NZ\t4,R1\n"
//
"\tADD\t1,SP\n"
"\tADD\t4,SP\n"
"\tJMP\tR0\n");
 
// The illegal instruction test. Specifically, illegal instructions cannot be
962,10 → 970,46
void ill_test(void);
asm("\t.text\n.global\till_test\n"
"\t.type\till_test,@function\n"
"ill_test:\n"
"\t.word\t0x7ff00000\n"
"ill_test:\n" // 0.111_1.110_11......
"\t.int\t0x7ec00000\n"
"\tJMP\tR0\n");
 
// Are sim instructions considered valid? Just hit the illegal instruction
// so we can report the result
void sim_test(void);
asm("\t.text\n.global\tsim_test\n"
"\t.type\tsim_test,@function\n"
"sim_test:\n" // 0.111_1.111_10......
"\t.int\t0x7f800000\n"
"\tJMP\tR0\n");
 
// Are CIS instructions considered valid? Try two compare instructions to
// see if they are built into our CPU.
void cis_test(void);
asm("\t.text\n.global\tcis_test\n"
"\t.type\tcis_test,@function\n"
"cis_test:\n" // 1.000_0.011._1.101_0.000 ... 1.000_1.011._1.110_0.000
"\t.int\t0x83d08be0\n"
"\tJMP\tR0\n");
 
void cmpeq_test(void);
asm("\t.text\n.global\tcmpeq_test\n"
"\t.type\tcmpeq_test,@function\n"
"cmpeq_test:\n"
"\tCMP\tR1,R2\n"
"\tCMP.Z\tR3,R4\n"
"\tLDILO.NZ\t1,R1\n"
"\tJMP\tR0\n");
 
void cmpneq_test(void);
asm("\t.text\n.global\tcmpneq_test\n"
"\t.type\tcmpneq_test,@function\n"
"cmpneq_test:\n"
"\tLDI\t1,R4\n"
"\tCMP\tR1,R2\n"
"\tCMP.Z\tR3,R4\n"
"\tLDILO.Z\t1,R0\n"
"\tJMP\tR0\n");
//
// The CC register has some ... unique requirements associated with it.
// Particularly, flags are unavailable until after an ALU operation completes,
1033,11 → 1077,11
 
__attribute__((noinline))
void wait(unsigned int msk) {
*PIC = 0x7fff0000|msk;
PIC = 0x7fff0000|msk;
asm("MOV\tidle_task(PC),uPC\n");
*PIC = 0x80000000|(msk<<16);
PIC = 0x80000000|(msk<<16);
asm("WAIT\n");
*PIC = 0; // Turn interrupts back off, lest they confuse the test
PIC = 0; // Turn interrupts back off, lest they confuse the test
}
 
asm("\n\t.text\nidle_task:\n\tWAIT\n\tBRA\tidle_task\n");
1044,6 → 1088,13
 
__attribute__((noinline))
void txchr(char v) {
#ifdef _ZIP_HAS_WBUART
while(_uart->u_fifo & 0x010000)
;
uint8_t c = v;
_uart->u_tx = (unsigned)c;
#endif
/*
if (zip_cc() & CC_GIE) {
while(*UARTTX & 0x100)
;
1050,8 → 1101,18
} else
wait(INT_UARTTX);
*UARTTX = v;
*/
}
 
void wait_for_uart_idle(void) {
#ifdef _ZIP_HAS_WBUART
while(_uart->u_fifo & 0x100) // While the FIFO is non-empty
;
#else
#error "No uart defined"
#endif
}
 
__attribute__((noinline))
void txstr(const char *str) {
const char *ptr = str;
1148,6 → 1209,8
txreg("uPC : ", context[15]);
txstr("\r\n\r\n");
 
wait_for_uart_idle();
asm("NEXIT -1");
// While previous versions of cputest.c called zip_busy(), here we
// reject that notion for the simple reason that zip_busy may not
// necessarily halt any Verilator simulation. Instead, we try to
1174,20 → 1237,24
int context[16];
int user_stack[256], *user_stack_ptr = &user_stack[256];
int start_time, i;
int cc_fail, cis_insns = 0;
 
 
for(i=0; i<32; i++)
testlist[i] = -1;
 
#ifdef HAVE_TIMER
*TIMER = 0x7fffffff;
#ifdef TIMER
TIMER = 0x7fffffff;
#endif
#ifdef HAVE_COUNTER
*COUNTER = 0;
#ifdef COUNTER
COUNTER = 0;
#endif
#ifdef HAVE_SCOPE
SCOPEc = PREPARE_SCOPE;
#endif
 
// UART_CTRL = 82; // 1MBaud, given n 82.5MHz clock
UART_CTRL = 705; // 115200 Baud, given n 81.25MHz clock
// *UART_CTRL = 8333; // 9600 Baud, 8-bit chars, no parity, one stop bit
// *UART_CTRL = 25; // 9600 Baud, 8-bit chars, no parity, one stop bit
//
1198,36 → 1265,62
 
int tnum = 0;
 
// Check whether or not this CPU correctly identifies SIM instructions
// as illegal instructions
testid("SIM Instructions"); MARKSTART;
cc_fail = CC_MMUERR|CC_FPUERR|CC_DIVERR|CC_BUSERR|CC_TRAP|CC_STEP|CC_SLEEP;
if ((run_test(sim_test, user_stack_ptr))||(zip_ucc()&cc_fail))
test_fails(start_time, &testlist[tnum]);
else if (zip_ucc() & CC_ILL) {
txstr("Pass\r\n"); testlist[tnum++]; // 0
} else
txstr("Is this a simulator?\r\n");
 
testid("CIS Instructions"); MARKSTART;
cc_fail = CC_MMUERR|CC_FPUERR|CC_DIVERR|CC_BUSERR|CC_STEP|CC_SLEEP;
if ((run_test(cis_test, user_stack_ptr))||(zip_ucc()&cc_fail))
test_fails(start_time, &testlist[tnum]);
else if (zip_ucc() & CC_ILL)
txstr("Not supported\r\n");
else {
txstr("Supported\r\n");
cis_insns = 1;
}
 
// Test break instruction in user mode
// Make sure the break works as designed
testid("Break test #1"); MARKSTART;
 
if ((run_test(break_one, user_stack_ptr))||(zip_ucc()&0x1f50))
cc_fail = CC_MMUERR|CC_FPUERR|CC_DIVERR|CC_BUSERR|CC_TRAP|CC_ILL|CC_STEP|CC_SLEEP;
if ((run_test(break_one, user_stack_ptr))||(zip_ucc()&cc_fail))
test_fails(start_time, &testlist[tnum]);
 
save_context(context);
if ((context[15] != (int)break_one+1)||(0==(zip_ucc()&0x80)))
if ((context[15] != (int)break_one+4)||(0==(zip_ucc()&CC_BREAK)))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // 0
txstr("Pass\r\n"); testlist[tnum++] = 0; // #1
 
 
// Test break instruction in user mode
// Make sure that a decision on the clock prior won't still cause a
// break condition
cc_fail = CC_MMUERR|CC_FPUERR|CC_DIVERR|CC_BUSERR|CC_ILL|CC_BREAK|CC_STEP|CC_SLEEP;
testid("Break test #2"); MARKSTART;
if ((run_test(break_two, user_stack_ptr))||(zip_ucc()&0x1d90))
if ((run_test(break_two, user_stack_ptr))||(zip_ucc()&cc_fail))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #1
txstr("Pass\r\n"); testlist[tnum++] = 0; // #2
 
// Test break instruction in user mode
// Make sure that a decision on the clock prior won't still cause a
// break condition
cc_fail = (CC_FAULT)|CC_MMUERR|CC_TRAP|CC_STEP|CC_SLEEP;
testid("Break test #3"); MARKSTART;
run_test(break_three, user_stack_ptr);
save_context(context);
if ((context[15] != (int)break_three) // Insist we stop at the break
||(0==(zip_ucc()&0x80)) // insn, that the break flag is
||(zip_ucc()&0x01d10)) // set, and no other excpt flags
||(0==(zip_ucc()&CC_BREAK))//insn,that the break flag is
||(zip_ucc()&cc_fail)) // set, and no other excpt flags
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // 0
txstr("Pass\r\n"); testlist[tnum++] = 0; // #3
 
// LJMP test ... not (yet) written
 
1234,130 → 1327,159
// Test the early branching capability
// Does it successfully clear whatever else is in the pipeline?
testid("Early Branch test"); MARKSTART;
if ((run_test(early_branch_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(early_branch_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #2
txstr("Pass\r\n"); testlist[tnum++] = 0; // #4
 
// TRAP test
testid("Trap test/AND"); MARKSTART;
if ((run_test(trap_test_and, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(trap_test_and, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
if ((zip_ucc() & 0x0200)==0)
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #3
txstr("Pass\r\n"); testlist[tnum++] = 0; // #5
 
testid("Trap test/CLR"); MARKSTART;
if ((run_test(trap_test_clr, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(trap_test_clr, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
if ((zip_ucc() & 0x0200)==0)
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #4
txstr("Pass\r\n"); testlist[tnum++] = 0; // #6
 
// Overflow test
testid("Overflow test"); MARKSTART;
if ((run_test(overflow_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(overflow_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #5
txstr("Pass\r\n"); testlist[tnum++] = 0; // #7
 
// Carry test
testid("Carry test"); MARKSTART;
if ((run_test(carry_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(carry_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #6
txstr("Pass\r\n"); testlist[tnum++] = 0; // #8
 
// LOOP_TEST
testid("Loop test"); MARKSTART;
if ((run_test(loop_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(loop_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #7 -- FAILS
txstr("Pass\r\n"); testlist[tnum++] = 0; // #9
 
// SHIFT_TEST
testid("Shift test"); MARKSTART;
if ((run_test(shift_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(shift_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #8
txstr("Pass\r\n"); testlist[tnum++] = 0; // #10
 
// BREV_TEST
//testid("BREV/stack test"); MARKSTART;
//if ((run_test(brev_test, user_stack_ptr))||(zip_ucc()&0x01d90))
//test_fails(start_time);
//test_fails(start_time); // #10
//txstr("Pass\r\n");
 
// PIPELINE_TEST
testid("Pipeline test"); MARKSTART;
if ((run_test(pipeline_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(pipeline_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #10
txstr("Pass\r\n"); testlist[tnum++] = 0; // #11
 
// MEM_PIPELINE_STACK_TEST
testid("Mem-Pipeline test"); MARKSTART;
if ((run_test(mempipe_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(mempipe_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #11
txstr("Pass\r\n"); testlist[tnum++] = 0; // #12
 
// CONDITIONAL EXECUTION test
testid("Conditional Execution test"); MARKSTART;
if ((run_test(cexec_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(cexec_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #12 -- FAILS
txstr("Pass\r\n"); testlist[tnum++] = 0; // #13
 
// NOWAIT pipeline test
testid("No-waiting pipeline test"); MARKSTART;
if ((run_test(nowaitpipe_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(nowaitpipe_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #13
txstr("Pass\r\n"); testlist[tnum++] = 0; // #14
 
// BCMEM test
testid("Conditional Branching test"); MARKSTART;
if ((run_test(bcmem_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(bcmem_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #14
txstr("Pass\r\n"); testlist[tnum++] = 0; // #15
 
// Illegal Instruction test
testid("Ill Instruction test, NULL PC"); MARKSTART;
if ((run_test(NULL, user_stack_ptr))||((zip_ucc()^0x100)&0x01d90))
if ((run_test(NULL, user_stack_ptr))||((zip_ucc()^CC_ILL)&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0;
txstr("Pass\r\n"); testlist[tnum++] = 0; // #16
 
// Illegal Instruction test
cc_fail = CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_BREAK|CC_MMUERR;
testid("Ill Instruction test, two"); MARKSTART;
if ((run_test(ill_test, user_stack_ptr))||((zip_ucc()^0x100)&0x01d90))
if ((run_test(ill_test, user_stack_ptr))||(zip_ucc()&cc_fail))
test_fails(start_time, &testlist[tnum]);
save_context(context);
if (context[15] != (int)&ill_test)
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0;
txstr("Pass\r\n"); testlist[tnum++] = 0; // #17
 
// Compare EQuals test
cc_fail = CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_BREAK|CC_MMUERR|CC_ILL;
testid("Comparison test, =="); MARKSTART;
if ((run_test(cmpeq_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #18
 
// Compare !EQuals test
cc_fail = CC_BUSERR|CC_DIVERR|CC_FPUERR|CC_BREAK|CC_MMUERR|CC_ILL;
testid("Comparison test, !="); MARKSTART;
if ((run_test(cmpneq_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #19
 
// Pipeline memory race condition test
// DIVIDE test
 
// CC Register test
testid("CC Register test"); MARKSTART;
if ((run_test(ccreg_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(ccreg_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0;
txstr("Pass\r\n"); testlist[tnum++] = 0; // #20
 
// Multiple argument test
testid("Multi-Arg test"); MARKSTART;
if ((run_test(multiarg_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(multiarg_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0;
txstr("Pass\r\n"); testlist[tnum++] = 0; // #21
 
// MPY_TEST
testid("Multiply test"); MARKSTART;
if ((run_test(mpy_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(mpy_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #9
txstr("Pass\r\n"); testlist[tnum++] = 0; // #22
 
// MPYxHI_TEST
testid("Multiply HI-word test"); MARKSTART;
if ((run_test(mpyhi_test, user_stack_ptr))||(zip_ucc()&0x01d90))
if ((run_test(mpyhi_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
txstr("Pass\r\n"); testlist[tnum++] = 0; // #9
txstr("Pass\r\n"); testlist[tnum++] = 0; // #23
 
// DIV_TEST
testid("Divide test");
if ((zip_cc() & 0x20000000)==0) {
txstr("No divide unit installed\r\n");
} else { MARKSTART;
if ((run_test(div_test, user_stack_ptr))||(zip_ucc()&CC_EXCEPTION))
test_fails(start_time, &testlist[tnum]);
} txstr("Pass\r\n"); testlist[tnum++] = 0; // #24
 
 
txstr("\r\n");
txstr("-----------------------------------\r\n");
txstr("All tests passed. Halting CPU.\r\n");
wait_for_uart_idle();
for(int k=0; k<50000; k++)
asm("NOOP");
asm("NEXIT 0");
zip_halt();
}
 
/trunk/sw/board/exmulti.c
37,10 → 37,14
////////////////////////////////////////////////////////////////////////////////
//
//
#include "artyboard.h"
#include "zipcpu.h"
#include "zipsys.h"
#include "artyboard.h"
#include <stdio.h>
#include <string.h>
 
#define sys _sys
 
void idle_task(void) {
while(1)
zip_idle();
47,6 → 51,9
}
 
void wait_on_interrupt(int mask) {
if (mask & SYSINT_AUX) {
zip->z_apic = INT_ENABLE;
}
zip->z_pic = DALLPIC|mask;
zip->z_pic = EINT(mask);
zip_rtu();
58,7 → 65,7
while(1) {
unsigned btn, subnow, sw;
 
subnow = (sys->io_gps_sub >> 28)&0x0f;
subnow = (sys->io_b.i_tim.sub >> 28)&0x0f;
 
// If the button is pressed, toggle the LED
// Otherwise, turn the LED off.
65,19 → 72,19
//
 
// First, get all the pressed buttons
btn = (sys->io_btnsw) & 0x0f0;
btn = (sys->io_b.i_btnsw) & 0x0f0;
// Now, acknowledge the button presses that we just read
sys->io_btnsw = btn;
sys->io_b.i_btnsw = btn;
btn >>= 4;
 
// Now, use the time as the toggle function.
btn = (subnow ^ btn)&btn & 0x07;
 
sys->io_ledctrl = btn | 0x070;
sys->io_b.i_leds = btn | 0x070;
 
sw = sys->io_btnsw & 0x0f;
sw = sys->io_b.i_btnsw & 0x0f;
for(int i=0; i<4; i++)
sys->io_clrled[i] = (sw & (1<<i)) ? white : black;
sys->io_b.i_clrled[i] = (sw & (1<<i)) ? white : black;
 
}
}
103,15 → 110,76
// return ahi;
}
 
int hexdigit(int v) {
if (v < 10)
return v + '0';
else
return v + 'A' - 10;
 
int gps_lock = 0;
void gps_process_line(const char *line) {
if ((line[0] != '$')||(line[1] != 'G')
||(line[2] != 'P'))
return;
 
// GGA, GSV(x3), RMC, VTG
if (line[3] == 'G') {
/*
if ((line[4] == 'G')&&(line[5] == 'A')) {
} // else if ((line[5] == 'S')&&(line[6] == 'V')) {
}
*/
// printf("GPS Line: %s\r\n", line);
} else if (line[3] == 'R') {
// if ((line[4] == 'M')&&(line[5] == 'C')&&(line[6] == ','))
{
// char outbuf[256], *outptr = outbuf;
// const char *here = &line[8], *there;
// there = strchr(here, ',');
fputs("RMC-Line\r\n", stdout);
#ifdef PROCLINE
if ((there)&&(there - here > 6)) {
outptr += sprintf(outptr,
"TIME: %c%c:%c%c:%c%c\r\n",
here[0], here[1],
here[2], here[3],
here[4], here[5]);
here = there + 1;
there = strchr(here, ',');
} if (there) {
if (*here == 'A')
gps_lock = 1;
else
gps_lock = 0;
here = there + 1;
there = strchr(there+1, ',');
} if (there) {
there = strchr(there+1, ',');
} if (there) {
char tmp[32];
strncpy(tmp, here, there-here);
outptr += sprintf(outptr, "LATITUDE: %s\r\n");
here = there + 1;
there = strchr(there+1, ',');
} if (there) {
there = strchr(there+1, ',');
} if (there) {
char tmp[32];
strncpy(tmp, here, there-here);
outptr += sprintf(outptr, "LONGITUDE: %s\r\n");
} if (gps_lock)
fputs(outbuf, stdout);
else puts("No GPS lock\r\n");
#endif
}
printf("GPS RMC Line: %s\r\n", line);
} else if (line[3] == 'V') {
/*
if ((line[4] == 'T')&&(line[5] == 'G')) {
}
*/
// printf("GPS Line: %s\r\n", line);
} else printf("Other GPS Line: %s\r\n", line);
}
 
int errstring[128];
char errstring[128];
 
 
void main(int argc, char **argv) {
const unsigned red = 0x0ff0000, green = 0x0ff00, blue = 0x0ff,
white = 0x070707, black = 0, dimgreen = 0x1f00,
123,6 → 191,7
sys->io_gps.g_beta = 0x14bda12f;
sys->io_gps.g_gamma = 0x1f533ae8;
 
//
int user_context[16];
for(i=0; i<15; i++)
user_context[i] = 0;
130,8 → 199,8
zip_restore_context(user_context);
 
for(i=0; i<4; i++)
sys->io_clrled[i] = red;
sys->io_ledctrl = 0x0ff;
sys->io_b.i_clrled[i] = red;
sys->io_b.i_leds = 0x0ff;
 
// Clear the PIC
//
138,7 → 207,7
// Acknowledge all interrupts, turn off all interrupts
//
zip->z_pic = CLEARPIC;
while(sys->io_pwrcount < (second >> 4))
while(sys->io_b.i_pwrcount < (second >> 4))
;
 
// Repeating timer, every 250ms
145,36 → 214,36
zip->z_tma = TMR_INTERVAL | (second/4);
wait_on_interrupt(SYSINT_TMA);
 
sys->io_clrled[0] = green;
sys->io_ledctrl = 0x010;
sys->io_b.i_clrled[0] = green;
sys->io_b.i_leds = 0x010;
 
wait_on_interrupt(SYSINT_TMA);
 
sys->io_clrled[0] = dimgreen;
sys->io_clrled[1] = green;
sys->io_scope[0].s_ctrl = SCOPE_NO_RESET | 32;
sys->io_ledctrl = 0x020;
sys->io_b.i_clrled[0] = dimgreen;
sys->io_b.i_clrled[1] = green;
sys->io_scope[0].s_ctrl = WBSCOPE_NO_RESET | 32;
sys->io_b.i_leds = 0x020;
 
wait_on_interrupt(SYSINT_TMA);
 
sys->io_clrled[1] = dimgreen;
sys->io_clrled[2] = green;
sys->io_ledctrl = 0x040;
sys->io_b.i_clrled[1] = dimgreen;
sys->io_b.i_clrled[2] = green;
sys->io_b.i_leds = 0x040;
 
wait_on_interrupt(SYSINT_TMA);
 
sys->io_clrled[2] = dimgreen;
sys->io_clrled[3] = green;
sys->io_ledctrl = 0x080;
sys->io_b.i_clrled[2] = dimgreen;
sys->io_b.i_clrled[3] = green;
sys->io_b.i_leds = 0x080;
 
wait_on_interrupt(SYSINT_TMA);
 
sys->io_clrled[3] = dimgreen;
sys->io_b.i_clrled[3] = dimgreen;
 
wait_on_interrupt(SYSINT_TMA);
 
for(i=0; i<4; i++)
sys->io_clrled[i] = black;
sys->io_b.i_clrled[i] = black;
 
// Wait one second ...
for(i=0; i<4; i++)
182,11 → 251,11
 
// Blink all the LEDs
// First turn them on
sys->io_ledctrl = 0x0ff;
sys->io_b.i_leds = 0x0ff;
// Then wait a quarter second
wait_on_interrupt(SYSINT_TMA);
// Then turn the back off
sys->io_ledctrl = 0x0f0;
sys->io_b.i_leds = 0x0f0;
// and wait another quarter second
wait_on_interrupt(SYSINT_TMA);
 
201,171 → 270,64
do {
wait_on_interrupt(SYSINT_PPS|SYSINT_TMA);
} while((zip->z_pic & SYSINT_PPS)==0);
 
printf("GPS RECORD START\r\n");
 
zip->z_tma = TMR_INTERVAL | (second/1000);
wait_on_interrupt(SYSINT_TMA);
sys->io_gpsu.u_rx = 0x01000;
while(1) {
int *s = errstring;
char *s = errstring;
 
zip->z_wdt = CLOCKFREQ_HZ*4;
sys->io_ledctrl = 0x088;
sys->io_b.i_leds = 0x088;
 
// 1. Read and report the GPS tracking err
 
// Get the upper 32-bits of the error;
int err = *(int *)(&sys->io_gpstb.tb_err);
int err_in_ns;
/*
long err_in_ns_long = err;
err_in_ns_long *= 1000000000l;
err_in_ns_long >>= 32;
int err_in_ns = (int)(err_in_ns_long);
*/
int err_sgn = (err < 0)?1:0;
int err_in_ns, err_in_us;
int err_sgn = (err < 0)?1:0, err_in_ns_rem;
 
err_in_ns = (err<0)?-err:err;
err_in_ns = mpyuhi(err_in_ns, 1000000000);
int digit;
 
err_in_us = err_in_ns / 1000;
err_in_ns_rem = err_in_ns - err_in_us * 1000;
if (err_sgn)
err_in_us = - err_in_us;
 
*s++ = '\r';
*s++ = '\n';
*s++ = 'G';
*s++ = 'P';
*s++ = 'S';
*s++ = ' ';
*s++ = 'P';
*s++ = 'P';
*s++ = 'S';
*s++ = ' ';
*s++ = 'E';
*s++ = 'r';
*s++ = 'r';
*s++ = ':';
*s++ = ' ';
printf("\r\nGPS PPS Err: 0x%08x => 0x%08x => %+5d.%03d us\r\n",
err, err_in_ns, err_in_us, err_in_ns_rem);
 
 
*s++ = '0';
*s++ = 'x';
*s++ = hexdigit((err>>28)&0x0f);
*s++ = hexdigit((err>>24)&0x0f);
*s++ = hexdigit((err>>20)&0x0f);
*s++ = hexdigit((err>>16)&0x0f);
*s++ = hexdigit((err>>12)&0x0f);
*s++ = hexdigit((err>> 8)&0x0f);
*s++ = hexdigit((err>> 4)&0x0f);
*s++ = hexdigit((err )&0x0f);
 
*s++ = ' ';
*s++ = '=';
*s++ = '>';
*s++ = ' ';
sys->io_b.i_leds = 0x080;
 
*s++ = '0';
*s++ = 'x';
*s++ = hexdigit((err_in_ns>>28)&0x0f);
*s++ = hexdigit((err_in_ns>>24)&0x0f);
*s++ = hexdigit((err_in_ns>>20)&0x0f);
*s++ = hexdigit((err_in_ns>>16)&0x0f);
*s++ = hexdigit((err_in_ns>>12)&0x0f);
*s++ = hexdigit((err_in_ns>> 8)&0x0f);
*s++ = hexdigit((err_in_ns>> 4)&0x0f);
*s++ = hexdigit((err_in_ns )&0x0f);
zip->z_pic = SYSINT_GPSRXF | SYSINT_PPS | SYSINT_TMA;
{
const int LINEBUFSZ = 80;
char line[LINEBUFSZ], *linep = line;
do {
int v;
wait_on_interrupt(SYSINT_PPS|SYSINT_GPSRXF|SYSINT_TMA);
 
*s++ = ' ';
*s++ = '=';
*s++ = '>';
*s++ = ' ';
 
*s++ = (err_sgn)?'-':' ';
// Milliseconds
digit = err_in_ns / 100000000;
*s++ = digit+'0';
err_in_ns -= digit * 100000000;
//
digit = err_in_ns / 10000000;
*s++ = digit+'0';
err_in_ns -= digit * 10000000;
//
digit = err_in_ns / 1000000;
*s++ = digit+'0';
err_in_ns -= digit * 1000000;
// Micro seconds
digit = err_in_ns / 100000;
*s++ = digit+'0';
err_in_ns -= digit * 100000;
//
digit = err_in_ns / 10000;
*s++ = digit+'0';
err_in_ns -= digit * 10000;
//
digit = err_in_ns / 1000;
*s++ = digit+'0';
err_in_ns -= digit * 1000;
// Nano seconds
*s++ = '.';
digit = err_in_ns / 100;
*s++ = digit+'0';
err_in_ns -= digit * 100;
//
digit = err_in_ns / 10;
*s++ = digit+'0';
err_in_ns -= digit * 10;
//
digit = err_in_ns;
*s++ = digit+'0';
//
*s++ = ' ';
*s++ = 'u';
*s++ = 'S';
*s++ = '\r';
*s++ = '\n';
*s++ = '\r';
*s++ = '\n';
*s++ = '\0';
 
/*
zip->z_dma.d_ctrl = DMACLEAR;
zip->z_dma.d_rd = errstring;
zip->z_dma.d_wr = &sys->io_uart_tx;
zip->z_dma.d_len = s - errstring-1;
zip->z_dma.d_ctrl = (DMAONEATATIME|DMA_CONSTDST|DMA_GPSRX);
wait_on_interrupt(SYSINT_DMAC);
*/
 
for(int i=0; errstring[i]; i++) {
wait_on_interrupt(SYSINT_UARTTX);
sys->io_uart_tx = errstring[i];
zip->z_pic = SYSINT_UARTTX;
while(((v = sys->io_gpsu.u_rx)&0x100)==0) {
v &= 0x0ff;
// putchar(v);
// sys->io_uart.u_tx = v;
*linep++ = v;
if(linep-line > LINEBUFSZ)
linep = line;
if ((v == '\r')||(v == '\n')) {
*linep = '\0';
if (line[0] == '$')
gps_process_line(line);
linep = line;
}
}
} while((zip->z_pic & SYSINT_PPS)==0);
}
 
sys->io_ledctrl = 0x080;
 
/*
zip->z_dma.d_rd = &sys->io_gps_rx;
zip->z_dma.d_wr = &sys->io_uart_tx;
zip->z_dma.d_len = 0x01000000;
zip->z_dma.d_ctrl = (DMAONEATATIME|DMA_CONSTDST|DMA_CONSTSRC|DMA_ONGPSRX);
wait_on_interrupt(SYSINT_PPS);
*/
 
/*
if (zip_ucc() & CC_FAULT) {
zip_save_context(user_context);
user_context[14] = CC_GIE;
user_context[15] = (int)&idle_task;
zip_restore_context(user_context);
}
*/
 
zip->z_pic = SYSINT_GPSRX | SYSINT_PPS;
do {
wait_on_interrupt(SYSINT_PPS|SYSINT_GPSRX);
if (zip->z_pic & SYSINT_GPSRX) {
sys->io_uart_tx = sys->io_gps_rx;
zip->z_pic = SYSINT_GPSRX;
}
} while((zip->z_pic & SYSINT_PPS)==0);
 
// wait_on_interrupt(SYSINT_PPS);
// zip->z_dma.d_ctrl= DMACLEAR;
}
 
zip_halt();
/trunk/sw/board/exstartup.c
37,10 → 37,14
////////////////////////////////////////////////////////////////////////////////
//
//
#include <stdio.h>
 
#include "artyboard.h"
#include "zipcpu.h"
#include "zipsys.h"
#include "artyboard.h"
 
#define sys _sys
 
void idle_task(void) {
while(1)
zip_idle();
52,7 → 56,6
zip_rtu();
}
 
 
void main(int argc, char **argv) {
const unsigned red = 0x0ff0000, green = 0x0ff00, blue = 0x0ff,
white = 0x070707, black = 0, dimgreen = 0x1f00,
65,9 → 68,11
user_context[15] = (unsigned)idle_task;
zip_restore_context(user_context);
 
printf("Starting exstartup\r\n");
 
for(i=0; i<4; i++)
sys->io_clrled[i] = red;
sys->io_ledctrl = 0x0ff;
_sys->io_b.i_clrled[i] = red;
sys->io_b.i_leds = 0x0ff;
 
// Clear the PIC
//
74,7 → 79,7
// Acknowledge all interrupts, turn off all interrupts
//
zip->z_pic = CLEARPIC;
while(sys->io_pwrcount < (second >> 4))
while(sys->io_b.i_pwrcount < (second >> 4))
;
 
// Repeating timer, every 250ms
81,44 → 86,44
zip->z_tma = TMR_INTERVAL | (second/4);
wait_on_interrupt(SYSINT_TMA);
 
sys->io_clrled[0] = green;
sys->io_ledctrl = 0x010;
sys->io_b.i_clrled[0] = green;
sys->io_b.i_leds = 0x010;
 
wait_on_interrupt(SYSINT_TMA);
 
sys->io_clrled[0] = dimgreen;
sys->io_clrled[1] = green;
sys->io_scope[0].s_ctrl = SCOPE_NO_RESET | 32;
sys->io_ledctrl = 0x020;
sys->io_b.i_clrled[0] = dimgreen;
sys->io_b.i_clrled[1] = green;
sys->io_scope[0].s_ctrl = WBSCOPE_NO_RESET | 32;
sys->io_b.i_leds = 0x020;
 
wait_on_interrupt(SYSINT_TMA);
 
sys->io_clrled[1] = dimgreen;
sys->io_clrled[2] = green;
sys->io_ledctrl = 0x040;
sys->io_b.i_clrled[1] = dimgreen;
sys->io_b.i_clrled[2] = green;
sys->io_b.i_leds = 0x040;
 
wait_on_interrupt(SYSINT_TMA);
 
sys->io_clrled[2] = dimgreen;
sys->io_clrled[3] = green;
sys->io_ledctrl = 0x080;
sys->io_b.i_clrled[2] = dimgreen;
sys->io_b.i_clrled[3] = green;
sys->io_b.i_leds = 0x080;
 
wait_on_interrupt(SYSINT_TMA);
 
sys->io_clrled[3] = dimgreen;
sys->io_b.i_clrled[3] = dimgreen;
 
wait_on_interrupt(SYSINT_TMA);
 
for(i=0; i<4; i++)
sys->io_clrled[i] = black;
sys->io_b.i_clrled[i] = black;
 
// Wait one second ...
for(i=0; i<4; i++)
wait_on_interrupt(SYSINT_TMA);
 
sw = sys->io_btnsw & 0x0f;
sw = sys->io_b.i_btnsw & 0x0f;
for(int i=0; i<4; i++)
sys->io_clrled[i] = (sw & (1<<i)) ? white : black;
sys->io_b.i_clrled[i] = (sw & (1<<i)) ? white : black;
 
 
// Wait another two seconds ...
127,11 → 132,11
 
// Blink all the LEDs
// First turn them on
sys->io_ledctrl = 0x0ff;
sys->io_b.i_leds = 0x0ff;
// Then wait a quarter second
wait_on_interrupt(SYSINT_TMA);
// Then turn the back off
sys->io_ledctrl = 0x0f0;
sys->io_b.i_leds = 0x0f0;
// and wait another quarter second
wait_on_interrupt(SYSINT_TMA);
 
147,27 → 152,26
// Otherwise, turn the LED off.
//
// First, get all the pressed buttons
btn = (sys->io_btnsw >> 4) & 0x0f;
btn = (sys->io_b.i_btnsw >> 4) & 0x0f;
// Now, acknowledge the button presses that we just read
sys->io_btnsw = (btn<<4);
sys->io_b.i_btnsw = (btn<<4);
 
// Of any LEDs that are on, or buttons on, toggle their values
ledc = (sys->io_ledctrl)&0x0f;
ledc = (sys->io_b.i_leds)&0x0f;
ledc = (ledc | btn)&0x0f ^ ledc;
// Make sure we set everything
ledc |= 0x0f0;
// Now issue the command
sys->io_ledctrl = ledc;
sys->io_b.i_leds = ledc;
// That way, at the end, the toggle will leave them in the
// off position.
// sys->io_ledctrl = 0xf0 | ((sys->io_ledctrl&1)^1);
// sys->io_b.i_leds = 0xf0 | ((sys->io_b.i_leds&1)^1);
 
sw = sys->io_btnsw & 0x0f;
sw = sys->io_b.i_btnsw & 0x0f;
for(int i=0; i<4; i++)
sys->io_clrled[i] = (sw & (1<<i)) ? white : black;
sys->io_b.i_clrled[i] = (sw & (1<<i)) ? white : black;
 
}
 
zip_halt();
}
 
/trunk/sw/board/gpsdump.c
35,10 → 35,12
////////////////////////////////////////////////////////////////////////////////
//
//
#include "artyboard.h"
#include "zipcpu.h"
#include "zipsys.h"
#include "artyboard.h"
 
#define sys _sys
 
void main(int argc, char **argv) {
/*
// Method one: direct polling
51,12 → 53,14
*/
 
// Method two: Waiting on interrupts
zip->z_pic = SYSINT_GPSRX;
int lglen = (1<<((sys->io_gpsu.u_fifo >> 12)&0x0f))-1;
zip->z_pic = SYSINT_GPSRXF;
while(1) {
while((zip->z_pic & SYSINT_GPSRX)==0)
while((zip->z_pic & SYSINT_GPSRXF)==0)
;
sys->io_uart_tx = sys->io_gps_rx;
zip->z_pic = SYSINT_GPSRX;
for(int i=0; i<lglen/2; i++)
sys->io_uart.u_tx = sys->io_gpsu.u_rx & 0x0ff;
zip->z_pic = SYSINT_GPSRXF;
}
 
/*
/trunk/sw/board/hello.c
0,0 → 1,46
////////////////////////////////////////////////////////////////////////////////
//
// Filename: hello.c
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: The classical "Hello, world!\r\n" program. This one, however,
// runs on the Arty using the PModUSBUART
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include <stdio.h>
 
int main(int argc, char **argv) {
// Print Hello, World, out the UART!
printf("Hello, world!\r\n");
return 0;
}
 
/trunk/sw/board/ipcksum.c
0,0 → 1,78
////////////////////////////////////////////////////////////////////////////////
//
// Filename: ipsum.c
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: To calculate (and return) an IP checksum on a section of data.
// The data must be contiguous in memory, and the checksum field
// (which is usually a part of it) must be blank when calling this
// function.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include "zipcpu.h"
#include "ipcksum.h"
 
#define ASM
unsigned ipcksum(int len, unsigned *ptr) {
#ifndef ASM
unsigned checksum = 0;
 
for(int i=0; i<len; i++)
checksum = checksum + (ptr[i] & 0x0ffff) + (ptr[i] >> 16);
while(checksum & ~0x0ffff)
checksum = (checksum & 0x0ffff) + (checksum >> 16);
return checksum ^ 0x0ffff;
#else
asm(ASMFNSTR("ipcksum") // R1 = length (W), R2 = packet pointer
"\tMOV R1,R3\n" // R3 is now the remaining length
"\tCLR R1\n" // R1 will be our checksum accumulator
".Lloop:\n"
"\tLW (R2),R4\n"
"\tADD R4,R1\n"
"\tADD.C 1,R1\n"
"\tADD 4,R2\n"
"\tSUB 1,R3\n"
"\tBZ .Lexit\n"
"\tBRA .Lloop\n"
".Lexit:\n"
"\tMOV R1,R3\n"
"\tAND 0x0ffff,R1\n"
"\tLSR 16,R3\n"
"\tADD R3,R1\n"
"\tTEST 0xffff0000,R1\n" // The carry bit can only and will only
"\tADD.NZ 1,R1\n" // ever be a one here. Add it in.
"\tAND 0x0ffff,R1\n"
"\tXOR 0x0ffff,R1\n"
"\tRETN");
#endif
}
 
/trunk/sw/board/ipcksum.h
0,0 → 1,47
////////////////////////////////////////////////////////////////////////////////
//
// Filename: ipcksum.h
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: To calculate (and return) an IP checksum on a section of data.
// The data must be contiguous in memory, and the checksum field
// (which is usually a part of it) must be blank when calling this
// function.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef IPCKSUM_H
#define IPCKSUM_H
 
extern unsigned ipcksum(int len, unsigned *ptr);
 
#endif
 
/trunk/sw/board/ledcolors.h
0,0 → 1,55
////////////////////////////////////////////////////////////////////////////////
//
// Filename: ledcolors.h
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: Just to provide some simple color constants that can be used
// to drive the color LEDs present on the Arty.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef LEDCOLORS_H
#define LEDCOLORS_H
 
#define LEDC_BRIGHTRED 0x0ff0000
#define LEDC_BRIGHTGREEN 0x000ff00
#define LEDC_BRIGHTBLUE 0x00000ff
 
#define LEDC_RED 0x0070000
#define LEDC_GREEN 0x0000700
#define LEDC_BLUE 0x0000007
#define LEDC_YELLOW 0x0070700
 
#define LEDC_WHITE 0x0070707
#define LEDC_OFF 0
 
 
#endif
/trunk/sw/board/mug.c
42,7 → 42,7
////////////////////////////////////////////////////////////////////////////////
//
//
int mug[6144] = {
short mug[6144] = {
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xdedd,
0x8c54, 0x5acd, 0x39e9, 0x2966, 0x2105, 0x18e4, 0x10a3, 0x10a2,
0x1082, 0x1082, 0x1082, 0x1082, 0x0862, 0x0862, 0x1062, 0x1062,
/trunk/sw/board/oledtest.c
39,16 → 39,18
////////////////////////////////////////////////////////////////////////////////
//
//
#include "artyboard.h"
#include "zipcpu.h"
#include "zipsys.h"
#include "artyboard.h"
 
#define sys _sys
 
void idle_task(void) {
while(1)
zip_idle();
}
 
extern int splash[], mug[];
extern short splash[], mug[];
 
#define OLED_DISPLAYON 0x0af
#define MICROSECOND (CLOCKFREQ_HZ/1000000)
140,6 → 142,8
0x02e
};
 
const int num_init_items = sizeof(init_sequence)/sizeof(init_sequence[0]);
 
/*
* oled_init()
*
156,7 → 160,7
void oled_init(void) {
int i;
 
for(i=0; i<sizeof(init_sequence); i++) {
for(i=0; i<num_init_items; i++) {
while(OLED_BUSY(sys->io_oled))
;
sys->io_oled.o_ctrl = init_sequence[i];
268,20 → 272,12
* DMA transfer is complete, whereas the second version of the routine
* returns as soon as the image transfer is complete.
*/
void oled_show_image(int *img) {
#define USE_DMA
#ifdef USE_DMA
zip->z_dma.d_len= 6144;
zip->z_dma.d_rd = img;
zip->z_dma.d_wr = (int *)&sys->io_oled.o_data;
zip->z_dma.d_ctrl = DMAONEATATIME|DMA_CONSTDST|DMA_ONOLED;
#else
for(int i=0; i<6144; i++) {
while(OLED_BUSY(sys->io_oled))
;
sys->io_oled.o_data = img[i];
}
#endif
void oled_show_image(unsigned short *img) {
for(int i=0; i<6144; i++) {
while(OLED_BUSY(sys->io_oled))
;
sys->io_oled.o_data = (unsigned)img[i];
}
}
 
/*
313,15 → 309,15
// the master_ce line high within the CPU, and so it generates
// a whole lot of debug information in our Verilator simulation,
// busmaster_tb.
int pwrcount = sys->io_pwrcount;
int pwrcount = sys->io_b.i_pwrcount;
do {
pwrcount = sys->io_pwrcount;
pwrcount = sys->io_b.i_pwrcount;
} while((pwrcount>0)&&(pwrcount < CLOCKFREQ_HZ/4));
} else {
// By using the timer and sleeping instead, the simulator can
// be made to run a *lot* faster, with a *lot* less debugging
// ... junk.
int pwrcount = sys->io_pwrcount;
int pwrcount = sys->io_b.i_pwrcount;
if ((pwrcount > 0)&&(pwrcount < CLOCKFREQ_HZ/4)) {
pwrcount = CLOCKFREQ_HZ/4 - pwrcount;
timer_delay(pwrcount);
381,7 → 377,7
// so we're good here.
 
while(1) {
sys->io_ledctrl = 0x0f0;
sys->io_b.i_leds = 0x0f0;
 
sys->io_oled.o_ctrl = OLED_DISPLAYON;
 
401,28 → 397,28
 
// Now ... finally ... we can send our image.
oled_show_image(splash);
wait_on_interrupt(SYSINT_DMAC);
// wait_on_interrupt(SYSINT_DMAC);
 
// Wait 25 seconds. The LEDs are for a fun effect.
sys->io_ledctrl = 0x0f1;
sys->io_b.i_leds = 0x0f1;
timer_delay(CLOCKFREQ_HZ*5);
sys->io_ledctrl = 0x0f3;
sys->io_b.i_leds = 0x0f3;
timer_delay(CLOCKFREQ_HZ*5);
sys->io_ledctrl = 0x0f7;
sys->io_b.i_leds = 0x0f7;
timer_delay(CLOCKFREQ_HZ*5);
sys->io_ledctrl = 0x0ff;
sys->io_b.i_leds = 0x0ff;
timer_delay(CLOCKFREQ_HZ*5);
sys->io_ledctrl = 0x0fe;
sys->io_b.i_leds = 0x0fe;
timer_delay(CLOCKFREQ_HZ*5);
 
 
// Display a second image.
sys->io_ledctrl = 0x0fc;
sys->io_b.i_leds = 0x0fc;
oled_show_image(mug);
wait_on_interrupt(SYSINT_DMAC);
// wait_on_interrupt(SYSINT_DMAC);
 
// Leave this one in effect for 5 seconds only.
sys->io_ledctrl = 0x0f8;
sys->io_b.i_leds = 0x0f8;
timer_delay(CLOCKFREQ_HZ*5);
}
 
/trunk/sw/board/simple_ping.c
0,0 → 1,513
////////////////////////////////////////////////////////////////////////////////
//
// Filename: simple-ping.c
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: To exercise the network port by ...
//
// 1. Pinging another system, at 1PPS
// 2. Replying to ARP requests
// 3. Replying to external 'pings' requests
//
// To configure this for your network, you will need to adjust the
// following constants within this file:
//
// my_ip_addr
// This is the (fixed) IP address of your Arty board. The first
// octet of the IP address is kept in the high order word.
//
// my_mac_addr (unsigned long, 64 bits)
// This is the fixed MAC address of your Arty board. The first
// two octets appear in bits 47:32 (MSB #s are high), and the other
// four in bits 31:0. Since the Arty PHY does not come with a
// designated MAC address, I generated one for my PHY using
// /dev/rand. The key to this, though, is that the second nibble
// (bits 8..12) in my_mac_addr[0] must be set to 4'h2 to reflect
// this fact.
//
// ping_ip_addr
// This is the IP address of the computer you wish to ping.
//
// my_ip_router
// In case the computer you wish to ping is not your
// router/gateway, and worse that it is not on your network, then
// you will need to fill this value in with the IP address of a
// gateway server that is accessable from this network. Place
// that IP address into this variable.
//
// my_ip_mask
// The IP mask is used to determine what is on your subnet, versus
// what needs to be sent to your router/gateway. Set this mask
// such that a '1' is placed in every network bit of your IP
// address, and '0' in every host bit. For me, I am using a
// network of 192.168.10.x, where x is the computer on the network,
// so I set this to 0xffffff00.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include "artyboard.h"
#include "zipcpu.h"
#include "zipsys.h"
#define KTRAPID_SENDPKT 0
#include "etcnet.h"
#include "protoconst.h"
#include "ledcolors.h"
#include "ipcksum.h"
#include "arp.h"
 
#define sys _sys
 
unsigned pkts_received = 0, replies_received=0, arp_requests_received=0,
arp_pkt_count =0, arp_pkt_invalid =0,
arp_missed_ip = 0, arp_non_broadcast = 0,
ip_pkts_received = 0, ip_pkts_invalid = 0,
icmp_echo_requests=0, icmp_invalid= 0,
ping_reply_address_not_found = 0, ping_replies_sent = 0,
ping_reply_err = 0, user_tx_packets = 0,
user_heartbeats = 0;
 
unsigned long ping_mac_addr;
 
// These two numbers will allow us to keep track of how many ping's we've
// sent and how many we've received the returns for.
unsigned ping_tx_count = 0, ping_rx_count = 0;
 
// This is a cheater's approach to knowing what IP to ping: we pre-load the
// program with both the IP address to ping, as well as the MAC address
// associated with that IP address. Future implementations will need to
// 1. Look up the MAC address of the device we wish to ping (assuming our
// subnet), or
// 2. Later, check if the IP address is not on our subnet, and if not then
// look up the MAC address of the router and use that MAC address when
// sending (no change to the IP)
unsigned ping_ip_addr = IPADDR(192,168,10,1);
unsigned long ping_mac_addr = 0;
 
// My network ID. The 192.168.10 part comes from the fact that this is a
// local network. The .22 (last octet) is due to the fact that this is
// an unused ID on my network.
unsigned my_ip_addr = DEFAULTIP;
// Something from /dev/rand
// Only ... the second nibble must be two. Hence we start with d(2)d8.
unsigned long my_mac_addr = DEFAULTMAC, router_mac_addr = 0;
unsigned my_ip_mask = LCLNETMASK,
my_ip_router = DEFAULT_ROUTERIP;
 
unsigned pkt_id = 0;
 
///////////
//
//
// User tasks and functions (excluding ARP)
//
//
///////////
 
 
//
// We'll give our user 64kW of global variables
//
#define USER_STACK_SIZE 4096
int user_stack[USER_STACK_SIZE];
const int *user_sp = &user_stack[USER_STACK_SIZE];
 
 
void uping_reply(unsigned ipaddr, unsigned *icmp_request) {
unsigned pkt[2048];
unsigned long hwaddr;
int maxsz = 2048;
 
maxsz = 1<<((sys->io_enet.n_rxcmd>>24)&0x0f);
if (maxsz > 2048)
maxsz = 2048;
int pktln = (icmp_request[0] & 0x0ffff)+8, pktlnw = (pktln+3)>>2;
 
if (arp_lookup(ipaddr, &hwaddr)!=0) {
// Couldn't find the address -- don't reply, but send an arp
// request.
//
// ARP request is automatic when the address isn't found,
// and done by the arp_lookup.
ping_reply_address_not_found++;
} else if ((pktlnw < maxsz)
&&((icmp_request[0]>>24)==0x045)) {
int id;
 
pkt[0] = (unsigned)(hwaddr>>16);
pkt[1] = ((unsigned)(hwaddr<<16))|ETHERTYPE_IP;
pkt[2] = icmp_request[0] & 0xff00ffff;
id = pkt_id + sys->io_b.i_tim.sub;
pkt[3] = (id&0x0ffff)<<16; // no fragments
pkt[4] = 0xff010000;//No flags,frag offset=0,ttl=0,proto=1(ICMP)
pkt[5] = icmp_request[4]; // Swap sender and receiver
pkt[6] = icmp_request[3];
for(int k=7; k<pktlnw; k++)
pkt[k] = icmp_request[k-2];
pkt[7] = 0;
 
if ((pktln & 3)!=0)
pkt[pktlnw-1] &= ~((1<<((4-(pktln&3))<<3))-1);
 
// Now, let's go fill in the IP and ICMP checksums
pkt[4] |= ipcksum(5, &pkt[2]);
 
pkt[7] &= 0xffff0000;
pkt[7] |= ipcksum(pktlnw-7, &pkt[7]);
 
ping_replies_sent++;
syscall(KTRAPID_SENDPKT,0,(unsigned)pkt, pktln);
} else
ping_reply_err ++;
}
 
unsigned rxpkt[2048];
void user_task(void) {
unsigned rtc = sys->io_rtc.r_clock;
 
while(1) {
do {
unsigned long mac;
 
// Rate limit our ARP searching to one Hz
rtc = sys->io_rtc.r_clock;
 
if (arp_lookup(ping_ip_addr, &ping_mac_addr) == 0)
arp_lookup(my_ip_router, &mac);
 
while(((sys->io_enet.n_rxcmd & ENET_RXAVAIL)==0)
&&(sys->io_rtc.r_clock == rtc))
user_heartbeats++;
} while((sys->io_enet.n_rxcmd & ENET_RXAVAIL)==0);
 
// Okay, now we have a receive packet ... let's process it
int etype = sys->io_enet_rx[1] & 0x0ffff;
unsigned *epayload; // = (unsigned *)&sys->io_enet_rx[2];
int invalid = 0;
int ln, rxcmd = sys->io_enet.n_rxcmd;
 
ln = sys->io_enet.n_rxcmd & 0x07ff;
for(int k=0; k<(ln+3)>>2; k++)
rxpkt[k] = sys->io_enet_rx[k];
epayload = &rxpkt[2];
sys->io_enet.n_rxcmd = ENET_RXCLR|ENET_RXCLRERR;
 
pkts_received++;
 
if (etype == ETHERTYPE_IP) {
unsigned *ip = epayload,
*ippayload = &ip[(ip[0]>>24)&0x0f];
 
if (((ip[0]>>28)&15)!=4)
invalid = 1;
else if (ip[1] & 0x0bfff)
// Packet is fragmented--toss it out
invalid = 1;
else if (ip[4] != my_ip_addr)
invalid = 1;
 
ip_pkts_received += (invalid^1);
ip_pkts_invalid += (invalid);
 
unsigned ipproto = (ip[2]>>16)&0x0ff;
if((invalid==0)&&(ipproto == IPPROTO_ICMP)) {
unsigned icmp_type = ippayload[0]>>24;
if (icmp_type == ICMP_ECHOREPLY) {
// We got our ping response
sys->io_b.i_clrled[3] = LEDC_GREEN;
sys->io_b.i_leds = 0x80;
ping_rx_count++;
} else if (icmp_type == ICMP_ECHO) {
// Someone is pinging us
uping_reply(ip[3],ip);
icmp_echo_requests++;
} else
icmp_invalid++;
}
} else if (etype == ETHERTYPE_ARP) {
arp_pkt_count++;
if (epayload[0] != 0x010800) {
invalid = 1;
arp_pkt_invalid++;
} else if ((epayload[1] == 0x06040001)
&&(rxcmd & ENET_RXBROADCAST)
&&(epayload[6] == my_ip_addr))
{ // ARP Request
unsigned sha[2], // Senders HW address
sip, // Senders IP address
dip; // Desired IP address
sha[0] = epayload[2];
sha[1] = epayload[3]>>16;
sha[1] |= sha[0]<<16;
sha[0] >>= 16;
sip = (epayload[3]<<16)|(epayload[4]>>16);
arp_requests_received++;
send_arp_reply(sha[0], sha[1], sip);
} else if ((epayload[1] == 0x06040002) // Reply
&&((rxcmd & ENET_RXBROADCAST)==0)
&&(epayload[6] == my_ip_addr)) {
unsigned sip;
unsigned long sha;
 
sha = *(unsigned long *)(&epayload[2]);
sha >>= 16;
sip = (epayload[3]<<16)|(epayload[4]>>16);
if (sip == ping_ip_addr)
ping_mac_addr = sha;
arp_table_add(sip, sha);
}
}
}
}
 
 
///////////
//
//
// Supervisor tasks and functions
//
//
///////////
 
 
void send_ping(void) {
unsigned *pkt;
 
// If we don't know our destination MAC address yet, just return
if (ping_mac_addr==0) {
sys->io_b.i_clrled[1] = LEDC_YELLOW;
return;
}
 
// If the network is busy transmitting, wait for it to finish
if (sys->io_enet.n_txcmd & ENET_TXBUSY) {
while(sys->io_enet.n_txcmd & ENET_TXBUSY)
;
}
 
// Form a packet to transmit
pkt = (unsigned *)&sys->io_enet_tx;
pkt[0] = (ping_mac_addr>>16);
pkt[1] = ((unsigned)(ping_mac_addr<<16))|ETHERTYPE_IP;
pkt[2] = 0x4500001c;
pkt_id += BIG_PRIME; // A BIG prime number
pkt[3] = (pkt_id&0x0ffff)<<16;;
pkt[4] = 0x80010000; // No flags, ragment offset = 0, ttl=0, proto=1(ICMP)
pkt[5] = my_ip_addr;
pkt[6] = ping_ip_addr;
// Ping payload: type = 0x08 (PING, the response will be zero)
// CODE = 0
// Checksum will be filled in later
pkt[7] = 0x08000000;
pkt_id += BIG_PRIME;
pkt[8] = (pkt_id + BIG_PRIME);
 
// Calculate the IP header checksum
pkt[4] |= ipcksum(5, &pkt[2]);
 
// Calculate the PING payload checksum
pkt[7] &= 0xffff0000;
pkt[7] |= ipcksum(2, &pkt[7]);
 
// Finally, send the packet -- 9*4 = our total number of octets
sys->io_enet.n_txcmd = ENET_TXCMD(9*4);
 
ping_tx_count++;
}
 
 
int heartbeats = 0, subbeats = 0, gbl_picv = 0;
int main(int argc, char **argv) {
unsigned user_context[16];
int lastpps;
 
for(int i=0; i<16; i++)
user_context[i] = 0;
user_context[13] = (unsigned)user_sp;
user_context[15] = (unsigned)user_task;
restore_context(user_context);
 
init_arp_table();
 
for(int i=0; i<4; i++)
sys->io_b.i_clrled[i] = LEDC_BRIGHTRED;
sys->io_b.i_leds = 0x0ff;
 
// Start up the network interface
if ((sys->io_enet.n_txcmd & ENET_RESET)!=0)
sys->io_enet.n_txcmd = 0; // Turn on all our features
{
volatile unsigned long *emac = (volatile unsigned long *)&sys->io_enet.n_mac;
*emac = my_mac_addr;
}
 
// Turn off our right-hand LED, first part of startup is complete
sys->io_b.i_leds = 0x010;
// Turn our first CLR LED green as well
sys->io_b.i_clrled[0] = LEDC_GREEN;
 
// Set our timer to have us send a ping 1/sec
zip->z_tma = CLOCKFREQ_HZ | TMR_INTERVAL;
 
sys->io_enet.n_rxcmd = ENET_RXCLRERR|ENET_RXCLR;
 
while(1) {
unsigned picv, bmsr;
 
heartbeats++;
 
// Wait while the link is being negotiated
// --- Read the MDIO status register
bmsr = sys->io_netmdio.e_v[MDIO_BMSR];
if ((bmsr & 4)==0) {
// Link is down, do nothing this time through
sys->io_b.i_clrled[1] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[2] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[3] = LEDC_BRIGHTRED;
} else {
sys->io_b.i_leds = 0x020;
sys->io_b.i_clrled[1] = LEDC_GREEN;
send_ping();
sys->io_b.i_clrled[2] = LEDC_BRIGHTRED; // Have we received a response?
sys->io_b.i_clrled[3] = LEDC_BRIGHTRED; // Was it our ping response?
}
 
// Clear any timer or PPS interrupts, disable all others
zip->z_pic = DALLPIC;
zip->z_pic = EINT(SYSINT_TMA|SYSINT_PPS|SYSINT_ENETRX);
do {
if ((zip->z_pic & INTNOW)==0)
zip_rtu();
subbeats++;
 
picv = zip->z_pic;
gbl_picv = picv;
 
// Clear the ints we just saw. Warning, though, we'll
// need to re-enable them later
zip->z_pic = (picv & 0x0ffff);
 
if (zip_ucc() & CC_FAULT) {
sys->io_b.i_leds = 0x0ff;
sys->io_b.i_clrled[0] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[1] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[2] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[3] = LEDC_BRIGHTRED;
zip_halt();
} else if (zip_ucc() & CC_TRAP) {
save_context((int *)user_context);
// R0 = return address
// R1 = Trap ID, write or send
// R2 = FD, or socketFD
// R3 = buffer
// R4 = count
// R5 = (flags, i socket)
unsigned *sptr = (void *)user_context[3], ln;
ln = user_context[4];
while(sys->io_enet.n_txcmd & ENET_TXBUSY)
;
if (ln < 1400) {
for(int i=0; i<(ln+3)>>2; i++)
sys->io_enet_tx[i] = *sptr++;
sys->io_enet.n_txcmd = ENET_TXCMD(ln);
 
user_tx_packets++;
// (Re-)Enable the transmit complete
// interrupt
//
// At this point, we are also ready to
// receive another packet
zip->z_pic = EINT(SYSINT_ENETTX|SYSINT_ENETRX);
}
 
user_context[14] &= ~CC_TRAP;
restore_context(user_context);
} else if ((picv & INTNOW)==0) {
sys->io_b.i_leds = 0x0ff;
sys->io_b.i_clrled[0] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[1] = LEDC_WHITE;
sys->io_b.i_clrled[2] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[3] = LEDC_BRIGHTRED;
zip_halt();
} else if ((picv & DINT(SYSINT_TMA))==0) {
sys->io_b.i_leds = 0x0ff;
sys->io_b.i_clrled[0] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[1] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[2] = LEDC_WHITE;
sys->io_b.i_clrled[3] = LEDC_BRIGHTRED;
zip_halt();
} else if ((picv & DINT(SYSINT_PPS))==0) {
sys->io_b.i_leds = 0x0ff;
sys->io_b.i_clrled[0] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[1] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[2] = LEDC_BRIGHTRED;
sys->io_b.i_clrled[3] = LEDC_WHITE;
zip_halt();
} if (picv & SYSINT_ENETRX) {
// This will not clear until the packet has
// been removed and the interface reset. For
// now, just double check that the interrupt
// has been disabled.
if (picv&(DINT(SYSINT_ENETRX))) {
zip->z_pic = DINT(SYSINT_ENETRX);
sys->io_b.i_leds = 0x040;
sys->io_b.i_clrled[2] = LEDC_GREEN;
}
} else
zip->z_pic = EINT(SYSINT_ENETRX);
if (picv & SYSINT_ENETTX) {
// This will also likewise not clear until a
// packet has been queued up for transmission.
// Hence, let's just disable the interrupt.
if (picv&(DINT(SYSINT_ENETTX)))
zip->z_pic = DINT(SYSINT_ENETTX);
} else
zip->z_pic = EINT(SYSINT_ENETTX);
// Make certain interrupts remain enabled
zip->z_pic = EINT(SYSINT_TMA|SYSINT_PPS);
 
if (picv & SYSINT_TMA) {
if (lastpps==1)
lastpps = 2;
else {
picv &= ~SYSINT_TMA;
lastpps = 0;
}
}
} while((picv & (SYSINT_TMA|SYSINT_PPS))==0);
if (picv & SYSINT_PPS) {
lastpps = 1;
zip->z_tma = CLOCKFREQ_HZ | TMR_INTERVAL;
}
}
}
 
/trunk/sw/board/splash.c
42,7 → 42,7
////////////////////////////////////////////////////////////////////////////////
//
//
int splash[6144] = {
short splash[6144] = {
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
/trunk/sw/board/syscall.h
0,0 → 1,186
////////////////////////////////////////////////////////////////////////////////
//
// Filename: syscall.h
//
// Project: OpenArty, an entirely open SoC based upon the Arty platform
//
// Purpose: User programs often need O/S support. To get such support, they
// call O/S functions, often named "system calls". These functions
// run at a different privilege level, and often even within a different
// address space. Therefore, making a system call usually takes a touch
// of hardware support. From a hardware standpoint, asking to switch to
// a higher privilege level is called a "TRAP".
//
// For the ZipCPU, a system call is as simple as executing the "TRAP"
// instruction--one that just clears the GIE bit in the CC register. This
// can be as simple as "MOV 0,CC", or even "AND ~GIE,CC". Of course, this
// only works from user mode where the GIE bit is set in the first place.
// This then transitions the CPU from user to supervisor mode, in a fashion
// where the supervisor can now examine the user process and tell that it
// was a trap that caused the return to supervisor mode. To turn this
// concept into a system call with arguments set and a potential value
// returned, we place up to four arguments into registers R1-R4, and
// expect R1 to have any return value.
//
// Getting the compiler to do this (place four values into R1-R4 and issue
// a trap instruction), however, was a nightmare. So, instead, call a
// function that accepts the same number of arguments (forcing GCC to
// place them into the registers R1-R4), and we set that function up so
// that it just does the system call assembly command listed above,
// followed by a "JMP R0" to return from the system call. This function,
// because it is so tightly integrated with the compiler and system, is
// implemented within zipsys as the assembly language routine, system().
//
// Here, we just specify what system calls the kernel knows about, what
// their calling conventions are, etc. In particular, we use R1 (i.e. the
// first argument) to reference a system call number (a.k.a. trap ID),
// and the next three arguments can be understood in the context of the
// system call number.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. (It's in the $(ROOT)/doc directory, run make with no
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#ifndef SYSCALL_H
#define SYSCALL_H
 
typedef enum {
// First two deal with interrupts:
// syscall(TRAPID_WAIT, intmask, timeout, ?)
// returns when an interrupt in intmask has taken place.
// May return immediately if such an interrupt has
// occurred between the last such syscall and this one
// If timeout is != 0, specifies the maximum amount of
// time to wait for the event to occurr.
// If intmask = 0, then the task will wait for a timeout
// alone.
// If the task is stalled for another reason, it may wake
// early from the trap when the timeout is up.
// syscall(TRAPID_CLEAR, intmask, timeout, ?)
// Same thing, except this returns immediately after
// clearing any potentially pending interrupts
// If the timeout < 0, clears any pending timeout wakeup
// If the timeout > 0, sets a pending timeout wakeup and
// returns.
// If the timeout == 0, it does nothing with the timeout.
// syscall(TRAPID_POST, intmask, ?, ?)
// "Posts" the events in intmask, allowing software
// "interrupts" to be created. That is, if another
// piece of software is waiting on an event/interrupt,
// this can be used to wake up all such pieces of software.
//
TRAPID_WAIT, TRAPID_CLEAR, TRAPID_POST,
//
// Yield: Yields the processor until the next scheduled time slice.
// Takes no arguments.
TRAPID_YIELD,
//
// Read/write: Implemented in much the same fashion as the Unix/Posix
// read/write system calls.
TRAPID_READ, TRAPID_WRITE,
//
// Time: Get the
TRAPID_TIME,
//
// kreturn: Return from a kernel system call. This is necessary if
// ever an exception triggers a system call. In such cases, it will be
// impossible to return the caller back to his context in a pristine
// manner ... without help.
// TRAPID_KRETURN,
//
// Semaphore ID's. These allow us to run the rest of the trap
// stuffs in kernel space
TRAPID_SEMGET, TRAPID_SEMPUT, TRAPID_SEMNEW,
//
TRAPID_RECV, TRAPID_SEND,
//
// Malloc--since we're using a system level malloc, from a system
// heap for everything, malloc/free require system calls
// Eventually, this call should be replaced with an sbrk() POSIX
// system call, but not until a full MMU is implemented and passes
// testing.
TRAPID_MALLOC, TRAPID_FREE,
// EXIT -- end a task
TRAPID_EXIT
} TRAPID;
 
extern int syscall(const int id, const int a, const int b, const int c);
 
static inline int read(int fid, void *buf, int ln) {
return syscall(TRAPID_READ, fid,(int)buf,ln);
} static inline int write(int fid, const void *buf, int ln) {
return syscall(TRAPID_WRITE, fid, (int)buf, ln);
}
 
static inline unsigned time(void) {
return syscall1(TRAPID_TIME);
}
 
static inline void yield(void) {
syscall(TRAPID_YIELD, 0, 0, 0);
} static inline int wait(unsigned event_mask, int timeout) {
return syscall(TRAPID_WAIT, (int)event_mask, timeout, 0);
} static inline int clear(unsigned event, int timeout) {
return syscall(TRAPID_CLEAR, (int)event, timeout, 0);
} static inline void post(unsigned event) {
syscall2(TRAPID_POST, (int)event);
}
 
 
// PORTS:
// Raw ethernet
// Just gets sent
// Raw internet
// (Needs to MAC via ARP, then IP)
// UDP ports
// Adds IP header (sip/dip/dport/sport/etc), sends to raw internet
// TCP ports
// Adds IP header (sip/dip/dport/sport/etc), sends to raw internet
//
static inline len recv(unsigned port, int buflen, unsigned *buf,
int timeout) {
// Timeout = 0 -> wait forever
// Port = -1 -> system task, receive *any*/all packets
return syscall5(TRAPID_RECV, port, buflen, buf, timeout);
}
 
static inline void send(unsigned port, int buflen, unsigned *buf) {
syscall(TRAPID_SEND, port, buflen, buf);
}
 
static inline void *malloc(unsigned nbytes) {
return (void *)syscall2(TRAPID_MALLOC, (int)nbytes0, 0);
} static inline void free(void *buf) {
syscall2(TRAPID_FREE,(int)buf);
}
 
static inline void exit(int status) {
syscall2(TRAPID_EXIT,status);
}
 
#endif
/trunk/sw/board/zipcpu.c
0,0 → 1,79
////////////////////////////////////////////////////////////////////////////////
//
// Filename: zipsystem.c
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: Implements some ZipCPU specific functions. Specifically, these
// are the system call trap (which just switches to supervisor
// mode), and the two context switching functions.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#include "zipcpu.h"
 
// Implement a save_context function. This really boils into a long series of
// instructions within the compiler. For this reason, it makes more sense
// for it to be a function call rather than an inline function--although
// zip_save_context could be either. Of course, the difficult part of placing
// it in line is that the CPU may not realize the context changes between one
// invocation of save_context and the corresponding restore_context function...
void save_context(int *c) {
zip_save_context(c);
}
 
void restore_context(int *c) {
zip_restore_context(c);
}
 
#ifdef C_SYSCALL
/* While the following system call *should* be identical to the assembly
* equivalent beneath it, the dependency is actually dependent upon any
* optimizations within the compiler. If the compiler is not optimized,
* then it may try to create a stack frame, store id, a, b, and c, on the
* stack frame, call the system call, clear the stack frame and return.
*
* The problem with this is that system traps may believe that they can replace
* the system call with a goto. In that case, there is no knowledge of the
* stack frame that needs to be unwound. Hence, we need to make certain that
* the system call does not create a stack frame, and thus use the assembly
* form beneath here.
*/
int syscall(const int id, const int a, const int b, const int c) {
zip_syscall();
}
#else
/* By making this into an assembly language equivalent, we can be specific about
* what we are expecting. That way the kernel can just set the PC address and
* the system call may believe that it was called like any ordinary subroutine.
*/
asm(ASMFNSTR("syscall")
"\tCLR\tCC\n"
"\tRETN\n"
);
#endif
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.