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

Subversion Repositories igor

[/] [igor/] [trunk/] [avr/] [src/] [dispatch.c] - Rev 4

Compare with Previous | Blame | View Log

#include <avr/io.h>
#include <avr/interrupt.h>
#include "global.h"
 
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
#include "encdec.h"
#include "req.h"
#include "device.h"
#include "dispatch.h"
#include "dev/7seg.h"
#include "dev/spi.h"
 
#if ETHERNET_ENABLED
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
#include "uip/uip.h"
#include "uip/uip_arp.h"
#include "uip/timer.h"
#include "enc28j60-uip.c"
#endif
 
#include "req.h"
#include "bus.h"
 
/* Peripherals we know of. */
extern struct igordev igordev_boot;
extern struct igordev igordev_usart;
extern struct igordev igordev_mmc;
extern struct igordev igordev_kvga;
#ifdef ETHERNET_ENABLED
extern struct igordev igordev_telnet;
#define NUMDEV	5
#else
#define NUMDEV 4
#endif
struct igordev *idevs[NUMDEV];
 
// Currently seleted device
volatile uint32_t curdev;
// Last device performing interrupt.
volatile uint32_t intrdev;
 
volatile struct rqueue r_queue;
 
static void	dispatch_request_perform(struct req *);
 
#if ETHERNET_ENABLED
void init_network_stuff(void);
req_fn_t do_network_stuff;
#endif
 
#ifdef WITH_DEBUG
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#else
#define DEBUG(...)
#endif
 
#if 0
void init_sram(void) __attribute__ ((naked)) __attribute__ ((section (".init3")));
 
void
init_sram(void)
{
	DDRC = 0xFF;
	PORTC = 0x00;
	XMCRA = (1 << SRE) | (1 << SRW11) | (1 << SRW10);
	XMCRB = 0x00;
}
#endif
 
/* Contains the dispatcher and its routines. */
int
main(void)
{
	struct idev_mgmt *imgmt;
	struct req *req;
	struct rqueue *rq;
	uint32_t i, data;
 
	cli();
	DDRC = 0xFF;
	PORTC = 0x00;
	XMCRA = (1 << SRE) | (1 << SRW11) | (1 << SRW10);
	XMCRB = 0x00;
 
	curdev = DEVTYPE_BOOT;
 
	display_init(); // 7Seg init
 
	/* Initialize device structure with the different device types. */
	idevs[DEVTYPE_BOOT] = &igordev_boot;
	idevs[DEVTYPE_SERIAL] = &igordev_usart;
	idevs[DEVTYPE_STORAGE] = &igordev_mmc;
	idevs[DEVTYPE_TERM] = &igordev_kvga;
#ifdef ETHERNET_ENABLED
	idevs[DEVTYPE_TELNET] = &igordev_telnet;
#endif
	rq = (struct rqueue *)&r_queue;
	rqueue_init(rq);
 
	init_fpgabus();
	_delay_ms(1);
	//display_init(); // 7Seg init
	DEBUG("Initializing devices\n");
	configure_spi(); //Must run before Ethernet/MMC init
	for (i = 0; i < NUMDEV; i++) {
		idevs[i]->init();
		imgmt = &idevs[i]->imgmt;
		imgmt->irqenable = 0;
		imgmt->baseaddr = 0;
		imgmt->curaddr = 0;
		imgmt->size = 0;
	}
#if ETHERNET_ENABLED
	 //This also activates global interrupts as a side-effect
	init_network_stuff();
#endif
	DEBUG("Done initializing devices\n");
 
	/* Boot load test. */
	for (i = 0; i < 10; i++) {
		display_char(i);
		_delay_ms(50.0);
	}
	display_char(curdev);
/*
   BOOT BLOCK LAYOUT
 
   +---------------------------+----------+
   | Boot program size         | 4 bytes  |
   +---------------------------+----------+
   | Data area size            | 4 bytes  |
   +---------------------------+----------+
   |                           |          |
   |  Boot program             | Variable |
   |                           |          |
   +---------------------------+----------+
   |                           |          |
   |  Data area                | Variable |
   |                           |          |
   +---------------------------+----------+
 
 */
	/* Initialize the device boot block layout. */
	/* Read boot program size */
	igordev_mmc.read(0, (uint8_t *)&data, 4);
	igordev_boot.imgmt.size = swap32(data);
	igordev_mmc.read(0, (uint8_t *)&data, 4);
	igordev_mmc.imgmt.size = swap32(data);
	/* Set up segments. */
	igordev_boot.imgmt.baseaddr = 8;
	igordev_mmc.imgmt.baseaddr = 8 + igordev_boot.imgmt.size;
	_delay_ms(10);
	sei();
	avr_online();
 
#if ETHERNET_ENABLED
	//Do periodic polling of network interface
	//and housekeeping of TCP/IP stuff
	do_network_stuff(NULL);
#endif
	while (1) {
		/* Look through queue to see if we have anything. */
		while (!RQUEUE_EMPTY(rq)) {
			req = req_peak(rq);
			// Was empty
			if (req == NULL)
				break;
			dispatch_request_perform(req);
			req_free(rq);
		}
 
	}
	return (0);
}
 
