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 |
|
|