URL
https://opencores.org/ocsvn/amber/amber/trunk
Subversion Repositories amber
Compare Revisions
- This comparison shows the changes necessary to convert path
/amber/trunk/sw
- from Rev 55 to Rev 61
- ↔ Reverse comparison
Rev 55 → Rev 61
/tools/amber-elfsplitter.c
207,16 → 207,18
int main(int argc,char *argv[]) |
{ |
FILE *infile,*outfile; |
unsigned char *buf; |
unsigned char *inbuf; |
unsigned char *outbuf; |
int buf_size; |
unsigned int length,i; |
unsigned int StringSectionOffset; |
unsigned int StringSectionOffsetFound = 0; |
|
unsigned int outP; |
|
char filename_mem[80], filename_nopath[80]; |
char tmp[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; |
FILE *file_mem; |
unsigned int j, k; |
unsigned int j, k, last_k; |
int m; |
ElfHeader *elfHeader; |
Elf32_Phdr *elfProgram; |
225,6 → 227,8
char* ptr=argv[1]; |
|
int infile_size; |
int boffset; |
int max_out = 0; |
|
if (argc<2){ |
printf("%s ERROR: no input file specified. Quitting\n", argv[0]); |
239,8 → 243,9
} |
infile_size = fsize(infile); |
|
buf=(unsigned char*)malloc(infile_size); |
buf_size=fread(buf,1,infile_size,infile); |
inbuf =(unsigned char*)malloc(infile_size); |
outbuf=(unsigned char*)malloc(infile_size*2); |
buf_size=fread(inbuf,1,infile_size,infile); |
fclose(infile); |
|
if ( buf_size != infile_size ) { |
255,7 → 260,7
argv[0], argv[1], infile_size); |
} |
|
elfHeader=(ElfHeader*)buf; |
elfHeader=(ElfHeader*)inbuf; |
|
#ifdef DEBUG |
strncpy(tmp, (char*)elfHeader->e_ident+1, 3); |
281,7 → 286,7
#endif |
|
for(i=0;i<elfHeader->e_phnum;++i) { |
elfProgram = (Elf32_Phdr*)(buf+elfHeader->e_phoff+elfHeader->e_phentsize*i); |
elfProgram = (Elf32_Phdr*)(inbuf+elfHeader->e_phoff+elfHeader->e_phentsize*i); |
|
length=elfProgram->p_vaddr+elfProgram->p_memsz; |
#ifdef DEBUG |
294,7 → 299,7
containing the section names |
*/ |
for(i=0;i<elfHeader->e_shnum;++i) { |
elfSection=(Elf32_Shdr*)(buf+elfHeader->e_shoff+elfHeader->e_shentsize*i); |
elfSection=(Elf32_Shdr*)(inbuf+elfHeader->e_shoff+elfHeader->e_shentsize*i); |
if (elfSection->sh_type == SHT_STRTAB && !StringSectionOffsetFound) { |
StringSectionOffset = elfSection->sh_offset; |
StringSectionOffsetFound = 1; |
302,39 → 307,50
} |
|
for(i=0;i<elfHeader->e_shnum;++i) { |
elfSection=(Elf32_Shdr*)(buf+elfHeader->e_shoff+elfHeader->e_shentsize*i); |
elfSection=(Elf32_Shdr*)(inbuf+elfHeader->e_shoff+elfHeader->e_shentsize*i); |
|
/* Get the byte offset and use it to word-align the data */ |
boffset = elfSection->sh_offset & 3; |
|
if (elfSection->sh_type != SHT_NULL) { |
printf("// Section name %s\n", (char*)(buf+StringSectionOffset+elfSection->sh_name)); |
printf("// Type %s, Size 0x%x, Start address 0x%08x, File offset 0x%x\n", |
printf("// Section name %s\n", (char*)(inbuf+StringSectionOffset+elfSection->sh_name)); |
printf("// Type %s, Size 0x%x, Start address 0x%08x, File offset 0x%x, boffset %d\n", |
pSHT(elfSection->sh_type), |
elfSection->sh_size, |
elfSection->sh_addr, |
elfSection->sh_offset); |
elfSection->sh_offset, |
boffset); |
} |
|
|
/* section with non-zero bits, can be either text or data */ |
if (elfSection->sh_type == SHT_PROGBITS && elfSection->sh_size != 0) { |
for (j=0; j<elfSection->sh_size; j=j+4) { |
for (j=0; j<elfSection->sh_size; j++) { |
k = j + elfSection->sh_offset; |
printf("@%08x %02x%02x%02x%02x\n", |
(elfSection->sh_addr + j), /* use word addresses */ |
buf[k+3], buf[k+2], buf[k+1], buf[k+0]); |
outP = elfSection->sh_addr + j; |
outbuf[outP] = inbuf[k]; |
if (outP > max_out) max_out = outP; |
} |
} |
|
|
if (elfSection->sh_type == SHT_NOBITS && elfSection->sh_size != 0) { |
printf("// .bss Dump Zeros\n"); |
for (j=elfSection->sh_offset; j<elfSection->sh_offset+elfSection->sh_size; j=j+4) { |
printf("@%08x 00000000\n", |
(j + elfSection->sh_addr - elfSection->sh_offset)); /* use word addresses */ |
for (j=0; j<elfSection->sh_size; j++) { |
outP = j + elfSection->sh_addr; |
outbuf[outP] = 0; |
if (outP > max_out) max_out = outP; |
} |
} |
} |
|
|
} |
|
free(buf); |
for(j=0;j<max_out+3;j=j+4) { |
printf("@%08x %02x%02x%02x%02x\n", j, outbuf[j+3], outbuf[j+2], outbuf[j+1], outbuf[j+0]); |
} |
|
free(inbuf); |
free(outbuf); |
|
return 0; |
} |
/tools/amber-memparams32.sh
42,7 → 42,9
|
grep '@' $1 | awk '{print $2}' | awk -F '' '{print $1 $2}' |\ |
paste -d" " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | \ |
awk '{printf " .SRAM0_INIT_" NR-1 " ( 256%ch", 39 } \ |
awk '{ if (NR<=64) { printf " .SRAM0_INIT_" NR-1 " ( 256%ch", 39 } \ |
else if (NR<=128) { printf " .SRAM4_INIT_" NR-65 " ( 256%ch", 39 }} \ |
$32=="" {printf "00"} \ |
$31=="" {printf "00"} \ |
$30=="" {printf "00"} \ |
$29=="" {printf "00"} \ |
79,7 → 81,9
|
grep '@' $1 | awk '{print $2}' | awk -F '' '{print $3 $4}' |\ |
paste -d" " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | \ |
awk '{printf " .SRAM1_INIT_" NR-1 " ( 256%ch", 39 } \ |
awk '{ if (NR<=64) { printf " .SRAM1_INIT_" NR-1 " ( 256%ch", 39 } \ |
else if (NR<=128) { printf " .SRAM5_INIT_" NR-65 " ( 256%ch", 39 }} \ |
$32=="" {printf "00"} \ |
$31=="" {printf "00"} \ |
$30=="" {printf "00"} \ |
$29=="" {printf "00"} \ |
116,7 → 120,9
|
grep '@' $1 | awk '{print $2}' | awk -F '' '{print $5 $6}' |\ |
paste -d" " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | \ |
awk '{printf " .SRAM2_INIT_" NR-1 " ( 256%ch", 39 } \ |
awk '{ if (NR<=64) { printf " .SRAM2_INIT_" NR-1 " ( 256%ch", 39 } \ |
else if (NR<=128) { printf " .SRAM6_INIT_" NR-65 " ( 256%ch", 39 }} \ |
$32=="" {printf "00"} \ |
$31=="" {printf "00"} \ |
$30=="" {printf "00"} \ |
$29=="" {printf "00"} \ |
153,7 → 159,9
|
grep '@' $1 | awk '{print $2}' | awk -F '' '{print $7 $8}' |\ |
paste -d" " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | \ |
awk '{printf " .SRAM3_INIT_" NR-1 " ( 256%ch", 39 } \ |
awk '{ if (NR<=64) { printf " .SRAM3_INIT_" NR-1 " ( 256%ch", 39 } \ |
else if (NR<=128) { printf " .SRAM7_INIT_" NR-65 " ( 256%ch", 39 }} \ |
$32=="" {printf "00"} \ |
$31=="" {printf "00"} \ |
$30=="" {printf "00"} \ |
$29=="" {printf "00"} \ |
/tools/amber-memparams128.sh
42,7 → 42,8
|
grep '@' $1 | awk '{print $2}' | awk 'NR%4==1' |\ |
paste -d" " - - - - - - - - | \ |
awk '{printf " .SRAM0_INIT_" NR-1 " ( 256%ch", 39 } \ |
awk '{ if (NR<=64) { printf " .SRAM0_INIT_" NR-1 " ( 256%ch", 39 } \ |
else if (NR<=128) { printf " .SRAM4_INIT_" NR-65 " ( 256%ch", 39 }} \ |
$8=="" {printf "00000000"} \ |
$7=="" {printf "00000000"} \ |
$6=="" {printf "00000000"} \ |
55,7 → 56,8
|
grep '@' $1 | awk '{print $2}' | awk 'NR%4==2' |\ |
paste -d" " - - - - - - - - | \ |
awk '{printf " .SRAM1_INIT_" NR-1 " ( 256%ch", 39 } \ |
awk '{ if (NR<=64) { printf " .SRAM1_INIT_" NR-1 " ( 256%ch", 39 } \ |
else if (NR<=128) { printf " .SRAM5_INIT_" NR-65 " ( 256%ch", 39 }} \ |
$8=="" {printf "00000000"} \ |
$7=="" {printf "00000000"} \ |
$6=="" {printf "00000000"} \ |
68,7 → 70,8
|
grep '@' $1 | awk '{print $2}' | awk 'NR%4==3' |\ |
paste -d" " - - - - - - - - | \ |
awk '{printf " .SRAM2_INIT_" NR-1 " ( 256%ch", 39 } \ |
awk '{ if (NR<=64) { printf " .SRAM2_INIT_" NR-1 " ( 256%ch", 39 } \ |
else if (NR<=128) { printf " .SRAM6_INIT_" NR-65 " ( 256%ch", 39 }} \ |
$8=="" {printf "00000000"} \ |
$7=="" {printf "00000000"} \ |
$6=="" {printf "00000000"} \ |
82,7 → 85,8
|
grep '@' $1 | awk '{print $2}' | awk 'NR%4==0' |\ |
paste -d" " - - - - - - - - | \ |
awk '{printf " .SRAM3_INIT_" NR-1 " ( 256%ch", 39 } \ |
awk '{ if (NR<=64) { printf " .SRAM3_INIT_" NR-1 " ( 256%ch", 39 } \ |
else if (NR<=128) { printf " .SRAM7_INIT_" NR-65 " ( 256%ch", 39 }} \ |
$8=="" {printf "00000000"} \ |
$7=="" {printf "00000000"} \ |
$6=="" {printf "00000000"} \ |
/tools/amber-jumps.sh
78,7 → 78,7
fi |
|
|
grep jump amber.dis | awk '{print $1, $4, $6, $8}' | sed 's/,//' > /tmp/jumps |
grep jump amber.dis | awk '{print $1, $4, $6, $8, $10}' | sed 's/,//g' > /tmp/jumps |
|
grep '>:' $TEST_DIS | sed 's/<//' | sed 's/>://' > /tmp/funcsx |
|
/tools/amber-func-jumps.c
93,9 → 93,10
|
struct func_name func_names [NAMES_SIZE]; |
char a[12], n[48]; |
char s_clk_count[12], s_from_addr[12], s_to_addr[12], s_r0[12]; |
char s_clk_count[12], s_from_addr[12], s_to_addr[12], s_r0[12], s_r1[12]; |
unsigned int from_addr, to_addr, clk_count; |
unsigned int x; |
char current_func_name [48] = "none"; |
|
unsigned int slen; |
|
154,7 → 155,7
/* Assign names to jumps */ |
while ( (bytes_read = getline (&line_buffer, &nbytes, jumps_file)) > 0) |
{ |
sscanf(line_buffer, "%s %s %s %s", s_clk_count, s_from_addr, s_to_addr, s_r0); |
sscanf(line_buffer, "%s %s %s %s %s", s_clk_count, s_from_addr, s_to_addr, s_r0, s_r1); |
|
if ( !conv_hstring(s_from_addr, &from_addr) ) |
{ |
185,8 → 186,8
{ |
mid = (start + end) / 2; |
|
if ( to_addr >= func_names[mid].address && |
to_addr < func_names[mid+1].address ) |
if ( to_addr >= func_names[mid].address && |
(to_addr < func_names[mid+1].address || mid == end) ) |
{ |
found = 1; |
to_func_num = mid; |
203,7 → 204,11
end = mid; |
} |
} |
|
|
|
if (!found) |
fprintf(stderr,"WARNING: to_addr 0x%08x not found\n", to_addr); |
|
/* |
now assign a function to the from_address |
this just assigns a function within the range |
219,8 → 224,8
{ |
mid = (start + end) / 2; |
|
if ( from_addr >= func_names[mid].address && |
from_addr < func_names[mid+1].address ) |
if ( from_addr >= func_names[mid].address && |
(from_addr < func_names[mid+1].address || mid == end) ) |
{ |
found = 1; |
if ( strcmp ( func_names[mid].name, func_names[to_func_num].name ) ) |
227,10 → 232,7
{ |
|
if ( exact ) { |
if ( func_names[to_func_num].address < 0x02000000 ) |
printf("%9d u %s ->", clk_count, func_names[mid].name); |
else |
printf("%9d %s ->", clk_count, func_names[mid].name); |
printf("%9d %s ->", clk_count, func_names[mid].name); |
|
slen = 35 - strlen ( func_names[mid].name ); |
if ( slen > 0 ) { |
237,19 → 239,16
for (x=0;x<slen;x++) printf(" "); |
} |
|
printf("( r0 %s, r1 %s ) %s\n", |
s_r0, |
s_r1, |
func_names[to_func_num].name); |
|
if ( func_names[to_func_num].address < 0x02000000 ) |
printf("( %s ) %s u\n", |
s_r0, |
func_names[to_func_num].name); |
else |
printf("( %s ) %s\n", |
s_r0, |
func_names[to_func_num].name); |
strcpy(current_func_name, func_names[to_func_num].name); |
|
} |
else { |
printf("%9d %s <-", |
else if ( strcmp(func_names[to_func_num].name, current_func_name)) { |
printf("%9d %s <-", |
clk_count, |
func_names[to_func_num].name); |
|
259,8 → 258,8
} |
|
|
printf("( %s )\n", |
s_r0); |
printf("( r0 %s, r1 %s )\n", |
s_r0, s_r1); |
} |
} |
} |
/tools/Makefile
41,7 → 41,7
|
CC = gcc |
|
all : amber-elfsplitter amber-func-jumps amber-bin2mem amber-mem-ascii amber-ascii-mem |
all : amber-elfsplitter amber-func-jumps amber-bin2mem amber-mem-ascii amber-ascii-mem amber-pkt2mem |
|
amber-elfsplitter : amber-elfsplitter.c |
$(CC) amber-elfsplitter.c -o amber-elfsplitter |
/include/amber_registers.h
50,7 → 50,10
#define ADR_AMBER_TEST_SIM_CTRL 0xf000001c |
#define ADR_AMBER_TEST_MEM_CTRL 0xf0000020 |
#define ADR_AMBER_TEST_CYCLES 0xf0000024 |
#define ADR_AMBER_TEST_LED 0xf0000028 |
#define ADR_AMBER_TEST_PHY_RST 0xf000002c |
|
|
/* Allow access to the random register over |
a 16-word address range to load a series |
of random numbers using lmd instruction. */ |
71,17 → 74,48
#define ADR_AMBER_TEST_RANDOM_NUM13 0xf0000134 |
#define ADR_AMBER_TEST_RANDOM_NUM14 0xf0000138 |
#define ADR_AMBER_TEST_RANDOM_NUM15 0xf000013c |
|
|
#define ADR_AMBER_IC_IRQ0_STATUS 0x14000000 |
#define ADR_AMBER_IC_IRQ0_RAWSTAT 0x14000004 |
#define ADR_AMBER_IC_IRQ0_ENABLESET 0x14000008 |
#define ADR_AMBER_IC_IRQ1_ENABLESET 0x14000048 |
#define ADR_AMBER_IC_IRQ0_ENABLECLR 0x1400000c |
#define ADR_AMBER_IC_INT_SOFTSET_0 0x14000010 |
#define ADR_AMBER_IC_INT_SOFTCLEAR_0 0x14000014 |
#define ADR_AMBER_IC_FIRQ0_STATUS 0x14000020 |
#define ADR_AMBER_IC_FIRQ0_RAWSTAT 0x14000024 |
#define ADR_AMBER_IC_FIRQ0_ENABLESET 0x14000028 |
#define ADR_AMBER_IC_FIRQ0_ENABLECLR 0x1400002c |
#define ADR_AMBER_IC_IRQ1_STATUS 0x14000040 |
#define ADR_AMBER_IC_IRQ1_RAWSTAT 0x14000044 |
#define ADR_AMBER_IC_IRQ1_ENABLESET 0x14000048 |
#define ADR_AMBER_IC_IRQ1_ENABLECLR 0x1400004c |
#define ADR_AMBER_IC_INT_SOFTSET_1 0x14000050 |
#define ADR_AMBER_IC_INT_SOFTCLEAR_1 0x14000054 |
#define ADR_AMBER_IC_FIRQ1_STATUS 0x14000060 |
#define ADR_AMBER_IC_FIRQ1_RAWSTAT 0x14000064 |
#define ADR_AMBER_IC_FIRQ1_ENABLESET 0x14000068 |
#define ADR_AMBER_IC_FIRQ1_ENABLECLR 0x1400006c |
#define ADR_AMBER_IC_INT_SOFTSET_2 0x14000090 |
#define ADR_AMBER_IC_INT_SOFTCLEAR_2 0x14000094 |
#define ADR_AMBER_IC_INT_SOFTSET_3 0x140000d0 |
#define ADR_AMBER_IC_INT_SOFTCLEAR_3 0x140000d4 |
|
|
#define ADR_AMBER_CT_TIMER0_LOAD 0x13000000 |
#define ADR_AMBER_TM_TIMER0_LOAD 0x13000000 |
#define ADR_AMBER_TM_TIMER0_VALUE 0x13000004 |
#define ADR_AMBER_TM_TIMER0_CTRL 0x13000008 |
#define ADR_AMBER_TM_TIMER0_CLR 0x1300000c |
#define ADR_AMBER_CT_TIMER1_LOAD 0x13000100 |
#define ADR_AMBER_TM_TIMER1_LOAD 0x13000100 |
#define ADR_AMBER_TM_TIMER1_VALUE 0x13000104 |
#define ADR_AMBER_TM_TIMER1_CTRL 0x13000108 |
#define ADR_AMBER_TM_TIMER1_CLR 0x1300010c |
#define ADR_AMBER_CT_TIMER2_LOAD 0x13000200 |
#define ADR_AMBER_TM_TIMER2_LOAD 0x13000200 |
#define ADR_AMBER_TM_TIMER2_VALUE 0x13000204 |
#define ADR_AMBER_TM_TIMER2_CTRL 0x13000208 |
#define ADR_AMBER_TM_TIMER2_CLR 0x1300020c |
|
#define ADR_AMBER_UART0_DR 0x16000000 |
#define ADR_AMBER_UART0_RSR 0x16000004 |
106,6 → 140,8
#define ADR_AMBER_CORE_CTRL 0x1300031c |
|
#define ADR_ETHMAC_MODER 0x20000000 |
#define ADR_ETHMAC_INT_SOURCE 0x20000004 |
#define ADR_ETHMAC_INT_MASK 0x20000008 |
#define ADR_ETHMAC_MIIMODER 0x20000028 |
#define ADR_ETHMAC_MIICOMMAND 0x2000002C |
#define ADR_ETHMAC_MIIADDRESS 0x20000030 |
112,6 → 148,9
#define ADR_ETHMAC_MIITXDATA 0x20000034 |
#define ADR_ETHMAC_MIIRXDATA 0x20000038 |
#define ADR_ETHMAC_MIISTATUS 0x2000003C |
#define ADR_ETHMAC_MAC_ADDR0 0x20000040 |
#define ADR_ETHMAC_MAC_ADDR1 0x20000044 |
|
#define ADR_ETHMAC_BDBASE 0x20000400 |
|
#define ADR_HIBOOT_BASE 0x28000000 |
/include/common.mk
94,7 → 94,7
ifdef USE_MINI_LIBC |
debug: mini-libc $(ELF) $(MMP32) $(MMP128) $(DIS) |
else |
debug: $(ELF) $(MMP) $(DIS) |
debug: $(ELF) $(MMP32) $(MMP128) $(DIS) |
endif |
|
$(MMP32): $(MEM) |
112,6 → 112,9
endif |
$(LD) $(LDFLAGS) -o $(TGT) $(TLDS) $(OBJ) |
$(OC) -R .comment -R .note $(TGT) |
ifdef CHANGE_ADDRESS |
$(OC) --change-addresses -0x1000000 $(TGT) |
endif |
|
$(OBJ): $(DEP) |
|
/mini-libc/libc_asm.S
514,7 → 514,7
add r4, r0, r2 @ set r4 to the address of the last byte copied |
1: ldrb r3, [r1], #1 |
strb r3, [r0], #1 |
cmp r2, r4 |
cmp r0, r4 |
bne 1b |
2: ldmia sp!, {r4, pc}^ |
|
/boot-loader-ethmac/line-buffer.c
0,0 → 1,146
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#include "utilities.h" |
#include "line-buffer.h" |
#include "timer.h" |
#include "packet.h" |
|
line_buf_t* init_line_buffer (int size) |
{ |
line_buf_t* lbuf; |
int i; |
|
lbuf = malloc(sizeof(line_buf_t)); |
lbuf->read_ptr = 0; |
lbuf->write_ptr = 0; |
lbuf->len_bytes = size; |
lbuf->buf = malloc(size); |
return lbuf; |
} |
|
|
/* Add a single byte to the line buffer */ |
void put_byte (line_buf_t* telnet_buf, char byte, int last) |
{ |
|
/* Need to pass a pointer to a pointer to the location to |
write the character, to that the pointer to the location |
can be incremented by the final output function |
*/ |
telnet_buf->buf[telnet_buf->write_ptr] = byte; |
if (last) |
telnet_buf->buf[telnet_buf->write_ptr+1] = 0; |
else |
telnet_buf->buf[telnet_buf->write_ptr+1] = 1; |
telnet_buf->write_ptr++; |
|
/* Wrap the write pointer */ |
if ((telnet_buf->write_ptr + MAX_LINE) >= telnet_buf->len_bytes) |
telnet_buf->write_ptr = 0; |
} |
|
|
/* Add a line to the line buffer */ |
void put_line (line_buf_t* telnet_buf, const char *fmt, ...) |
{ |
int len; |
char *buf; |
int i; |
|
register unsigned long *varg = (unsigned long *)(&fmt); |
*varg++; |
|
/* Need to pass a pointer to a pointer to the location to |
write the character, to that the pointer to the location |
can be incremented by the final output function |
*/ |
buf = &telnet_buf->buf[telnet_buf->write_ptr]; |
len = print(&buf, fmt, varg); |
buf[len] = 0; |
telnet_buf->write_ptr += len; |
|
/* Wrap the write pointer */ |
if ((telnet_buf->write_ptr + MAX_LINE) >= telnet_buf->len_bytes) |
telnet_buf->write_ptr = 0; |
telnet_buf->buf[telnet_buf->write_ptr] = 0; |
} |
|
|
|
/* Retrieve the next line from a line buffer. |
return 0 if buffer doesn't have a complete line */ |
int get_line (line_buf_t* telnet_buf, char** line) |
{ |
int len = 0; |
|
// Grab these once at the start in case they are changed by an interrupt |
register int write_ptr = telnet_buf->write_ptr; |
|
/* Wrap the read pointer */ |
if ((telnet_buf->read_ptr + MAX_LINE) >= telnet_buf->len_bytes) |
telnet_buf->read_ptr = 0; |
|
*line = telnet_buf->buf + telnet_buf->read_ptr; |
|
/* Find the length of the next line in the buffer */ |
if (telnet_buf->read_ptr != write_ptr) { |
/* Find next 0 */ |
while (telnet_buf->read_ptr+len != write_ptr && |
telnet_buf->buf[telnet_buf->read_ptr+len]!=0 && |
telnet_buf->buf[telnet_buf->read_ptr+len]!=1 && |
len < MAX_LINE) |
len++; |
|
/* Check if there are some chars from put_char but not a complete line */ |
if (telnet_buf->buf[telnet_buf->read_ptr+len]==1) |
return 0; |
else { |
telnet_buf->read_ptr += len; |
return len; |
} |
} |
else |
return 0; |
} |
|
/boot-loader-ethmac/telnet.h
0,0 → 1,54
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
/* Max number of characters to transmit from a line buffer in a single packet */ |
#define MAX_TELNET_TX 1024 |
|
|
#define telnet_broadcast(args ...) \ |
do { put_line (socket0_g->telnet_txbuf, args); \ |
put_line (socket1_g->telnet_txbuf, args); } while (0) |
|
|
void parse_telnet_options (char *, socket_t*); |
void parse_telnet_payload (char *, socket_t*); |
void telnet_options (socket_t*); |
void telnet_tx (socket_t*, line_buf_t*); |
|
/boot-loader-ethmac/ethmac.c
0,0 → 1,319
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
|
#include "amber_registers.h" |
#include "address_map.h" |
#include "timer.h" |
#include "utilities.h" |
#include "line-buffer.h" |
#include "packet.h" |
#include "ethmac.h" |
|
|
void close_link (void) |
{ |
/* Disable EthMac interrupts in Ethmac core */ |
*(unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0x0; |
|
/* Disable Ethmac interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
/* Disable Rx & Tx - MODER Register |
[15] = Add pads to short frames |
[13] = CRCEN |
[10] = Enable full duplex |
[7] = loopback |
[5] = 1 for promiscuous, 0 rx only frames that match mac address |
[1] = txen |
[0] = rxen */ |
*(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa420; |
|
/* Put the PHY into reset */ |
phy_rst(0); /* reset is active low */ |
|
} |
|
|
/* return 1 if link comes up */ |
int open_link (void) |
{ |
int packet; |
int n; |
unsigned int d32; |
|
/* Disable Ethmac interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
/* Set my MAC address */ |
d32 = self_g.mac[2]<<24|self_g.mac[3]<<16|self_g.mac[4]<<8|self_g.mac[5]; |
*(unsigned int *) ( ADR_ETHMAC_MAC_ADDR0 ) = d32; |
|
d32 = self_g.mac[0]<<8|self_g.mac[1]; |
*(unsigned int *) ( ADR_ETHMAC_MAC_ADDR1 ) = d32; |
|
if (!config_phy()) return 0; |
|
/* Write the Receive Packet Buffer Descriptor */ |
/* Buffer Pointer */ |
for (packet=0; packet<ETHMAC_RX_BUFFERS; packet++) { |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x204 + packet*8 ) = ETHMAC_RX_BUFFER + packet * 0x1000; |
/* Ready Rx buffer |
[31:16] = length in bytes, |
[15] = empty |
[14] = Enable IRQ |
[13] = wrap bit */ |
/* set empty flag again */ |
if (packet == ETHMAC_RX_BUFFERS-1) /* last receive buffer ? */ |
/* Set wrap bit is last buffer */ |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + packet*8 ) = 0x0000e000; |
else |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + packet*8 ) = 0x0000c000; |
} |
|
/* Enable EthMac interrupts in Ethmac core */ |
/* Receive frame and receive error botgh enabled */ |
/* When a bad frame is received is still gets written to a buffer |
so needs to be dealt with */ |
*(unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0xc; |
|
/* Enable Ethmac interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100; |
|
/* Set transmit packet buffer location */ |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 4 ) = ETHMAC_TX_BUFFER; |
|
/* Set the ready bit, bit 15, low */ |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0 ) = 0x7800; |
|
/* Enable Rx & Tx - MODER Register |
[15] = Add pads to short frames |
[13] = CRCEN |
[10] = Enable full duplex |
[7] = loopback |
[5] = 1 for promiscuous, 0 rx only frames that match mac address |
[1] = txen |
[0] = rxen */ |
*(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa423; |
|
return 1; |
} |
|
|
void tx_packet(int len) |
{ |
unsigned int status = 0; |
|
|
/* Poll the ready bit. |
Wait until the ready bit is cleared by the ethmac hardware |
This holds everything up while the packet is being transmitted, but |
it keeps things simple. */ |
status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0 ); |
while ((status & 0x8000) != 0) { |
udelay20(); |
status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0 ); |
} |
|
|
/* Enable packet tx |
[31:16] = length in bytes, |
[15] = ready |
[14] = tx int |
[13] = wrap bit |
[12] = pad enable for short packets |
[11] = crc en |
*/ |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0 ) = len<<16 | 0xf800; |
} |
|
|
/* returns 1 if link comes up */ |
int config_phy (void) |
{ |
int addr; |
int bmcr; |
int stat; |
int phy_id; |
int link_up = 1; |
|
time_t* link_timer; |
|
link_timer = init_timer(); |
|
/* Bring PHY out of reset */ |
phy_rst(1); /* reset is active low */ |
|
/* Discover phy addr by searching addrs in order {1,0,2,..., 31} */ |
for(addr = 0; addr < 32; addr++) { |
phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr; |
bmcr = mdio_read(phy_id, MII_BMCR); /* Basic Mode Control Register */ |
stat = mdio_read(phy_id, MII_BMSR); |
stat = mdio_read(phy_id, MII_BMSR); |
if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) |
break; |
} |
|
/* Reset PHY */ |
bmcr = mdio_read(phy_id, MII_BMCR); |
mdio_write(phy_id, MII_BMCR, bmcr | BMCR_RESET); |
|
/* Advertise that PHY is NOT B1000-T capable */ |
/* Set bits 9.8, 9.9 to 0 */ |
bmcr = mdio_read(phy_id, MII_CTRL1000); |
mdio_write(phy_id, MII_CTRL1000, bmcr & 0xfcff ); |
|
/* Restart autoneg */ |
bmcr = mdio_read(phy_id, MII_BMCR); |
mdio_write(phy_id, MII_BMCR, bmcr | BMCR_ANRESTART); |
|
/* Wait for link up */ |
/* Print PHY status MII_BMSR = Basic Mode Status Register*/ |
/* allow 2 seconds for the link to come up before giving up */ |
set_timer(link_timer, 5000); |
while (!((stat = mdio_read(phy_id, MII_BMSR)) & BMSR_LSTATUS)) { |
if (timer_expired(link_timer)) { |
link_up = 0; |
break; |
} |
} |
|
return link_up; |
} |
|
|
int mdio_read(int addr, int reg) |
{ |
return mdio_ctrl(addr, mdi_read, reg, 0); |
} |
|
|
void mdio_write(int addr, int reg, int data) |
{ |
mdio_ctrl(addr, mdi_write, reg, data); |
} |
|
|
/* |
addr = PHY address |
reg = register address within PHY |
*/ |
unsigned short mdio_ctrl(unsigned int addr, unsigned int dir, unsigned int reg, unsigned short data) |
{ |
unsigned int data_out = 0; |
unsigned int i; |
unsigned long flags; |
|
mdio_ready(); |
|
*(volatile unsigned int *)(ADR_ETHMAC_MIIADDRESS) = (reg << 8) | (addr & 0x1f); |
|
if (dir == mdi_write) { |
*(volatile unsigned int *)(ADR_ETHMAC_MIITXDATA) = data; |
/* Execute Write ! */ |
*(volatile unsigned int *)(ADR_ETHMAC_MIICOMMAND) = 0x4; |
} |
else { |
/* Execute Read ! */ |
*(volatile unsigned int *)(ADR_ETHMAC_MIICOMMAND) = 0x2; |
mdio_ready(); |
data_out = *(volatile unsigned int *)(ADR_ETHMAC_MIIRXDATA); |
} |
|
return (unsigned short) data_out; |
} |
|
|
/* Wait until its ready */ |
void mdio_ready() |
{ |
int i; |
for (;;) { |
/* Bit 1 is high when the MD i/f is busy */ |
if ((*(volatile unsigned int *)(ADR_ETHMAC_MIISTATUS) & 0x2) == 0x0) |
break; |
|
i++; |
if (i==10000000) { |
i=0; |
} |
} |
} |
|
|
|
void ethmac_interrupt(void) |
{ |
int buffer; |
unsigned int int_src; |
unsigned int rx_buf_status; |
|
/* Mask ethmac interrupts */ |
*(volatile unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0; |
|
int_src = *(volatile unsigned int *) ( ADR_ETHMAC_INT_SOURCE ); |
|
for (buffer=0; buffer<ETHMAC_RX_BUFFERS; buffer++) { |
|
rx_buf_status = *(volatile unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ); |
|
if ((rx_buf_status & 0x8000) == 0) { |
|
parse_rx_packet((char*)(ETHMAC_RX_BUFFER+buffer*0x1000), rx_packet_g); |
|
/* set empty flag again */ |
if (buffer == ETHMAC_RX_BUFFERS-1) /* last receive buffer ? */ |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ) = 0x0000e000; |
else |
*(unsigned int *) ( ADR_ETHMAC_BDBASE + 0x200 + buffer*8 ) = 0x0000c000; |
} |
} |
|
/* Clear all ethmac interrupts */ |
*(volatile unsigned int *) ( ADR_ETHMAC_INT_SOURCE ) = int_src; |
|
/* UnMask ethmac interrupts */ |
*(volatile unsigned int *) ( ADR_ETHMAC_INT_MASK ) = 0xc; |
} |
|
|
/boot-loader-ethmac/elfsplitter.h
0,0 → 1,112
/*---------------------------------------------------------------- |
// // |
// elfsplitter.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Used by the boot loader to split an elf file and copy it // |
// to the correct memory locations ready for execution. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#define MEM_BUF_ENTRIES 32 |
|
/* |
ELF File Structure |
A single segment usually consist of several sections. E.g., a loadable |
read-only segment could contain sections for executable code, read-only |
data, and symbols for the dynamic linker. Relocatable files have section |
header tables. Executable files have program header tables. Shared object |
files have both. Sections are intended for further processing by a linker, |
while the segments are intended to be mapped into memory. |
*/ |
|
#define EI_NIDENT 16 |
#define SHT_PROGBITS 1 |
#define SHT_NOBITS 8 |
|
|
/* Main ELF Header Table */ |
typedef struct { |
unsigned char e_ident[EI_NIDENT]; /* bytes 0 to 15 */ |
unsigned short e_e_type; /* bytes 15 to 16 */ |
unsigned short e_machine; /* bytes 17 to 18 */ |
unsigned int e_version; /* bytes 19 to 22 */ |
unsigned int e_entry; /* bytes 23 to 26 */ |
unsigned int e_phoff; /* bytes 27 to 30 */ |
unsigned int e_shoff; /* bytes 31 to 34 */ |
unsigned int e_flags; /* bytes 35 to 38 */ |
unsigned short e_ehsize; /* bytes 39 to 40 */ |
unsigned short e_phentsize; /* bytes 41 to 42 */ |
unsigned short e_phnum; /* bytes 43 to 44 (2B to 2C) */ |
unsigned short e_shentsize; /* bytes 45 to 46 */ |
unsigned short e_shnum; /* bytes 47 to 48 */ |
unsigned short e_shstrndx; /* bytes 49 to 50 */ |
} ElfHeader; |
|
|
/* Section Headers */ |
typedef struct { |
unsigned int sh_name; /* section name - index into string table */ |
unsigned int sh_type; /* SHT_... */ |
unsigned int sh_flags; /* SHF_... */ |
unsigned int sh_addr; /* virtual address */ |
unsigned int sh_offset; /* file offset */ |
unsigned int sh_size; /* section size */ |
unsigned int sh_link; /* misc info */ |
unsigned int sh_info; /* misc info */ |
unsigned int sh_addralign; /* memory alignment */ |
unsigned int sh_entsize; /* entry size if table */ |
} Elf32_Shdr; |
|
|
/* Buffer to hold interrupt vector memory values |
Can't copy these into mem0 locations until ready to pass control |
t new program |
*/ |
typedef struct { |
char data; |
int valid; |
} mem_entry_t; |
|
|
typedef struct { |
mem_entry_t entry [MEM_BUF_ENTRIES]; |
} mem_buf_t; |
|
|
/* global vectors */ |
mem_buf_t* elf_mem0_g; |
|
/* function prototypes */ |
int elfsplitter (char*, socket_t*); |
/boot-loader-ethmac/line-buffer.h
0,0 → 1,56
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#define MAX_LINE 128 |
|
|
typedef struct { |
unsigned int write_ptr; |
unsigned int read_ptr; |
unsigned int len_bytes; |
char * buf; |
} line_buf_t; |
|
|
/* function prototypes */ |
line_buf_t* init_line_buffer (int); |
int get_line (line_buf_t*, char**); |
void put_line (line_buf_t*, const char*, ...); |
void put_byte (line_buf_t*, char, int); |
/boot-loader-ethmac/boot-loader-ethmac.c
0,0 → 1,331
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
// TODO list |
// tcp.c clean up |
// Cleanup self_g structure and usage |
// tcp window - what is it, whats it set to? Add it to status stuff |
// Get A25 version working |
// test with booting linux |
|
#include "amber_registers.h" |
#include "address_map.h" |
#include "line-buffer.h" |
#include "timer.h" |
#include "utilities.h" |
|
#include "ethmac.h" |
#include "packet.h" |
#include "tcp.h" |
#include "udp.h" |
#include "telnet.h" |
|
#include "elfsplitter.h" |
#include "boot-loader-ethmac.h" |
|
|
int main ( void ) { |
char* line; |
time_t* led_flash_timer; |
time_t* reboot_timer; |
socket_t* socket = socket0_g; |
int reboot_stage = 0; |
|
/* Turn off all LEDs as a starting point */ |
led_clear(); |
|
/* this must be first, because all the other init functions call malloc */ |
init_malloc(); |
|
/* Initialize current time and some timers */ |
init_current_time(); |
led_flash_timer = init_timer(); |
set_timer(led_flash_timer, 500); |
reboot_timer = init_timer(); |
|
|
/* receive packet buffer */ |
rx_packet_g = malloc(sizeof(packet_t)); |
|
/* socket init */ |
socket0_g = init_socket(0); |
socket1_g = init_socket(1); |
|
/* open ethernet port and wait for connection requests |
keep trying forever */ |
while (!open_link()); |
|
/* infinite loop. Everything is timer, interrupt and queue driven from here on down */ |
while (1) { |
|
/* Flash a heartbeat LED */ |
if (timer_expired(led_flash_timer)) { |
led_flip(0); |
set_timer(led_flash_timer, 500); |
} |
|
|
/* Check for newly downloaded tftp file. Add to all tx buffers */ |
/* Has a file been uploaded via tftp ? */ |
if (udp_file_g != NULL) { |
/* Notify telnet clients that file has been received */ |
if (udp_file_g->ready) { |
udp_file_g->ready = 0; |
telnet_broadcast("Received file %s, %d bytes, linux %d\r\n", |
udp_file_g->filename, udp_file_g->total_bytes, udp_file_g->linux_boot); |
if (process_file(socket0_g) == 0) |
/* Disconnect in 1 second */ |
set_timer(reboot_timer, 1000); |
else |
telnet_broadcast("Not an elf file\r\n"); |
} |
} |
|
|
/* reboot timer expired */ |
if (timer_expired(reboot_timer)) { |
/* First stage of reboot sequence is to nicely disconnect */ |
if (reboot_stage == 0) { |
set_timer(reboot_timer, 1000); |
reboot_stage = 1; |
socket0_g->tcp_disconnect = 1; |
socket1_g->tcp_disconnect = 1; |
} |
else { |
/* Second stage of reboot sequence is to turn off ethmac and then jump to restart vector */ |
close_link(); |
reboot(); |
} |
} |
|
|
/* Poll both sockets in turn for activity */ |
if (socket == socket0_g) |
socket = socket1_g; |
else |
socket = socket0_g; |
|
|
/* Check if any tcp packets need to be re-transmitted */ |
tcp_retransmit(socket); |
|
|
/* Handle exit command */ |
if (socket->tcp_disconnect && socket->tcp_connection_state == TCP_OPEN) { |
tcp_disconnect(socket); |
} |
|
|
/* Reset connection */ |
if (socket->tcp_reset) { |
socket->tcp_connection_state = TCP_CLOSED; |
socket->telnet_connection_state = TELNET_CLOSED; |
socket->telnet_options_sent = 0; |
tcp_reply(socket, NULL, 0); |
socket->tcp_reset = 0; |
} |
|
|
/* Send telnet options */ |
if (socket->tcp_connection_state == TCP_OPEN && !socket->telnet_options_sent){ |
telnet_options(socket); |
socket->telnet_options_sent = 1; |
} |
|
/* telnet connection open |
Communicate with client */ |
else if (socket->telnet_connection_state == TELNET_OPEN) { |
/* Send telnet greeting */ |
if (!socket->telnet_sent_opening_message){ |
put_line (socket->telnet_txbuf, "Amber Processor Boot Loader\r\n> "); |
socket->telnet_sent_opening_message = 1; |
} |
|
/* Parse telnet rx buffer */ |
if (get_line(socket->telnet_rxbuf, &line)) |
parse_command (socket, line); |
|
/* Transmit text from telnet tx buffer */ |
telnet_tx(socket, socket->telnet_txbuf); |
} |
} |
} |
|
|
|
/* Parse a command line passed from main and execute the command */ |
/* returns the length of the reply string */ |
int parse_command (socket_t* socket, char* line) |
{ |
unsigned int start_addr; |
unsigned int address; |
unsigned int range; |
int len, error = 0; |
|
/* All commands are just a single character. |
Just ignore anything else */ |
switch (line[0]) { |
/* Disconnect */ |
case 'e': |
case 'x': |
case 'q': |
socket->tcp_disconnect = 1; |
return 0; |
|
case 'r': /* Read mem */ |
{ |
if (len = get_hex (&line[2], &start_addr)) { |
if (len = get_hex (&line[3+len], &range)) { |
for (address=start_addr; address<start_addr+range; address+=4) { |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
address, *(unsigned int *)address); |
} |
} |
else { |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
start_addr, *(unsigned int *)start_addr); |
} |
} |
else |
error=1; |
break; |
} |
|
|
case 'h': {/* Help */ |
put_line (socket->telnet_txbuf, "You need help alright\r\n"); |
break; |
} |
|
|
case 's': {/* Status */ |
put_line (socket->telnet_txbuf, "Socket ID %d\r\n", socket->id); |
put_line (socket->telnet_txbuf, "Packets received %d\r\n", socket->packets_received); |
put_line (socket->telnet_txbuf, "Packets transmitted %d\r\n", socket->packets_sent); |
put_line (socket->telnet_txbuf, "Packets resent %d\r\n", socket->packets_resent); |
put_line (socket->telnet_txbuf, "TCP checksum errors %d\r\n", tcp_checksum_errors_g); |
|
put_line (socket->telnet_txbuf, "Counterparty IP %d.%d.%d.%d\r\n", |
socket->rx_packet->src_ip[0], |
socket->rx_packet->src_ip[1], |
socket->rx_packet->src_ip[2], |
socket->rx_packet->src_ip[3]); |
|
put_line (socket->telnet_txbuf, "Counterparty Port %d\r\n", |
socket->rx_packet->tcp_src_port); |
|
put_line (socket->telnet_txbuf, "Malloc pointer 0x%08x\r\n", |
*(unsigned int *)(ADR_MALLOC_POINTER)); |
put_line (socket->telnet_txbuf, "Malloc count %d\r\n", |
*(unsigned int *)(ADR_MALLOC_COUNT)); |
put_line (socket->telnet_txbuf, "Uptime %d seconds\r\n", current_time_g->seconds); |
break; |
} |
|
|
default: { |
error=1; break; |
} |
} |
|
|
if (error) |
put_line (socket->telnet_txbuf, "You're not making any sense\r\n", |
line[0], line[1], line[2]); |
|
put_line (socket->telnet_txbuf, "> "); |
return 0; |
} |
|
|
/* copy tftp file into a single contiguous buffer so |
if can be processed by elf splitter */ |
int process_file(socket_t* socket) |
{ |
block_t* block; |
char* buf512; |
char* tftp_file; |
char* line; |
int line_len; |
int ret; |
|
tftp_file = malloc(udp_file_g->total_bytes); |
|
block = udp_file_g; |
buf512= tftp_file; |
|
while (block->next) { |
memcpy(buf512, block->buf512, block->bytes); |
buf512=&buf512[512]; |
block=block->next; |
} |
memcpy(buf512, block->buf512, block->bytes); |
buf512=&buf512[512]; |
|
return elfsplitter(tftp_file, socket); |
} |
|
|
/* Disable interrupts |
Load new values into the interrupt vector memory space |
Jump to address 0 |
*/ |
void reboot() |
{ |
int i; |
|
/* Disable all interrupts */ |
/* Disable ethmac_int interrupt */ |
/* Disable timer 0 interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x120; |
|
for(i=0;i<MEM_BUF_ENTRIES;i++) |
if (elf_mem0_g->entry[i].valid) |
*(char *)(i) = elf_mem0_g->entry[i].data; |
|
if (udp_file_g->linux_boot) |
_jump_to_program(LINUX_JUMP_ADR); |
else |
_restart(); |
} |
|
/boot-loader-ethmac/ethmac.h
0,0 → 1,52
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
|
/* Function prototypes */ |
int open_link (void); |
void close_link (void); |
int config_phy (void); |
|
void mdio_ready (); |
int mdio_read (int addr, int reg); |
void mdio_write (int addr, int reg, int data); |
unsigned short mdio_ctrl (unsigned int addr, unsigned int dir, unsigned int reg, unsigned short data); |
|
void ethmac_interrupt (void); |
/boot-loader-ethmac/packet.c
0,0 → 1,465
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
|
#include "amber_registers.h" |
#include "address_map.h" |
#include "line-buffer.h" |
#include "timer.h" |
#include "utilities.h" |
#include "packet.h" |
#include "tcp.h" |
|
|
/* Global variables */ |
mac_ip_t self_g = { {0x00, 0x0e, 0x70, 0x70, 0x70, 0x70}, /* MAC Address */ |
{192, 168, 0, 17} /* IPv4 address */ |
}; |
|
|
packet_t* rx_packet_g; |
socket_t* socket0_g; |
socket_t* socket1_g; |
|
|
|
socket_t* init_socket(int socket_id) |
{ |
socket_t* socket; |
|
socket = (socket_t*) malloc(sizeof(socket_t)); |
socket->rx_packet =(packet_t*) malloc(sizeof(packet_t)); |
init_packet_buffers(socket); |
|
socket->telnet_txbuf = init_line_buffer(0x80000); |
socket->telnet_rxbuf = init_line_buffer(0x1000); |
|
socket->id = socket_id; |
|
socket->packets_sent = 0; |
socket->packets_received = 0; |
socket->packets_resent = 0; |
|
socket->telnet_sent_opening_message = 0; |
socket->telnet_echo_mode = 0; |
socket->telnet_connection_state = TELNET_CLOSED; |
socket->telnet_options_sent = 0; |
|
socket->tcp_current_buf = 0; |
socket->tcp_reset = 0; |
socket->tcp_connection_state = TCP_CLOSED; |
socket->tcp_disconnect = 0; |
socket->tcp_seq = 0x100; /* should be random initial seq number for tcp */ |
socket->tcp_last_seq = socket->tcp_seq; |
socket->tcp_last_ack = 0; |
|
return socket; |
} |
|
|
void init_packet_buffers (socket_t* socket) |
{ |
int i; |
|
/* Create space for an array of pointers */ |
socket->tcp_buf = malloc (TCP_TX_BUFFERS * sizeof (void *)); |
|
/* Create space for a set of buffers, each pointed to by an element of the array */ |
for (i=0;i<TCP_TX_BUFFERS;i=i+1) { |
socket->tcp_buf[i] = (packet_buffer_t*) malloc (sizeof (packet_buffer_t)); |
socket->tcp_buf[i]->payload_valid = 0; |
socket->tcp_buf[i]->starting_seq = 0; |
socket->tcp_buf[i]->ending_seq = 0; |
socket->tcp_buf[i]->len_bytes = 0; |
socket->tcp_buf[i]->ack_received = 0; |
} |
} |
|
|
void ethernet_header(char *buf, mac_ip_t* target, unsigned short type) |
{ |
/* ethernet header */ |
/* DA */ |
buf[ 0] = target->mac[0]; |
buf[ 1] = target->mac[1]; |
buf[ 2] = target->mac[2]; |
buf[ 3] = target->mac[3]; |
buf[ 4] = target->mac[4]; |
buf[ 5] = target->mac[5]; |
|
/* SA */ |
buf[ 6] = self_g.mac[0]; |
buf[ 7] = self_g.mac[1]; |
buf[ 8] = self_g.mac[2]; |
buf[ 9] = self_g.mac[3]; |
buf[10] = self_g.mac[4]; |
buf[11] = self_g.mac[5]; |
|
/* type */ |
buf[12] = type>>8; |
buf[13] = type&0xff; |
} |
|
|
void ip_header(char *buf, mac_ip_t* target, unsigned short ip_len, char ip_proto) |
{ |
unsigned short header_checksum; |
static unsigned short ip_id = 0; |
|
/* Version, Header length */ |
buf[0] = 0x45; |
|
/* dscp */ |
buf[1] = 0; |
|
/* ip len */ |
buf[2] = ip_len>>8; |
buf[3] = ip_len&0xff; |
|
/* ID */ |
buf[4] = (ip_id>>8)&0xff; |
buf[5] = ip_id&0xff; |
//ip_id++; |
|
/* Fragment */ |
buf[6] = 0; |
buf[7] = 0; |
|
/* ttl */ |
buf[8] = 64; |
|
/* Protocol */ |
buf[9] = ip_proto; |
|
/* header checksum */ |
buf[10] = 0; |
buf[11] = 0; |
|
/* Source IP */ |
buf[12] = self_g.ip[0]; |
buf[13] = self_g.ip[1]; |
buf[14] = self_g.ip[2]; |
buf[15] = self_g.ip[3]; |
|
/* Destination IP */ |
buf[16] = target->ip[0]; |
buf[17] = target->ip[1]; |
buf[18] = target->ip[2]; |
buf[19] = target->ip[3]; |
|
/* header checksum */ |
header_checksum = header_checksum16(buf, 20, 0); |
buf[10] = (header_checksum>>8)&0xff; |
buf[11] = header_checksum&0xff; |
} |
|
|
void arp_reply(char *buf, mac_ip_t* arp_sender) |
{ |
|
ethernet_header(buf, arp_sender, 0x0806); |
|
/* Hardware Type */ |
buf[14] = 0x00; |
buf[15] = 0x01; |
/* Protocol Type */ |
buf[16] = 0x08; |
buf[17] = 0x00; |
/* HLEN */ |
buf[18] = 0x06; |
/* PLEN */ |
buf[19] = 0x04; |
|
/* Operation = Reply */ |
buf[20] = 0x00; |
buf[21] = 0x02; |
|
/* Sender MAC */ |
buf[22] = self_g.mac[0]; |
buf[23] = self_g.mac[1]; |
buf[24] = self_g.mac[2]; |
buf[25] = self_g.mac[3]; |
buf[26] = self_g.mac[4]; |
buf[27] = self_g.mac[5]; |
|
/* Sender IP */ |
buf[28] = self_g.ip[0]; |
buf[29] = self_g.ip[1]; |
buf[30] = self_g.ip[2]; |
buf[31] = self_g.ip[3]; |
|
/* Target MAC */ |
buf[32] = arp_sender->mac[0]; |
buf[33] = arp_sender->mac[1]; |
buf[34] = arp_sender->mac[2]; |
buf[35] = arp_sender->mac[3]; |
buf[36] = arp_sender->mac[4]; |
buf[37] = arp_sender->mac[5]; |
|
/* Target IP */ |
buf[38] = arp_sender->ip[0]; |
buf[39] = arp_sender->ip[1]; |
buf[40] = arp_sender->ip[2]; |
buf[41] = arp_sender->ip[3]; |
tx_packet(42); |
} |
|
|
void ping_reply(packet_t* rx_packet, int ping_id, int ping_seq, char * rxbuf) |
{ |
|
int i; |
unsigned short header_checksum; |
mac_ip_t target; |
char * buf = (char*)ETHMAC_TX_BUFFER; |
|
target.mac[0] = rx_packet->src_mac[0]; |
target.mac[1] = rx_packet->src_mac[1]; |
target.mac[2] = rx_packet->src_mac[2]; |
target.mac[3] = rx_packet->src_mac[3]; |
target.mac[4] = rx_packet->src_mac[4]; |
target.mac[5] = rx_packet->src_mac[5]; |
|
target.ip[0] = rx_packet->src_ip[0]; |
target.ip[1] = rx_packet->src_ip[1]; |
target.ip[2] = rx_packet->src_ip[2]; |
target.ip[3] = rx_packet->src_ip[3]; |
|
ethernet_header(buf, &target, 0x0800); /*bytes 0 to 13*/ |
ip_header(&buf[14], &target, rx_packet->ip_len, 1); /* bytes 14 to 33, ip_proto = 1, ICMP*/ |
|
/* ICMP */ |
/* Type = reply */ |
buf[34] = 0; |
|
/* Code = 0 */ |
buf[35] = 0; |
|
/* checksum */ |
buf[36] = 0; |
buf[37] = 0; |
|
/* ID */ |
buf[38] = ping_id>>8; |
buf[39] = ping_id&0xff; |
|
/* SEQ */ |
buf[40] = ping_seq>>8; |
buf[41] = ping_seq&0xff; |
|
for (i=8; i< rx_packet->ip_len - rx_packet->ip_header_len*4; i++) { |
buf[34+i] = rxbuf[i]; |
} |
|
header_checksum = header_checksum16(&buf[34], (rx_packet->ip_len)-20, 0); |
buf[36] = (header_checksum>>8)&0xff; |
buf[37] = header_checksum&0xff; |
tx_packet(rx_packet->ip_len+14); |
} |
|
|
void parse_rx_packet(char * buf, packet_t* rx_packet) |
{ |
int i; |
|
rx_packet->dst_mac[0] = buf[0]; |
rx_packet->dst_mac[1] = buf[1]; |
rx_packet->dst_mac[1] = buf[2]; |
rx_packet->dst_mac[3] = buf[3]; |
rx_packet->dst_mac[4] = buf[4]; |
rx_packet->dst_mac[5] = buf[5]; |
|
rx_packet->src_mac[0] = buf[6]; |
rx_packet->src_mac[1] = buf[7]; |
rx_packet->src_mac[2] = buf[8]; |
rx_packet->src_mac[3] = buf[9]; |
rx_packet->src_mac[4] = buf[10]; |
rx_packet->src_mac[5] = buf[11]; |
rx_packet->eth_type = (buf[12]<<8) + buf[13]; |
|
|
/* ARP */ |
if (rx_packet->eth_type == 0x0806) { |
parse_arp_packet(&buf[14]); |
} |
|
|
/* Internet Protocol */ |
else if (rx_packet->eth_type == 0x0800){ |
parse_ip_packet(&buf[14], rx_packet); |
} |
} |
|
|
void parse_arp_packet(char * buf) |
{ |
/* ARP is a broadcast message (mac broadcast address) |
asking 'does this IP address belong to you?" |
*/ |
int arp_op; |
mac_ip_t arp_sender, arp_target; |
|
arp_op = buf[6]<<8 | buf[7]; |
|
arp_sender.mac[0] = buf[8]; |
arp_sender.mac[1] = buf[9]; |
arp_sender.mac[2] = buf[10]; |
arp_sender.mac[3] = buf[11]; |
arp_sender.mac[4] = buf[12]; |
arp_sender.mac[5] = buf[13]; |
|
arp_sender.ip [0] = buf[14]; |
arp_sender.ip [1] = buf[15]; |
arp_sender.ip [2] = buf[16]; |
arp_sender.ip [3] = buf[17]; |
|
arp_target.mac[0] = buf[18]; |
arp_target.mac[1] = buf[19]; |
arp_target.mac[2] = buf[20]; |
arp_target.mac[3] = buf[21]; |
arp_target.mac[4] = buf[22]; |
arp_target.mac[5] = buf[23]; |
|
arp_target.ip [0] = buf[24]; |
arp_target.ip [1] = buf[25]; |
arp_target.ip [2] = buf[26]; |
arp_target.ip [3] = buf[27]; |
|
/* Send a reply ? */ |
if (arp_op==1 && |
arp_target.ip[0]==self_g.ip[0] && |
arp_target.ip[1]==self_g.ip[1] && |
arp_target.ip[2]==self_g.ip[2] && |
arp_target.ip[3]==self_g.ip[3]) { |
|
// ARP reply |
arp_reply((char*)ETHMAC_TX_BUFFER, &arp_sender); |
} |
} |
|
|
|
void parse_ip_packet(char * buf, packet_t* rx_packet) |
{ |
unsigned int ip_version; |
|
ip_version = buf[0]>>4; |
if (ip_version != 4) { |
//printf("%s: IP version %d not supported\n", __func__, ip_version); |
return; |
} |
|
/* Get destination IP address */ |
rx_packet->dst_ip[0] = buf[16]; |
rx_packet->dst_ip[1] = buf[17]; |
rx_packet->dst_ip[2] = buf[18]; |
rx_packet->dst_ip[3] = buf[19]; |
|
/* If its not my address then ignore the packet */ |
if (rx_packet->dst_ip[0] != self_g.ip[0] || |
rx_packet->dst_ip[1] != self_g.ip[1] || |
rx_packet->dst_ip[2] != self_g.ip[2] || |
rx_packet->dst_ip[3] != self_g.ip[3] ) { |
return; |
} |
|
rx_packet->ip_len = buf[ 2]<<8|buf[ 3]; |
rx_packet->ip_header_len = buf[0] & 0xf; |
rx_packet->ip_proto = buf[9]; |
rx_packet->src_ip[0] = buf[12]; |
rx_packet->src_ip[1] = buf[13]; |
rx_packet->src_ip[2] = buf[14]; |
rx_packet->src_ip[3] = buf[15]; |
|
|
/* Ping packets */ |
if (rx_packet->ip_proto == 1){ |
parse_ping_packet(&buf[(rx_packet->ip_header_len)*4], rx_packet); |
} |
|
/* TCP packets */ |
else if (rx_packet->ip_proto == 6){ |
parse_tcp_packet(&buf[(rx_packet->ip_header_len)*4], rx_packet); |
} |
|
/* UDP packets */ |
else if (rx_packet->ip_proto == 17){ |
parse_udp_packet(&buf[(rx_packet->ip_header_len)*4], rx_packet); |
} |
} |
|
|
void parse_ping_packet(char * buf, packet_t* rx_packet) |
{ |
int ping_id; |
int ping_seq; |
|
ping_id = buf[4]<<8|buf[5]; |
ping_seq = buf[6]<<8|buf[7]; |
|
ping_reply(rx_packet, ping_id, ping_seq, buf); |
} |
|
|
unsigned short header_checksum16(unsigned char *buf, unsigned short len, unsigned int sum) |
{ |
// build the sum of 16bit words |
while(len>1) { |
sum += 0xFFFF & (*buf<<8|*(buf+1)); |
buf+=2; |
len-=2; |
} |
// if there is a byte left then add it (padded with zero) |
if (len) { |
sum += (0xFF & *buf)<<8; |
} |
// now calculate the sum over the bytes in the sum |
// until the result is only 16bit long |
while (sum>>16) { |
sum = (sum & 0xFFFF)+(sum >> 16); |
} |
|
// build 1's complement: |
return( (unsigned short ) sum ^ 0xFFFF); |
} |
|
/boot-loader-ethmac/utilities.c
0,0 → 1,162
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#include "amber_registers.h" |
#include "utilities.h" |
|
|
int next_string(char*buf) |
{ |
int pos = 0; |
while (*buf != 0) {buf++; pos++;} |
return ++pos; |
} |
|
|
int strcmp(char* str1, char*str2) |
{ |
int pos = 0; |
int equal=1; |
|
while (*str1!=0 && *str2!=0 && pos<256 && equal) { |
equal = *str1==*str2; |
str1++; |
str2++; |
pos++; |
} |
return equal; |
} |
|
|
/* Return a number recovered from a string of hex digits */ |
int get_hex (char * buf, unsigned int *num) |
{ |
int cpos = 0, done = 0; |
*num = 0; |
|
while (!done) { |
if ( buf[cpos] >= '0' && buf[cpos] <= '9' ) { |
*num = *num<<4; |
*num = *num + buf[cpos] - '0'; |
} |
else if ( buf[cpos] >= 'A' && buf[cpos] <= 'F' ) { |
*num = *num<<4; |
*num = *num + buf[cpos] - 'A' + 10; |
} |
else if ( buf[cpos] >= 'a' && buf[cpos] <= 'f' ) { |
*num = *num<<4; |
*num = *num + buf[cpos] - 'a' + 10; |
} |
else |
done = 1; |
|
// Don't increment cops if the first character is not part of an ascii-hex string |
// oo that a 0 is returned to indicate failure. |
if (!done) |
cpos++; |
|
if (cpos >= 8) |
done = 1; |
} |
|
/* Return length of acsii-hex string */ |
return cpos; |
} |
|
|
void udelay20(void) |
{ |
volatile int i; |
for (i=0;i<500;i++) ; |
} |
|
|
void phy_rst(int value) |
{ |
*(unsigned int *) ADR_AMBER_TEST_PHY_RST = value; |
} |
|
|
/* turn off all leds */ |
void led_clear() |
{ |
*(unsigned int *) ADR_AMBER_TEST_LED = 0; |
} |
|
|
/* led is either 0,1,2 or 3 */ |
void led_flip(int led) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = current_value ^ (1<<led); |
} |
|
|
|
/* led is either 0,1,2 or 3 */ |
void led_on(int led) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = current_value | (1<<led); |
} |
|
|
|
/* led is either 0,1,2 or 3 */ |
void led_off(int led) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = current_value & ~(1<<led); |
} |
|
|
/* led is either 0,1,2 or 3 */ |
void led_123(int value) |
{ |
int current_value; |
current_value = *(unsigned int *) ADR_AMBER_TEST_LED; |
*(unsigned int *) ADR_AMBER_TEST_LED = (current_value & 1) | value<<1; |
} |
/boot-loader-ethmac/boot-loader-ethmac.h
0,0 → 1,48
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#define LINUX_JUMP_ADR 0x00080000 |
|
|
/* Function prototypes */ |
int parse_command (socket_t*, char*); |
int process_file (socket_t*); |
void reboot (); |
|
/boot-loader-ethmac/packet.h
0,0 → 1,238
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
#define TELNET_PORT 23 |
|
#define MAX_PACKET_SIZE 2000 |
#define ETHMAC_RX_BUFFERS 8 |
#define TCP_TX_BUFFERS 256 |
|
#define TELNET_WILL 251 |
#define TELNET_WONT 252 |
#define TELNET_DO 253 |
#define TELNET_DONT 254 |
|
#define UDP_READ 1 |
#define UDP_WRITE 2 |
#define UDP_DATA 3 |
#define UDP_ACK 4 |
#define UDP_ERROR 5 |
|
|
/* Generic MII registers. */ |
/* Taken from kernel source file include/linux/mii.h */ |
#define MII_BMCR 0x00 /* Basic mode control register */ |
#define MII_BMSR 0x01 /* Basic mode status register */ |
#define MII_PHYSID1 0x02 /* PHYS ID 1 */ |
#define MII_PHYSID2 0x03 /* PHYS ID 2 */ |
#define MII_ADVERTISE 0x04 /* Advertisement control reg */ |
#define MII_LPA 0x05 /* Link partner ability reg */ |
#define MII_EXPANSION 0x06 /* Expansion register */ |
#define MII_CTRL1000 0x09 /* 1000BASE-T control */ |
#define MII_STAT1000 0x0a /* 1000BASE-T status */ |
#define MII_ESTATUS 0x0f /* Extended Status */ |
#define MII_DCOUNTER 0x12 /* Disconnect counter */ |
#define MII_FCSCOUNTER 0x13 /* False carrier counter */ |
#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ |
#define MII_RERRCOUNTER 0x15 /* Receive error counter */ |
#define MII_SREVISION 0x16 /* Silicon revision */ |
#define MII_RESV1 0x17 /* Reserved... */ |
#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ |
#define MII_PHYADDR 0x19 /* PHY address */ |
#define MII_RESV2 0x1a /* Reserved... */ |
#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ |
#define MII_NCONFIG 0x1c /* Network interface config */ |
|
/* Basic mode control register. */ |
/* Taken from kernel source file include/linux/mii.h */ |
#define BMCR_RESV 0x003f /* Unused... */ |
#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ |
#define BMCR_CTST 0x0080 /* Collision test */ |
#define BMCR_FULLDPLX 0x0100 /* Full duplex */ |
#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ |
#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ |
#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ |
#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ |
#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ |
#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ |
#define BMCR_RESET 0x8000 /* Reset the DP83840 */ |
|
/* Basic mode status register. */ |
/* Taken from kernel source file include/linux/mii.h */ |
#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ |
#define BMSR_JCD 0x0002 /* Jabber detected */ |
#define BMSR_LSTATUS 0x0004 /* Link status */ |
#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ |
#define BMSR_RFAULT 0x0010 /* Remote fault detected */ |
#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ |
#define BMSR_RESV 0x00c0 /* Unused... */ |
#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ |
#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ |
#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ |
#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ |
#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ |
#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ |
#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ |
#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ |
|
|
typedef struct { |
unsigned char mac[6]; |
unsigned char ip[4]; |
} mac_ip_t; |
|
|
typedef struct { |
unsigned int payload_valid; |
unsigned int starting_seq; |
unsigned int ending_seq; |
unsigned int len_bytes; |
unsigned int ack_received; |
time_t resend_time; |
char buf[MAX_PACKET_SIZE]; |
} packet_buffer_t; |
|
|
typedef struct { |
/* Ethernet */ |
unsigned char src_mac[6]; |
unsigned char dst_mac[6]; |
unsigned int eth_type; |
|
/* IPv4 */ |
unsigned char src_ip[4]; |
unsigned char dst_ip[4]; |
unsigned int ip_len; // IP; in bytres |
unsigned int ip_header_len; // IP; in 32-bit words |
unsigned int ip_proto; |
|
/* TCP */ |
unsigned int tcp_src_port; |
unsigned int tcp_dst_port; |
unsigned int tcp_hdr_len; |
unsigned int tcp_seq; |
unsigned int tcp_ack; |
unsigned int tcp_flags; |
unsigned int tcp_window_size; |
unsigned int tcp_len; |
unsigned int tcp_payload_len; |
unsigned int tcp_src_time_stamp; |
|
/* Telnet */ |
unsigned int telnet_payload_len; |
} packet_t; |
|
|
|
typedef struct { |
|
packet_buffer_t** tcp_buf; |
int tcp_current_buf; |
|
/* Telnet rx and tx line buffers */ |
line_buf_t* telnet_rxbuf; |
line_buf_t* telnet_txbuf; |
|
int telnet_sent_opening_message; |
int telnet_echo_mode; |
int telnet_connection_state; |
int telnet_options_sent; |
|
int packets_sent; |
int packets_received; |
int packets_resent; |
|
int tcp_connection_state; |
int tcp_reset; |
int tcp_disconnect; |
int tcp_seq; /* should be random initial seq number for tcp */ |
int tcp_last_seq; |
unsigned int tcp_last_ack; |
|
int id; |
|
packet_t* rx_packet; /* Header info from last packet received */ |
} socket_t; |
|
|
|
/* Enumerated types */ |
enum mdi_ctrl { |
mdi_write = 0x04000000, |
mdi_read = 0x08000000, |
mdi_ready = 0x10000000, |
}; |
|
|
|
enum telnet_state { |
TELNET_CLOSED = 0, |
TELNET_OPEN = 1 |
}; |
|
|
/* Global Variables */ |
extern mac_ip_t self_g; |
extern packet_t* rx_packet_g; |
extern socket_t* socket0_g; |
extern socket_t* socket1_g; |
|
|
/* Functions */ |
void init_packet_buffers (socket_t*); |
unsigned short header_checksum16 (unsigned char *buf, unsigned short len, unsigned int sum); |
|
void arp_reply (char *buf, mac_ip_t*); |
void ping_reply (packet_t* packet0, int ping_id, int ping_seq, char * rx_buf); |
|
void ethernet_header (char *buf, mac_ip_t* target, unsigned short type); |
void ip_header (char *buf, mac_ip_t* target, unsigned short ip_len, char ip_proto); |
|
void parse_rx_packet (char*, packet_t*); |
void parse_arp_packet (char*); |
void parse_ip_packet (char*, packet_t*); |
void parse_ping_packet (char*, packet_t*); |
|
socket_t* init_socket (int); |
|
|
|
|
|
|
/boot-loader-ethmac/start.S
0,0 → 1,509
/*---------------------------------------------------------------- |
// // |
// start.S // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Assembly routines for boot-loader. // |
// As boot-loader is a stand-alone application, it needs a // |
// simple start function written in assembly to call the // |
// C code main() function. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#include "amber_registers.h" |
#include "address_map.h" |
|
/* Defined in vmlinux/include/asm-arm/setup.h */ |
#define ATAG_CORE 0x54410001 |
#define ATAG_MEM 0x54410002 |
#define ATAG_INITRD 0x54410005 |
#define ATAG_RAMDISK 0x54410004 |
#define ATAG_NONE 0x00000000 |
|
#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2) |
#define ATAG_MEM_SIZE ((2*4 + 2*4) >> 2) |
#define ATAG_INITRD_SIZE ((2*4 + 2*4) >> 2) |
#define ATAG_RAMDISK_SIZE ((2*4 + 3*4) >> 2) |
|
|
/* from vmlinux/arch/arm/kernel/compat.c */ |
#define FLAG_READONLY 1 |
|
/* from the list in wmlinux/arch/arm/tools/mach-types */ |
#define MACH_TYPE_A5K 11 |
|
|
|
.section .text |
.globl start |
start: |
/* 0x00 Reset Interrupt vector address */ |
b startup |
|
/* 0x04 Undefined Instruction Interrupt vector address */ |
b _testfail |
|
/* 0x08 SWI Interrupt vector address */ |
b _testfail |
|
/* 0x0c Prefetch abort Interrupt vector address */ |
b _testfail |
|
/* 0x10 Data abort Interrupt vector address */ |
b _testfail |
b _testfail |
|
/* 0x18 IRQ vector address */ |
b service_irq |
|
/* 0x1c FIRQ vector address */ |
b _testfail |
|
|
.global _restart |
_restart: |
@ jump to address 0 in irq mode |
mov pc, #0x00000002 |
nop |
nop |
nop |
|
|
startup: |
/* copy program to exec space */ |
mov r0, #0 |
ldr r1, AdrExecBase |
1: ldm r0!, {r2-r9} |
stm r1!, {r2-r9} |
cmp r0, #0x4000 |
bne 1b |
|
/* Fix the interrupt jump pointers */ |
ldr r0, AdrExecBase |
mov r1, r0, lsr #2 |
mov r2, #0 |
|
2: ldr r3, [r2] |
orr r3, r3, r1 |
str r3, [r2], #4 |
cmp r2, #0x1c |
bne 2b |
|
/* Jump to 2f but offset from ExecBase not current location */ |
3: ldr r0, AdrExecBase |
ldr r1, AdrJumpPoint |
orr r0, r0, r1 |
mov pc, r0 |
|
_jump_point: |
|
/* Switch to IRQ Mode */ |
mov r0, #0x00000002 |
teqp pc, r0 |
/* Set IRQ Mode stack pointer */ |
ldr sp, AdrIRQStack |
|
/* Switch to SVC mode and Unset interrupt mask bits */ |
mov r0, #0x00000003 |
teqp pc, r0 |
|
@ Enable the cache |
@ set region 24 to be uncached. Used for packet buffers |
mov r0, #0xfeffffff |
mcr 15, 0, r0, cr3, cr0, 0 @ cacheable area |
mov r0, #1 |
mcr 15, 0, r0, cr2, cr0, 0 @ cache enable |
|
@ init SP |
ldr sp, AdrStack |
|
@ Set 32MB memory mode |
ldr r0, AdrMemCtrl |
mov r1, #1 |
str r1, [r0] |
|
.extern main |
bl main |
|
@ jump to program at r0 |
.globl _jump_to_program |
_jump_to_program: |
|
|
@ ---------------------------------------------- |
@ Copy ATAG structure to AdrBootParams |
@ ---------------------------------------------- |
ldr r1, AdrBootParams |
ldr r2, AdrATAGBase |
ldr r3, AdeEndATAG |
|
1: cmp r2, r3 |
beq 2f |
ldr r4, [r2], #4 |
str r4, [r1], #4 |
b 1b |
|
@ Set memc page tables |
2: ldr r2, AdrPageTabes |
mov r3, #0 |
mov r4, #40 |
3: str r3,[r2],#4 |
subs r4, r4, #1 |
bne 3b |
|
@ ---------------------------------------------- |
@ jump to start of program in svc mode with interrupts disabled |
@ ---------------------------------------------- |
mov r4, r0 |
orr r4, #0x0c000003 |
mov r0, #0 |
mov pc, r4 |
|
|
service_irq: |
@ Save all registers to the stack |
stmfd sp!, {r0-r12, lr} |
|
@ is it a timer interrupt ? |
ldr r0, AdrInterruptStatus |
ldr r1, [r0] |
ands r2, r1, #0x20 |
beq 1f @ not timer int, jump |
.extern timer_interrupt |
bl timer_interrupt |
|
@ is it an ethernet interrupt ? |
1: ands r2, r1, #0x100 |
beq 2f @ not ethmac int, jump |
.extern ethmac_interrupt |
bl ethmac_interrupt |
|
|
2: @ Restore all registers from the stack |
ldmfd sp!, {r0-r12, lr} |
|
@ Jump straight back to normal execution |
subs pc, lr, #4 |
|
|
|
/* _testfail: Used to terminate execution in Verilog simulations */ |
/* On the board just puts the processor into an infinite loop */ |
.globl _testfail |
_testfail: |
ldr r11, AdrTestStatus |
str r0, [r11] |
b _testfail |
|
|
/* _testpass: Used to terminate execution in Verilog simulations */ |
/* On the board just puts the processor into an infinite loop */ |
.globl _testpass |
_testpass: |
ldr r11, AdrTestStatus |
mov r10, #17 |
str r10, [r11] |
b _testpass |
|
|
|
|
/* _div: Integer division function */ |
@ Divide r0 by r1 |
@ Answer returned in r1 |
.globl _div |
.globl __aeabi_idiv |
__aeabi_idiv: |
_div: |
stmdb sp!, {r4, lr} |
|
@ set r4 to 1 if one of the two inputs is negative |
and r2, r0, #0x80000000 |
and r3, r1, #0x80000000 |
eor r4, r2, r3 |
|
@ Invert negative numbers |
tst r0, #0x80000000 |
mvnne r0, r0 |
addne r0, r0, #1 |
|
tst r1, #0x80000000 |
mvnne r1, r1 |
addne r1, r1, #1 |
|
@ divide r1 by r2, also use registers r0 and r4 |
mov r2, r1 |
mov r1, r0 |
|
cmp r2, #0 |
beq 3f |
|
@ In order to divide r1 by r2, the first thing we need to do is to shift r2 |
@ left by the necessary number of places. The easiest method of doing this |
@ is simply by trial and error - shift until we discover that r2 has become |
@ too big, then stop. |
mov r0,#0 @ clear r0 to accumulate result |
mov r3,#1 @ set bit 0 in r3, which will be |
@ shifted left then right |
|
1: cmp r3, #0 @ escape on error |
moveq r3, #0x10000000 |
beq 2f |
cmp r2,r1 |
movls r2,r2,lsl#1 |
movls r3,r3,lsl#1 |
bls 1b |
@ shift r2 left until it is about to be bigger than r1 |
@ shift r3 left in parallel in order to flag how far we have to go |
|
@ r0 will be used to hold the result. The role of r3 is more complicated. |
@ In effect, we are using r3 to mark where the right-hand end of r2 has got to |
@ - if we shift r2 three places left, this will be indicated by a value of %1000 |
@ in r3. However, we also add it to r0 every time we manage a successful subtraction, |
@ since it marks the position of the digit currently being calculated in the answer. |
|
@ so at the time of the first subtraction, r3 would have been %100, at the time |
@ of the second (which failed) it would have been %10, and at the time of the |
@ third %1. Adding it to r0 after each successful subtraction would have |
@ given us, once again, the answer of %101! |
|
@ Now for the loop that actually does the work: |
2: cmp r1,r2 @ carry set if r1>r2 (don't ask why) |
subcs r1,r1,r2 @ subtract r2 from r1 if this would |
@ give a positive answer |
addcs r0,r0,r3 @ and add the current bit in r3 to |
@ the accumulating answer in r0 |
|
@ In subtraction (a cmp instruction simulates a subtraction in |
@ order to set the flags), if r1 - r2 gives a positive answer and no 'borrow' |
@ is required, the carry flag is set. This is required in order to make SBC |
@ (Subtract with Carry) work properly when used to carry out a 64-bit subtraction, |
@ but it is confusing! |
|
@ In this case, we are turning it to our advantage. The carry flag is set to |
@ indicate that a successful subtraction is possible, i.e. one that doesn't |
@ generate a negative result, and the two following instructions are carried |
@ out only when the condition Carry Set applies. Note that the 'S' on the end |
@ of these instructions is part of the 'CS' condition code and does not mean |
@ that they set the flags! |
|
movs r3,r3,lsr #1 @ Shift r3 right into carry flag |
movcc r2,r2,lsr #1 @ and if bit 0 of r3 was zero, also |
@ shift r2 right |
bcc 2b @ If carry not clear, r3 has shifted |
@ back to where it started, and we |
@ can end |
|
@ if one of the inputs is negetive then return a negative result |
tst r4, #0x80000000 |
mvnne r0, r0 |
addne r0, r0, #1 |
3: ldmia sp!, {r4, pc}^ |
|
|
/* strcpy: String copy function |
char * strcpy ( char * destination, const char * source ); |
destination is returned |
*/ |
@ r0 points to destination |
@ r1 points to source string which terminates with a 0 |
.globl strcpy |
strcpy: |
stmdb sp!, {r4-r6, lr} |
@ Use r6 to process the destination pointer. |
@ At the end of the function, r0 is returned, so need to preserve it |
mov r6, r0 |
|
strcpy_main: |
@ unroll the loop 4 times |
ldrb r3, [r1], #1 |
strb r3, [r6], #1 |
cmp r3, #0 |
ldmeqia sp!, {r4-r6, pc}^ |
|
ldrb r3, [r1], #1 |
strb r3, [r6], #1 |
cmp r3, #0 |
ldmeqia sp!, {r4-r6, pc}^ |
|
ldrb r3, [r1], #1 |
strb r3, [r6], #1 |
cmp r3, #0 |
ldmeqia sp!, {r4-r6, pc}^ |
|
ldrb r3, [r1], #1 |
strb r3, [r6], #1 |
cmp r3, #0 |
ldmeqia sp!, {r4-r6, pc}^ |
|
b strcpy_main |
|
|
|
/* strncpy: String copy function */ |
@ r0 points to destination |
@ r1 points to source string |
@ r2 is the number of bytes to copy |
.globl strncpy |
strncpy: |
stmdb sp!, {r4, lr} |
cmp r2, #0 |
beq 2f |
add r4, r0, r2 @ set r4 to the address of the last byte copied |
1: ldrb r3, [r1], #1 |
strb r3, [r0], #1 |
cmp r0, r4 |
bne 1b |
2: ldmia sp!, {r4, pc}^ |
|
|
|
/* strncpy: String compare function */ |
@ r0 points to first string |
@ r1 points to second string |
@ r2 is the number of bytes to compare |
@ return the difference if the strings don't match |
.globl strncmp |
strncmp: |
stmdb sp!, {r4, r5, r6, lr} |
|
@ check for 0 length |
cmp r2, #0 |
moveq r0, #1 |
beq 2f |
|
mov r3, #0 |
|
1: add r3, r3, #1 |
ldrb r4, [r0], #1 |
ldrb r5, [r1], #1 |
|
subs r6, r4, r5 |
movne r0, r6 |
bne 2f |
|
cmp r3, r2 |
moveq r0, #0 |
beq 2f |
|
b 1b |
2: ldmia sp!, {r4, r5, r6, pc}^ |
|
|
|
.globl init_malloc |
init_malloc: |
ldr r0, AdrMallocBase |
ldr r1, AdrMallocPointer |
str r0, [r1] |
|
@ initialize the counter to 0 |
ldr r1, AdrMallocCount |
mov r2, #0 |
str r2, [r1] |
|
mov pc, lr |
|
|
/* void *malloc(size_t size); */ |
.globl malloc |
malloc: |
/* r0 contains the size of the object in bytes */ |
ldr r1, AdrMallocPointer |
ldr r2, [r1] /* r2 now containts the starting address of the next memory block to use */ |
add r3, r0, r2 /* r3 contains the address after the end of the new object */ |
|
/* Round r3 up to the nearest 0x100 to keep memory aligned */ |
tst r3, #0xff |
beq 1f |
bic r3, r3, #0xff |
add r3, r3, #0x100 |
|
1: str r3, [r1] /* Update the malloc pointer */ |
mov r0, r2 /* Return the address from before the pointer was updated */ |
|
@ Update the block count |
ldr r1, AdrMallocCount |
ldr r2, [r1] |
add r2, r2, #1 |
str r2, [r1] |
|
mov pc, lr |
|
|
/* stack at top of ddr3 memory space */ |
AdrJumpPoint: .word _jump_point |
AdrExecBase: .word ADR_EXEC_BASE |
AdrStack: .word ADR_STACK |
AdrIRQStack: .word ADR_IRQ_STACK |
AdrMallocPointer: .word ADR_MALLOC_POINTER |
AdrMallocCount: .word ADR_MALLOC_COUNT |
AdrMallocBase: .word ADR_MALLOC_BASE |
|
AdrMemCtrl: .word ADR_AMBER_TEST_MEM_CTRL |
AdrTestStatus: .word ADR_AMBER_TEST_STATUS |
AdrInterruptStatus: .word ADR_AMBER_IC_IRQ0_STATUS |
|
.align 2 |
AdrATAGBase: .word ATAGBase |
AdeEndATAG: .word EndATAG |
|
ATAGBase: .word ATAG_CORE_SIZE |
.word ATAG_CORE |
.word FLAG_READONLY @ flags |
.word 4096 @ page size |
.word 0x0 @ rootdev |
|
.word ATAG_MEM_SIZE |
.word ATAG_MEM |
.word 32*1024*1024 @ size - 32MB |
.word 0x0 @ start |
|
.word ATAG_RAMDISK_SIZE |
.word ATAG_RAMDISK |
.word 1 @ flags: bit 0 = load, bit 1 = prompt |
.word 0x000000d0 @ size in 1k blocks |
.word 0x00800000 @ physical address of start of ramdisk |
|
.word ATAG_INITRD_SIZE |
.word ATAG_INITRD |
.word 0x02800000 @ virtual address of start of initrd image |
.word 0x00032000 @ size = 200k |
|
.word ATAG_NONE |
.word 0x0 |
EndATAG: .word 0x0 |
|
AdrBootParams: .word 0x7c000 |
AdrPageTabes: .word 0x3f01000 |
/boot-loader-ethmac/utilities.h
0,0 → 1,54
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
#define NULL 0 |
|
void udelay20 (void); |
void * malloc (unsigned int); |
int get_hex (char*, unsigned int*); |
int next_string (char*); |
int strcmp (char*, char*); |
|
void led_clear (void); |
void led_flip (int); |
void led_on (int); |
void led_off (int); |
void led_123 (int); |
|
void phy_rst (int); |
/boot-loader-ethmac/timer.c
0,0 → 1,141
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#include "amber_registers.h" |
#include "utilities.h" |
#include "timer.h" |
|
|
/* Global variable for the current time */ |
time_t* current_time_g; |
|
|
time_t* init_timer() |
{ |
time_t* timer; |
timer= malloc(sizeof(time_t)); |
timer->milliseconds = 0; |
timer->seconds = 0; |
return timer; |
} |
|
|
|
/*Initialize a global variable that keeps |
track of the current up time. Timers are |
compared against this running value. |
*/ |
void init_current_time() |
{ |
/* Configure timer 0 */ |
/* Counts down from this value and generates an interrupt every 1/100 seconds */ |
*(unsigned int *) ( ADR_AMBER_TM_TIMER0_LOAD ) = 1562; // 16-bit, x 256 |
*(unsigned int *) ( ADR_AMBER_TM_TIMER0_CTRL ) = 0xc8; // enable[7], periodic[6], |
|
/* Enable timer 0 interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x020; |
|
current_time_g = malloc(sizeof(time_t)); |
current_time_g->milliseconds = 0; |
current_time_g->seconds = 0; |
} |
|
|
|
void timer_interrupt() |
{ |
/* Clear timer 0 interrupt in timer */ |
*(unsigned int *) ( ADR_AMBER_TM_TIMER0_CLR ) = 1; |
|
/* Disable timer 0 interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x020; |
|
/* Update the global current_time variable */ |
if (current_time_g->milliseconds == 990) { |
current_time_g->milliseconds = 0; |
current_time_g->seconds++; |
} |
else { |
current_time_g->milliseconds+=10; |
} |
|
/* Enable timer 0 interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x020; |
} |
|
|
/* Return true if timer has expired */ |
int timer_expired(time_t * expiry_time) |
{ |
if (!expiry_time->seconds && !expiry_time->milliseconds) |
/* timer is not set */ |
return 0; |
else if (expiry_time->seconds < current_time_g->seconds) |
return 1; |
else if ((expiry_time->seconds == current_time_g->seconds) && |
(expiry_time->milliseconds < current_time_g->milliseconds)) |
return 1; |
else |
return 0; |
} |
|
|
/* Set the timer to current time plus 5 seconds */ |
void set_timer (time_t* timer, int milliseconds) |
{ |
int seconds = _div(milliseconds, 1000); |
int mseconds = milliseconds - seconds*1000; /* milliseconds % 1000 */ |
|
|
if (current_time_g->milliseconds >= (1000 - mseconds)) { |
timer->seconds = current_time_g->seconds + 1; |
timer->milliseconds = current_time_g->milliseconds + mseconds - 1000; |
} |
else { |
timer->seconds = current_time_g->seconds; |
timer->milliseconds = current_time_g->milliseconds + mseconds; |
} |
|
timer->seconds += seconds; |
} |
|
/boot-loader-ethmac/timer.h
0,0 → 1,55
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
|
typedef struct { |
volatile unsigned int seconds; |
volatile unsigned int milliseconds; |
} time_t; |
|
|
void init_current_time (); |
time_t* init_timer (); |
void timer_interrupt (); |
void set_timer (time_t*, int); |
int timer_expired (time_t*); |
|
/* Global variables */ |
extern time_t* current_time_g; |
/boot-loader-ethmac/tcp.c
0,0 → 1,582
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
|
#include "amber_registers.h" |
#include "address_map.h" |
#include "line-buffer.h" |
#include "timer.h" |
#include "utilities.h" |
#include "packet.h" |
#include "tcp.h" |
#include "telnet.h" |
|
|
/* Global variables */ |
int tcp_checksum_errors_g = 0; |
|
|
void parse_tcp_packet(char * buf, packet_t* rx_packet) |
{ |
int i; |
int ptr; |
socket_t* socket; |
|
/* TCP Length */ |
rx_packet->tcp_len = rx_packet->ip_len - rx_packet->ip_header_len*4; |
rx_packet->tcp_hdr_len = (buf[12]>>4)*4; |
|
// Guard against incorrect tcp_hdr_len value |
if (rx_packet->tcp_hdr_len < rx_packet->tcp_len) |
rx_packet->tcp_payload_len = rx_packet->tcp_len - rx_packet->tcp_hdr_len; |
else |
rx_packet->tcp_payload_len = 0; |
|
/* Verify the TCP checksum is correct */ |
if (tcp_checksum(buf, rx_packet, 0)) { |
tcp_checksum_errors_g++; |
goto error_out; |
} |
|
|
rx_packet->tcp_src_port = buf[0]<<8|buf[1]; |
rx_packet->tcp_dst_port = buf[2]<<8|buf[3]; |
rx_packet->tcp_seq = buf[4]<<24|buf[5]<<16|buf[6]<<8|buf[7]; |
rx_packet->tcp_ack = buf[8]<<24|buf[9]<<16|buf[10]<<8|buf[11]; |
rx_packet->tcp_flags = buf[13]; |
rx_packet->tcp_window_size = buf[14]<<8|buf[15]; |
|
|
if (rx_packet->tcp_hdr_len > 20) { |
/* Get the source time stamp */ |
parse_tcp_options(buf, rx_packet); |
} |
|
|
/* -------------------------------------------------- |
Assign the received packet to a socket |
-------------------------------------------------- */ |
|
/* socket 0 open and matches ? */ |
if (socket0_g->tcp_connection_state != TCP_CLOSED && |
socket0_g->rx_packet->tcp_src_port == rx_packet->tcp_src_port) |
socket = socket0_g; |
|
/* socket 1 open and matches ? */ |
else if (socket1_g->tcp_connection_state != TCP_CLOSED && |
socket1_g->rx_packet->tcp_src_port == rx_packet->tcp_src_port) |
socket = socket1_g; |
|
/* no matches. Pick an unused socket */ |
else if (socket0_g->tcp_connection_state == TCP_CLOSED) |
socket = socket0_g; |
else if (socket1_g->tcp_connection_state == TCP_CLOSED) |
socket = socket1_g; |
else |
goto error_out; |
|
|
/* Copy the rx_packet structure into the socket */ |
memcpy(socket->rx_packet, rx_packet, sizeof(packet_t)); |
|
tcp_response(buf, socket); |
|
error_out: |
return; |
} |
|
|
/* Get the tcp source time stamp by walking through the options */ |
void parse_tcp_options(char * buf, packet_t* rx_packet) |
{ |
int ptr; |
|
ptr = 20; |
while (ptr < rx_packet->tcp_hdr_len-1) { |
switch (buf[ptr]) { |
case 0: ptr=rx_packet->tcp_hdr_len; break; // end of options |
case 1: ptr++; break; |
case 2: ptr = ptr + buf[ptr+1]; break; // max segment size |
case 3: ptr = ptr + buf[ptr+1]; break; // Window Scale |
case 4: ptr = ptr + buf[ptr+1]; break; // SACK Permitted |
case 5: ptr = ptr + buf[ptr+1]; break; // SACK |
case 8: |
// Time Stamp Option |
rx_packet->tcp_src_time_stamp = buf[ptr+2]<<24|buf[ptr+3]<<16|buf[ptr+4]<<8|buf[ptr+5]; |
ptr = ptr + buf[ptr+1]; |
break; |
|
case 28: // User Timeout Option |
ptr = ptr + buf[ptr+1]; break; |
|
default: |
ptr++; break; |
} |
} |
} |
|
|
void tcp_response(char * buf, socket_t* socket) |
{ |
socket->packets_received++; |
|
/* Mark the ack in the tcp tx packet buffer so the tx packet does not get resent */ |
if (socket->rx_packet->tcp_flags & 0x10) // ack flag set ? |
tcp_ack(socket); |
|
|
// Other side requesting to reset a connection ? |
if (socket->rx_packet->tcp_flags & 0x04) { // RST |
// Reset the connection |
socket->tcp_disconnect = 1; |
} |
|
// open a connection |
else if (socket->tcp_connection_state == TCP_CLOSED) { |
|
if (socket->rx_packet->tcp_flags & 0x02) { // SYN |
// Open connection |
tcp_open(socket); |
socket->tcp_connection_state = TCP_PENDING; |
} |
|
/* ACK any FIN received */ |
else if (socket->rx_packet->tcp_flags & 0x01) // FIN |
tcp_reply(socket, NULL, 0); |
} |
|
|
// Sent the first ack packet to establish a connection. |
// Have just received the second packet from the server |
else if (socket->tcp_connection_state == TCP_PENDING) { |
/* Add 1 to the sequence number as a special case to open |
the connection */ |
socket->tcp_seq++; |
socket->tcp_connection_state = TCP_OPEN; |
} |
|
|
// connection is already open |
else { |
|
/* contains tcp payload */ |
if (socket->rx_packet->tcp_payload_len != 0) { |
/* Ack the packet only if the payload length is non-zero */ |
tcp_reply(socket, NULL, 0); |
|
/* Process the tcp contents */ |
if (socket->rx_packet->tcp_dst_port == TELNET_PORT) |
/* telnet */ |
parse_telnet_options(&buf[socket->rx_packet->tcp_hdr_len], socket); |
} |
} |
} |
|
|
void tcp_disconnect(socket_t * socket) |
{ |
if (socket->tcp_connection_state != TCP_CLOSED) { |
socket->tcp_connection_state = TCP_CLOSED; |
socket->telnet_connection_state = TELNET_CLOSED; |
socket->telnet_options_sent = 0; |
socket->telnet_sent_opening_message = 0; |
tcp_reply(socket, NULL, 0); |
socket->tcp_disconnect = 0; |
socket->telnet_echo_mode = 0; // reset this setting |
} |
} |
|
|
|
/* Transmit a string of length line_len |
Suspend interrupts so this process does not get interrupted */ |
void tcp_tx(socket_t* socket, char* buf, int len) |
{ |
/* Disable ethmac_int interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
tcp_reply(socket, buf, len); |
|
/* Enable ethmac_int interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100; |
} |
|
|
|
/* TODO merge this into tcp_reply */ |
void tcp_open(socket_t* socket) |
{ |
|
int i, j; |
unsigned short header_checksum; |
mac_ip_t target; |
int ip_length; |
char * buf; |
|
|
buf = socket->tcp_buf[socket->tcp_current_buf]->buf; |
|
|
target.mac[0] = socket->rx_packet->src_mac[0]; |
target.mac[1] = socket->rx_packet->src_mac[1]; |
target.mac[2] = socket->rx_packet->src_mac[2]; |
target.mac[3] = socket->rx_packet->src_mac[3]; |
target.mac[4] = socket->rx_packet->src_mac[4]; |
target.mac[5] = socket->rx_packet->src_mac[5]; |
target.ip[0] = socket->rx_packet->src_ip[0]; |
target.ip[1] = socket->rx_packet->src_ip[1]; |
target.ip[2] = socket->rx_packet->src_ip[2]; |
target.ip[3] = socket->rx_packet->src_ip[3]; |
|
|
/* Include 20 bytes of tcp options */ |
ip_length = 20+20+20; /* 20 bytes ip header, 20 bytes tcp header, 20 bytes tcp options */ |
|
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1; |
socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0; |
socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, 0, TCP_NEW); |
socket->tcp_buf[socket->tcp_current_buf]->ending_seq = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + 1; |
set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500); |
|
ip_header(&buf[14], &target, ip_length, 6); /* 20 byes of tcp options, bytes 14 to 33, ip_proto = 6, TCP*/ |
ethernet_header(buf, &target, 0x0800); /* bytes 0 to 13*/ |
|
socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length; |
|
strncpy((char*)ETHMAC_TX_BUFFER, buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes); |
|
tx_packet(socket->tcp_buf[socket->tcp_current_buf]->len_bytes); // MAC header, IP header, TCP header, TCP options |
socket->packets_sent++; |
|
|
/* Pick the next tx buffer to use */ |
if (socket->tcp_current_buf == TCP_TX_BUFFERS-1) |
socket->tcp_current_buf=0; |
else |
socket->tcp_current_buf++; |
} |
|
|
|
void tcp_reply(socket_t* socket, char* telnet_payload, int telnet_payload_length) |
{ |
|
int i, j; |
mac_ip_t target; |
int ip_length; |
char * buf; |
|
|
buf = socket->tcp_buf[socket->tcp_current_buf]->buf; |
|
target.mac[0] = socket->rx_packet->src_mac[0]; |
target.mac[1] = socket->rx_packet->src_mac[1]; |
target.mac[2] = socket->rx_packet->src_mac[2]; |
target.mac[3] = socket->rx_packet->src_mac[3]; |
target.mac[4] = socket->rx_packet->src_mac[4]; |
target.mac[5] = socket->rx_packet->src_mac[5]; |
target.ip[0] = socket->rx_packet->src_ip[0]; |
target.ip[1] = socket->rx_packet->src_ip[1]; |
target.ip[2] = socket->rx_packet->src_ip[2]; |
target.ip[3] = socket->rx_packet->src_ip[3]; |
|
ip_length = 20+20 + telnet_payload_length; |
|
/* Copy the payload into the transmit buffer */ |
if (telnet_payload_length != 0) { |
for (i=14+ip_length-telnet_payload_length, j=0; i<14+ip_length;i++,j++) { |
buf[i] = telnet_payload[j]; |
} |
} |
|
if (telnet_payload_length) |
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1; |
else |
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 0; |
|
socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0; |
socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, telnet_payload_length, TCP_NORMAL); |
socket->tcp_buf[socket->tcp_current_buf]->ending_seq = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + telnet_payload_length; |
set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500); |
|
ip_header(&buf[14], &target, ip_length, 6); /* 20 byes of tcp options, bytes 14 to 33, ip_proto = 6, TCP*/ |
ethernet_header(buf, &target, 0x0800); /*bytes 0 to 13*/ |
|
socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length; |
|
strncpy((char*)ETHMAC_TX_BUFFER, buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes); |
|
tx_packet(socket->tcp_buf[socket->tcp_current_buf]->len_bytes); // MAC header, IP header, TCP header, TCP options |
socket->packets_sent++; |
|
|
/* Pick the next tx buffer to use */ |
if (socket->tcp_current_buf == TCP_TX_BUFFERS-1) |
socket->tcp_current_buf=0; |
else |
socket->tcp_current_buf++; |
} |
|
|
|
|
/* Find the packets lower than or equal to seq and mark them as acked */ |
void tcp_ack(socket_t* socket) |
{ |
int i, ack_valid; |
unsigned int ack = socket->rx_packet->tcp_ack; |
unsigned int last_ack = socket->tcp_last_ack; |
|
for (i=0;i<TCP_TX_BUFFERS;i=i+1) { |
if (socket->tcp_buf[i]->payload_valid) { |
|
if (ack > last_ack) { |
ack_valid = (socket->tcp_buf[i]->ending_seq > last_ack) && |
(socket->tcp_buf[i]->ending_seq <= ack); |
} |
else { /* ack is a little after 0, last_ack is a little before 0 */ |
if (socket->tcp_buf[i]->ending_seq < last_ack) |
/* ending sequence is a little after 0 */ |
ack_valid = socket->tcp_buf[i]->ending_seq <= ack; |
else |
ack_valid = 1; |
} |
|
if (ack_valid) { |
socket->tcp_buf[i]->ack_received = 1; |
if (socket->tcp_buf[i]->ending_seq == ack) break; |
} |
} |
} |
|
socket->tcp_last_ack = ack; |
} |
|
|
/* Check if any tcp packets need to be re-transmitted */ |
void tcp_retransmit(socket_t* socket) |
{ |
int i; |
|
/* Find the packet that matches seq */ |
for (i=0;i<TCP_TX_BUFFERS;i=i+1) { |
if (socket->tcp_buf[i]->payload_valid && !socket->tcp_buf[i]->ack_received) { |
if (timer_expired(&socket->tcp_buf[i]->resend_time)) { |
|
/* Update the timer to trigger again in another little while */ |
set_timer(&socket->tcp_buf[i]->resend_time, 500); |
|
socket->packets_resent++; |
|
/* Disable ethmac_int interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
strncpy((char*)ETHMAC_TX_BUFFER, socket->tcp_buf[i]->buf, socket->tcp_buf[i]->len_bytes); |
tx_packet(socket->tcp_buf[i]->len_bytes); // MAC header, IP header, TCP header, TCP options |
socket->packets_sent++; |
|
|
/* Enable ethmac_int interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100; |
break; |
} |
} |
} |
} |
|
|
/* return the starting seq number for this packet */ |
unsigned int tcp_header(char *buf, socket_t* socket, int payload_length, int options) |
{ |
unsigned short header_checksum; |
unsigned int seq_num; |
unsigned int ack_num; |
char flags = 0; |
unsigned short len_tcp; |
unsigned int starting_seq; |
|
/* Source Port */ |
buf[0] = socket->rx_packet->tcp_dst_port >>8; |
buf[1] = socket->rx_packet->tcp_dst_port &0xff; |
|
/* Destination Port */ |
buf[2] = socket->rx_packet->tcp_src_port >>8; |
buf[3] = socket->rx_packet->tcp_src_port &0xff; |
|
/* Sequence Number */ |
/* Increment the sequence number for the next packet */ |
starting_seq = socket->tcp_seq; |
socket->tcp_last_seq = socket->tcp_seq; |
socket->tcp_seq += payload_length; |
|
|
buf[4] = starting_seq>>24; |
buf[5] = (starting_seq>>16)&0xff; |
buf[6] = (starting_seq>>8)&0xff; |
buf[7] = starting_seq&0xff; |
|
|
/* Ack Number */ |
if (options == TCP_NEW) |
ack_num = socket->rx_packet->tcp_seq + 1; |
else if (socket->rx_packet->tcp_flags & 0x01) // FIN |
// +1 to the final ack |
ack_num = socket->rx_packet->tcp_seq + 1; |
else |
ack_num = socket->rx_packet->tcp_seq + socket->rx_packet->tcp_payload_len; |
|
buf[8] = ack_num>>24; |
buf[9] = (ack_num>>16)&0xff; |
buf[10] = (ack_num>>8)&0xff; |
buf[11] = ack_num&0xff; |
|
|
/* Data offset with OPTIONS */ |
if (options == TCP_NEW) |
buf[12] = 0xa0; /* upper 4 bits, min is 5 */ |
else |
buf[12] = 0x50; /* upper 4 bits, min is 5 */ |
|
|
/* Flags */ |
flags = 0x10; /* ACK */ |
if (options == TCP_NEW) /* Valid in first reply in new connection only */ |
flags |= 0x02; /* SYNchronise */ |
if (socket->tcp_disconnect) |
flags |= 0x01; /* FINish */ |
if (socket->tcp_reset) |
flags |= 0x04; /* Reset */ |
|
buf[13] = flags; |
|
/* Window Size */ |
buf[14] = socket->rx_packet->tcp_window_size >> 8; |
buf[15] = socket->rx_packet->tcp_window_size & 0xff; |
|
/* Checksum */ |
buf[16] = 0; |
buf[17] = 0; |
|
/* Urgent Pointer */ |
buf[18] = 0; |
buf[19] = 0; |
|
|
if (options == TCP_NEW) { |
/* OPTION: max seg size */ |
buf[20] = 0x02; |
buf[21] = 0x04; |
buf[22] = 0x05; |
buf[23] = 0xb4; |
|
/* OPTION Sack OK */ |
buf[24] = 0x04; |
buf[25] = 0x02; |
|
/* OPTION Time Stamp */ |
buf[26] = 0x08; |
buf[27] = 0x0a; |
buf[28] = 0x00; |
buf[29] = 0x61; |
buf[30] = 0x1f; |
buf[31] = 0xc6; |
buf[32] = socket->rx_packet->tcp_src_time_stamp>>24; |
buf[33] = (socket->rx_packet->tcp_src_time_stamp>>16)&0xff; |
buf[34] = (socket->rx_packet->tcp_src_time_stamp>>8)&0xff; |
buf[35] = socket->rx_packet->tcp_src_time_stamp&0xff; |
|
/* OPTION: NOP */ |
buf[36] = 0x01; |
|
/* OPTION Window Scale */ |
buf[37] = 0x03; |
buf[38] = 0x03; |
buf[39] = 0x06; |
} |
|
|
/* Length */ |
if (options == TCP_NEW) |
len_tcp = 40+payload_length; |
else |
len_tcp = 20+payload_length; |
|
|
/* header checksum */ |
header_checksum = tcp_checksum(buf, socket->rx_packet, len_tcp); |
buf[16] = (header_checksum>>8)&0xff; |
buf[17] = header_checksum&0xff; |
|
return starting_seq; |
} |
|
|
unsigned short tcp_checksum(unsigned char *buf, packet_t* rx_packet, unsigned short len_tcp) |
{ |
unsigned short prot_tcp=6; |
unsigned short word16; |
unsigned long sum; |
int i; |
|
//initialize sum to zero |
sum=0; |
if (!len_tcp) len_tcp = rx_packet->tcp_len; |
|
|
// add the TCP pseudo header which contains: |
// the IP source and destinationn addresses, |
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->src_ip[i]<<8)&0xFF00)+(rx_packet->src_ip[i+1]&0xFF); |
sum=sum+word16; |
} |
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->dst_ip[i]<<8)&0xFF00)+(rx_packet->dst_ip[i+1]&0xFF); |
sum=sum+word16; |
} |
// the protocol number and the length of the TCP packet |
sum = sum + prot_tcp + len_tcp; |
|
|
return header_checksum16(buf, len_tcp, sum); |
} |
|
/boot-loader-ethmac/address_map.h
0,0 → 1,18
|
/* Address map */ |
/* System has 128MB which is 0x04000000 */ |
/* First 16KB is embedded block RAMs. The rest is ddr3 memory */ |
|
/* boot program in block RAM gets copied here to execute */ |
#define ADR_EXEC_BASE 0x01000000 /* 16KB program size */ |
#define ADR_STACK 0x0100f000 /* 44KB stack space */ |
#define ADR_IRQ_STACK 0x01010000 /* 4KB IRQ stack space */ |
|
#define ADR_MALLOC_POINTER 0x01020000 |
#define ADR_MALLOC_COUNT 0x01020004 |
#define ADR_MALLOC_BASE 0x01020100 /* ~95MB malloc space */ |
|
/* Packet buffers. These need to be in non-cached space |
The cache is configured in startup in start.S */ |
#define ETHMAC_RX_BUFFER 0x03010000 |
#define ETHMAC_TX_BUFFER 0x03040002 |
/boot-loader-ethmac/sections.lds
0,0 → 1,79
/*---------------------------------------------------------------- |
// // |
// sections.lds // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Sections linker file for the boot-loader application. // |
// Note that the address map starts at 0x0 because this is // |
// a stand-alone application . // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
ENTRY(main) |
|
|
SECTIONS { |
. = 0x01000000; |
|
.start : |
{ |
start*(.text) |
} |
|
.text : |
{ |
*(.text) |
} |
|
.rodata : |
{ |
*(.rodata) |
} |
|
.data : |
{ |
*(.data) |
} |
|
.bss : |
{ |
*(.bss) |
} |
|
.stack : |
{ |
__stack = . ; |
} |
|
} |
/boot-loader-ethmac/udp.c
0,0 → 1,254
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
|
#include "address_map.h" |
#include "line-buffer.h" |
#include "timer.h" |
#include "utilities.h" |
#include "packet.h" |
#include "udp.h" |
|
|
int udp_checksum_errors_g = 0; |
block_t* udp_file_g = NULL; |
block_t* udp_current_block_g = NULL; |
|
|
void parse_udp_packet(char * buf, packet_t* rx_packet) |
{ |
unsigned int udp_src_port = buf[0]<<8|buf[1]; |
unsigned int udp_dst_port = buf[2]<<8|buf[3]; |
unsigned int udp_len = buf[4]<<8|buf[5]; |
|
unsigned short prot_udp=17; |
unsigned short word16; |
unsigned long sum = 0; |
unsigned int checksum; |
int mode_offset; |
int binary_mode; |
int i; |
|
|
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->src_ip[i]<<8)&0xFF00)+(rx_packet->src_ip[i+1]&0xFF); |
sum=sum+word16; |
} |
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->dst_ip[i]<<8)&0xFF00)+(rx_packet->dst_ip[i+1]&0xFF); |
sum=sum+word16; |
} |
// the protocol number and the length of the TCP packet |
sum = sum + prot_udp + udp_len; |
|
checksum = header_checksum16(buf, udp_len, sum); |
|
if (checksum) |
udp_checksum_errors_g++; |
|
|
/* TFTP */ |
if (udp_dst_port == 69 && !checksum) { |
unsigned int opcode = buf[8]<<8|buf[9]; |
unsigned int block = buf[10]<<8|buf[11]; |
int tftp_len = udp_len - 12; |
|
mode_offset = next_string(&buf[10]); |
binary_mode = strcmp("octet", &buf[10+mode_offset]); |
|
switch (opcode) { |
|
case UDP_READ: |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ERROR); |
break; |
|
case UDP_WRITE: |
udp_file_g = init_buffer_512(); |
udp_file_g->filename = malloc(256); |
strcpy(udp_file_g->filename, &buf[10]); |
|
if (strncmp(&buf[10], "vmlinux") == 0) |
udp_file_g->linux_boot == 1; |
|
udp_current_block_g = udp_file_g; |
|
|
if (binary_mode) |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ACK); |
else |
udp_reply(rx_packet, udp_dst_port, udp_src_port, 0, UDP_ERROR); |
break; |
|
|
case UDP_DATA: |
udp_reply(rx_packet, udp_dst_port, udp_src_port, block, UDP_ACK); |
|
if (block > udp_file_g->last_block) { |
// Have not already received this block |
udp_file_g->last_block = block; |
|
/* receive and save a block */ |
udp_current_block_g->bytes = tftp_len; |
udp_file_g->total_bytes += tftp_len; |
udp_file_g->total_blocks++; |
|
memcpy(udp_current_block_g->buf512, &buf[12], tftp_len); |
|
/* Prepare the next block */ |
if (tftp_len == 512) { |
udp_current_block_g->next = init_buffer_512(); |
udp_current_block_g = udp_current_block_g->next; |
} |
else { /* Last block */ |
udp_file_g->ready = 1; |
} |
} |
break; |
|
|
default: break; |
} |
} |
} |
|
|
|
void udp_reply(packet_t* rx_packet, int udp_src_port, int udp_dst_port, int block, int reply_type) |
{ |
char* buf = (char*)ETHMAC_TX_BUFFER; |
unsigned short checksum; |
unsigned short prot_udp=17; |
unsigned short udp_len; |
unsigned short word16; |
unsigned long sum = 0; |
int i; |
mac_ip_t target; |
|
target.mac[0] = rx_packet->src_mac[0]; |
target.mac[1] = rx_packet->src_mac[1]; |
target.mac[2] = rx_packet->src_mac[2]; |
target.mac[3] = rx_packet->src_mac[3]; |
target.mac[4] = rx_packet->src_mac[4]; |
target.mac[5] = rx_packet->src_mac[5]; |
target.ip[0] = rx_packet->src_ip[0]; |
target.ip[1] = rx_packet->src_ip[1]; |
target.ip[2] = rx_packet->src_ip[2]; |
target.ip[3] = rx_packet->src_ip[3]; |
|
/* udp header */ |
buf[34] = (udp_src_port & 0xff00)>>8; |
buf[35] = udp_src_port & 0xff; |
buf[36] = (udp_dst_port & 0xff00)>>8; |
buf[37] = udp_dst_port & 0xff; |
|
if (reply_type == UDP_ACK) |
udp_len = 8+4; |
else /* error */ |
udp_len = 8+2+2+14; |
|
|
buf[38] = (udp_len & 0xff00)>>8; |
buf[39] = udp_len & 0xff; |
|
buf[40] = 0; // checksum |
buf[41] = 0; // checksum |
|
// ------------------------------------- |
// tftf payload |
// ------------------------------------- |
// Opcode |
buf[42] = 0; |
buf[43] = reply_type & 0xff; // Acknowledgment |
|
if (reply_type == UDP_ACK) { |
// block |
buf[44] = (block & 0xff00)>>8; |
buf[45] = block & 0xff; |
} |
else {/* error */ |
// Error Code |
buf[44] = 0; |
buf[45] = 0; |
// 46 to 59 |
strncpy(&buf[46], "Not supported", 14); |
} |
|
|
// ------------------------------------- |
// UDP Checksum calculation |
// ------------------------------------- |
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->src_ip[i]<<8)&0xFF00)+(rx_packet->src_ip[i+1]&0xFF); |
sum=sum+word16; |
} |
for (i=0;i<4;i=i+2){ |
word16 =((rx_packet->dst_ip[i]<<8)&0xFF00)+(rx_packet->dst_ip[i+1]&0xFF); |
sum=sum+word16; |
} |
// the protocol number and the length of the TCP packet |
sum = sum + prot_udp + udp_len; |
|
checksum = header_checksum16(&buf[34], udp_len, sum); |
buf[40] = (checksum & 0xff00)>>8; // checksum |
buf[41] = checksum & 0xff; // checksum |
|
ip_header(&buf[14], &target, 20+udp_len, 17); /* 20 byes of tcp options, bytes 14 to 33, ip_proto = 17, UDP */ |
ethernet_header(buf, &target, 0x0800); /*bytes 0 to 13*/ |
tx_packet(34+udp_len); // packet length in bytes |
} |
|
|
block_t* init_buffer_512() |
{ |
block_t* block = malloc(sizeof(block_t)); |
block->buf512 = malloc(512); |
block->next = NULL; |
block->bytes = 0; |
block->last_block = 0; |
block->total_bytes = 0; |
block->total_blocks = 0; |
block->ready = 0; |
block->filename = NULL; |
return block; |
} |
|
/boot-loader-ethmac/tcp.h
0,0 → 1,70
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
|
enum tcp_state { |
TCP_CLOSED = 0, |
TCP_PENDING = 1, |
TCP_OPEN = 2 |
}; |
|
|
enum tcp_options { |
TCP_NEW = 0, |
TCP_NORMAL = 1, |
TCP_RESET = 2 |
}; |
|
|
unsigned short tcp_checksum (unsigned char *, packet_t*, unsigned short); |
unsigned int tcp_header (char *, socket_t*, int, int); |
void tcp_reply (socket_t*, char*, int); |
void tcp_open (socket_t*); |
void tcp_retransmit (socket_t*); |
void tcp_ack (socket_t*); |
void tcp_response (char*, socket_t*); |
void tcp_disconnect (socket_t*); |
void tcp_tx (socket_t*, char*, int); |
void parse_tcp_options (char*, packet_t*); |
void parse_tcp_packet (char*, packet_t*); |
|
extern int tcp_checksum_errors_g; |
|
|
/boot-loader-ethmac/telnet.c
0,0 → 1,191
/*---------------------------------------------------------------- |
// // |
// boot-loader-ethmac.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
|
#include "timer.h" |
#include "line-buffer.h" |
#include "packet.h" |
#include "tcp.h" |
#include "telnet.h" |
|
void parse_telnet_options(char* buf, socket_t* socket) |
{ |
int i; |
int stage = 0; |
char stage1; |
|
for (i=0;i<socket->rx_packet->tcp_payload_len;i++) { |
|
if (stage == 0) { |
switch (buf[i]) { |
case 241: stage = 0; break; // NOP |
case 255: stage = 1; |
if (socket->telnet_connection_state == TELNET_CLOSED) { |
socket->telnet_connection_state = TELNET_OPEN; |
} |
break; // IAC |
|
default: if (buf[i] < 128) |
goto telnet_payload; |
} |
|
} else if (stage == 1) { |
stage1 = buf[i]; |
switch (buf[i]) { |
case 241 : stage = 0; break; // NOP |
case 250 : stage = 2; break; // SB |
case TELNET_WILL: stage = 2; break; // 0xfb WILL |
case TELNET_WONT: stage = 2; break; // 0xfc WONT |
case TELNET_DO : stage = 2; break; // 0xfd DO |
case TELNET_DONT: stage = 2; break; // 0xfe DONT |
default : stage = 2; break; |
} |
|
} else { // stage = 2 |
stage = 0; |
switch (buf[i]) { |
case 1: // echo |
/* Client request that server echos stuff back to client */ |
if (stage1 == TELNET_DO) |
socket->telnet_echo_mode = 1; |
/* Client request that server does not echo stuff back to client */ |
else if (stage1 == TELNET_DONT) |
socket->telnet_echo_mode = 0; |
break; |
|
case 3: break; // suppress go ahead |
case 5: break; // status |
case 6: break; // time mark |
case 24: break; // terminal type |
case 31: break; // window size |
case 32: break; // terminal speed |
case 33: break; // remote flow control |
case 34: break; // linemode |
case 35: break; // X display location |
case 39: break; // New environmental variable option |
default: break; |
} |
} |
} |
|
return; |
|
telnet_payload: |
socket->rx_packet->telnet_payload_len = socket->rx_packet->tcp_payload_len - i; |
parse_telnet_payload(&buf[i], socket); |
} |
|
|
void parse_telnet_payload(char * buf, socket_t* socket) |
{ |
int i; |
int cr = 0; |
int windows = 0; |
for (i=0;i<socket->rx_packet->telnet_payload_len;i++) { |
if (buf[i] == '\n') |
windows = 1; |
else if (buf[i] < 128 && buf[i] != 0) { |
/* end of a line */ |
/* receive \r\n from Windows, \r from Linux */ |
if (buf[i] == '\r') { |
cr=1; |
put_byte(socket->telnet_rxbuf, buf[i], 1); /* last byte of line */ |
} |
else { |
put_byte(socket->telnet_rxbuf, buf[i], 0); /* not last byte of line */ |
} |
} |
} |
|
if (socket->telnet_echo_mode) { |
if (cr && !windows) { |
buf[socket->rx_packet->telnet_payload_len] = '\n'; |
socket->rx_packet->telnet_payload_len++; |
} |
tcp_reply(socket, buf, socket->rx_packet->telnet_payload_len); |
} |
} |
|
|
void telnet_options(socket_t* socket) |
{ |
char buf[3]; |
|
// telnet options |
// Will echo - advertise that I have the ability to echo back commands to the client |
buf[0] = 0xff; buf[1] = TELNET_WILL; buf[2] = 0x01; |
tcp_reply(socket, buf, 3); |
|
} |
|
|
void telnet_tx(socket_t* socket, line_buf_t* txbuf) |
{ |
int line_len; |
int total_line_len; |
char* line; |
char* first_line; |
|
/* Parse telnet tx buffer |
Grab as many lines as possible to stuff into a packet to transmit */ |
line_len = get_line(txbuf, &first_line); |
if (line_len) { |
total_line_len = line_len; |
while (total_line_len < MAX_TELNET_TX && line_len) { |
line_len = get_line(txbuf, &line); |
total_line_len += line_len; |
} |
tcp_tx(socket, first_line, total_line_len); |
} |
} |
|
/* |
void telnet_broadcast (const char *fmt, ...) |
{ |
register unsigned long *varg = (unsigned long *)(&fmt); |
*varg++; |
|
put_line (socket0_g->telnet_txbuf, fmt, varg); |
put_line (socket1_g->telnet_txbuf, fmt, varg); |
} |
*/ |
/boot-loader-ethmac/Makefile
0,0 → 1,59
# ---------------------------------------------------------------- |
# // |
# Makefile for the boot-loader application. // |
# // |
# This file is part of the Amber project // |
# http://www.opencores.org/project,amber // |
# // |
# Description // |
# Simple makefile that defines the sources and target. // |
# Uses the common.mk common makefile script. // |
# // |
# Author(s): // |
# - Conor Santifort, csantifort.amber@gmail.com // |
# // |
#/ /////////////////////////////////////////////////////////////// |
# // |
# Copyright (C) 2010 Authors and OPENCORES.ORG // |
# // |
# This source file may be used and distributed without // |
# restriction provided that this copyright statement is not // |
# removed from the file and that any derivative work contains // |
# the original copyright notice and the associated disclaimer. // |
# // |
# This source file is free software; you can redistribute it // |
# and/or modify it under the terms of the GNU Lesser General // |
# Public License as published by the Free Software Foundation; // |
# either version 2.1 of the License, or (at your option) any // |
# later version. // |
# // |
# This source is distributed in the hope that it will be // |
# useful, but WITHOUT ANY WARRANTY; without even the implied // |
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
# PURPOSE. See the GNU Lesser General Public License for more // |
# details. // |
# // |
# You should have received a copy of the GNU Lesser General // |
# Public License along with this source; if not, download it // |
# from http://www.opencores.org/lgpl.shtml // |
# // |
# ---------------------------------------------------------------- |
# Assembly source files |
|
SRC = boot-loader-ethmac.c line-buffer.c timer.c print.c elfsplitter.c utilities.c \ |
ethmac.c packet.c tcp.c udp.c telnet.c start.S ../mini-libc/memcpy.c |
DEP = address_map.h boot-loader-ethmac.h line-buffer.h timer.h utilities.h \ |
ethmac.h tcp.h udp.h telnet.h packet.h elfsplitter.h |
TGT = boot-loader-ethmac.elf |
LDS = sections.lds |
|
|
# Needs to fit into the boot memory on the FPGA - 8kBytes |
# so size is important |
MIN_SIZE = 1 |
CHANGE_ADDRESS = 1 |
|
all : debug |
../tools/check_mem_size.sh $(MEM) "@000040" |
|
include ../include/common.mk |
/boot-loader-ethmac/print.c
0,0 → 1,201
/*---------------------------------------------------------------- |
// // |
// sprintf.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// printf functions for the mini-libc library. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2011 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#include "stdio.h" |
|
/* Defines */ |
#define PAD_RIGHT 1 |
#define PAD_ZERO 2 |
|
/* the following should be enough for 32 bit int */ |
#define PRINT_BUF_LEN 16 |
|
|
|
int print(char** dst, const char *format, unsigned long *varg) |
{ |
register int width, pad; |
register int pc = 0; |
char scr[2]; |
|
for (; *format != 0; ++format) { |
if (*format == '%') { |
++format; |
width = pad = 0; |
if (*format == '\0') break; |
if (*format == '%') goto out; |
if (*format == '-') { |
++format; |
pad = PAD_RIGHT; |
} |
while (*format == '0') { |
++format; |
pad |= PAD_ZERO; |
} |
for ( ; *format >= '0' && *format <= '9'; ++format) { |
width *= 10; |
width += *format - '0'; |
} |
if( *format == 's' ) { |
register char *s = *((char **)varg++); |
pc += prints (dst, s?s:"(null)", width, pad); |
continue; |
} |
if( *format == 'd' ) { |
pc += printi (dst, *varg++, 10, 1, width, pad, 'a'); |
continue; |
} |
if( *format == 'x' ) { |
pc += printi (dst, *varg++, 16, 0, width, pad, 'a'); |
continue; |
} |
if( *format == 'X' ) { |
pc += printi (dst, *varg++, 16, 0, width, pad, 'A'); |
continue; |
} |
if( *format == 'u' ) { |
pc += printi (dst, *varg++, 10, 0, width, pad, 'a'); |
continue; |
} |
if( *format == 'c' ) { |
/* char are converted to int then pushed on the stack */ |
scr[0] = *varg++; |
scr[1] = '\0'; |
pc += prints (dst, scr, width, pad); |
continue; |
} |
} |
else { |
out: |
//outbyte (dst, *format); |
*(*dst)++ = *format; |
++pc; |
} |
} |
|
return pc; |
} |
|
|
/* Print a string - no formatting characters will be interpreted here */ |
int prints(char** dst, const char *string, int width, int pad) |
{ |
register int pc = 0, padchar = ' '; |
|
if (width > 0) { |
register int len = 0; |
register const char *ptr; |
for (ptr = string; *ptr; ++ptr) ++len; |
if (len >= width) width = 0; |
else width -= len; |
if (pad & PAD_ZERO) padchar = '0'; |
} |
if (!(pad & PAD_RIGHT)) { |
for ( ; width > 0; --width) { |
//outbyte(dst, padchar); |
*(*dst)++ = padchar; |
++pc; |
} |
} |
for ( ; *string ; ++string) { |
//outbyte(dst, *string); |
*(*dst)++ = *string; |
++pc; |
} |
for ( ; width > 0; --width) { |
//outbyte(dst, padchar); |
*(*dst)++ = padchar; |
++pc; |
} |
|
return pc; |
} |
|
|
/* Printf an integer */ |
int printi(char** dst, int i, int b, int sg, int width, int pad, int letbase) |
{ |
char print_buf[PRINT_BUF_LEN]; |
char *s; |
int t, neg = 0, pc = 0; |
unsigned int u = i; |
|
if (i == 0) { |
print_buf[0] = '0'; |
print_buf[1] = '\0'; |
return prints (dst, print_buf, width, pad); |
} |
|
if (sg && b == 10 && i < 0) { |
neg = 1; |
u = -i; |
} |
|
s = print_buf + PRINT_BUF_LEN-1; |
*s = '\0'; |
|
while (u) { |
if ( b == 16 ) t = u & 0xf; /* hex modulous */ |
else t = u - ( _div (u, b) * b ); /* Modulous */ |
|
if( t >= 10 ) |
t += letbase - '0' - 10; |
*--s = t + '0'; |
|
/* u /= b; */ |
if ( b == 16) u = u >> 4; /* divide by 16 */ |
else u = _div(u, b); |
} |
|
if (neg) { |
if( width && (pad & PAD_ZERO) ) { |
//outbyte(dst,'-'); |
*(*dst)++ = '-'; |
++pc; |
--width; |
} |
else { |
*--s = '-'; |
} |
} |
|
return pc + prints (dst, s, width, pad); |
} |
|
/boot-loader-ethmac/elfsplitter.c
0,0 → 1,135
/*---------------------------------------------------------------- |
// // |
// elfsplitter.c // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Used by the boot loader to split an elf file and copy it // |
// to the correct memory locations ready for execution. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
#include "amber_registers.h" |
#include "address_map.h" |
#include "utilities.h" |
#include "line-buffer.h" |
#include "timer.h" |
#include "packet.h" |
#include "telnet.h" |
#include "elfsplitter.h" |
|
|
|
int elfsplitter (char* inbuf, socket_t* socket) |
{ |
unsigned int i, j, k; |
ElfHeader* elfHeader; |
Elf32_Shdr* elfSection; |
char *outbuf; |
unsigned int outP; |
int interrupt_table_written = 0; |
int interrupt_table_zero_written = 0; |
|
|
/* Create buffer to hold interrupt vector memory values |
Can't copy these into mem0 locations until ready to pass control |
t new program |
*/ |
elf_mem0_g = malloc(sizeof(mem_buf_t)); |
for(i=0;i<MEM_BUF_ENTRIES;i++) |
elf_mem0_g->entry[i].valid = 0; |
|
|
elfHeader=(ElfHeader*)inbuf; |
|
|
if (strncmp((char*)elfHeader->e_ident+1,"ELF",3)) { |
return(1); |
} |
|
if (elfHeader->e_machine != 40) { |
telnet_broadcast ("%s ERROR: ELF file not targetting correct processor type.\r\n", |
__func__); |
return(1); |
} |
|
|
for (i=0;i<elfHeader->e_shnum;++i) { |
elfSection=(Elf32_Shdr*)(inbuf+elfHeader->e_shoff+elfHeader->e_shentsize*i); |
|
/* section with non-zero bits, can be either text or data */ |
if (elfSection->sh_type == SHT_PROGBITS && elfSection->sh_size != 0) { |
for (j=0; j<elfSection->sh_size; j++) { |
k = j + elfSection->sh_offset; |
outP = elfSection->sh_addr + j; |
|
/* debug */ |
if (outP >= ADR_EXEC_BASE) |
telnet_broadcast("%s ERROR: 1 outP value 0x%08x\r\n",__func__, outP); |
else if (outP > MEM_BUF_ENTRIES) |
outbuf[outP] = inbuf[k]; |
else { |
elf_mem0_g->entry[outP].valid = 1; |
elf_mem0_g->entry[outP].data = inbuf[k]; |
interrupt_table_written = 1; |
} |
} |
} |
|
if (elfSection->sh_type == SHT_NOBITS && elfSection->sh_size != 0) { |
for (j=0; j<elfSection->sh_size; j++) { |
outP = j + elfSection->sh_addr; |
|
/* debug */ |
if (outP >= ADR_EXEC_BASE) |
telnet_broadcast("%s ERROR: 2 outP value 0x%08x\r\n",__func__, outP); |
else if (outP > MEM_BUF_ENTRIES) |
outbuf[outP] = 0; |
else { |
elf_mem0_g->entry[outP].valid = 1; |
elf_mem0_g->entry[outP].data = 0; |
interrupt_table_zero_written = 1; |
} |
} |
} |
} |
|
/* |
if (interrupt_table_written) |
telnet_broadcast ("%s WARNING: Interrupt table writes\r\n",__func__); |
if (interrupt_table_zero_written) |
telnet_broadcast ("%s WARNING: Interrupt table ZERO writes\r\n",__func__); |
*/ |
return 0; |
} |
|
/boot-loader-ethmac/udp.h
0,0 → 1,64
/*---------------------------------------------------------------- |
// // |
// boot-loader.h // |
// // |
// This file is part of the Amber project // |
// http://www.opencores.org/project,amber // |
// // |
// Description // |
// Defines for the boot-loader application. // |
// // |
// Author(s): // |
// - Conor Santifort, csantifort.amber@gmail.com // |
// // |
////////////////////////////////////////////////////////////////// |
// // |
// Copyright (C) 2010 Authors and OPENCORES.ORG // |
// // |
// This source file may be used and distributed without // |
// restriction provided that this copyright statement is not // |
// removed from the file and that any derivative work contains // |
// the original copyright notice and the associated disclaimer. // |
// // |
// This source file is free software; you can redistribute it // |
// and/or modify it under the terms of the GNU Lesser General // |
// Public License as published by the Free Software Foundation; // |
// either version 2.1 of the License, or (at your option) any // |
// later version. // |
// // |
// This source is distributed in the hope that it will be // |
// useful, but WITHOUT ANY WARRANTY; without even the implied // |
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // |
// PURPOSE. See the GNU Lesser General Public License for more // |
// details. // |
// // |
// You should have received a copy of the GNU Lesser General // |
// Public License along with this source; if not, download it // |
// from http://www.opencores.org/lgpl.shtml // |
// // |
----------------------------------------------------------------*/ |
|
|
typedef struct { |
char * buf512; |
void * next; |
unsigned int bytes; |
unsigned int last_block; |
unsigned int total_bytes; |
unsigned int total_blocks; |
unsigned int ready; |
unsigned int linux_boot; |
char* filename; |
} block_t; |
|
|
|
void parse_udp_packet (char*, packet_t*); |
void udp_reply (packet_t*, int, int, int, int); |
block_t* init_buffer_512 (); |
|
|
/* Global variables */ |
extern int udp_checksum_errors_g; |
extern block_t* udp_file_g; |
extern block_t* udp_current_block_g; |
.
Property changes :
Added: svn:ignore
## -0,0 +1 ##
+bak