static void
dispatch_request_perform(struct req *req)
{
	struct igordev *idev;
	struct idev_mgmt *imgmt;
	//char output[128];
	uint32_t data, d;
	uint8_t num, osize, total, *ptr;
 
	idev = req->dev;
	imgmt = &idev->imgmt;
	switch (req->type) {
	case REQ_TYPE_READ:
		/* Wait until device is ready. */
		while (idev->read_status != IDEV_STATUS_OK);
		total = DATA_SIZE_TYPE(DATA_TYPE_DEV(req->devnum));
		ptr = (uint8_t *)&data;
		while (idev->read_status != IDEV_STATUS_ERROR) {
			cli();
			num = idev->read(imgmt->curaddr + imgmt->baseaddr, ptr,
			    total);
			sei();
			/* If we were not able to read anything, postpone the
			 * request. */
			if (num == 0) {
				dispatch_request_make(idev, req->type,
				    req->flags, req->devnum, NULL);
				return;
			}
			total -= num;
			imgmt->curaddr += num;
			if (total <= 0)
				break;
			ptr += num;
		}
		if (idev->read_status == IDEV_STATUS_ERROR)
			return;
		if (req->flags & REQ_CALLBACK) {
			d = encode_object(data, req->devnum);
			DEBUG("Perform buffer read from main: '%c'\n", d);
			fpga_finish_read(d);
		}
		break;
	case REQ_TYPE_WRITE:
		/* Wait until device is ready. */
		while (idev->write_status != IDEV_STATUS_OK);
 
		data = decode_object(fpga_delayed_write(), req->devnum, &osize);
		total = osize;
//		if (imgmt->curaddr + total >= imgmt->size)
//			imgmt->curaddr = 0;
		/* Write until we have been able to write the data. */
		/*if (req->devnum == DEVTYPE_STORAGE) {
			snprintf(output, sizeof(output), "SD: c: %lld b: %lld"
			    " d:'%lx'\n", imgmt->curaddr, imgmt->baseaddr, data);
			igordev_usart.write(0, output, strlen(output));
			igordev_usart.flush();
		}*/
		ptr = (uint8_t *)&data;
		while (idev->write_status != IDEV_STATUS_ERROR) {
			num = idev->write(imgmt->curaddr + imgmt->baseaddr, ptr,
			    osize);
			// Try and flush if we can't write
			// XXX: Should count and report error if it doesn't
			// help.
			if (num == 0)
				idev->flush();
			total -= num;
			imgmt->curaddr += num;
			if (total <= 0)
				break;
			ptr += num;
		}
		if (idev->write_status == IDEV_STATUS_ERROR)
			return;
		// Request a flush now that we finished the write. We don't
		// check return value, but not much we can do really.
		idev->flush();
//		dispatch_request_make(idev, REQ_TYPE_FLUSH, 0, req->devnum, NULL);
		break;
	case REQ_TYPE_FLUSH:
		idev->flush();
		break;
	case REQ_TYPE_FUNC:
		req->func(idev->priv);
		break;
	}
}
 
/* 
 * Make a request for the dispatcher.
 */
int8_t 
dispatch_request_make(struct igordev *dev, uint8_t type, uint8_t flags,
    uint32_t devnum, req_fn_t *func)
{
	return (req_alloc((struct rqueue *)&r_queue, dev, type, flags, devnum, func));
}
 
