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

Subversion Repositories igor

[/] [igor/] [trunk/] [simulator/] [io.c] - Rev 4

Compare with Previous | Blame | View Log

#include <stdio.h>
#include <err.h>
 
#include "io.h"
#include "types.h"
#include "object.h"
 
uint32_t n_devices, curdev;
 
device_t devices[MAX_DEVICES];
 
void io_init_dev(uint32_t devnr);
 
void
io_init(void)
{
	int i;
	n_devices = MAX_DEVICES;
	curdev = DEV_TERMINAL;
	for (i = 0; i < MAX_DEVICES; i++) {
		io_init_dev(i);
	}
}
 
void
io_init_dev(uint32_t devnr)
{
	device_t *dev = &devices[devnr];
	dev->make_object = 0;
	dev->addr = 0;
	dev->size = 0;
	dev->status = 0;
	dev->irqenable = 0;
	dev->fw = dev->fr = NULL;
	dev->ident = devnr << DEVTYPE_SHIFT;
	switch (devnr) {
	case DEV_BOOT:
		dev->ident |= CAN_READ | ADDR_READ;
		dev->make_object = 1;
		break;
	case DEV_TERMINAL:
	case DEV_SERIAL:
	case DEV_NETWORK:
		dev->ident |= CAN_READ | CAN_WRITE;
		break;
	case DEV_STORAGE:
		dev->ident |= CAN_READ | CAN_WRITE | ADDR_READ | ADDR_WRITE;
		dev->make_object = 1;
		break;
	default:
		errx(1, "unknown device 0x%X", devnr);
	}
}
 
void
io_find_size(uint32_t devnr, int write)
{
	device_t *dev = &devices[devnr];
	FILE *f = write?dev->fw:dev->fr;
	if (dev->ident & (write?ADDR_WRITE:ADDR_READ)) {
		if (fseek(f, 0, SEEK_END) == -1) {
			warn("could not find size for device %X", devnr);
			return;
		}
		dev->size = ftell(f);
		if (dev->size == -1) {
			warn("could not find size for device %X", devnr);
			return;
		}
		if (fseek(f, 0, SEEK_SET) == -1) {
			warn("could not rewind device %X", devnr);
			return;
		}
		if (dev->make_object)
			dev->size /= 4;
		printf("size of device %X: 0x%lX\n", devnr, (long)dev->size);
	}
}
 
void
io_set_file(uint32_t devnr, char *filename)
{
	printf("set_file(%X, %s)\n", devnr, filename);
	device_t *dev = &devices[devnr];
	char *mode =
		(dev->ident & (CAN_READ|CAN_WRITE)) ?
		"r+" :
		((dev->ident & CAN_WRITE) ? "w" : "r");
	dev->fr = dev->fw = fopen(filename, mode);
	if (dev->fr == NULL)
		warn("could not open %s", filename);
	io_find_size(devnr, 0);
	io_find_size(devnr, 1);
}
 
void
io_set_files(uint32_t devnr, char *readfile, char *writefile)
{
	printf("set_files(%X, %s, %s)\n", devnr,
	       readfile==NULL?"NULL":readfile, writefile==NULL?"NULL":writefile);
	device_t *dev = &devices[devnr];
	if (readfile != NULL) {
		dev->fr = fopen(readfile, "r");
		if (dev->fr == NULL)
			warn("could not open %s for reading", readfile);
		printf("fr=%X\n", (int)(dev->fr));
		io_find_size(devnr, 0);
	}
	if (writefile != NULL) {
		dev->fw = fopen(writefile, "w");
		if (dev->fw == NULL)
			warn("could not open %s for writing", writefile);
		io_find_size(devnr, 1);
	}
}
 
int
check_device_connected(uint32_t devnr, int write)
{
	device_t *dev = &devices[devnr];
	/*
	printf("check_conn(%X,%d): fw=%X, fr=%X\n",
	       devnr, write, (int)(dev->fw), (int)(dev->fr));
	*/
	if ((write?dev->fw:dev->fr) == NULL) {
		warnx("(I/O %s) device 0x%X not connected",
		      write?"write":"read", curdev);
		return 0;
	}
	return 1;
}
 
void
io_update_address(uint32_t devnr)
{
	device_t *dev = &devices[devnr];
 
	uint64_t addr = dev->addr;
	if (dev->make_object) addr *= 4;
 
	if ((dev->ident & ADDR_WRITE) && check_device_connected(devnr, 1)) {
		if (fseek(dev->fw, addr, SEEK_SET) == -1)
			warn("could not set write address on device %X", curdev);
	}
	if ((dev->ident & ADDR_READ) && check_device_connected(curdev, 0)) {
		if (fseek(dev->fw, addr, SEEK_SET) == -1)
			warn("could not set read address on device %X", curdev);
	}
}
 
void
io_get_new_address(uint32_t devnr, int write)
{
	device_t *dev = &devices[devnr];
 
	if (dev->ident & (write?ADDR_WRITE:ADDR_READ)) {
		int addr = ftell(write?dev->fw:dev->fr);
		if (addr == -1) {
			warn("could not get new %s address from device %X",
			     write?"write":"read", devnr);
		} else {
			if (dev->make_object) addr /= 4;
			dev->addr = addr;
		}
	}
}
 
