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/boot-loader-ethmac
- from Rev 64 to Rev 78
- ↔ Reverse comparison
Rev 64 → Rev 78
/telnet.h
42,11 → 42,6
#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*); |
/ethmac.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
55,10 → 55,10
{ |
/* 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 |
67,8 → 67,8
[5] = 1 for promiscuous, 0 rx only frames that match mac address |
[1] = txen |
[0] = rxen */ |
*(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa420; |
|
*(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa420; |
|
/* Put the PHY into reset */ |
phy_rst(0); /* reset is active low */ |
|
81,7 → 81,7
int packet; |
int n; |
unsigned int d32; |
|
|
/* Disable Ethmac interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100; |
|
88,10 → 88,10
/* 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 */ |
98,31 → 98,32
/* 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, |
/* 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 */ |
/* 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; |
|
135,7 → 136,7
[1] = txen |
[0] = rxen */ |
*(unsigned int *) ( ADR_ETHMAC_MODER ) = 0xa423; |
|
|
return 1; |
} |
|
143,8 → 144,8
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 |
157,10 → 158,10
|
|
/* Enable packet tx |
[31:16] = length in bytes, |
[31:16] = length in bytes, |
[15] = ready |
[14] = tx int |
[13] = wrap bit |
[13] = wrap bit |
[12] = pad enable for short packets |
[11] = crc en |
*/ |
176,14 → 177,13
int stat; |
int phy_id; |
int link_up = 1; |
time_t* link_timer; |
|
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; |
191,9 → 191,12
stat = mdio_read(phy_id, MII_BMSR); |
stat = mdio_read(phy_id, MII_BMSR); |
if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0)))) |
break; |
break; |
} |
|
/* Failed to find a PHY on the md bus */ |
if (addr == 32) |
return 0; |
|
/* Reset PHY */ |
bmcr = mdio_read(phy_id, MII_BMCR); |
mdio_write(phy_id, MII_BMCR, bmcr | BMCR_RESET); |
202,22 → 205,23
/* 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); |
/* allow a few 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; |
link_up = 0; |
break; |
} |
} |
|
|
return link_up; |
} |
|
236,7 → 240,7
|
/* |
addr = PHY address |
reg = register address within PHY |
reg = register address within PHY |
*/ |
unsigned short mdio_ctrl(unsigned int addr, unsigned int dir, unsigned int reg, unsigned short data) |
{ |
243,23 → 247,23
unsigned int data_out = 0; |
unsigned int i; |
unsigned long flags; |
|
mdio_ready(); |
|
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); |
} |
|
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; |
} |
|
266,13 → 270,13
|
/* 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) |
/* 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; |
283,29 → 287,31
|
|
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; |
|
if (int_src) { |
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; |
} |
} |
} |
|
/boot-loader-ethmac.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
41,29 → 41,23
// // |
----------------------------------------------------------------*/ |
|
// 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 "serial.h" |
|
#include "elfsplitter.h" |
#include "boot-loader-ethmac.h" |
|
|
|
int main ( void ) { |
char* line; |
time_t* led_flash_timer; |
70,41 → 64,52
time_t* reboot_timer; |
socket_t* socket = socket0_g; |
int reboot_stage = 0; |
|
/* Turn off all LEDs as a starting point */ |
|
|
/* Enable the serial debug port */ |
init_serial(); |
print_serial("Amber debug port\n\r"); |
|
|
/* Turn off all LEDs */ |
led_clear(); |
|
/* this must be first, because all the other init functions call malloc */ |
|
/* initialize the memory allocation system */ |
init_malloc(); |
|
|
|
/* Initialize current time and some timers */ |
init_current_time(); |
led_flash_timer = init_timer(); |
set_timer(led_flash_timer, 500); |
set_timer(led_flash_timer, 500); |
reboot_timer = init_timer(); |
|
|
|
|
/* receive packet buffer */ |
rx_packet_g = malloc(sizeof(packet_t)); |
|
/* socket init */ |
|
|
/* initialize two tcp sockets */ |
socket0_g = init_socket(0); |
socket1_g = init_socket(1); |
|
/* open ethernet port and wait for connection requests |
|
|
/* 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) { |
111,17 → 116,24
/* 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) |
|
print_serial("Received file %s, %d bytes", |
udp_file_g->filename, udp_file_g->total_bytes); |
if (udp_file_g->linux_boot) |
print_serial(", linux image detected\r\n"); |
else |
print_serial("\r\n"); |
|
if (process_file(socket0_g) == 0) { |
/* Disconnect in 1 second */ |
set_timer(reboot_timer, 1000); |
} |
else |
telnet_broadcast("Not an elf file\r\n"); |
print_serial("Not an elf file\r\n"); |
} |
} |
|
|
|
|
/* reboot timer expired */ |
if (timer_expired(reboot_timer)) { |
/* First stage of reboot sequence is to nicely disconnect */ |
130,7 → 142,7
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(); |
144,8 → 156,8
socket = socket1_g; |
else |
socket = socket0_g; |
|
|
|
|
/* Check if any tcp packets need to be re-transmitted */ |
tcp_retransmit(socket); |
|
154,8 → 166,8
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; |
164,15 → 176,15
tcp_reply(socket, NULL, 0); |
socket->tcp_reset = 0; |
} |
|
|
/* Send telnet options */ |
|
|
/* 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 |
|
/* telnet connection open |
Communicate with client */ |
else if (socket->telnet_connection_state == TELNET_OPEN) { |
/* Send telnet greeting */ |
180,9 → 192,9
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)) |
if (get_line(socket->telnet_rxbuf, &line)) |
parse_command (socket, line); |
|
/* Transmit text from telnet tx buffer */ |
195,13 → 207,13
|
/* 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) |
{ |
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]) { |
208,52 → 220,52
/* Disconnect */ |
case 'e': |
case 'x': |
case 'q': |
case 'q': |
socket->tcp_disconnect = 1; |
return 0; |
|
case 'r': /* Read mem */ |
|
case 'r': /* Read mem */ |
{ |
if (len = get_hex (&line[2], &start_addr)) { |
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", |
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", |
put_line (socket->telnet_txbuf, "0x%08x 0x%08x\r\n", |
start_addr, *(unsigned int *)start_addr); |
} |
} |
else |
else |
error=1; |
break; |
break; |
} |
|
|
case 'h': {/* Help */ |
|
case 'h': {/* Help */ |
put_line (socket->telnet_txbuf, "You need help alright\r\n"); |
break; |
break; |
} |
|
|
case 's': {/* Status */ |
|
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", |
261,18 → 273,18
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", |
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; |
} |
281,7 → 293,7
/* 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; |
288,12 → 300,12
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]; |
301,7 → 313,7
} |
memcpy(buf512, block->buf512, block->bytes); |
buf512=&buf512[512]; |
|
|
return elfsplitter(tftp_file, socket); |
} |
|
313,9 → 325,9
void reboot() |
{ |
int i; |
|
|
/* Disable all interrupts */ |
/* Disable ethmac_int interrupt */ |
/* Disable ethmac_int interrupt */ |
/* Disable timer 0 interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x120; |
|
322,10 → 334,14
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(); |
|
if (udp_file_g->linux_boot) { |
print_serial("linux reboot\n\r"); |
_jump_to_program(LINUX_JUMP_ADR); |
} |
else { |
print_serial("normal reboot\n\r"); |
_restart(); |
} |
} |
|
/start.S
66,31 → 66,31
|
|
.section .text |
.globl start |
start: |
.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 |
105,23 → 105,23
mov r0, #0 |
ldr r1, AdrExecBase |
1: ldm r0!, {r2-r9} |
stm r1!, {r2-r9} |
stm r1!, {r2-r9} |
cmp r0, #0x4000 |
bne 1b |
|
/* Fix the interrupt jump pointers */ |
ldr r0, AdrExecBase |
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 |
3: ldr r0, AdrExecBase |
ldr r1, AdrJumpPoint |
orr r0, r0, r1 |
mov pc, r0 |
130,21 → 130,21
|
/* Switch to IRQ Mode */ |
mov r0, #0x00000002 |
teqp pc, r0 |
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 |
|
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 |
mcr 15, 0, r0, cr3, cr0, 0 @ cacheable area |
mov r0, #1 |
mcr 15, 0, r0, cr2, cr0, 0 @ cache enable |
|
mcr 15, 0, r0, cr2, cr0, 0 @ cache enable |
|
@ init SP |
ldr sp, AdrStack |
|
152,15 → 152,15
ldr r0, AdrMemCtrl |
mov r1, #1 |
str r1, [r0] |
|
|
.extern main |
bl main |
|
|
@ jump to program at r0 |
.globl _jump_to_program |
.globl _jump_to_program |
_jump_to_program: |
|
|
|
@ ---------------------------------------------- |
@ Copy ATAG structure to AdrBootParams |
@ ---------------------------------------------- |
167,52 → 167,54
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 |
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 r0, #0 |
mov pc, r4 |
|
|
|
service_irq: |
@ Save all registers to the stack |
stmfd sp!, {r0-r12, lr} |
@ As this is an interrupt, need tp save all registers to the stack |
stmfd sp!, {r0-r3, lr} |
|
@ is it a timer interrupt ? |
ldr r0, AdrInterruptStatus |
ldr r1, [r0] |
ands r2, r1, #0x20 |
ldr r3, [r0] |
ands r2, r3, #0x20 |
beq 1f @ not timer int, jump |
@ Remember that registers r0 to r2 can be changed by this function |
.extern timer_interrupt |
bl timer_interrupt |
|
bl timer_interrupt |
|
@ is it an ethernet interrupt ? |
1: ands r2, r1, #0x100 |
beq 2f @ not ethmac int, jump |
1: ands r2, r3, #0x100 |
beq 2f @ not ethmac int, jump |
.extern ethmac_interrupt |
@ Remember that registers r0 to r2 can be changed by this function |
bl ethmac_interrupt |
|
|
|
2: @ Restore all registers from the stack |
ldmfd sp!, {r0-r12, lr} |
|
ldmfd sp!, {r0-r3, lr} |
|
@ Jump straight back to normal execution |
subs pc, lr, #4 |
|
220,17 → 222,17
|
/* _testfail: Used to terminate execution in Verilog simulations */ |
/* On the board just puts the processor into an infinite loop */ |
.globl _testfail |
.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: |
.globl _testpass |
_testpass: |
ldr r11, AdrTestStatus |
mov r10, #17 |
str r10, [r11] |
237,8 → 239,8
b _testpass |
|
|
|
|
|
/* _div: Integer division function */ |
@ Divide r0 by r1 |
@ Answer returned in r1 |
256,22 → 258,22
@ Invert negative numbers |
tst r0, #0x80000000 |
mvnne r0, r0 |
addne r0, r0, #1 |
addne r0, r0, #1 |
|
tst r1, #0x80000000 |
mvnne r1, r1 |
addne r1, r1, #1 |
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 |
@ 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 |
288,14 → 290,14
@ 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 |
@ 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: |
305,19 → 307,19
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, |
@ 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 |
|
@ 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 |
324,20 → 326,20
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 |
|
@ if one of the inputs is negetive then return a negative result |
tst r4, #0x80000000 |
mvnne r0, r0 |
addne r0, r0, #1 |
addne r0, r0, #1 |
3: ldmia sp!, {r4, pc}^ |
|
|
/* strcpy: String copy function |
/* 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 |
@ r1 points to source string which terminates with a 0 |
.globl strcpy |
strcpy: |
stmdb sp!, {r4-r6, lr} |
351,22 → 353,22
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 |
|
|
376,7 → 378,7
@ r1 points to source string |
@ r2 is the number of bytes to copy |
.globl strncpy |
strncpy: |
strncpy: |
stmdb sp!, {r4, lr} |
cmp r2, #0 |
beq 2f |
397,26 → 399,26
.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}^ |
|
427,12 → 429,12
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 |
|
|
443,25 → 445,38
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 |
|
|
.global serial_putchar_ |
serial_putchar_: |
ldr r1, AdrUARTDR |
ldr r3, AdrUARTFR |
@ Check the tx_full flag |
1: ldr r2, [r3] |
and r2, r2, #0x20 |
cmp r2, #0 |
streqb r0, [r1] |
moveqs pc, lr @ return |
bne 1b |
|
|
/* stack at top of ddr3 memory space */ |
AdrJumpPoint: .word _jump_point |
AdrExecBase: .word ADR_EXEC_BASE |
475,6 → 490,9
AdrTestStatus: .word ADR_AMBER_TEST_STATUS |
AdrInterruptStatus: .word ADR_AMBER_IC_IRQ0_STATUS |
|
AdrUARTDR: .word ADR_AMBER_UART0_DR |
AdrUARTFR: .word ADR_AMBER_UART0_FR |
|
.align 2 |
AdrATAGBase: .word ATAGBase |
AdeEndATAG: .word EndATAG |
484,7 → 502,7
.word FLAG_READONLY @ flags |
.word 4096 @ page size |
.word 0x0 @ rootdev |
|
|
.word ATAG_MEM_SIZE |
.word ATAG_MEM |
.word 32*1024*1024 @ size - 32MB |
500,7 → 518,7
.word ATAG_INITRD |
.word 0x02800000 @ virtual address of start of initrd image |
.word 0x00032000 @ size = 200k |
|
|
.word ATAG_NONE |
.word 0x0 |
EndATAG: .word 0x0 |
/serial.c
0,0 → 1,66
/*---------------------------------------------------------------- |
// // |
// 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) 2010-2013 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" |
|
|
void init_serial() |
{ |
/* Enable UART 0 */ |
*(unsigned int *) ADR_AMBER_UART0_LCRH = 0x10; |
} |
|
|
/* Add a line to the line buffer */ |
void print_serial(const char *fmt, ...) |
{ |
int len; |
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 |
*/ |
len = print(0, fmt, varg); |
} |
|
/utilities.h
44,6 → 44,7
int get_hex (char*, unsigned int*); |
int next_string (char*); |
int strcmp (char*, char*); |
int serial_putchar_ (char *); |
|
void led_clear (void); |
void led_flip (int); |
/timer.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
62,7 → 62,7
|
|
/*Initialize a global variable that keeps |
track of the current up time. Timers are |
track of the current up time. Timers are |
compared against this running value. |
*/ |
void init_current_time() |
70,7 → 70,7
/* 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], |
*(unsigned int *) ( ADR_AMBER_TM_TIMER0_CTRL ) = 0xc8; // enable[7], periodic[6], |
|
/* Enable timer 0 interrupt */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x020; |
86,7 → 86,7
{ |
/* 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; |
|
98,9 → 98,9
else { |
current_time_g->milliseconds+=10; |
} |
|
|
/* Enable timer 0 interrupt in interrupt controller */ |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x020; |
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x020; |
} |
|
|
109,13 → 109,13
{ |
if (!expiry_time->seconds && !expiry_time->milliseconds) |
/* timer is not set */ |
return 0; |
return 0; |
else if (expiry_time->seconds < current_time_g->seconds) |
return 1; |
else if ((expiry_time->seconds == current_time_g->seconds) && |
else if ((expiry_time->seconds == current_time_g->seconds) && |
(expiry_time->milliseconds < current_time_g->milliseconds)) |
return 1; |
else |
else |
return 0; |
} |
|
125,8 → 125,8
{ |
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; |
135,7 → 135,7
timer->seconds = current_time_g->seconds; |
timer->milliseconds = current_time_g->milliseconds + mseconds; |
} |
|
|
timer->seconds += seconds; |
} |
|
/serial.h
0,0 → 1,46
/*---------------------------------------------------------------- |
// // |
// 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) 2010-2013 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 */ |
void init_serial(); |
void print_serial(const char *fmt, ...); |
/udp.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
60,59 → 60,58
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 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; |
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; |
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 (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; |
|
|
if (strncmp(&buf[10], "vmlinux", 7) == 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 |
122,21 → 121,21
|
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->next = init_buffer_512(); |
udp_current_block_g = udp_current_block_g->next; |
} |
else { /* Last block */ |
144,8 → 143,8
} |
} |
break; |
|
|
|
|
default: break; |
} |
} |
160,10 → 159,10
unsigned short prot_udp=17; |
unsigned short udp_len; |
unsigned short word16; |
unsigned long sum = 0; |
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]; |
180,8 → 179,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) |
|
if (reply_type == UDP_ACK) |
udp_len = 8+4; |
else /* error */ |
udp_len = 8+2+2+14; |
189,17 → 188,17
|
buf[38] = (udp_len & 0xff00)>>8; |
buf[39] = udp_len & 0xff; |
|
|
buf[40] = 0; // checksum |
buf[41] = 0; // checksum |
|
|
// ------------------------------------- |
// tftf payload |
// tftf payload |
// ------------------------------------- |
// Opcode |
buf[42] = 0; |
buf[43] = reply_type & 0xff; // Acknowledgment |
|
buf[42] = 0; |
buf[43] = reply_type & 0xff; // Acknowledgment |
|
if (reply_type == UDP_ACK) { |
// block |
buf[44] = (block & 0xff00)>>8; |
212,18 → 211,18
// 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; |
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; |
sum=sum+word16; |
} |
// the protocol number and the length of the TCP packet |
sum = sum + prot_udp + udp_len; |
231,7 → 230,7
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 |
249,6 → 248,7
block->total_blocks = 0; |
block->ready = 0; |
block->filename = NULL; |
block->linux_boot = 0; |
return block; |
} |
|
/telnet.c
7,7 → 7,7
// // |
// Description // |
// The main functions for the boot loader application. This // |
// application is embedded in the FPGA's SRAM and is used // |
// application is embedded in the FPGA's SRAM and is used // |
// to load larger applications into the DDR3 memory on // |
// the development board. // |
// // |
53,22 → 53,22
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; |
case 255: stage = 1; |
if (socket->telnet_connection_state == TELNET_CLOSED) { |
socket->telnet_connection_state = TELNET_OPEN; |
} |
break; // IAC |
|
default: if (buf[i] < 128) |
|
default: if (buf[i] < 128) |
goto telnet_payload; |
} |
|
|
} else if (stage == 1) { |
stage1 = buf[i]; |
switch (buf[i]) { |
80,9 → 80,9
case TELNET_DONT: stage = 2; break; // 0xfe DONT |
default : stage = 2; break; |
} |
|
|
} else { // stage = 2 |
stage = 0; |
stage = 0; |
switch (buf[i]) { |
case 1: // echo |
/* Client request that server echos stuff back to client */ |
92,7 → 92,7
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 |
108,8 → 108,8
} |
} |
|
return; |
|
return; |
|
telnet_payload: |
socket->rx_packet->telnet_payload_len = socket->rx_packet->tcp_payload_len - i; |
parse_telnet_payload(&buf[i], socket); |
122,7 → 122,7
int cr = 0; |
int windows = 0; |
for (i=0;i<socket->rx_packet->telnet_payload_len;i++) { |
if (buf[i] == '\n') |
if (buf[i] == '\n') |
windows = 1; |
else if (buf[i] < 128 && buf[i] != 0) { |
/* end of a line */ |
130,13 → 130,13
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'; |
153,7 → 153,7
|
// 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; |
buf[0] = 0xff; buf[1] = TELNET_WILL; buf[2] = 0x01; |
tcp_reply(socket, buf, 3); |
|
} |
165,27 → 165,17
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); |
/* 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); |
} |
} |
*/ |
|
/print.c
48,13 → 48,16
#define PRINT_BUF_LEN 16 |
|
|
|
/* format and print a string, inserting variables, to dst char buffer, |
return the number of characters printed. If dst is 0, the string is |
sent to the serial output |
*/ |
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; |
104,8 → 107,10
} |
else { |
out: |
//outbyte (dst, *format); |
*(*dst)++ = *format; |
if (dst) |
*(*dst)++ = *format; |
else |
serial_putchar_(*format); |
++pc; |
} |
} |
119,33 → 124,39
{ |
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); |
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) { |
if (dst) |
*(*dst)++ = padchar; |
else |
serial_putchar_(padchar); |
++pc; |
} |
} |
for ( ; *string ; ++string) { |
if (dst) |
*(*dst)++ = *string; |
else |
serial_putchar_(*string); |
++pc; |
} |
for ( ; width > 0; --width) { |
if (dst) |
*(*dst)++ = padchar; |
++pc; |
} |
} |
for ( ; *string ; ++string) { |
//outbyte(dst, *string); |
*(*dst)++ = *string; |
++pc; |
} |
for ( ; width > 0; --width) { |
//outbyte(dst, padchar); |
*(*dst)++ = padchar; |
++pc; |
} |
else |
serial_putchar_(padchar); |
++pc; |
} |
|
return pc; |
return pc; |
} |
|
|
174,11 → 185,11
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); |
186,8 → 197,10
|
if (neg) { |
if( width && (pad & PAD_ZERO) ) { |
//outbyte(dst,'-'); |
*(*dst)++ = '-'; |
if (dst) |
*(*dst)++ = '-'; |
else |
serial_putchar_('-'); |
++pc; |
--width; |
} |
/Makefile
41,9 → 41,9
# 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 |
serial.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 |
serial.h ethmac.h tcp.h udp.h telnet.h packet.h elfsplitter.h |
TGT = boot-loader-ethmac.elf |
LDS = sections.lds |
|
55,5 → 55,5
|
all : debug |
../tools/check_mem_size.sh $(MEM) "@000040" |
|
|
include ../include/common.mk |
/elfsplitter.c
59,8 → 59,7
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 |
68,8 → 67,8
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; |
|
|
76,60 → 75,54
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__); |
print_serial ("%s:L%d ERROR: ELF file not targetting correct processor type.\r\n", |
__FILE__, __LINE__); |
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]; |
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) |
print_serial("%s:L%d ERROR: 1 outP value 0x%08x\r\n",__FILE__, __LINE__, 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; |
} |
} |
|
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) |
print_serial("%s:L%d ERROR: 2 outP value 0x%08x\r\n",__FILE__, __LINE__, 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; |
} |
|