int8_t
dispatch_request_read(uint8_t addr, uint32_t *data)
{
	struct igordev *idev;
	struct idev_mgmt *imgmt;
	uint32_t status;
 
	/* See what address we want to read from. */
	switch (addr) {
	case DEVICES:
		*data = OBJECT_NEW(TYPE_INT, NUMDEV);
		return (0);
	case CURDEV:
		*data = OBJECT_NEW(TYPE_INT, curdev);
		return (0);
	case CLI:
	case SAI:
		*data = 0;
		return (0);
	case INTRDEV:
		*data = OBJECT_NEW(TYPE_INT, intrdev);
		return (0);
	};
 
	/* Device-specific operation, so fetch currently enabled device. */
	idev = idevs[curdev];
	imgmt = &idev->imgmt;
 
	switch (addr) {
	/* Read an object from current device. */
	case OBJECT:
		/* Request for a read. */
		if (dispatch_request_make(idev, REQ_TYPE_READ, REQ_CALLBACK,
		    curdev, NULL) != 0)
			return (-2); /* XXX: Set error. */
		return (-1); /* Tell FPGA to wait. */
	/* Read lower 26 bits of current address from device. */
	case ADDR_L:
		*data = OBJECT_NEW(TYPE_INT,
		    ((uint32_t)(imgmt->curaddr >> 2)));
		return (0);
	/* Read upper 26 bits of current address from device. */
	case ADDR_H:
		*data = OBJECT_NEW(TYPE_INT,
		    ((uint32_t)((imgmt->curaddr >> 2) >> SIZE_INT)));
		return (0);
	/* Read lower 26 bits of device size. */
	case SIZE_L:
		*data = OBJECT_NEW(TYPE_INT,
		    ((uint32_t)(imgmt->size >> 2)));
		return (0);
	/* Read upper 26 bits of device size. */
	case SIZE_H:
		*data = OBJECT_NEW(TYPE_INT,
		    ((uint32_t)((imgmt->size >> 2) >> SIZE_INT)));
		return (0);
	/* Read status register of device. */
	case STATUS:
		status = (idev->read_status == IDEV_STATUS_OK);
		status |= ((idev->write_status == IDEV_STATUS_OK) <<
		    1);
		/* XXX: Error codes. */
		*data = OBJECT_NEW(TYPE_INT, status);
		return (0);
	/* Device identification. */
	case IDENTIFICATION:
		*data = OBJECT_NEW(TYPE_INT, idev->id);
		return (0);
	/* Read irq enable for device. */
	case IRQENABLE:
		*data = OBJECT_NEW(TYPE_INT,
		    ((uint32_t)imgmt->irqenable));
		return (0);
	}
	return (0); /* Invalid request. */
}
 
int8_t
dispatch_request_write(uint8_t addr, uint32_t data)
{
	struct igordev *idev;
	struct idev_mgmt *imgmt;
	uint32_t status;
	uint64_t newaddr;
	uint8_t i; //num, osize;
 
	/* See what address we want to read from. */
	switch (addr) {
	/* Read-only */
	case DEVICES:
	case INTRDEV:
		return (0);
	case CURDEV:
		DEBUG("Setting current device\n");
		/* Should perhaps have some error signalling. */
		if (OBJECT_DATUM(data) >= NUMDEV)
			return (0); /* Invalid device. */
		curdev = OBJECT_DATUM(data);
		display_char(curdev);
		return (0);
	case CLI:
		for (i = 0; i < NUMDEV; i++)
			idevs[i]->imgmt.irqenable = 0;
		return (0);
	case SAI:
		for (i = 0; i < NUMDEV; i++)
			idevs[i]->imgmt.irqenable = 1;
		return (0);
	};
	idev = idevs[curdev];
	imgmt = &idev->imgmt;
	switch (addr) {
	/* Read-only. */
	case SIZE_L:
	case SIZE_H:
	case IDENTIFICATION:
		return (0);
	/* Write an object from current device. */
	case OBJECT:
		if (dispatch_request_make(idev, REQ_TYPE_WRITE, REQ_CALLBACK,
		    curdev, NULL) != 0)
			return (-2); /* XXX: panic. */
		return (-1);
	/* Write lower 26 bits of current address from device. */
	case ADDR_L:
		newaddr = (OBJECT_DATUM(data) << 2) |
		    ((uint64_t)((uint32_t)(imgmt->curaddr >> BSIZE_INT)) <<
		    BSIZE_INT);
		// Only set it if it does not exceed the device space.
		if (newaddr < imgmt->size)
			imgmt->curaddr = newaddr;
		return (0);
	/* Read upper 26 bits of current address from device. */
	case ADDR_H:
		newaddr = ((OBJECT_DATUM(data) << 2) << BSIZE_INT) |
		    ((uint32_t)imgmt->curaddr);
		// Only set it if it does not exceed the device space.
		if (newaddr < imgmt->size)
			imgmt->curaddr = newaddr;
		return (0);
	/* Read status register of device. */
	case STATUS:
		/* Writing 0 resets the error codes. */
		status = OBJECT_DATUM(data);
		if (status != 0)
			return (0); /* Not allowed. */
		/* XXX: reset error codes. */
		return (0);
	/* Set irq enable for device. */
	case IRQENABLE:
		imgmt->irqenable = OBJECT_DATUM(data);
		return (0);
	}
	return (0); /* Invalid address. */
}
 