void
io_memory_set(unsigned int pos, reg_t value)
{
	device_t *dev = &devices[curdev];
	uint32_t datum = object_get_datum(value);
 
	switch (pos) {
	case IO_DEVICES:
		warnx("write to read-only I/O register DEVICES");
		break;
	case IO_CURDEV:
		curdev = datum;
		break;
	case IO_CLI:
		warnx("CLI: not implemented");
		break;
	case IO_SAI:
		warnx("SAI: not implemented");
		break;
	case IO_INTRDEV:
		warnx("write to read-only I/O register INTRDEV");
		break;
	case IO_OBJECT:
		if (check_device_connected(curdev, 1)) {
//			printf("writing '%c' to device %X\n", datum, curdev);
			if(dev->make_object) {
				object_write(&value, 1, dev->fw);
			}else{
				if (fputc(datum, dev->fw) == EOF ||
						fflush(dev->fw) == EOF)
					warn("could not write to device %X", curdev);
			}
			io_get_new_address(curdev, 1);
		}
		break;
	case IO_ADDR_L:
		if (dev->ident & (ADDR_READ | ADDR_WRITE)) {
			check_device_connected(curdev, 1);
			dev->addr &= (~0) << 26;
			dev->addr |= datum;
			io_update_address(curdev);
		}
		break;
	case IO_ADDR_H:
		if (dev->ident & (ADDR_READ | ADDR_WRITE)) {
			dev->addr &= OBJECT_DATUM_MASK;
			dev->addr |= datum << 26;
			io_update_address(curdev);
		}
		break;
	case IO_SIZE_L:
		warnx("write to read-only I/O register SIZE_L");
		break;
	case IO_SIZE_H:
		warnx("write to read-only I/O register SIZE_H");
		break;
	case IO_STATUS:
		if (datum == 0) {
			dev->status &= (~ERRCODE_MASK) << ERRCODE_SHIFT;
		} else {
			warnx("nonzero write to I/O register STATUS");
		}
		break;
	case IO_IDENT:
		warnx("write to read-only I/O register INDENT");
		break;
	case IO_IRQENABLE:
		dev->irqenable = datum;
		break;
	default:
		warnx("write to unused I/O register 0x%X", pos);
	}
}
 
char
dev_getchar(uint32_t devnr)
{
	device_t *dev = &devices[curdev];
	char ch;
 
 getcharrestart:
	ch = fgetc(dev->fr);
	if (ch == EOF) {
		if (devnr == DEV_SERIAL)
			goto getcharrestart;
 
		warnx("could not read from device %X", curdev);
		return EOF;
	}
	//printf("Char: %d/%c\n", ch, ch);
	return ch;
}
 
reg_t
io_memory_get(unsigned int pos)
{
	device_t *dev = &devices[curdev];
	reg_t val = object_make(TYPE_INT, 0);
	switch (pos) {
	case IO_DEVICES:
		val = object_make(TYPE_INT, n_devices);
		break;
	case IO_CURDEV:
		val = object_make(TYPE_INT, curdev);
		break;
	case IO_CLI:
		warnx("read from write-only I/O register CLI");
		break;
	case IO_SAI:
		warnx("read from write-only I/O register SAI");
		break;
	case IO_INTRDEV:
		warnx("INTRDEV: not implemented");
		break;
	case IO_OBJECT:
		if (check_device_connected(curdev, 0)) {
			if (dev->make_object) {
				if (!object_read(&val, 1, dev->fr))
					warn("could not read from any device");
			} else {
				val = object_make(TYPE_CHAR, dev_getchar(curdev));
			}
			io_get_new_address(curdev, 0);
		} else {
			warnx("device %X not connected", curdev);
		}
		break;
	case IO_ADDR_L:
		val = object_make(TYPE_INT, dev->addr & OBJECT_DATUM_MASK);
		break;
	case IO_ADDR_H:
		val = object_make(TYPE_INT, (dev->addr>>26) & OBJECT_DATUM_MASK);
		break;
	case IO_SIZE_L:
		printf("asking for size (l) of device %X; size is %lX\n",
		       curdev, (long)dev->size);
		val = object_make(TYPE_INT, dev->size & OBJECT_DATUM_MASK);
		break;
	case IO_SIZE_H:
		printf("asking for size (h) of device %X; size is %lX\n",
		       curdev, (long)dev->size);
		val = object_make(TYPE_INT, (dev->size>>26) & OBJECT_DATUM_MASK);
		break;
	case IO_STATUS:
		val = object_make(TYPE_INT, dev->status);
		break;
	case IO_IDENT:
		val = object_make(TYPE_INT, dev->ident);
		break;
	case IO_IRQENABLE:
		val = object_make(TYPE_INT, dev->irqenable);
		break;
	default:
		warnx("read from unused I/O register 0x%X", pos);
		break;
	}
 
	return val;
}
 

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.