/* Read data from kvga and put it in usart output buffer. */
void
dispatch_vga_to_usart(void *args)
{
	uint8_t data[MAXBUFLEN];
	uint8_t num;
 
	num = igordev_kvga.read(1, data, MAXBUFLEN);
	igordev_usart.write(1, data, num);
	while (igordev_usart.write_status != IDEV_STATUS_OK);
}
 
#if ETHERNET_ENABLED
struct timer periodic_timer, arp_timer;
 
void init_network_stuff(void)
{
	uip_ipaddr_t ipaddr;
 
	clock_init(); //This also activates global interrupts
 
	timer_set(&periodic_timer, (clock_time_t)(F_CPU / 2));
	timer_set(&arp_timer, (clock_time_t)(F_CPU * 10));
 
	network_init();
 
	uip_init();
 
	uip_ipaddr(ipaddr, 192,168,0,25);
	uip_sethostaddr(ipaddr);
 
	uip_ipaddr(ipaddr, 255,255,255,0);
	uip_setnetmask(ipaddr);
 
	//Init applications
	telnetd_init();
}
 
void do_network_stuff(void *args)
{
	int i;
	uip_len = network_read();
	if(uip_len > 0) {
		if(BUF->type == htons(UIP_ETHTYPE_IP)) {
			uip_arp_ipin();
			uip_input();
	/* If the above function invocation resulted in data that
	   should be sent out on the network, the global variable
	   uip_len is set to a value > 0. */
			if(uip_len > 0) {
				uip_arp_out();
				network_send();
			}
		} else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
			uip_arp_arpin();
	/* If the above function invocation resulted in data that
	   should be sent out on the network, the global variable
	   uip_len is set to a value > 0. */
			if(uip_len > 0) {
				network_send();
			}
		}
 
	} else if(timer_expired(&periodic_timer)) {
		timer_reset(&periodic_timer);
		for(i = 0; i < UIP_CONNS; i++) {
			uip_periodic(i);
	/* If the above function invocation resulted in data that
	   should be sent out on the network, the global variable
	   uip_len is set to a value > 0. */
			if(uip_len > 0) {
				uip_arp_out();
				network_send();
			}
		}
 
#if UIP_UDP
		for(i = 0; i < UIP_UDP_CONNS; i++) {
			uip_udp_periodic(i);
	/* If the above function invocation resulted in data that
	   should be sent out on the network, the global variable
	   uip_len is set to a value > 0. */
			if(uip_len > 0) {
				uip_arp_out();
				network_send();
			}
		}
#endif /* UIP_UDP */
 
	/* Call the ARP timer function every 10 seconds. */
		if(timer_expired(&arp_timer)) {
			timer_reset(&arp_timer);
			uip_arp_timer();
		}
	}
	dispatch_request_make(&igordev_telnet, REQ_TYPE_FUNC, 0, DEVTYPE_TELNET,
	    do_network_stuff);
}
#endif
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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