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

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /or1k/tags/tn_m001/or1ksim/peripheral
    from Rev 861 to Rev 1765
    Reverse comparison

Rev 861 → Rev 1765

/eth.c
0,0 → 1,797
/* ethernet.c -- Simulation of Ethernet MAC
Copyright (C) 2001 by Erez Volk, erez@opencores.org
Ivan Guzvinec, ivang@opencores.org
 
This file is part of OpenRISC 1000 Architectural Simulator.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <unistd.h>
#include <errno.h>
 
#include "abstract.h"
#include "ethernet_i.h"
#include "dma.h"
#include "sim-config.h"
#include "fields.h"
#include "crc32.h"
 
static struct eth_device eths[MAX_ETHERNETS];
 
/* simulator interface */
static void eth_reset_controller( struct eth_device *eth);
/* register interface */
static void eth_write32( unsigned long addr, unsigned long value );
static unsigned long eth_read32( unsigned long addr );
/* clock */
static void eth_controller_tx_clock( struct eth_device * );
static void eth_controller_rx_clock( struct eth_device * );
/* utility functions */
static int eth_find_controller( unsigned long addr, struct eth_device **eth, unsigned long *reladdr );
static ssize_t eth_read_rx_file( struct eth_device *, void *, size_t );
static void eth_skip_rx_file( struct eth_device *, off_t );
static void eth_rewind_rx_file( struct eth_device *, off_t );
static void eth_rx_next_packet( struct eth_device * );
static void eth_write_tx_bd_num( struct eth_device *, unsigned long value );
/* ========================================================================= */
/* TX LOGIC */
/*---------------------------------------------------------------------------*/
 
/*
* TX clock
* Responsible for starting and finishing TX
*/
void eth_controller_tx_clock( struct eth_device *eth )
{
int breakpoint = 0;
int bAdvance = 1;
struct sockaddr_ll sll;
long nwritten;
unsigned long read_word;
 
switch (eth->tx.state) {
case ETH_TXSTATE_IDLE:
if ( TEST_FLAG( eth->regs.moder, ETH_MODER, TXEN ) ) {
/* wait for TxBuffer to be ready */
debug (3, "TX - entering state WAIT4BD (%d)\n", eth->tx.bd_index);
eth->tx.state = ETH_TXSTATE_WAIT4BD;
}
break;
case ETH_TXSTATE_WAIT4BD:
/* Read buffer descriptor */
eth->tx.bd = eth->regs.bd_ram[eth->tx.bd_index];
eth->tx.bd_addr = eth->regs.bd_ram[eth->tx.bd_index + 1];
if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, READY ) ) {
/*****************/
/* initialize TX */
eth->tx.bytes_left = eth->tx.packet_length = GET_FIELD( eth->tx.bd, ETH_TX_BD, LENGTH );
eth->tx.bytes_sent = 0;
/* Initialize error status bits */
CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, DEFER );
CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, COLLISION );
CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, RETRANSMIT );
CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, UNDERRUN );
CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, NO_CARRIER );
SET_FIELD ( eth->tx.bd, ETH_TX_BD, RETRY, 0 );
/* Find out minimum length */
if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, PAD ) ||
TEST_FLAG( eth->regs.moder, ETH_MODER, PAD ) )
eth->tx.minimum_length = GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MINFL );
else
eth->tx.minimum_length = eth->tx.packet_length;
/* Find out maximum length */
if ( TEST_FLAG( eth->regs.moder, ETH_MODER, HUGEN ) )
eth->tx.maximum_length = eth->tx.packet_length;
else
eth->tx.maximum_length = GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MAXFL );
/* Do we need CRC on this packet? */
if ( TEST_FLAG( eth->regs.moder, ETH_MODER, CRCEN ) ||
(TEST_FLAG( eth->tx.bd, ETH_TX_BD, CRC) &&
TEST_FLAG( eth->tx.bd, ETH_TX_BD, LAST)) )
eth->tx.add_crc = 1;
else
eth->tx.add_crc = 0;
if ( TEST_FLAG( eth->regs.moder, ETH_MODER, DLYCRCEN ) )
eth->tx.crc_dly = 1;
else
eth->tx.crc_dly = 0;
/* XXX - For now we skip CRC calculation */
debug( 3, "Ethernet: Starting TX of %u bytes (min. %u, max. %u)\n", eth->tx.packet_length,
eth->tx.minimum_length, eth->tx.maximum_length );
if (eth->rtx_type == ETH_RTX_FILE) {
/* write packet length to file */
nwritten = write( eth->txfd, &(eth->tx.packet_length), sizeof(eth->tx.packet_length) );
}
/************************************************/
/* start transmit with reading packet into FIFO */
debug (3, "TX - entering state READFIFO\n");
eth->tx.state = ETH_TXSTATE_READFIFO;
}
else if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, TXEN ) ) {
/* stop TX logic */
debug (3, "TX - entering state IDLE\n");
eth->tx.state = ETH_TXSTATE_IDLE;
}
/* stay in this state if (TXEN && !READY) */
break;
case ETH_TXSTATE_READFIFO:
#if 1
if ( eth->tx.bytes_sent < eth->tx.packet_length ) {
read_word = eval_mem32(eth->tx.bytes_sent + eth->tx.bd_addr, &breakpoint);
eth->tx_buff[eth->tx.bytes_sent] = (unsigned char)(read_word >> 24);
eth->tx_buff[eth->tx.bytes_sent+1] = (unsigned char)(read_word >> 16);
eth->tx_buff[eth->tx.bytes_sent+2] = (unsigned char)(read_word >> 8);
eth->tx_buff[eth->tx.bytes_sent+3] = (unsigned char)(read_word);
eth->tx.bytes_sent += 4;
}
#else
if ( eth->tx.bytes_sent < eth->tx.packet_length ) {
eth->tx_buff[eth->tx.bytes_sent] = eval_mem8(eth->tx.bytes_sent + eth->tx.bd_addr, &breakpoint);
eth->tx.bytes_sent += 1;
}
#endif
else {
debug (3, "TX - entering state TRANSMIT\n");
eth->tx.state = ETH_TXSTATE_TRANSMIT;
}
break;
case ETH_TXSTATE_TRANSMIT:
/* send packet */
switch (eth->rtx_type) {
case ETH_RTX_FILE:
nwritten = write( eth->txfd, eth->tx_buff, eth->tx.packet_length );
break;
case ETH_RTX_SOCK:
memset(&sll, 0, sizeof(sll));
sll.sll_ifindex = eth->ifr.ifr_ifindex;
nwritten = sendto(eth->rtx_sock, eth->tx_buff, eth->tx.packet_length, 0, (struct sockaddr *)&sll, sizeof(sll));
break;
}
/* set BD status */
if (nwritten == eth->tx.packet_length) {
CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, READY);
SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXB);
debug (4, "ETH_INT_SOURCE = %0x\n", eth->regs.int_source);
debug (3, "TX - entering state IDLE\n");
eth->tx.state = ETH_TXSTATE_IDLE;
debug (3, "send (%d)bytes OK\n", nwritten);
}
else {
/* XXX - implement retry mechanism here! */
CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, READY);
CLEAR_FLAG (eth->tx.bd, ETH_TX_BD, COLLISION);
SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXE);
debug (3, "TX - entering state IDLE\n");
eth->tx.state = ETH_TXSTATE_IDLE;
debug (3, "send FAILED!\n");
}
eth->regs.bd_ram[eth->tx.bd_index] = eth->tx.bd;
/* advance to next BD */
if (bAdvance) {
if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, WRAP ) ||
eth->tx.bd_index >= ETH_BD_COUNT )
eth->tx.bd_index = 0;
else
eth->tx.bd_index += 2;
}
/* generate OK interrupt */
if ( TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, TXE_M) ||
TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, TXB_M) )
{
report_interrupt( eth->mac_int );
}
break;
}
}
/* ========================================================================= */
 
 
/* ========================================================================= */
/* RX LOGIC */
/*---------------------------------------------------------------------------*/
 
/*
* RX clock
* Responsible for starting and finishing RX
*/
void eth_controller_rx_clock( struct eth_device *eth )
{
int i;
int breakpoint = 0;
long nread;
unsigned long send_word;
fd_set rfds;
switch (eth->rx.state) {
case ETH_RXSTATE_IDLE:
if ( TEST_FLAG( eth->regs.moder, ETH_MODER, RXEN) ) {
debug (3, "RX - entering state WAIT4BD (%d)\n", eth->rx.bd_index);
eth->rx.state = ETH_RXSTATE_WAIT4BD;
}
break;
case ETH_RXSTATE_WAIT4BD:
eth->rx.bd = eth->regs.bd_ram[eth->rx.bd_index];
eth->rx.bd_addr = eth->regs.bd_ram[eth->rx.bd_index + 1];
if ( TEST_FLAG( eth->rx.bd, ETH_RX_BD, READY ) ) {
/*****************/
/* Initialize RX */
CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, MISS );
CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, INVALID );
CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, DRIBBLE );
CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, UVERRUN );
CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, COLLISION );
CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, TOOBIG );
CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, TOOSHORT );
debug( 3, "Ethernet: Starting RX\n" );
/* Setup file to read from */
if ( TEST_FLAG( eth->regs.moder, ETH_MODER, LOOPBCK ) ) {
eth->rx.fd = eth->txfd;
eth->rx.offset = &(eth->loopback_offset);
} else {
eth->rx.fd = eth->rxfd;
eth->rx.offset = 0;
}
debug (3, "RX - entering state RECV\n");
eth->rx.state = ETH_RXSTATE_RECV;
}
else if (!TEST_FLAG( eth->regs.moder, ETH_MODER, RXEN)) {
debug (3, "RX - entering state IDLE\n");
eth->rx.state = ETH_RXSTATE_IDLE;
}
else {
nread = recv(eth->rtx_sock, eth->rx_buff, ETH_MAXPL, /*MSG_PEEK | */MSG_DONTWAIT);
if (nread > 0) {
SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, BUSY);
if ( TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, BUSY_M) )
report_interrupt(eth->mac_int);
}
}
break;
case ETH_RXSTATE_RECV:
switch (eth->rtx_type) {
case ETH_RTX_FILE:
/* Read packet length */
if ( eth_read_rx_file( eth, &(eth->rx.packet_length), sizeof(eth->rx.packet_length) )
< sizeof(eth->rx.packet_length) ) {
/* TODO: just do what real ethernet would do (some kind of error state) */
debug (4, "eth_start_rx(): File does not have a packet ready for RX (len = %d)\n", eth->rx.packet_length );
cont_run = 0;
break;
}
 
/* Packet must be big enough to hold a header */
if ( eth->rx.packet_length < ETH_HLEN ){
debug( 3, "eth_start_rx(): Packet too small\n" );
eth_rx_next_packet( eth );
 
debug (3, "RX - entering state IDLE\n");
eth->rx.state = ETH_RXSTATE_IDLE;
break;
}
eth->rx.bytes_read = 0;
eth->rx.bytes_left = eth->rx.packet_length;
/* for now Read entire packet into memory */
nread = eth_read_rx_file( eth, eth->rx_buff, eth->rx.bytes_left );
if ( nread < eth->rx.bytes_left )
debug (3, "Read %d from %d. Error!\n", nread, eth->rx.bytes_left);
eth->rx.error = 1;
break;
case ETH_RTX_SOCK:
nread = recv(eth->rtx_sock, eth->rx_buff, ETH_MAXPL, MSG_DONTWAIT);
 
if (nread == 0)
break;
else if (nread < 0) {
if ( errno != EAGAIN ) {
debug (3, "recv() FAILED!\n");
break;
}
else {
break;
}
}
/* If not promiscouos mode, check the destination address */
if (!TEST_FLAG(eth->regs.moder, ETH_MODER, PRO)) {
if (TEST_FLAG(eth->regs.moder, ETH_MODER, IAM) && (eth->rx_buff[0] & 1)) {
/* Nothing for now */
}
 
if (eth->mac_address[5] != eth->rx_buff[0] ||
eth->mac_address[4] != eth->rx_buff[1] ||
eth->mac_address[3] != eth->rx_buff[2] ||
eth->mac_address[2] != eth->rx_buff[3] ||
eth->mac_address[1] != eth->rx_buff[4] ||
eth->mac_address[0] != eth->rx_buff[5])
break;
}
break;
}
 
eth->rx.packet_length = nread;
eth->rx.bytes_left = nread;
eth->rx.bytes_read = 0;
 
debug (3, "RX - entering state WRITEFIFO\n");
eth->rx.state = ETH_RXSTATE_WRITEFIFO;
break;
case ETH_RXSTATE_WRITEFIFO:
#if 1
send_word = ((unsigned long)eth->rx_buff[eth->rx.bytes_read] << 24) |
((unsigned long)eth->rx_buff[eth->rx.bytes_read+1] << 16) |
((unsigned long)eth->rx_buff[eth->rx.bytes_read+2] << 8) |
((unsigned long)eth->rx_buff[eth->rx.bytes_read+3] );
set_mem32( eth->rx.bd_addr + eth->rx.bytes_read, send_word, &breakpoint);
/* update counters */
debug (3, "Write %d, left %d - %08lXd\n", eth->rx.bytes_read, eth->rx.bytes_left, send_word);
eth->rx.bytes_left -= 4;
eth->rx.bytes_read += 4;
#else
set_mem8( eth->rx.bd_addr + eth->rx.bytes_read, eth->rx_buff[eth->rx.bytes_read], &breakpoint);
eth->rx.bytes_left -= 1;
eth->rx.bytes_read += 1;
#endif
if ( eth->rx.bytes_left <= 0 ) {
/* Write result to bd */
SET_FIELD( eth->rx.bd, ETH_RX_BD, LENGTH, eth->rx.packet_length );
CLEAR_FLAG( eth->rx.bd, ETH_RX_BD, READY);
SET_FLAG( eth->regs.int_source, ETH_INT_SOURCE, RXB);
debug (4, "ETH_INT_SOURCE = %0x\n", eth->regs.int_source);
if ( eth->rx.packet_length < GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MINFL ) )
SET_FLAG( eth->rx.bd, ETH_RX_BD, TOOSHORT);
if ( eth->rx.packet_length > GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MAXFL ) )
SET_FLAG( eth->rx.bd, ETH_RX_BD, TOOBIG);
eth->regs.bd_ram[eth->rx.bd_index] = eth->rx.bd;
/* advance to next BD */
if ( TEST_FLAG( eth->rx.bd, ETH_RX_BD, WRAP ) || eth->rx.bd_index >= ETH_BD_COUNT )
eth->rx.bd_index = eth->regs.tx_bd_num;
else
eth->rx.bd_index += 2;
if ( TEST_FLAG(eth->regs.int_mask, ETH_INT_MASK, RXB_M) ) {
report_interrupt( eth->mac_int );
}
/* ready to receive next packet */
debug (3, "RX - entering state IDLE\n");
eth->rx.state = ETH_RXSTATE_IDLE;
}
break;
}
}
 
/* ========================================================================= */
/* Move to next RX BD */
void eth_rx_next_packet( struct eth_device *eth )
{
/* Skip any possible leftovers */
if ( eth->rx.bytes_left )
eth_skip_rx_file( eth, eth->rx.bytes_left );
}
/* "Skip" bytes in RX file */
void eth_skip_rx_file( struct eth_device *eth, off_t count )
{
eth->rx.offset += count;
}
 
/* Move RX file position back */
void eth_rewind_rx_file( struct eth_device *eth, off_t count )
{
eth->rx.offset -= count;
}
/*
* Utility function to read from the ethernet RX file
* This function moves the file pointer to the current place in the packet before reading
*/
ssize_t eth_read_rx_file( struct eth_device *eth, void *buf, size_t count )
{
ssize_t result;
if ( eth->rx.fd <= 0 ) {
debug( 3, "Ethernet: No RX file\n" );
return 0;
}
if ( eth->rx.offset )
if ( lseek( eth->rx.fd, *(eth->rx.offset), SEEK_SET ) == (off_t)-1 ) {
debug( 3, "Ethernet: Error seeking RX file\n" );
return 0;
}
 
result = read( eth->rx.fd, buf, count );
debug (4, "Ethernet: read result = %d \n", result);
if ( eth->rx.offset && result >= 0 )
*(eth->rx.offset) += result;
return result;
}
 
/* ========================================================================= */
 
/*
Reset. Initializes all registers to default and places devices in
memory address space.
*/
void eth_reset()
{
static int first_time = 1;
unsigned i;
if (!config.nethernets)
return;
if ( first_time ) {
memset( eths, 0, sizeof(eths) );
first_time = 0;
}
for ( i = 0; i < MAX_ETHERNETS; ++ i ) {
struct eth_device *eth = &(eths[i]);
eth->eth_number = i;
eth_reset_controller( eth );
}
}
/* ========================================================================= */
 
 
static void eth_reset_controller(struct eth_device *eth)
{
int i = eth->eth_number;
int j;
struct sockaddr_ll sll;
eth->baseaddr = config.ethernets[i].baseaddr;
if ( eth->baseaddr != 0 ) {
/* Mark which DMA controller and channels */
eth->dma = config.ethernets[i].dma;
eth->mac_int = config.ethernets[i].irq;
eth->tx_channel = config.ethernets[i].tx_channel;
eth->rx_channel = config.ethernets[i].rx_channel;
eth->rtx_type = config.ethernets[i].rtx_type;
switch (eth->rtx_type) {
case ETH_RTX_FILE:
/* (Re-)open TX/RX files */
eth->rxfile = config.ethernets[i].rxfile;
eth->txfile = config.ethernets[i].txfile;
if ( eth->rxfd > 0 )
close( eth->rxfd );
if ( eth->txfd > 0 )
close( eth->txfd );
eth->rxfd = eth->txfd = -1;
if ( (eth->rxfd = open( eth->rxfile, O_RDONLY )) < 0 )
fprintf( stderr, "Cannot open Ethernet RX file \"%s\"\n", eth->rxfile );
if ( (eth->txfd = open( eth->txfile,
O_RDWR | O_CREAT | O_APPEND | O_SYNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH )) < 0 )
fprintf( stderr, "Cannot open Ethernet TX file \"%s\"\n", eth->txfile );
eth->loopback_offset = lseek( eth->txfd, 0, SEEK_END );
break;
case ETH_RTX_SOCK:
/* (Re-)open TX/RX sockets */
if (eth->rtx_sock != 0)
break;
debug (3, "RTX oppening socket...\n");
eth->rtx_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (eth->rtx_sock == -1) {
fprintf( stderr, "Cannot open rtx_sock.\n");
return;
}
/* get interface index number */
debug (3, "RTX getting interface...\n");
memset(&(eth->ifr), 0, sizeof(eth->ifr));
strncpy(eth->ifr.ifr_name, config.ethernets[i].sockif, IFNAMSIZ);
if (ioctl(eth->rtx_sock, SIOCGIFINDEX, &(eth->ifr)) == -1) {
fprintf( stderr, "SIOCGIFINDEX failed!\n");
return;
}
debug (3, "RTX Socket Interface : %d\n", eth->ifr.ifr_ifindex);
/* Bind to interface... */
debug (3, "Binding to the interface ifindex=%d\n", eth->ifr.ifr_ifindex);
memset(&sll, 0xff, sizeof(sll));
sll.sll_family = AF_PACKET; /* allways AF_PACKET */
sll.sll_protocol = htons(ETH_P_ALL);
sll.sll_ifindex = eth->ifr.ifr_ifindex;
if (bind(eth->rtx_sock, (struct sockaddr *)&sll, sizeof(sll)) == -1) {
fprintf( stderr, "Error bind().\n");
return;
}
/* first, flush all received packets. */
debug (3, "Flush");
do {
fd_set fds;
struct timeval t;
debug( 3, ".");
FD_ZERO(&fds);
FD_SET(eth->rtx_sock, &fds);
memset(&t, 0, sizeof(t));
j = select(FD_SETSIZE, &fds, NULL, NULL, &t);
if (j > 0)
recv(eth->rtx_sock, eth->rx_buff, j, 0);
} while (j);
debug (3, "\n");
break;
}
/* Set registers to default values */
memset( &(eth->regs), 0, sizeof(eth->regs) );
eth->regs.moder = 0x0000A000;
eth->regs.ipgt = 0x00000012;
eth->regs.ipgr1 = 0x0000000C;
eth->regs.ipgr2 = 0x00000012;
eth->regs.packetlen = 0x003C0600;
eth->regs.collconf = 0x000F003F;
eth->regs.miimoder = 0x00000064;
eth->regs.tx_bd_num = 0x00000080;
/* Initialize TX/RX status */
memset( &(eth->tx), 0, sizeof(eth->tx) );
memset( &(eth->rx), 0, sizeof(eth->rx) );
eth->rx.bd_index = eth->regs.tx_bd_num;
/* Register memory range */
register_memoryarea( eth->baseaddr, ETH_ADDR_SPACE, 4, eth_read32, eth_write32 );
}
}
/* ========================================================================= */
 
 
/*
Print register values on stdout
*/
void eth_status( void )
{
unsigned i;
for ( i = 0; i < MAX_ETHERNETS; ++ i ) {
struct eth_device *eth = &(eths[i]);
if ( eth->baseaddr == 0 )
continue;
printf( "\nEthernet MAC %u at 0x%08X:\n", i, eth->baseaddr );
printf( "MODER : 0x%08lX\n", eth->regs.moder );
printf( "INT_SOURCE : 0x%08lX\n", eth->regs.int_source );
printf( "INT_MASK : 0x%08lX\n", eth->regs.int_mask );
printf( "IPGT : 0x%08lX\n", eth->regs.ipgt );
printf( "IPGR1 : 0x%08lX\n", eth->regs.ipgr1 );
printf( "IPGR2 : 0x%08lX\n", eth->regs.ipgr2 );
printf( "PACKETLEN : 0x%08lX\n", eth->regs.packetlen );
printf( "COLLCONF : 0x%08lX\n", eth->regs.collconf );
printf( "TX_BD_NUM : 0x%08lX\n", eth->regs.tx_bd_num );
printf( "CTRLMODER : 0x%08lX\n", eth->regs.controlmoder );
printf( "MIIMODER : 0x%08lX\n", eth->regs.miimoder );
printf( "MIICOMMAND : 0x%08lX\n", eth->regs.miicommand );
printf( "MIIADDRESS : 0x%08lX\n", eth->regs.miiaddress );
printf( "MIITX_DATA : 0x%08lX\n", eth->regs.miitx_data );
printf( "MIIRX_DATA : 0x%08lX\n", eth->regs.miirx_data );
printf( "MIISTATUS : 0x%08lX\n", eth->regs.miistatus );
printf( "MAC Address : %02X:%02X:%02X:%02X:%02X:%02X\n",
eth->mac_address[0], eth->mac_address[1], eth->mac_address[2],
eth->mac_address[3], eth->mac_address[4], eth->mac_address[5] );
printf( "HASH0 : 0x%08lX\n", eth->regs.hash0 );
printf( "HASH1 : 0x%08lX\n", eth->regs.hash1 );
}
}
/* ========================================================================= */
 
 
/*
Simulation hook. Must be called every clock cycle to simulate Ethernet MAC.
*/
void eth_clock()
{
unsigned i;
for ( i = 0; i < config.nethernets; ++ i ) {
eth_controller_tx_clock( &(eths[i]) );
eth_controller_rx_clock( &(eths[i]) );
}
}
/* ========================================================================= */
 
 
/*
Read a register
*/
unsigned long eth_read32( unsigned long addr )
{
struct eth_device *eth;
if ( !eth_find_controller( addr, &eth, &addr ) ) {
printf( "eth_read32( 0x%08lX ): Not in registered range(s)\n", addr );
return 0;
}
 
switch( addr ) {
case ETH_MODER: return eth->regs.moder;
case ETH_INT_SOURCE: return eth->regs.int_source;
case ETH_INT_MASK: return eth->regs.int_mask;
case ETH_IPGT: return eth->regs.ipgt;
case ETH_IPGR1: return eth->regs.ipgr1;
case ETH_IPGR2: return eth->regs.ipgr2;
case ETH_PACKETLEN: return eth->regs.packetlen;
case ETH_COLLCONF: return eth->regs.collconf;
case ETH_TX_BD_NUM: return eth->regs.tx_bd_num;
case ETH_CTRLMODER: return eth->regs.controlmoder;
case ETH_MIIMODER: return eth->regs.miimoder;
case ETH_MIICOMMAND: return eth->regs.miicommand;
case ETH_MIIADDRESS: return eth->regs.miiaddress;
case ETH_MIITX_DATA: return eth->regs.miitx_data;
case ETH_MIIRX_DATA: return eth->regs.miirx_data;
case ETH_MIISTATUS: return eth->regs.miistatus;
case ETH_MAC_ADDR0: return (((unsigned long)eth->mac_address[3]) << 24) |
(((unsigned long)eth->mac_address[2]) << 16) |
(((unsigned long)eth->mac_address[1]) << 8) |
(unsigned long)eth->mac_address[0];
case ETH_MAC_ADDR1: return (((unsigned long)eth->mac_address[5]) << 8) |
(unsigned long)eth->mac_address[4];
case ETH_HASH0: return eth->regs.hash0;
case ETH_HASH1: return eth->regs.hash1;
/*case ETH_DMA_RX_TX: return eth_rx( eth );*/
}
 
if ( (addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE) )
return eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4];
printf( "eth_read32( 0x%08lX ): Illegal address\n", addr + eth->baseaddr );
cont_run = 0;
return 0;
}
/* ========================================================================= */
 
 
/*
Write a register
*/
void eth_write32( unsigned long addr, unsigned long value )
{
struct eth_device *eth;
if ( !eth_find_controller( addr, &eth, &addr ) ) {
printf( "eth_write32( 0x%08lX ): Not in registered range(s)\n", addr );
return;
}
switch( addr ) {
case ETH_MODER: eth->regs.moder = value; return;
case ETH_INT_SOURCE: eth->regs.int_source &= ~value; return;
case ETH_INT_MASK: eth->regs.int_mask = value; return;
case ETH_IPGT: eth->regs.ipgt = value; return;
case ETH_IPGR1: eth->regs.ipgr1 = value; return;
case ETH_IPGR2: eth->regs.ipgr2 = value; return;
case ETH_PACKETLEN: eth->regs.packetlen = value; return;
case ETH_COLLCONF: eth->regs.collconf = value; return;
case ETH_TX_BD_NUM: eth_write_tx_bd_num( eth, value ); return;
case ETH_CTRLMODER: eth->regs.controlmoder = value; return;
case ETH_MIIMODER: eth->regs.miimoder = value; return;
case ETH_MIICOMMAND: eth->regs.miicommand = value; return;
case ETH_MIIADDRESS: eth->regs.miiaddress = value; return;
case ETH_MIITX_DATA: eth->regs.miitx_data = value; return;
case ETH_MIIRX_DATA: eth->regs.miirx_data = value; return;
case ETH_MIISTATUS: eth->regs.miistatus = value; return;
case ETH_MAC_ADDR0:
eth->mac_address[0] = value & 0xFF;
eth->mac_address[1] = (value >> 8) & 0xFF;
eth->mac_address[2] = (value >> 16) & 0xFF;
eth->mac_address[3] = (value >> 24) & 0xFF;
return;
case ETH_MAC_ADDR1:
eth->mac_address[4] = value & 0xFF;
eth->mac_address[5] = (value >> 8) & 0xFF;
return;
case ETH_HASH0: eth->regs.hash0 = value; return;
case ETH_HASH1: eth->regs.hash1 = value; return;
/*case ETH_DMA_RX_TX: eth_tx( eth, value ); return;*/
}
 
if ( (addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE) ) {
eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4] = value;
return;
}
printf( "eth_write32( 0x%08lX ): Illegal address\n", addr + eth->baseaddr );
cont_run = 0;
return;
}
/* ========================================================================= */
 
 
/* When TX_BD_NUM is written, also reset current RX BD index */
void eth_write_tx_bd_num( struct eth_device *eth, unsigned long value )
{
eth->rx.bd_index = eth->regs.tx_bd_num = value & 0xFF;
}
/* ========================================================================= */
 
 
/*
Convert a memory address to a oontroller struct and relative address.
Return nonzero on success
*/
int eth_find_controller( unsigned long addr, struct eth_device **eth, unsigned long *reladdr )
{
unsigned i;
*eth = NULL;
for ( i = 0; i < MAX_ETHERNETS && *eth == NULL; ++ i ) {
if ( (addr >= eths[i].baseaddr) && (addr < eths[i].baseaddr + ETH_ADDR_SPACE) )
*eth = &(eths[i]);
}
/* verify we found a controller */
if ( *eth == NULL )
return 0;
/* Verify legal address */
if ( (addr - (*eth)->baseaddr) % 4 != 0 )
return 0;
*reladdr = addr - (*eth)->baseaddr;
return 1;
}
/16450.c
0,0 → 1,640
/* 16450.c -- Simulation of 8250/16450 serial UART
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
 
This file is part of OpenRISC 1000 Architectural Simulator.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
/* This is functional simulation of 8250/16450 UARTs. Since we RX/TX data
via file streams, we can't simulate modem control lines coming from the
DCE and similar details of communication with the DCE.
 
This simulated UART device is intended for basic UART device driver
verification. From device driver perspective this device looks like a
regular UART but never reports and modem control lines changes (the
only DCE responses are incoming characters from the file stream).
*/
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
 
#include "abstract.h"
#include "16450.h"
#include "sim-config.h"
#include "pic.h"
#include "vapi.h"
#include "sched.h"
 
#define MIN(a,b) ((a) < (b) ? (a) : (b))
 
static struct dev_16450 uarts[MAX_UARTS];
static int thre_int;
 
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
before a single character is transmitted or received. */
static unsigned long char_clks(int dll, int dlh, int lcr)
{
float bauds_per_char = 1.;
unsigned long char_clks = ((dlh << 8) + dll);
if (lcr & UART_LCR_PARITY)
bauds_per_char = bauds_per_char + 1.;
 
/* stop bits 1 or two */
if (lcr & UART_LCR_STOP)
bauds_per_char = bauds_per_char + 2.;
else
if ((lcr & 0x3) != 0)
bauds_per_char = bauds_per_char + 1.;
else
bauds_per_char = bauds_per_char + 1.5;
bauds_per_char = bauds_per_char + (5. + (lcr & 0x3));
 
return char_clks * bauds_per_char;
}
 
/* Set a specific UART register with value. */
void uart_write_byte(unsigned long addr, unsigned long value)
{
int chipsel;
debug(4, "uart_write_byte(%x,%02x)\n", addr, (unsigned)value);
 
for(chipsel = 0; chipsel < MAX_UARTS; chipsel++)
if ((addr & ~(UART_ADDR_SPACE-1)) == config.uarts[chipsel].baseaddr)
break;
if (chipsel >= MAX_UARTS) return;
 
if (uarts[chipsel].regs.lcr & UART_LCR_DLAB) {
switch (addr % UART_ADDR_SPACE) {
case UART_DLL:
uarts[chipsel].regs.dll = value;
uarts[chipsel].char_clks = char_clks(uarts[chipsel].regs.dll, uarts[chipsel].regs.dlh, uarts[chipsel].regs.lcr);
return;
case UART_DLH:
uarts[chipsel].regs.dlh = value;
return;
}
}
switch (addr % UART_ADDR_SPACE) {
case UART_TXBUF:
if (uarts[chipsel].istat.txbuf_full < uarts[chipsel].fifo_len) {
uarts[chipsel].istat.txbuf_full++;
uarts[chipsel].regs.txbuf[uarts[chipsel].istat.txbuf_head] = value;
uarts[chipsel].istat.txbuf_head = (uarts[chipsel].istat.txbuf_head + 1) % uarts[chipsel].fifo_len;
} else
uarts[chipsel].regs.txbuf[uarts[chipsel].istat.txbuf_head] = value;
 
uarts[chipsel].regs.lsr &= ~(UART_LSR_TXSERE | UART_LSR_TXBUFE);
uarts[chipsel].istat.thre_int = 0;
break;
case UART_FCR:
uarts[chipsel].regs.fcr = value & UART_VALID_FCR;
if (uarts[chipsel].fifo_len == 1 && (value & UART_FCR_FIE)
|| uarts[chipsel].fifo_len != 1 && !(value & UART_FCR_FIE))
value |= UART_FCR_RRXFI | UART_FCR_RTXFI;
uarts[chipsel].fifo_len = (value & UART_FCR_FIE) ? 16 : 1;
if (value & UART_FCR_RTXFI) {
uarts[chipsel].istat.txbuf_head = uarts[chipsel].istat.txbuf_tail = 0;
uarts[chipsel].istat.txbuf_full = 0;
uarts[chipsel].regs.lsr &= ~UART_LSR_TXBUFE;
}
if (value & UART_FCR_RRXFI) {
uarts[chipsel].istat.rxbuf_head = uarts[chipsel].istat.rxbuf_tail = 0;
uarts[chipsel].istat.rxbuf_full = 0;
uarts[chipsel].regs.lsr &= ~UART_LSR_RDRDY;
}
break;
case UART_IER:
uarts[chipsel].regs.ier = value & UART_VALID_IER;
#if 0
if (uarts[chipsel].regs.ier & UART_IER_THRI)
uarts[chipsel].istat.thre_int = 1;
#endif
break;
case UART_LCR:
uarts[chipsel].regs.lcr = value & UART_VALID_LCR;
uarts[chipsel].char_clks = char_clks(uarts[chipsel].regs.dll, uarts[chipsel].regs.dlh, uarts[chipsel].regs.lcr);
break;
case UART_MCR:
uarts[chipsel].regs.mcr = value & UART_VALID_MCR;
break;
case UART_SCR:
uarts[chipsel].regs.scr = value;
break;
default:
debug(1, "write out of range (addr %x)\n", addr);
}
}
 
/* Read a specific UART register. */
unsigned long uart_read_byte(unsigned long addr)
{
unsigned char value = 0;
int chipsel;
debug(4, "uart_read_byte(%x)", addr);
for(chipsel = 0; chipsel < MAX_UARTS; chipsel++)
if ((addr & ~(UART_ADDR_SPACE-1)) == config.uarts[chipsel].baseaddr)
break;
 
if (chipsel >= MAX_UARTS)
return 0;
 
if (uarts[chipsel].regs.lcr & UART_LCR_DLAB) {
switch (addr % UART_ADDR_SPACE) {
case UART_DLL:
value = uarts[chipsel].regs.dll;
debug(4, "= %x\n", value);
return value;
case UART_DLH:
value = uarts[chipsel].regs.dlh;
debug(4, "= %x\n", value);
return value;
}
}
switch (addr % UART_ADDR_SPACE) {
case UART_RXBUF:
{ /* Print out FIFO for debugging */
int i;
debug(4, "(%i/%i,%i,%i:", uarts[chipsel].istat.rxbuf_full, uarts[chipsel].fifo_len,
uarts[chipsel].istat.rxbuf_head, uarts[chipsel].istat.rxbuf_tail);
for (i = 0; i < uarts[chipsel].istat.rxbuf_full; i++)
debug(4, "%02x ", uarts[chipsel].regs.rxbuf[(uarts[chipsel].istat.rxbuf_tail + i) % uarts[chipsel].fifo_len]);
debug(4, ")");
}
if (uarts[chipsel].istat.rxbuf_full) {
value = uarts[chipsel].regs.rxbuf[uarts[chipsel].istat.rxbuf_tail];
uarts[chipsel].istat.rxbuf_tail = (uarts[chipsel].istat.rxbuf_tail + 1) % uarts[chipsel].fifo_len;
uarts[chipsel].istat.rxbuf_full--;
}
if (uarts[chipsel].istat.rxbuf_full)
uarts[chipsel].regs.lsr |= UART_LSR_RDRDY;
else
uarts[chipsel].regs.lsr &= ~UART_LSR_RDRDY;
uarts[chipsel].istat.timeout_count = 0;
break;
case UART_IER:
value = uarts[chipsel].regs.ier & UART_VALID_IER;
break;
case UART_IIR:
value = (uarts[chipsel].regs.iir & UART_VALID_IIR) | 0xc0;
if (uarts[chipsel].regs.ier & UART_IER_THRI)
uarts[chipsel].istat.thre_int = 0;
break;
case UART_LCR:
value = uarts[chipsel].regs.lcr & UART_VALID_LCR;
break;
case UART_MCR:
value = 0;
break;
case UART_LSR:
value = uarts[chipsel].regs.lsr & UART_VALID_LSR;
uarts[chipsel].regs.lsr &=
~(UART_LSR_OVRRUN | UART_LSR_BREAK | UART_LSR_PARITY
| UART_LSR_FRAME | UART_LSR_RXERR);
break;
case UART_MSR:
value = uarts[chipsel].regs.msr & UART_VALID_MSR;
uarts[chipsel].regs.msr = 0;
break;
case UART_SCR:
value = uarts[chipsel].regs.scr;
break;
default:
debug(1, "read out of range (addr %x)\n", addr);
}
debug(4, " = %x\n", value);
return value;
}
 
/* Function that handles incoming VAPI data. */
void uart_vapi_read (unsigned long id, unsigned long data)
{
int uart;
debug(4, "UART: id %08x, data %08x\n", id, data);
uart = id & VAPI_DEVICE_ID;
uarts[uart].vapi_buf[uarts[uart].vapi_buf_head_ptr] = data;
uarts[uart].vapi_buf_head_ptr = (uarts[uart].vapi_buf_head_ptr + 1) % UART_VAPI_BUF_LEN;
if (uarts[uart].vapi_buf_tail_ptr == uarts[uart].vapi_buf_head_ptr) {
fprintf (stderr, "FATAL: uart VAPI buffer to small.\n");
exit (1);
}
}
 
static void send_char (int uart, int bits_send)
{
printf ("'%c'\n", uarts[uart].iregs.txser);
debug(4, "TX \'%c\' via UART%d...\n", uarts[uart].iregs.txser, uart);
if (uarts[uart].regs.mcr & UART_MCR_LOOP)
uarts[uart].iregs.loopback = uarts[uart].iregs.txser;
else {
/* Send to either VAPI or to file */
if (config.uarts[uart].vapi_id) {
int par, pe, fe, nbits;
int j, data;
unsigned long packet = 0;
 
nbits = MIN (bits_send, (uarts[uart].regs.lcr & UART_LCR_WLEN8) + 5);
/* Encode a packet */
packet = uarts[uart].iregs.txser & ((1 << nbits) - 1);
 
/* Calculate parity */
for (j = 0, par = 0; j < nbits; j++)
par ^= (packet >> j) & 1;
 
if (uarts[uart].regs.lcr & UART_LCR_PARITY) {
if (uarts[uart].regs.lcr & UART_LCR_SPAR) {
packet |= 1 << nbits;
} else {
if (uarts[uart].regs.lcr & UART_LCR_EPAR)
packet |= par << nbits;
else
packet |= (par ^ 1) << nbits;
}
nbits++;
}
packet |= 1 << (nbits++);
if (uarts[uart].regs.lcr & UART_LCR_STOP)
packet |= 1 << (nbits++);
/* Decode a packet */
nbits = (uarts[uart].vapi.lcr & UART_LCR_WLEN8) + 5;
data = packet & ((1 << nbits) - 1);
/* Calculate parity, including parity bit */
for (j = 0, par = 0; j < nbits + 1; j++)
par ^= (packet >> j) & 1;
if (uarts[uart].vapi.lcr & UART_LCR_PARITY) {
if (uarts[uart].vapi.lcr & UART_LCR_SPAR) {
pe = !((packet >> nbits) & 1);
} else {
if (uarts[uart].vapi.lcr & UART_LCR_EPAR)
pe = par != 0;
else
pe = par != 1;
}
nbits++;
} else
pe = 0;
fe = ((packet >> (nbits++)) & 1) ^ 1;
if (uarts[uart].vapi.lcr & UART_LCR_STOP)
fe |= ((packet >> (nbits++)) & 1) ^ 1;
 
debug (4, "lcr vapi %02x, uart %02x\n", uarts[uart].vapi.lcr, uarts[uart].regs.lcr);
data |= (uarts[uart].vapi.lcr << 8) | (pe << 16) | (fe << 17) | (uarts[uart].vapi.lcr << 8);
printf ("vapi_send (%08x, %08x)\n", config.uarts[uart].vapi_id, data);
debug (4, "vapi_send (%08x, %08x)\n", config.uarts[uart].vapi_id, data);
vapi_send (config.uarts[uart].vapi_id, data);
} else {
fputc((int)(uarts[uart].iregs.txser & 0xFF), uarts[uart].txfs);
fflush(uarts[uart].txfs);
}
}
uarts[uart].istat.txser_full = 0;
uarts[uart].istat.txser_clks = 0;
}
 
/* Adds a character to the FIFO */
 
void uart_add_char (int uart, int ch)
{
if (uarts[uart].istat.rxbuf_full + 1 > uarts[uart].fifo_len)
uarts[uart].regs.lsr |= UART_LSR_OVRRUN | UART_LSR_RXERR;
else {
debug(4, "add %02x\n", ch);
uarts[uart].regs.rxbuf[uarts[uart].istat.rxbuf_head] = ch;
uarts[uart].istat.rxbuf_head = (uarts[uart].istat.rxbuf_head + 1) % uarts[uart].fifo_len;
uarts[uart].istat.rxbuf_full++;
}
uarts[uart].regs.lsr |= UART_LSR_RDRDY;
uarts[uart].istat.timeout_count = 0;
}
 
/* Simulation hook. Must be called every clock cycle to simulate all UART
devices. It does internal functional UART simulation. */
void uart_clock16 (int i)
{
int retval;
/* Schedule for later */
SCHED_ADD (uart_clock16, i, cycles + UART_CLOCK_DIVIDER);
/* If VAPI is not selected, UART communicates with two file streams;
if VAPI is selected, we use VAPI streams. */
/* if txfs is corrupted, skip this uart. */
if (!config.uarts[i].vapi_id && !uarts[i].txfs) return;
if (uarts[i].vapi.next_break_cnt >= 0)
if (--uarts[i].vapi.next_break_cnt < 0) {
if (!(uarts[i].vapi.cur_break = uarts[i].vapi.next_break))
uarts[i].istat.break_set = 0;
}
 
/***************** Transmit *****************/
if (!uarts[i].istat.txser_full) {
// uarts[i].regs.lsr |= UART_LSR_TXBUFE;
if (uarts[i].istat.txbuf_full) {
uarts[i].iregs.txser = uarts[i].regs.txbuf[uarts[i].istat.txbuf_tail];
uarts[i].istat.txbuf_tail = (uarts[i].istat.txbuf_tail + 1) % uarts[i].fifo_len;
uarts[i].istat.txser_full = 1;
uarts[i].istat.txbuf_full--;
uarts[i].regs.lsr &= ~UART_LSR_TXSERE;
uarts[i].istat.thre_int = 1;
} else {
uarts[i].regs.lsr |= UART_LSR_TXSERE;
uarts[i].regs.lsr |= UART_LSR_TXBUFE;
}
} else if (uarts[i].char_clks <= uarts[i].istat.txser_clks++) {
send_char(i, (uarts[i].regs.lcr & UART_LCR_WLEN8) + 5); /* We've sent all bits */
} else {
/* We are still sending char here*/
/* Check if we set the break bit */
if (uarts[i].regs.lcr & UART_LCR_SBC) {
if (!uarts[i].vapi.break_sent) {
#if 0
/* Send broken frame */
int nbits_sent = ((uarts[i].regs.lcr & UART_LCR_WLEN8) + 5) * (uarts[i].istat.txser_clks - 1) / uarts[i].char_clks;
send_char(i, nbits_sent);
#endif
/* Send one break signal */
vapi_send (config.uarts[i].vapi_id, UART_LCR_SBC << 8);
uarts[i].vapi.break_sent = 1;
}
/* mark as character was sent */
uarts[i].istat.txser_full = 0;
uarts[i].istat.txser_clks = 0;
} else
uarts[i].vapi.break_sent = 0;
}
 
/***************** Receive *****************/
/* Is there a break? */
if (uarts[i].vapi.cur_break) {
uarts[i].vapi.cur_break_cnt++;
if (uarts[i].vapi.cur_break_cnt > UART_BREAK_COUNT * uarts[i].vapi.char_clks) {
if (!uarts[i].istat.break_set) {
unsigned lsr;
uarts[i].istat.break_set = 1;
lsr = UART_LSR_BREAK | UART_LSR_RXERR | UART_LSR_RDRDY;
printf ("[%x]\n", uarts[i].regs.lsr);
uarts[i].istat.rxser_full = 0;
uarts[i].istat.rxser_clks = 0;
uart_add_char (i, lsr << 8);
} else
uarts[i].vapi.cur_break_cnt = 0;
}
if (uarts[i].istat.rxser_full) {
uarts[i].istat.rxser_full = 0;
uarts[i].istat.rxser_clks = 0;
}
} else {
if (uarts[i].istat.rxser_full) {
if (uarts[i].char_clks <= uarts[i].istat.rxser_clks++) {
/* Set unused character bits to zero and allow lsr register in fifo */
uarts[i].iregs.rxser &= ((1 << ((uarts[i].regs.lcr & 3) + 5)) - 1) | 0xff00;
debug(4, "Receiving 0x%02x'%c' via UART%d...\n", uarts[i].iregs.rxser, uarts[i].iregs.rxser, i);
uarts[i].istat.rxser_full = 0;
uarts[i].istat.rxser_clks = 0;
uart_add_char (i, uarts[i].iregs.rxser);
}
}
}
 
/* Check if there is something waiting, and put it into rxser */
if (uarts[i].regs.mcr & UART_MCR_LOOP) {
uarts[i].iregs.rxser = uarts[i].iregs.loopback;
uarts[i].istat.rxser_full = 1;
} else {
if (!config.uarts[i].vapi_id) {
if(uarts[i].istat.rxser_full == 0) {
if (uarts[i].slowdown)
uarts[i].slowdown--;
else if((retval = fgetc(uarts[i].rxfs)) != EOF) {
uarts[i].iregs.rxser = (char)retval;
uarts[i].istat.rxser_full = 1;
} else uarts[i].slowdown = UART_FGETC_SLOWDOWN;
}
} else { /* VAPI */
int received = 0;
/* do not handle commands while receiving */
if (uarts[i].istat.rxser_full) return;
while (!received) {
if (uarts[i].vapi_buf_head_ptr != uarts[i].vapi_buf_tail_ptr) {
unsigned long data = uarts[i].vapi_buf[uarts[i].vapi_buf_tail_ptr];
debug(4, "Handling: %08x (%i,%i)\n", data, uarts[i].vapi_buf_head_ptr, uarts[i].vapi_buf_tail_ptr);
uarts[i].vapi_buf_tail_ptr = (uarts[i].vapi_buf_tail_ptr + 1) % UART_VAPI_BUF_LEN;
switch (data >> 24) {
case 0x00:
uarts[i].vapi.lcr = (data >> 8) & 0xff;
/* Put data into rx fifo */
uarts[i].iregs.rxser = data & 0xff;
uarts[i].vapi.char_clks = char_clks (uarts[i].vapi.dll, uarts[i].vapi.dlh, uarts[i].vapi.lcr);
if ((uarts[i].vapi.lcr & ~UART_LCR_SBC) != (uarts[i].regs.lcr & ~UART_LCR_SBC)
|| uarts[i].vapi.char_clks != uarts[i].char_clks
|| uarts[i].vapi.skew < -MAX_SKEW || uarts[i].vapi.skew > MAX_SKEW) {
debug (3, "WARNING: unmatched VAPI (%02x) and uart (%02x) modes.\n",
uarts[i].vapi.lcr & ~UART_LCR_SBC, uarts[i].regs.lcr & ~UART_LCR_SBC);
/* Set error bits */
uarts[i].iregs.rxser |= (UART_LSR_FRAME | UART_LSR_RXERR) << 8;
if (uarts[i].regs.lcr & UART_LCR_PARITY) uarts[i].iregs.rxser |= UART_LSR_PARITY << 8;
}
uarts[i].istat.rxser_full = 1;
received = 1;
break;
case 0x01:
uarts[i].vapi.dll = (data >> 0) & 0xff;
uarts[i].vapi.dlh = (data >> 8) & 0xff;
break;
case 0x02:
uarts[i].vapi.lcr = (data >> 8) & 0xff;
break;
case 0x03:
uarts[i].vapi.skew = (signed short)(data & 0xffff);
break;
case 0x04:
uarts[i].vapi.next_break_cnt = data & 0xffff;
uarts[i].vapi.next_break = (data >> 16) & 1;
break;
default:
debug (0, "WARNING: Invalid vapi command %02x\n", data >> 24);
break;
}
} else break;
}
}
}
/***************** Loopback *****************/
if (uarts[i].regs.mcr & UART_MCR_LOOP) {
debug(5, "uart_clock: Loopback\n");
if ((uarts[i].regs.mcr & UART_MCR_AUX2) !=
((uarts[i].regs.msr & UART_MSR_DCD) >> 4))
uarts[i].regs.msr |= UART_MSR_DDCD;
if ((uarts[i].regs.mcr & UART_MCR_AUX1) <
((uarts[i].regs.msr & UART_MSR_RI) >> 4))
uarts[i].regs.msr |= UART_MSR_TERI;
if ((uarts[i].regs.mcr & UART_MCR_RTS) !=
((uarts[i].regs.msr & UART_MSR_CTS) >> 3))
uarts[i].regs.msr |= UART_MSR_DCTS;
if ((uarts[i].regs.mcr & UART_MCR_DTR) !=
((uarts[i].regs.msr & UART_MSR_DSR) >> 5))
uarts[i].regs.msr |= UART_MSR_DDSR;
uarts[i].regs.msr &= ~(UART_MSR_DCD | UART_MSR_RI
| UART_MSR_DSR | UART_MSR_CTS);
uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_AUX2) << 4);
uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_AUX1) << 4);
uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_RTS) << 3);
uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_DTR) << 5);
}
if (uarts[i].regs.lsr & UART_LSR_RDRDY)
uarts[i].istat.timeout_count++;
/* Update LSR error bits from the ones from rx FIFO */
if (uarts[i].istat.rxbuf_full) {
uarts[i].regs.lsr |= uarts[i].regs.rxbuf[uarts[i].istat.rxbuf_tail] >> 8;
/* we must delete the lsr status, so that we can clear it from lsr */
uarts[i].regs.rxbuf[uarts[i].istat.rxbuf_tail] &= 0xff;
}
/* Interrupt detection in proper priority order. */
uarts[i].regs.iir = UART_IIR_NO_INT;
if (uarts[i].regs.ier & UART_IER_RLSI && /* Receiver LS */
uarts[i].regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY
| UART_LSR_FRAME | UART_LSR_BREAK)) {
uarts[i].regs.iir = UART_IIR_RLSI;
} else if ((uarts[i].regs.ier & UART_IER_RDI) /* RD available */
&& (uarts[i].istat.rxbuf_full >= UART_FIFO_TRIGGER(uarts[i].regs.fcr >> 6))
&& (uarts[i].regs.lsr & UART_LSR_RDRDY)) {
uarts[i].regs.iir = UART_IIR_RDI;
} else if ((uarts[i].regs.ier & UART_IER_RDI) /* timeout */
&& (uarts[i].istat.timeout_count >= UART_CHAR_TIMEOUT * uarts[i].char_clks)) {
uarts[i].regs.iir = UART_IIR_CTI;
} else if (uarts[i].regs.ier & UART_IER_THRI && /* Transm. empty */
uarts[i].regs.lsr & UART_LSR_TXBUFE &&
uarts[i].istat.thre_int == 1) {
uarts[i].regs.iir = UART_IIR_THRI;
} else if (uarts[i].regs.ier & UART_IER_MSI && /* Modem status */
uarts[i].regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
| UART_MSR_TERI | UART_MSR_DDCD)) {
uarts[i].regs.iir = UART_IIR_MSI;
}
if (!(uarts[i].regs.iir & UART_IIR_NO_INT)) {
debug (4, "uarts[i].regs.iir = %i\t", uarts[i].regs.iir);
report_interrupt(config.uarts[i].irq);
}
}
 
/* Reset. It initializes all registers of all UART devices to zero values,
(re)opens all RX/TX file streams and places devices in memory address
space. */
void uart_reset()
{
int i;
if (config.sim.verbose && config.nuarts) printf("Resetting %u UART(s).\n", config.nuarts);
memset(uarts, 0, sizeof(uarts));
 
for(i = 0; i < config.nuarts; i++) {
if (config.uarts[i].vapi_id) {
if ((config.uarts[i].vapi_id & VAPI_DEVICE_ID) != i) {
fprintf (stderr, "ERROR: Wrong vapi_id (0x%x) for uart %i, last byte is required to be %02x; ignoring.\n", config.uarts[i].vapi_id, i, i);
config.uarts[i].vapi_id = 0;
uarts[i].txfs = 0;
} else {
vapi_install_handler (config.uarts[i].vapi_id, uart_vapi_read);
register_memoryarea(config.uarts[i].baseaddr, UART_ADDR_SPACE, 1, uart_read_byte, uart_write_byte);
}
} else if (config.uarts[i].txfile) { /* MM: Try to create stream. */
if (!(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r"))
&& !(uarts[i].rxfs = fopen(config.uarts[i].rxfile, "r+"))) {
debug (0, "WARNING: UART%d has problems with RX file stream.\n", i);
continue;
}
uarts[i].txfs = fopen(config.uarts[i].txfile, "a");
if (uarts[i].rxfs && uarts[i].txfs && config.sim.verbose) {
printf("UART%d at 0x%.8x uses ", i, config.uarts[i].baseaddr);
printf("%s for RX and %s for TX.\n", config.uarts[i].rxfile, config.uarts[i].txfile);
} else
debug (1, "WARNING: UART%d has problems with TX file stream.\n", i);
register_memoryarea(config.uarts[i].baseaddr, UART_ADDR_SPACE, 1, uart_read_byte, uart_write_byte);
}
if (config.uarts[i].uart16550)
uarts[i].fifo_len = 16;
else
uarts[i].fifo_len = 1;
 
uarts[i].istat.rxbuf_head = uarts[i].istat.rxbuf_tail = 0;
uarts[i].istat.txbuf_head = uarts[i].istat.txbuf_tail = 0;
uarts[i].istat.break_set = 0;
uarts[i].istat.timeout_count = 0;
uarts[i].istat.thre_int = 1; /* FIFO is empty at start */
uarts[i].slowdown = UART_FGETC_SLOWDOWN;
 
uarts[i].regs.lcr = UART_LCR_RESET;
uarts[i].vapi.cur_break = uarts[i].vapi.cur_break_cnt = uarts[i].vapi.next_break = 0;
uarts[i].vapi.next_break_cnt = -1;
printf ("%i\n", i);
SCHED_ADD (uart_clock16, i, cycles + UART_CLOCK_DIVIDER);
}
}
 
/* Print register values on stdout. */
void uart_status()
{
int i, j;
for(i = 0; i < config.nuarts; i++) {
if ( !config.uarts[i].baseaddr )
continue;
printf("\nUART%d visible registers at 0x%.8x:\n", i, config.uarts[i].baseaddr);
printf("RXBUF:");
for (j = uarts[i].istat.rxbuf_head; j != uarts[i].istat.rxbuf_tail; j = (j + 1) % uarts[i].fifo_len)
printf (" %.2x", uarts[i].regs.rxbuf[j]);
printf(" TXBUF: %.2x\n", uarts[i].regs.txbuf);
printf("DLL : %.2x DLH : %.2x\n", uarts[i].regs.dll, uarts[i].regs.dlh);
printf("IER : %.2x IIR : %.2x\n", uarts[i].regs.ier, uarts[i].regs.iir);
printf("LCR : %.2x MCR : %.2x\n", uarts[i].regs.lcr, uarts[i].regs.mcr);
printf("LSR : %.2x MSR : %.2x\n", uarts[i].regs.lsr, uarts[i].regs.msr);
printf("SCR : %.2x\n", uarts[i].regs.scr);
 
printf("\nInternal registers (sim debug):\n");
printf("RXSER: %.2x TXSER: %.2x\n", uarts[i].iregs.rxser, uarts[i].iregs.txser);
 
printf("\nInternal status (sim debug):\n");
printf("char_clks: %d\n", uarts[i].char_clks);
printf("rxser_clks: %d txser_clks: %d\n", uarts[i].istat.rxser_clks, uarts[i].istat.txser_clks);
printf("rxser: %d txser: %d\n", uarts[i].istat.rxser_full, uarts[i].istat.txser_full);
printf("rxbuf: %d txbuf: %d\n", uarts[i].istat.rxbuf_full, uarts[i].istat.txbuf_full);
printf("Using IRQ%i\n", config.uarts[i].irq);
if (config.uarts[i].vapi_id)
printf ("Connected to vapi ID=%x\n\n", config.uarts[i].vapi_id);
else
printf("RX fs: %p TX fs: %p\n\n", uarts[i].rxfs, uarts[i].txfs);
}
}
/16450.h
0,0 → 1,217
/* 16450.h -- Definition of types and structures for 8250/16450 serial UART
Copyright (C) 2000 Damjan Lampret, lampret@opencores.org
 
This file is part of OpenRISC 1000 Architectural Simulator.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
/* Prototypes */
void uart_reset();
 
/* Definitions */
#define UART_ADDR_SPACE (8) /* UART memory address space size in bytes */
#define UART_MAX_FIFO_LEN (16) /* rx FIFO for uart 16550 */
#define MAX_SKEW (1) /* max. clock skew in subclocks */
#define UART_VAPI_BUF_LEN 128 /* Size of VAPI command buffer - VAPI should not send more
that this amout of char before requesting something back */
#define UART_CLOCK_DIVIDER 16 /* Uart clock divider */
#define UART_FGETC_SLOWDOWN 100 /* fgetc slowdown factor */
 
/* Registers */
 
struct dev_16450 {
struct {
unsigned txbuf[UART_MAX_FIFO_LEN];
unsigned rxbuf[UART_MAX_FIFO_LEN];
unsigned char dll;
unsigned char dlh;
unsigned char ier;
unsigned char iir;
unsigned char fcr;
unsigned char lcr;
unsigned char mcr;
unsigned char lsr;
unsigned char msr;
unsigned char scr;
} regs; /* Visible registers */
struct {
unsigned long txser; /* Character just sending */
unsigned long rxser; /* Character just receiving */
unsigned char loopback;
} iregs; /* Internal registers */
struct {
int txbuf_head;
int txbuf_tail;
int rxbuf_head;
int rxbuf_tail;
unsigned int txser_full;
unsigned int rxser_full;
unsigned int txbuf_full;
unsigned int rxbuf_full;
unsigned thre_int;
unsigned break_set;
unsigned long txser_clks;
unsigned long rxser_clks;
unsigned timeout_count;
} istat; /* Internal status */
 
/* Clocks per char */
unsigned long char_clks;
/* VAPI internal registers */
struct {
unsigned long char_clks;
int dll, dlh;
int lcr;
int skew;
int next_break;
int next_break_cnt;
int cur_break;
int cur_break_cnt;
int break_sent;
} vapi;
/* Required by VAPI - circular buffer */
unsigned long vapi_buf[UART_VAPI_BUF_LEN]; /* Buffer to store incoming characters to,
since we cannot handle them so fast - we
are serial */
int vapi_buf_head_ptr; /* Where we write to */
int vapi_buf_tail_ptr; /* Where we read from */
/* Length of FIFO, 16 for 16550, 1 for 16450 */
int fifo_len;
 
/* fgetc slowdown */
int slowdown;
/* Required by standard file streams */
FILE * rxfs;
FILE * txfs;
};
 
/*
* Addresses of visible registers
*
*/
#define UART_RXBUF 0 /* R: Rx buffer, DLAB=0 */
#define UART_TXBUF 0 /* W: Tx buffer, DLAB=0 */
#define UART_DLL 0 /* R/W: Divisor Latch Low, DLAB=1 */
#define UART_DLH 1 /* R/W: Divisor Latch High, DLAB=1 */
#define UART_IER 1 /* R/W: Interrupt Enable Register */
#define UART_IIR 2 /* R: Interrupt ID Register */
#define UART_FCR 2 /* W: FIFO Control Register */
#define UART_LCR 3 /* R/W: Line Control Register */
#define UART_MCR 4 /* W: Modem Control Register */
#define UART_LSR 5 /* R: Line Status Register */
#define UART_MSR 6 /* R: Modem Status Register */
#define UART_SCR 7 /* R/W: Scratch Register */
 
/*
* R/W masks for valid bits in 8250/16450 (mask out 16550 and later bits)
*
*/
#define UART_VALID_LCR 0xff
#define UART_VALID_LSR 0xff
#define UART_VALID_IIR 0x0f
#define UART_VALID_FCR 0xc0
#define UART_VALID_IER 0x0f
#define UART_VALID_MCR 0x1f
#define UART_VALID_MSR 0xff
 
/*
* Bit definitions for the Line Control Register
*
*/
#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
#define UART_LCR_SBC 0x40 /* Set break control */
#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
#define UART_LCR_EPAR 0x10 /* Even parity select */
#define UART_LCR_PARITY 0x08 /* Parity Enable */
#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */
#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */
#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */
#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
#define UART_LCR_RESET 0x03
/*
* Bit definitions for the Line Status Register
*/
#define UART_LSR_RXERR 0x80 /* Error in rx fifo */
#define UART_LSR_TXSERE 0x40 /* Transmitter serial register empty */
#define UART_LSR_TXBUFE 0x20 /* Transmitter buffer register empty */
#define UART_LSR_BREAK 0x10 /* Break interrupt indicator */
#define UART_LSR_FRAME 0x08 /* Frame error indicator */
#define UART_LSR_PARITY 0x04 /* Parity error indicator */
#define UART_LSR_OVRRUN 0x02 /* Overrun error indicator */
#define UART_LSR_RDRDY 0x01 /* Receiver data ready */
 
/*
* Bit definitions for the Interrupt Identification Register
*/
#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
 
#define UART_IIR_MSI 0x00 /* Modem status interrupt (Low priority) */
#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt (High p.) */
#define UART_IIR_CTI 0x0c /* Character timeout */
 
/*
* Bit Definitions for the FIFO Control Register
*/
#define UART_FCR_FIE 0x01 /* FIFO enable */
#define UART_FCR_RRXFI 0x02 /* Reset rx FIFO */
#define UART_FCR_RTXFI 0x04 /* Reset tx FIFO */
#define UART_FIFO_TRIGGER(x) /* Trigger values for indexes 0..3 */\
((x) == 0 ? 1\
:(x) == 1 ? 4\
:(x) == 2 ? 8\
:(x) == 3 ? 14 : 0)
 
/*
* Bit definitions for the Interrupt Enable Register
*/
#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
 
/*
* Bit definitions for the Modem Control Register
*/
#define UART_MCR_LOOP 0x10 /* Enable loopback mode */
#define UART_MCR_AUX2 0x08 /* Auxilary 2 */
#define UART_MCR_AUX1 0x04 /* Auxilary 1 */
#define UART_MCR_RTS 0x02 /* Force RTS */
#define UART_MCR_DTR 0x01 /* Force DTR */
 
/*
* Bit definitions for the Modem Status Register
*/
#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
#define UART_MSR_RI 0x40 /* Ring Indicator */
#define UART_MSR_DSR 0x20 /* Data Set Ready */
#define UART_MSR_CTS 0x10 /* Clear to Send */
#define UART_MSR_DDCD 0x08 /* Delta DCD */
#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
#define UART_MSR_DDSR 0x02 /* Delta DSR */
#define UART_MSR_DCTS 0x01 /* Delta CTS */
 
/*
* Various definitions
*/
#define UART_BREAK_COUNT (1) /* # of chars to count when performing break */
#define UART_CHAR_TIMEOUT (4) /* # of chars to count when performing timeout int. */
/vga.c
0,0 → 1,254
/* vga.c -- Definition of types and structures for VGA/LCD
Copyright (C) 2001 Marko Mlinar, markom@opencores.org
 
This file is part of OpenRISC 1000 Architectural Simulator.
 
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
#include <stdio.h>
#include "sim-config.h"
#include "vga.h"
#include "abstract.h"
#include "sched.h"
 
/* When this counter reaches config.vgas[].refresh_rate, a screenshot is taken and outputted */
static struct {
int pics;
unsigned long ctrl, stat, htim, vtim;
int vbindex;
unsigned long vbar[2];
unsigned hlen, vlen;
int pindex;
unsigned long palette[2][256];
} vga[MAX_VGAS];
 
 
/* Write a register */
void vga_write32(unsigned long addr, unsigned long value)
{
int i, found = -1;
 
/* Find which controller this is */
for (i = 0; i < config.nvgas; i++ ) {
if ((addr >= config.vgas[i].baseaddr) && (addr < config.vgas[i].baseaddr + VGA_ADDR_SPACE)) {
found = i;
break;
}
}
if (found < 0) {
fprintf( stderr, "vga_write32( 0x%08lX ): Out of range\n", addr);
cont_run = 0;
return;
}
 
addr -= config.vgas[found].baseaddr;
 
switch (addr) {
case VGA_CTRL: vga[found].ctrl = value; break;
case VGA_STAT: vga[found].stat = value; break;
case VGA_HTIM: vga[found].htim = value; break;
case VGA_VTIM: vga[found].vtim = value; break;
case VGA_HVLEN: vga[found].hlen = (value >> 16) + 2; vga[found].hlen = (value & 0xffff) + 2; break;
case VGA_VBARA: vga[found].vbar[0] = value; break;
case VGA_VBARB: vga[found].vbar[1] = value; break;
default:
if (addr >= VGA_CLUTA && addr < VGA_CLUTB) {
vga[found].palette[0][addr - VGA_CLUTA] = value & 0x00ffffff;
} else if (addr >= VGA_CLUTB) {
vga[found].palette[1][addr - VGA_CLUTB] = value & 0x00ffffff;
} else {
fprintf( stderr, "vga_write32( 0x%08lX, 0x%08lX ): Out of range\n", addr + config.vgas[found].baseaddr, value);
cont_run = 0;
return;
}
break;
}
}
 
/* Read a register */
unsigned long vga_read32(unsigned long addr)
{
int i, found = -1;
 
/* Find which controller this is */
for (i = 0; i < config.nvgas; i++ ) {
if ((addr >= config.vgas[i].baseaddr) && (addr < config.vgas[i].baseaddr + VGA_ADDR_SPACE)) {
found = i;
break;
}
}
if (found < 0) {
fprintf( stderr, "vga_read32( 0x%08lX ): Out of range\n", addr);
cont_run = 0;
return 0;
}
 
addr -= config.vgas[found].baseaddr;
 
switch (addr) {
case VGA_CTRL: return vga[found].ctrl;
case VGA_STAT: return vga[found].stat;
case VGA_HTIM: return vga[found].htim;
case VGA_VTIM: return vga[found].vtim;
case VGA_HVLEN: return ((vga[found].hlen - 2) << 16) | (vga[found].vlen - 2);
case VGA_VBARA: return vga[found].vbar[0];
case VGA_VBARB: return vga[found].vbar[1];
default:
if (addr >= VGA_CLUTA && addr < VGA_CLUTB) {
return vga[found].palette[0][addr - VGA_CLUTA];
} else if (addr >= VGA_CLUTB) {
return vga[found].palette[1][addr - VGA_CLUTB];
} else {
fprintf( stderr, "vga_read32( 0x%08lX ): Out of range\n", addr);
cont_run = 0;
return 0;
}
break;
}
return 0;
}
 
/* This code will only work on little endian machines */
#ifdef __BIG_ENDIAN__
#warning Image dump not supported on big endian machines
 
static int vga_dump_image (char *filename, int v)
{
return 1;
}
 
#else
 
typedef struct {
unsigned short int type; /* Magic identifier */
unsigned int size; /* File size in bytes */
unsigned short int reserved1, reserved2;
unsigned int offset; /* Offset to image data, bytes */
} BMP_HEADER;
 
typedef struct {
unsigned int size; /* Header size in bytes */
int width,height; /* Width and height of image */
unsigned short int planes; /* Number of colour planes */
unsigned short int bits; /* Bits per pixel */
unsigned int compression; /* Compression type */
unsigned int imagesize; /* Image size in bytes */
int xresolution,yresolution; /* Pixels per meter */
unsigned int ncolours; /* Number of colours */
unsigned int importantcolours; /* Important colours */
} INFOHEADER;
 
 
/* Dumps a bmp file, based on current image */
static int vga_dump_image (char *filename, int v)
{
unsigned long addr = config.vgas[v].baseaddr;
int sx = vga[v].hlen;
int sy = vga[v].vlen;
int i, x, y;
int pc = vga[v].ctrl & VGA_CTRL_PC;
int rbpp = vga[v].ctrl & VGA_CTRL_CD;
int bpp = rbpp >> 8;
BMP_HEADER bh;
INFOHEADER ih;
FILE *fo;
 
if (!sx || !sy) return;
 
/* 16bpp and 32 bpp will be converted to 24bpp */
if (bpp == 1 || bpp == 3) bpp = 2;
bh.type = 19778; /* BM */
bh.size = sizeof (BMP_HEADER) + sizeof (INFOHEADER) + sx * sy * (bpp * 4 + 4) + (pc ? 1024 : 0);
bh.reserved1 = bh.reserved2 = 0;
bh.offset = sizeof (BMP_HEADER) + sizeof (INFOHEADER) + (pc ? 1024 : 0);
ih.size = sizeof (INFOHEADER);
ih.width = sx; ih.height = sy;
ih.planes = 1; ih.bits = bpp * 4 + 4;
ih.compression = 0; ih.imagesize = x * y * (bpp * 4 + 4);
ih.xresolution = ih.yresolution = 0;
ih.ncolours = 0; /* should be generated */
ih.importantcolours = 0; /* all are important */
fo = fopen (filename, "wb+");
if (!fwrite (&bh, sizeof (BMP_HEADER), 1, fo)) return 1;
if (!fwrite (&ih, sizeof (INFOHEADER), 1, fo)) return 1;
if (pc) { /* Write palette? */
for (i = 0; i < 256; i++) {
unsigned long val, d;
d = vga[v].palette[vga[v].pindex][i];
val = (d >> 0) & 0xff; /* Blue */
val |= (d >> 8) & 0xff; /* Green */
val |= (d >> 16) & 0xff; /* Red */
if (!fwrite (&val, sizeof (val), 1, fo)) return 1;
}
}
/* Data is stored upside down */
for (y = sy - 1; y >= 0; y--) {
int align = 4 - ((bpp + 1) * sx) % 4;
int zero = 0;
for (x = 0; x < sx; x++) {
unsigned long pixel = evalsim_mem32 (vga[v].vbar[vga[v].vbindex] + (y * sx + x) * (bpp + 1));
if (!fwrite (&pixel, sizeof (pixel), 1, fo)) return 1;
}
if (!fwrite (&zero, align, 1, fo)) return 1;
}
fclose (fo);
return 0;
}
#endif /* !__BIG_ENDIAN__ */
 
void vga_job (int param)
{
/* dump the image? */
char temp[STR_SIZE];
sprintf (temp, "%s%04i.bmp", config.vgas[param].filename, vga[param].pics++);
vga_dump_image (temp, param);
SCHED_ADD(vga_job, param, cycles + config.vgas[param].refresh_rate);
}
 
/* Reset all VGAs */
void vga_reset ()
{
int i, j;
for (i = 0; i < config.nvgas; i++) {
 
/* Init palette */
for (j = 0; j < 256; j++)
vga[i].palette[0][j] = vga[i].palette[1][j] = 0;
 
vga[i].ctrl = vga[i].stat = vga[i].htim = vga[i].vtim = 0;
vga[i].hlen = vga[i].vlen = 0;
vga[i].vbar[0] = vga[i].vbar[1] = 0;
/* Init screen dumping machine */
vga[i].pics = 0;
 
vga[i].pindex = 0;
vga[i].vbindex = 0;
 
if (config.vgas[i].baseaddr)
register_memoryarea(config.vgas[i].baseaddr, VGA_ADDR_SPACE, 4, vga_read32, vga_write32);
SCHED_ADD(vga_job, i, cycles + config.vgas[i].refresh_rate);
}
}
vga.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: vga.h =================================================================== --- vga.h (nonexistent) +++ vga.h (revision 1765) @@ -0,0 +1,53 @@ +/* vga.h -- Definition of types and structures for Richard's VGA/LCD controler. + Copyright (C) 2002 Marko Mlinar, markom@opencores.org + +NOTE: device is only partially implemented! + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _VGA_H_ +#define _VGA_H_ + +#define VGA_CTRL 0x00 /* Control Register */ +#define VGA_STAT 0x04 /* Status Register */ +#define VGA_HTIM 0x08 /* Horizontal Timing Register */ +#define VGA_VTIM 0x0c /* Vertical Timing Register */ +#define VGA_HVLEN 0x10 /* Horizontal and Vertical Length Register */ +#define VGA_VBARA 0x14 /* Video Memory Base Address Register A */ +#define VGA_VBARB 0x18 /* Video Memory Base Address Register B */ +#define VGA_CLUTA 0x800 +#define VGA_CLUTB 0xc00 +#define VGA_MASK 0xfff +#define VGA_ADDR_SPACE 1024 + + +/* List of implemented registers; all other are ignored. */ + +/* Control Register */ +#define VGA_CTRL_VEN 0x00000001 /* Video Enable */ +#define VGA_CTRL_CD 0x00000300 /* Color Depth */ +#define VGA_CTRL_PC 0x00000400 /* Pseudo Color */ + +/* Status Register */ +/* Horiz. Timing Register */ +/* Vert. Timing Register */ +/* Horiz. and Vert. Length Register */ + +/* Reset all VGAs */ +void vga_reset (); + +#endif /* _VGA_H_ */
vga.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: ps2kbd.c =================================================================== --- ps2kbd.c (nonexistent) +++ ps2kbd.c (revision 1765) @@ -0,0 +1,274 @@ +/* ps2kbd.c -- Very simple (and limited) PS/2 keyboard simulation + Copyright (C) 2002 Marko Mlinar, markom@opencores.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include "ps2kbd.h" +#include "sim-config.h" +#include "abstract.h" +#include "sched.h" + +/* ASCII to scan code conversion table */ +const static struct { + /* Whether shift must be pressed */ + unsigned char shift; + /* Scan code to be generated */ + unsigned char code; +} scan_table [128] = { +/* 0 - 15 */ +{0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, +{0, 0x0E}, {0, 0x0F}, {0, 0x1C}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, +/* 16 - 31 */ +{0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, +{0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x01}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, +/* 32 - 47 */ +{0, 0x39}, {1, 0x02}, {1, 0x28}, {1, 0x04}, {1, 0x05}, {1, 0x06}, {1, 0x08}, {0, 0x28}, +{1, 0x0A}, {1, 0x0B}, {1, 0x09}, {1, 0x0D}, {0, 0x33}, {0, 0x0C}, {0, 0x34}, {0, 0x35}, +/* 48 - 63 */ +{0, 0x0B}, {0, 0x02}, {0, 0x03}, {0, 0x04}, {0, 0x05}, {0, 0x06}, {0, 0x07}, {0, 0x08}, +{0, 0x09}, {0, 0x0A}, {1, 0x27}, {0, 0x27}, {1, 0x33}, {0, 0x0D}, {1, 0x34}, {1, 0x35}, +/* 64 - 79 */ +{1, 0x03}, {1, 0x1E}, {1, 0x30}, {1, 0x2E}, {1, 0x20}, {1, 0x12}, {1, 0x21}, {1, 0x22}, +{1, 0x23}, {1, 0x17}, {1, 0x24}, {1, 0x25}, {1, 0x26}, {1, 0x32}, {1, 0x31}, {1, 0x18}, +/* 80 - 95 */ +{1, 0x19}, {1, 0x10}, {1, 0x13}, {1, 0x1F}, {1, 0x14}, {1, 0x16}, {1, 0x2F}, {1, 0x11}, +{1, 0x2D}, {1, 0x15}, {1, 0x2C}, {0, 0x1A}, {0, 0x2B}, {0, 0x1B}, {1, 0x07}, {1, 0x0C}, +/* 96 - 111 */ +{0, 0x29}, {0, 0x1E}, {0, 0x30}, {0, 0x2E}, {0, 0x20}, {0, 0x12}, {0, 0x21}, {0, 0x22}, +{0, 0x23}, {0, 0x17}, {0, 0x24}, {0, 0x25}, {0, 0x26}, {0, 0x32}, {0, 0x31}, {0, 0x18}, +/* 112 - 127 */ +{0, 0x19}, {0, 0x10}, {0, 0x13}, {0, 0x1F}, {0, 0x14}, {0, 0x16}, {0, 0x2F}, {0, 0x11}, +{0, 0x2D}, {0, 0x15}, {0, 0x2C}, {1, 0x1A}, {1, 0x2B}, {1, 0x1B}, {1, 0x29}, {0, 0x00} +}; + +/* Temporary buffer to store incoming scan codes */ +static unsigned char kbd_buf[KBD_MAX_BUF] = {0}; + +/* Number of scan codes in buffer */ +static unsigned long kbd_buf_count = 0; +static unsigned long kbd_buf_head = 0; +static unsigned long kbd_buf_tail = 0; + +/* Input stream */ +static FILE *kbd_rxfs = NULL; + +/* Controller Command (write into 0x64) */ +static int kbd_ccmd; + +/* Keyboard Command (write into 0x60) */ +static unsigned char kbd_kcmd; + +/* Controller Command Byte */ +static unsigned char kbd_ccmdbyte; + +/* Keyboard response pending */ +static unsigned long kbd_kresp; + +/* Keyboard slowdown factor */ +static long kbd_slowdown; + +static void kbd_put (unsigned char c) +{ + if (kbd_buf_count >= KBD_MAX_BUF) { + fprintf (stderr, "WARNING: Keyboard buffer overflow.\n"); + } else { + kbd_buf[kbd_buf_head] = c; + kbd_buf_head = (kbd_buf_head + 1) % KBD_MAX_BUF; + kbd_buf_count++; + } +} + +/* Decodes ascii code c into multiple scan codes, placed into buf, length is returned */ +static void scan_decode (unsigned char c) +{ + /* Do not handle special characters and extended ascii */ + if (c >= 128 || !scan_table[c].code) + return; + + /* Make shift? */ + if (scan_table[c].shift) kbd_put (0x2a); + /* Make char */ + kbd_put (scan_table[c].code); + /* Break char */ + kbd_put (scan_table[c].code | 0x80); + /* Break shift? */ + if (scan_table[c].shift) kbd_put (0xaa); +} + +/* Write a register */ +void kbd_write8 (unsigned long addr, unsigned long value) +{ + int a = (addr - config.kbd.baseaddr); + switch (a) { + case KBD_CTRL: + kbd_ccmd = value & 0xff; + if (kbd_ccmd == KBD_CCMD_RCB) + kbd_kresp = 0x1; + if (kbd_ccmd == KBD_CCMD_ST1) + kbd_kresp = 0x1; + if (kbd_ccmd == KBD_CCMD_ST2) + kbd_kresp = 0x1; + if (kbd_ccmd == KBD_CCMD_DKI) + kbd_ccmdbyte |= KBD_CCMDBYTE_EN; + if (kbd_ccmd == KBD_CCMD_EKI) + kbd_ccmdbyte &= ~KBD_CCMDBYTE_EN; + if (config.sim.verbose) + printf("kbd_write8(%x) %x\n", addr, value); + break; + case KBD_DATA: + if (kbd_ccmd == KBD_CCMD_WCB) { + kbd_ccmdbyte = value & 0xff; + kbd_ccmd = 0x00; + } else + kbd_kcmd = value & 0xff; + if (kbd_kcmd == KBD_KCMD_DK) + kbd_ccmdbyte |= KBD_CCMDBYTE_EN; + if (kbd_kcmd == KBD_KCMD_EK) + kbd_ccmdbyte &= ~KBD_CCMDBYTE_EN; + kbd_kresp = 0x1; + kbd_ccmd = 0x00; + if (config.sim.verbose) + printf("kbd_write8(%x) %x\n", addr, value); + break; + default: + fprintf (stderr, "Write out of keyboard space (0x%08x)!\n", addr); + cont_run = 0; + break; + } +} + +/* Read a register */ +unsigned long kbd_read8 (unsigned long addr) +{ + int a = (addr - config.kbd.baseaddr); + switch (a) { + case KBD_CTRL: { + unsigned long c = 0x0; + if (kbd_kresp || kbd_buf_count) + c |= KBD_STATUS_OBF; + c |= kbd_ccmdbyte & KBD_CCMDBYTE_SYS; + c |= KBD_STATUS_INH; + if (config.sim.verbose) + printf("kbd_read8(%x) %x\n", addr, c); + return c; + } + case KBD_DATA: + if (kbd_ccmd) { + unsigned long rc; + if (kbd_ccmd == KBD_CCMD_RCB) + rc = kbd_ccmdbyte; + if (kbd_ccmd == KBD_CCMD_ST1) + rc = 0x55; + if (kbd_ccmd == KBD_CCMD_ST2) + rc = 0x00; + kbd_ccmd = 0x00; + kbd_kresp = 0x0; + if (config.sim.verbose) + printf("kbd_read8(%x) %x\n", addr, rc); + return rc; + } + else if (kbd_kresp) { + unsigned long rc; + if (kbd_kresp == 0x2) { + kbd_kresp = 0x0; + rc = KBD_KRESP_RSTOK; + } else if (kbd_kcmd == KBD_KCMD_RST) { + kbd_kresp = 0x2; + rc = KBD_KRESP_ACK; + } else if (kbd_kcmd == KBD_KCMD_ECHO) { + kbd_kresp = 0x0; + rc = KBD_KRESP_ECHO; + } else { + kbd_kresp = 0x0; + rc = KBD_KRESP_ACK; + } + kbd_kcmd = 0x00; + if (config.sim.verbose) + printf("kbd_read8(%x) %x\n", addr, rc); + return rc; + } else if (kbd_buf_count) { + unsigned long c = kbd_buf[kbd_buf_tail]; + kbd_buf_tail = (kbd_buf_tail + 1) % KBD_MAX_BUF; + kbd_buf_count--; + kbd_kresp = 0x0; + if (config.sim.verbose) + printf("kbd_read8(%x) %x\n", addr, c); + return c; + } + kbd_kresp = 0x0; + if (config.sim.verbose) + printf("kbd_read8(%x) fifo empty\n", addr); + return 0; + default: + fprintf (stderr, "Read out of keyboard space (0x%08x)!\n", addr); + cont_run = 0; + return 0; + } +} + + +/* Simulation hook. Must be called every couple of clock cycles to simulate incomming data. */ +void kbd_job(int param) +{ + int c; + int kbd_int = 0; + /* Check if there is something waiting, and decode it into kdb_buf */ + if((c = fgetc(kbd_rxfs)) != EOF) { + scan_decode (c); + } + kbd_int = kbd_kresp || kbd_buf_count; + kbd_int = kbd_kresp || kbd_buf_count ? kbd_ccmdbyte & KBD_CCMDBYTE_INT : 0; + if (config.sim.verbose && kbd_int) + printf("Keyboard Interrupt.... kbd_kresp %x kbd_buf_count %x \n", kbd_kresp, kbd_buf_count); + if (kbd_int) report_interrupt(config.kbd.irq); + SCHED_ADD(kbd_job, 0, cycles + kbd_slowdown); +} + +/* Reset all VGAs */ +void kbd_reset () +{ + if (config.kbd.enabled) { + kbd_buf_count = 0; + kbd_buf_head = 0; + kbd_buf_tail = 0; + kbd_kresp = 0x0; + kbd_ccmdbyte = 0x65; /* We reset into default normal operation. */ + register_memoryarea(config.kbd.baseaddr, KBD_SPACE, 1, kbd_read8, kbd_write8); + + if (!(kbd_rxfs = fopen(config.kbd.rxfile, "r")) + && !(kbd_rxfs = fopen(config.kbd.rxfile, "r+"))) { + fprintf (stderr, "WARNING: Keyboard has problems with RX file stream.\n"); + config.kbd.enabled = 0; + } + kbd_slowdown = (long) ((config.sim.system_kfreq * 1000.) / KBD_BAUD_RATE); + if (kbd_slowdown <= 0) kbd_slowdown = 1; + if (config.kbd.enabled) SCHED_ADD(kbd_job, 0, cycles + kbd_slowdown); + } +} + + +void kbd_info() +{ + printf("kbd_kcmd: %x\n", kbd_kcmd); + printf("kbd_ccmd: %x\n", kbd_ccmd); + printf("kbd_ccmdbyte: %x\n", kbd_ccmdbyte); + printf("kbd_kresp: %x\n", kbd_kresp); + printf("kbd_buf_count: %x\n", kbd_buf_count); +}
ps2kbd.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: fb.c =================================================================== --- fb.c (nonexistent) +++ fb.c (revision 1765) @@ -0,0 +1,184 @@ +/* fb.c -- Simple frame buffer + Copyright (C) 2001 Marko Mlinar, markom@opencores.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "sim-config.h" +#include "abstract.h" +#include "fb.h" +#include "sched.h" + +#define FB_WRAP (512*1024) + +static unsigned long pal[256]; +static int fb_ctrl = 0; +static int fb_pic = 0; +static unsigned long fb_addr = 0; + +static void change_buf_addr (unsigned long addr) +{ + fb_addr = addr; +} + +/* Write a register */ +void fb_write32 (unsigned long addr, unsigned long value) +{ + int a = (addr - config.fb.baseaddr); + switch (a) { + case FB_CTRL: fb_ctrl = value; break; + case FB_BUFADDR: change_buf_addr (value); break; + default: + a -= FB_PAL; + a /= 4; + if (a < 0 || a >= 256) { + fprintf (stderr, "Write out of palette buffer (0x%08x)!\n", addr); + cont_run = 0; + } else pal[a] = value; + break; + } +} + +/* Read a register */ +unsigned long fb_read32 (unsigned long addr) +{ + int a = (addr - config.fb.baseaddr); + switch (a) { + case FB_CTRL: return fb_ctrl; break; + case FB_BUFADDR: return fb_addr; break; + default: + a -= FB_PAL; + a /= 4; + if (a < 0 || a >= 256) { + fprintf (stderr, "Read out of palette buffer (0x%08x)!\n", addr); + cont_run = 0; + return 0; + } else return pal[a]; + } +} + +/* define these also for big endian */ +#define CNV16(x) (x) +#define CNV32(x) (x) + +/* Dumps a bmp file, based on current image */ +static int fb_dump_image (char *filename) +{ + int sx = FB_SIZEX; + int sy = FB_SIZEY; + int i, x, y; + FILE *fo; + + unsigned short int u16; + unsigned long int u32; + + if (config.sim.verbose) printf ("Creating %s...", filename); + fo = fopen (filename, "wb+"); + u16 = CNV16(19778); /* BM */ + if (!fwrite (&u16, 2, 1, fo)) return 1; + u32 = CNV32(14 + 40 + sx * sy + 1024); /* size */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + u32 = CNV32(0); /* reserved */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + u32 = 14 + 40 + 1024; /* offset */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + + u32 = CNV32(40); /* header size */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + u32 = CNV32(sx); /* width */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + u32 = CNV32(sy); /* height */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + u16 = CNV16(1); /* planes */ + if (!fwrite (&u16, 2, 1, fo)) return 1; + u16 = CNV16(8); /* bits */ + if (!fwrite (&u16, 2, 1, fo)) return 1; + u32 = CNV32(0); /* compression */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + u32 = CNV32(x * y); /* image size */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + u32 = CNV32(0); /* x resolution */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + u32 = CNV32(0); /* y resolution */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + u32 = CNV32(0); /* ncolours = 0; should be generated */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + u32 = CNV32(0); /* important colours; all are important */ + if (!fwrite (&u32, 4, 1, fo)) return 1; + + for (i = 0; i < 256; i++) { + unsigned long val, d; + d = pal[i]; +#if 1 + val = ((d >> 0) & 0x1f) << 3; /* Blue */ + val |= ((d >> 5) & 0x3f) << 10; /* Green */ + val |= ((d >> 11) & 0x1f) << 19; /* Red */ +#else + val = CNV32(pal[i]); +#endif + if (!fwrite (&val, 4, 1, fo)) return 1; + } + + if (config.sim.verbose) printf ("(%i,%i)", sx, sy); + /* Data is stored upside down */ + for (y = sy - 1; y >= 0; y--) { + int align = (4 - sx) % 4; + int zero = CNV32(0); + int add; + while (align < 0) align += 4; + for (x = 0; x < sx; x++) { + add = (fb_addr & ~(FB_WRAP - 1)) | ((fb_addr + y * sx + x) & (FB_WRAP - 1)); + fputc (evalsim_mem8 (add), fo); + } + if (align && !fwrite (&zero, align, 1, fo)) return 1; + } + + if (config.sim.verbose) printf ("DONE\n"); + fclose (fo); + return 0; +} + +void fb_job (int param) +{ + /* dump the image? */ + if (fb_ctrl) { + char temp[STR_SIZE]; + sprintf (temp, "%s%04i.bmp", &config.fb.filename[0], fb_pic); + fb_dump_image (temp); + fb_pic++; + } + SCHED_ADD(fb_job, 0, cycles + config.fb.refresh_rate); +} + +/* Reset all VGAs */ +void fb_reset () +{ + int i; + + if (config.fb.enabled) { + fb_pic = 0; + fb_addr = 0; + fb_ctrl = 0; + + for (i = 0; i < 256; i++) + pal[i] = (i << 16) | (i << 8) | (i << 0); + + if (config.fb.baseaddr) + register_memoryarea(config.fb.baseaddr, FB_PAL + 256*4, 4, fb_read32, fb_write32); + SCHED_ADD(fb_job, 0, cycles + config.fb.refresh_rate); + } +}
fb.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: ps2kbd.h =================================================================== --- ps2kbd.h (nonexistent) +++ ps2kbd.h (revision 1765) @@ -0,0 +1,72 @@ +/* ps2kbd.h -- Very simple PS/2 keyboard simulation header file + Copyright (C) 2002 Marko Mlinar, markom@opencores.org + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _PS2KBD_H_ +#define _PS2KBD_H_ + +/* Device registers */ +#define KBD_CTRL 4 +#define KBD_DATA 0 +#define KBD_SPACE 8 + +/* Keyboard commands */ +#define KBD_KCMD_RST 0xFF +#define KBD_KCMD_DK 0xF5 +#define KBD_KCMD_EK 0xF4 +#define KBD_KCMD_ECHO 0xFF +#define KBD_KCMD_SRL 0xED + +/* Keyboard responses */ +#define KBD_KRESP_RSTOK 0xAA +#define KBD_KRESP_ECHO 0xEE +#define KBD_KRESP_ACK 0xFA + +/* Controller commands */ +#define KBD_CCMD_RCB 0x20 +#define KBD_CCMD_WCB 0x60 +#define KBD_CCMD_ST1 0xAA +#define KBD_CCMD_ST2 0xAB +#define KBD_CCMD_DKI 0xAD +#define KBD_CCMD_EKI 0xAE + +/* Status register bits */ +#define KBD_STATUS_OBF 0x01 +#define KBD_STATUS_IBF 0x02 +#define KBD_STATUS_SYS 0x04 +#define KBD_STATUS_A2 0x08 +#define KBD_STATUS_INH 0x10 +#define KBD_STATUS_MOBF 0x20 +#define KBD_STATUS_TO 0x40 +#define KBD_STATUS_PERR 0x80 + +/* Command byte register bits */ +#define KBD_CCMDBYTE_INT 0x01 +#define KBD_CCMDBYTE_INT2 0x02 +#define KBD_CCMDBYTE_SYS 0x04 +#define KBD_CCMDBYTE_EN 0x10 +#define KBD_CCMDBYTE_EN2 0x20 +#define KBD_CCMDBYTE_XLAT 0x40 + +/* Length of internal scan code fifo */ +#define KBD_MAX_BUF 0x100 + +/* Keyboard is checked every KBD_SLOWDOWN cycle */ +#define KBD_BAUD_RATE 1200 + +#endif /* !_PS2KBD_H_ */
ps2kbd.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: fb.h =================================================================== --- fb.h (nonexistent) +++ fb.h (revision 1765) @@ -0,0 +1,35 @@ +/* fb.h -- Definition of types and structures for simple frame buffer. + Copyright (C) 2002 Marko Mlinar, markom@opencores.org + +NOTE: device is only partially implemented! + +This file is part of OpenRISC 1000 Architectural Simulator. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _FB_H_ +#define _FB_H_ + +#define FB_SIZEX 640 +#define FB_SIZEY 480 + +#define FB_CTRL 0x0000 +#define FB_BUFADDR 0x0004 +#define FB_PAL 0x0400 + +/* Reset all frame buffers */ +void fb_reset (); + +#endif /* _VGA_H_ */
fb.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: mc.c =================================================================== --- mc.c (nonexistent) +++ mc.c (revision 1765) @@ -0,0 +1,189 @@ +/* mc.c -- Simulation of Memory Controller + Copyright (C) 2001 by Marko Mlinar, markom@opencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Enable memory controller, via: + section mc + enable = 1 + POC = 0x13243545 + end + + Limitations: + - memory refresh is not simulated +*/ + +#include "mc.h" +#include "abstract.h" +#include "sim-config.h" + +extern struct dev_memarea *dev_list; + +static struct mc mc; + +void set_csc_tms (int cs, unsigned long csc, unsigned long tms) { + struct dev_memarea *mem_dev = dev_list; + + while (mem_dev) { + if (mem_dev->chip_select == cs) { + mem_dev->addr_mask = 0xe0000000 | mc.ba_mask << 21; + mem_dev->addr_compare = ((csc >> MC_CSC_SEL_OFFSET) /* & 0xff*/) << 21; + mem_dev->valid = (csc >> MC_CSC_EN_OFFSET) & 0x01; + + if ((csc >> MC_CSC_MEMTYPE_OFFSET) && 0x07 == MC_CSC_MEMTYPE_ASYNC) { + mem_dev->delayr = (tms & 0xff) + ((tms >> 8) & 0x0f); + mem_dev->delayw = ((tms >> 12) & 0x0f) + ((tms >> 16) & 0x0f) + ((tms >> 20) & 0x3f); + } else if ((csc >> MC_CSC_MEMTYPE_OFFSET) && 0x07 == MC_CSC_MEMTYPE_SDRAM) { + mem_dev->delayr = 3 + ((tms >> 4) & 0x03); + mem_dev->delayw = 3 + ((tms >> 4) & 0x03); + } else if ((csc >> MC_CSC_MEMTYPE_OFFSET) && 0x07 == MC_CSC_MEMTYPE_SSRAM) { + mem_dev->delayr = 2; + mem_dev->delayw = 2; + } else if ((csc >> MC_CSC_MEMTYPE_OFFSET) && 0x07 == MC_CSC_MEMTYPE_SYNC) { + mem_dev->delayr = 2; + mem_dev->delayw = 2; + } + return; + } + mem_dev = mem_dev->next; + } +} + +/* Set a specific MC register with value. */ +void mc_write_word(unsigned long addr, unsigned long value) +{ + int chipsel; + + debug(5, "mc_write_word(%x,%08x)\n", addr, (unsigned)value); + + addr -= config.mc.baseaddr; + + switch (addr) { + case MC_CSR: + mc.csr = value; + break; + case MC_POC: + fprintf (stderr, "warning: write to MC's POC register!"); + break; + case MC_BA_MASK: + mc.ba_mask = value & MC_BA_MASK_VALID; + for (chipsel = 0; chipsel < N_CE; chipsel++) + set_csc_tms (chipsel, mc.csc[chipsel], mc.tms[chipsel]); + break; + default: + if (addr >= MC_CSC(0) && addr <= MC_TMS(N_CE - 1)) { + addr -= MC_CSC(0); + if ((addr >> 2) & 1) + mc.tms[addr >> 3] = value; + else + mc.csc[addr >> 3] = value; + + set_csc_tms (addr >> 3, mc.csc[addr >> 3], mc.tms[addr >> 3]); + break; + } else + debug(1, "write out of range (addr %x)\n", addr + config.mc.baseaddr); + } +} + +/* Read a specific MC register. */ +unsigned long mc_read_word(unsigned long addr) +{ + unsigned long value = 0; + int chipsel; + + debug(5, "mc_read_word(%x)", addr); + + addr -= config.mc.baseaddr; + + switch (addr) { + case MC_CSR: + value = mc.csr; + break; + case MC_POC: + value = mc.poc; + break; + case MC_BA_MASK: + value = mc.ba_mask; + break; + default: + if (addr >= MC_CSC(0) && addr <= MC_TMS(N_CE - 1)) { + addr -= MC_CSC(0); + if ((addr >> 2) & 1) + value = mc.tms[addr >> 3]; + else + value = mc.csc[addr >> 3]; + } else + debug(1, " read out of range (addr %x)\n", addr + config.mc.baseaddr); + break; + } + debug(5, " value(%x)\n", value); + return value; +} + +/* Read POC register and init memory controler regs. */ +void mc_reset() +{ + struct dev_memarea *mem_dev = dev_list; + + if (config.mc.enabled) { + printf("Resetting memory controller.\n"); + memset(&mc, 0, sizeof(struct mc)); + + mc.poc = config.mc.POC; + + /* Set CS0 */ + mc.csc[0] = (((config.mc.POC & 0x0c) >> 2) << MC_CSC_MEMTYPE_OFFSET) | ((config.mc.POC & 0x03) << MC_CSC_BW_OFFSET) | 1; + + if ((mc.csc[0] >> MC_CSC_MEMTYPE_OFFSET) && 0x07 == MC_CSC_MEMTYPE_ASYNC) { + mc.tms[0] = MC_TMS_ASYNC_VALID; + } else if ((mc.csc[0] >> MC_CSC_MEMTYPE_OFFSET) && 0x07 == MC_CSC_MEMTYPE_SDRAM) { + mc.tms[0] = MC_TMS_SDRAM_VALID; + } else if ((mc.csc[0] >> MC_CSC_MEMTYPE_OFFSET) && 0x07 == MC_CSC_MEMTYPE_SSRAM) { + mc.tms[0] = MC_TMS_SSRAM_VALID; + } else if ((mc.csc[0] >> MC_CSC_MEMTYPE_OFFSET) && 0x07 == MC_CSC_MEMTYPE_SYNC) { + mc.tms[0] = MC_TMS_SYNC_VALID; + } + + while (mem_dev) { + mem_dev->valid = 0; + mem_dev = mem_dev->next; + } + + set_csc_tms (0, mc.csc[0], mc.tms[0]); + + register_memoryarea(config.mc.baseaddr, MC_ADDR_SPACE, 4, mc_read_word, mc_write_word); + } +} + +inline void mc_clock() +{ +} + +void mc_status() +{ + int i; + + printf( "\nMemory Controller at 0x%08X:\n", config.mc.baseaddr ); + printf( "POC: 0x%08X\n", mc.poc ); + printf( "BAS: 0x%08X\n", mc.ba_mask ); + printf( "CSR: 0x%08X\n", mc.csr ); + + for (i=0; i
mc.c Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: ethernet.h =================================================================== --- ethernet.h (nonexistent) +++ ethernet.h (revision 1765) @@ -0,0 +1,174 @@ +/* ethernet.h -- Definition of types and structures for Ethernet MAC + Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __OR1KSIM_PERIPHERAL_ETHERNET_H +#define __OR1KSIM_PERIPHERAL_ETHERNET_H + +/* Exported function prototypes */ +void eth_reset( void ); +void eth_clock( void ); +void eth_status( void ); + + +/* Address space required by one Ethernet MAC */ +#define ETH_ADDR_SPACE 0x1000 + +/* Relative Register Addresses */ +#define ETH_MODER (4 * 0x00) +#define ETH_INT_SOURCE (4 * 0x01) +#define ETH_INT_MASK (4 * 0x02) +#define ETH_IPGT (4 * 0x03) +#define ETH_IPGR1 (4 * 0x04) +#define ETH_IPGR2 (4 * 0x05) +#define ETH_PACKETLEN (4 * 0x06) +#define ETH_COLLCONF (4 * 0x07) +#define ETH_TX_BD_NUM (4 * 0x08) +#define ETH_CTRLMODER (4 * 0x09) +#define ETH_MIIMODER (4 * 0x0A) +#define ETH_MIICOMMAND (4 * 0x0B) +#define ETH_MIIADDRESS (4 * 0x0C) +#define ETH_MIITX_DATA (4 * 0x0D) +#define ETH_MIIRX_DATA (4 * 0x0E) +#define ETH_MIISTATUS (4 * 0x0F) +#define ETH_MAC_ADDR0 (4 * 0x10) +#define ETH_MAC_ADDR1 (4 * 0x11) +#define ETH_HASH0 (4 * 0x12) +#define ETH_HASH1 (4 * 0x13) + +/* Where BD's are stored */ +#define ETH_BD_BASE 0x400 +#define ETH_BD_COUNT 0x100 +#define ETH_BD_SPACE (4 * ETH_BD_COUNT) + +/* Where to point DMA to transmit/receive */ +#define ETH_DMA_RX_TX 0x800 + +/* Field definitions for MODER */ +#define ETH_MODER_DMAEN_OFFSET 17 +#define ETH_MODER_RECSMALL_OFFSET 16 +#define ETH_MODER_PAD_OFFSET 15 +#define ETH_MODER_HUGEN_OFFSET 14 +#define ETH_MODER_CRCEN_OFFSET 13 +#define ETH_MODER_DLYCRCEN_OFFSET 12 +#define ETH_MODER_RST_OFFSET 11 +#define ETH_MODER_FULLD_OFFSET 10 +#define ETH_MODER_EXDFREN_OFFSET 9 +#define ETH_MODER_NOBCKOF_OFFSET 8 +#define ETH_MODER_LOOPBCK_OFFSET 7 +#define ETH_MODER_IFG_OFFSET 6 +#define ETH_MODER_PRO_OFFSET 5 +#define ETH_MODER_IAM_OFFSET 4 +#define ETH_MODER_BRO_OFFSET 3 +#define ETH_MODER_NOPRE_OFFSET 2 +#define ETH_MODER_TXEN_OFFSET 1 +#define ETH_MODER_RXEN_OFFSET 0 + +/* Field definitions for INT_SOURCE */ +#define ETH_INT_SOURCE_RXC_OFFSET 6 +#define ETH_INT_SOURCE_TXC_OFFSET 5 +#define ETH_INT_SOURCE_BUSY_OFFSET 4 +#define ETH_INT_SOURCE_RXE_OFFSET 3 +#define ETH_INT_SOURCE_RXB_OFFSET 2 +#define ETH_INT_SOURCE_TXE_OFFSET 1 +#define ETH_INT_SOURCE_TXB_OFFSET 0 + +/* Field definitions for INT_MASK */ +#define ETH_INT_MASK_RXC_M_OFFSET 6 +#define ETH_INT_MASK_TXC_M_OFFSET 5 +#define ETH_INT_MASK_BUSY_M_OFFSET 4 +#define ETH_INT_MASK_RXE_M_OFFSET 3 +#define ETH_INT_MASK_RXB_M_OFFSET 2 +#define ETH_INT_MASK_TXE_M_OFFSET 1 +#define ETH_INT_MASK_TXB_M_OFFSET 0 + +/* Field definitions for PACKETLEN */ +#define ETH_PACKETLEN_MINFL_OFFSET 16 +#define ETH_PACKETLEN_MINFL_WIDTH 16 +#define ETH_PACKETLEN_MAXFL_OFFSET 0 +#define ETH_PACKETLEN_MAXFL_WIDTH 16 + +/* Field definitions for COLLCONF */ +#define ETH_COLLCONF_MAXRET_OFFSET 16 +#define ETH_COLLCONF_MAXRET_WIDTH 4 +#define ETH_COLLCONF_COLLVALID_OFFSET 0 +#define ETH_COLLCONF_COLLVALID_WIDTH 6 + +/* Field definitions for CTRLMODER */ +#define ETH_CMODER_TXFLOW_OFFSET 2 +#define ETH_CMODER_RXFLOW_OFFSET 1 +#define ETH_CMODER_PASSALL_OFFSET 0 + +/* Field definitions for MIIMODER */ +#define ETH_MIIMODER_MRST_OFFSET 9 +#define ETH_MIIMODER_NOPRE_OFFSET 8 +#define ETH_MIIMODER_CLKDIV_OFFSET 0 +#define ETH_MIIMODER_CLKDIV_WIDTH 8 + +/* Field definitions for MIICOMMAND */ +#define ETH_MIICOMM_WCDATA_OFFSET 2 +#define ETH_MIICOMM_RSTAT_OFFSET 1 +#define ETH_MIICOMM_SCANS_OFFSET 0 + +/* Field definitions for MIIADDRESS */ +#define ETH_MIIADDR_RGAD_OFFSET 8 +#define ETH_MIIADDR_RGAD_WIDTH 5 +#define ETH_MIIADDR_FIAD_OFFSET 0 +#define ETH_MIIADDR_FIAD_WIDTH 5 + +/* Field definitions for MIISTATUS */ +#define ETH_MIISTAT_NVALID_OFFSET 1 +#define ETH_MIISTAT_BUSY_OFFSET 1 +#define ETH_MIISTAT_FAIL_OFFSET 0 + +/* Field definitions for TX buffer descriptors */ +#define ETH_TX_BD_LENGTH_OFFSET 16 +#define ETH_TX_BD_LENGTH_WIDTH 16 +#define ETH_TX_BD_READY_OFFSET 15 +#define ETH_TX_BD_INTERRUPT_OFFSET 14 +#define ETH_TX_BD_WRAP_OFFSET 13 +#define ETH_TX_BD_PAD_OFFSET 12 +#define ETH_TX_BD_CRC_OFFSET 11 +#define ETH_TX_BD_LAST_OFFSET 10 +#define ETH_TX_BD_PAUSE_OFFSET 9 +#define ETH_TX_BD_UNDERRUN_OFFSET 8 +#define ETH_TX_BD_RETRY_OFFSET 4 +#define ETH_TX_BD_RETRY_WIDTH 4 +#define ETH_TX_BD_RETRANSMIT_OFFSET 3 +#define ETH_TX_BD_COLLISION_OFFSET 2 +#define ETH_TX_BD_DEFER_OFFSET 1 +#define ETH_TX_BD_NO_CARRIER_OFFSET 0 + + +/* Field definitions for RX buffer descriptors */ +#define ETH_RX_BD_LENGTH_OFFSET 16 +#define ETH_RX_BD_LENGTH_WIDTH 16 +#define ETH_RX_BD_READY_OFFSET 15 +#define ETH_RX_BD_INTERRUPT_OFFSET 14 +#define ETH_RX_BD_WRAP_OFFSET 13 +#define ETH_RX_BD_MISS_OFFSET 7 +#define ETH_RX_BD_UVERRUN_OFFSET 6 +#define ETH_RX_BD_INVALID_OFFSET 5 +#define ETH_RX_BD_DRIBBLE_OFFSET 4 +#define ETH_RX_BD_TOOBIG_OFFSET 3 +#define ETH_RX_BD_TOOSHORT_OFFSET 2 +#define ETH_RX_BD_CRC_OFFSET 1 +#define ETH_RX_BD_COLLISION_OFFSET 0 + +#endif /* __OR1KSIM_PERIPHERAL_ETHERNET_H */ Index: ethernet_i.h =================================================================== --- ethernet_i.h (nonexistent) +++ ethernet_i.h (revision 1765) @@ -0,0 +1,196 @@ +/* ethernet_i.h -- Definition of internal types and structures for Ethernet MAC + Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __OR1KSIM_PERIPHERAL_ETHERNET_I_H +#define __OR1KSIM_PERIPHERAL_ETHERNET_I_H + +#include "ethernet.h" +#include "config.h" +#include +#include +#include +#include + +/* + * Ethernet protocol definitions + */ +#if HAVE_NET_ETHERNET_H +# include +#else /* !HAVE_NET_ETHERNET_H -*/ + +#include + +#define ETH_ALEN 6 + +struct ether_addr +{ + u_int8_t ether_addr_octet[ETH_ALEN]; +}; + +struct ether_header +{ + u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ + u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ + u_int16_t ether_type; /* packet type ID field */ +}; + +/* Ethernet protocol ID's */ +#define ETHERTYPE_PUP 0x0200 /* Xerox PUP */ +#define ETHERTYPE_IP 0x0800 /* IP */ +#define ETHERTYPE_ARP 0x0806 /* Address resolution */ +#define ETHERTYPE_REVARP 0x8035 /* Reverse ARP */ + +#define ETHER_ADDR_LEN ETH_ALEN /* size of ethernet addr */ +#define ETHER_TYPE_LEN 2 /* bytes in type field */ +#define ETHER_CRC_LEN 4 /* bytes in CRC field */ +#define ETHER_HDR_LEN ETH_HLEN /* total octets in header */ +#define ETHER_MIN_LEN (ETH_ZLEN + ETHER_CRC_LEN) /* min packet length */ +#define ETHER_MAX_LEN (ETH_FRAME_LEN + ETHER_CRC_LEN) /* max packet length */ + +/* make sure ethenet length is valid */ +#define ETHER_IS_VALID_LEN(foo) \ + ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) + +/* + * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have + * (type-ETHERTYPE_TRAIL)*512 bytes of data followed + * by an ETHER type (as given above) and then the (variable-length) header. + */ +#define ETHERTYPE_TRAIL 0x1000 /* Trailer packet */ +#define ETHERTYPE_NTRAILER 16 + +#define ETHERMTU ETH_DATA_LEN +#define ETHERMIN (ETHER_MIN_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN) + +#endif /* HAVE_NET_ETHERNET_H */ + + +/* + * Implementatino of Ethernet MAC Registers and State + */ +#define ETH_TXSTATE_IDLE 0 +#define ETH_TXSTATE_WAIT4BD 10 +#define ETH_TXSTATE_READFIFO 20 +#define ETH_TXSTATE_TRANSMIT 30 + +#define ETH_RXSTATE_IDLE 0 +#define ETH_RXSTATE_WAIT4BD 10 +#define ETH_RXSTATE_RECV 20 +#define ETH_RXSTATE_WRITEFIFO 30 + +#define ETH_RTX_FILE 0 +#define ETH_RTX_SOCK 1 + +#define ETH_MAXPL 0x10000 + +struct eth_device +{ + /* Base address in memory */ + unsigned long baseaddr; + + /* Which Ethernet MAC is this? */ + unsigned eth_number; + + /* Which DMA controller is this MAC connected to */ + unsigned dma; + unsigned tx_channel; + unsigned rx_channel; + + /* Our address */ + unsigned char mac_address[ETH_ALEN]; + + /* interrupt line */ + unsigned long mac_int; + + /* RX and TX file names and handles */ + const char *rxfile, *txfile; + int txfd; + int rxfd; + off_t loopback_offset; + + int rtx_sock; + int rtx_type; + struct ifreq ifr; + fd_set rfds, wfds; + + /* Current TX state */ + struct + { + unsigned long state; + unsigned long bd_index; + unsigned long bd; + unsigned long bd_addr; + unsigned working, waiting_for_dma, error; + long packet_length; + unsigned minimum_length, maximum_length; + unsigned add_crc; + unsigned crc_dly; + unsigned long crc_value; + long bytes_left, bytes_sent; + } tx; + + /* Current RX state */ + struct + { + unsigned long state; + unsigned long bd_index; + unsigned long bd; + unsigned long bd_addr; + int fd; + off_t *offset; + unsigned working, error, waiting_for_dma; + long packet_length, bytes_read, bytes_left; + } rx; + + /* Visible registers */ + struct + { + unsigned long moder; + unsigned long int_source; + unsigned long int_mask; + unsigned long ipgt; + unsigned long ipgr1; + unsigned long ipgr2; + unsigned long packetlen; + unsigned long collconf; + unsigned long tx_bd_num; + unsigned long controlmoder; + unsigned long miimoder; + unsigned long miicommand; + unsigned long miiaddress; + unsigned long miitx_data; + unsigned long miirx_data; + unsigned long miistatus; + unsigned long hash0; + unsigned long hash1; + + /* Buffer descriptors */ + unsigned long bd_ram[ETH_BD_SPACE / 4]; + } regs; + + unsigned char rx_buff[ETH_MAXPL]; + unsigned char tx_buff[ETH_MAXPL]; + unsigned char lo_buff[ETH_MAXPL]; +}; + + + + +#endif /* __OR1KSIM_PERIPHERAL_ETHERNET_I_H */ Index: mc.h =================================================================== --- mc.h (nonexistent) +++ mc.h (revision 1765) @@ -0,0 +1,123 @@ +/* mc.h -- Simulation of Memory Controller + Copyright (C) 2001 by Marko Mlinar, markom@opencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Prototypes */ +#ifndef __MC_H +#define __MC_H + +void mc_reset(); +void mc_status(); +inline void mc_clock(); + +#define N_CE (8) + +#define MC_CSR (0x00) +#define MC_POC (0x04) +#define MC_BA_MASK (0x08) +#define MC_CSC(i) (0x10 + (i) * 8) +#define MC_TMS(i) (0x14 + (i) * 8) + +#define MC_ADDR_SPACE (MC_CSC(N_CE)) + +/* POC register field definition */ +#define MC_POC_EN_BW_OFFSET 0 +#define MC_POC_EN_BW_WIDTH 2 +#define MC_POC_EN_MEMTYPE_OFFSET 2 +#define MC_POC_EN_MEMTYPE_WIDTH 2 + +/* CSC register field definition */ +#define MC_CSC_EN_OFFSET 0 +#define MC_CSC_MEMTYPE_OFFSET 1 +#define MC_CSC_MEMTYPE_WIDTH 2 +#define MC_CSC_BW_OFFSET 4 +#define MC_CSC_BW_WIDTH 2 +#define MC_CSC_MS_OFFSET 6 +#define MC_CSC_MS_WIDTH 2 +#define MC_CSC_WP_OFFSET 8 +#define MC_CSC_BAS_OFFSET 9 +#define MC_CSC_KRO_OFFSET 10 +#define MC_CSC_PEN_OFFSET 11 +#define MC_CSC_SEL_OFFSET 16 +#define MC_CSC_SEL_WIDTH 8 + +#define MC_CSC_MEMTYPE_SDRAM 0 +#define MC_CSC_MEMTYPE_SSRAM 1 +#define MC_CSC_MEMTYPE_ASYNC 2 +#define MC_CSC_MEMTYPE_SYNC 3 + +#define MC_CSR_VALID 0xFF000703LU +#define MC_POC_VALID 0x0000000FLU +#define MC_BA_MASK_VALID 0x000000FFLU +#define MC_CSC_VALID 0x00FF0FFFLU +#define MC_TMS_SDRAM_VALID 0x0FFF83FFLU +#define MC_TMS_SSRAM_VALID 0x00000000LU +#define MC_TMS_ASYNC_VALID 0x03FFFFFFLU +#define MC_TMS_SYNC_VALID 0x01FFFFFFLU +#define MC_TMS_VALID 0xFFFFFFFFLU /* reg test compat. */ + +/* TMS register field definition SDRAM */ +#define MC_TMS_SDRAM_TRFC_OFFSET 24 +#define MC_TMS_SDRAM_TRFC_WIDTH 4 +#define MC_TMS_SDRAM_TRP_OFFSET 20 +#define MC_TMS_SDRAM_TRP_WIDTH 4 +#define MC_TMS_SDRAM_TRCD_OFFSET 17 +#define MC_TMS_SDRAM_TRCD_WIDTH 4 +#define MC_TMS_SDRAM_TWR_OFFSET 15 +#define MC_TMS_SDRAM_TWR_WIDTH 2 +#define MC_TMS_SDRAM_WBL_OFFSET 9 +#define MC_TMS_SDRAM_OM_OFFSET 7 +#define MC_TMS_SDRAM_OM_WIDTH 2 +#define MC_TMS_SDRAM_CL_OFFSET 4 +#define MC_TMS_SDRAM_CL_WIDTH 3 +#define MC_TMS_SDRAM_BT_OFFSET 3 +#define MC_TMS_SDRAM_BL_OFFSET 0 +#define MC_TMS_SDRAM_BL_WIDTH 3 + +/* TMS register field definition ASYNC */ +#define MC_TMS_ASYNC_TWWD_OFFSET 20 +#define MC_TMS_ASYNC_TWWD_WIDTH 6 +#define MC_TMS_ASYNC_TWD_OFFSET 16 +#define MC_TMS_ASYNC_TWD_WIDTH 4 +#define MC_TMS_ASYNC_TWPW_OFFSET 12 +#define MC_TMS_ASYNC_TWPW_WIDTH 4 +#define MC_TMS_ASYNC_TRDZ_OFFSET 8 +#define MC_TMS_ASYNC_TRDZ_WIDTH 4 +#define MC_TMS_ASYNC_TRDV_OFFSET 0 +#define MC_TMS_ASYNC_TRDV_WIDTH 8 + +/* TMS register field definition SYNC */ +#define MC_TMS_SYNC_TTO_OFFSET 16 +#define MC_TMS_SYNC_TTO_WIDTH 9 +#define MC_TMS_SYNC_TWR_OFFSET 12 +#define MC_TMS_SYNC_TWR_WIDTH 4 +#define MC_TMS_SYNC_TRDZ_OFFSET 8 +#define MC_TMS_SYNC_TRDZ_WIDTH 4 +#define MC_TMS_SYNC_TRDV_OFFSET 0 +#define MC_TMS_SYNC_TRDV_WIDTH 8 + +struct mc { + unsigned long csr; + unsigned long poc; + unsigned long ba_mask; + unsigned long csc[N_CE]; + unsigned long tms[N_CE]; +}; + +#endif
mc.h Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: Makefile.in =================================================================== --- Makefile.in (nonexistent) +++ Makefile.in (revision 1765) @@ -0,0 +1,334 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Makefile -- Makefile for peripherals simulation +# Copyright (C) 1999 Damjan Lampret, lampret@opencores.org +# +# This file is part of OpenRISC 1000 Architectural Simulator. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AR = @AR@ +ARFLAGS = @ARFLAGS@ +BUILD_DIR = @BUILD_DIR@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPU_ARCH = @CPU_ARCH@ +INCLUDES = @INCLUDES@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +LOCAL_DEFS = @LOCAL_DEFS@ +LOCAL_LDFLAGS = @LOCAL_LDFLAGS@ +MAKEINFO = @MAKEINFO@ +MAKE_SHELL = @MAKE_SHELL@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +SUMVERSION = @SUMVERSION@ +TERMCAP_LIB = @TERMCAP_LIB@ +VERSION = @VERSION@ +host = @host@ +host_cpu = @host_cpu@ +host_os = @host_os@ + +noinst_LIBRARIES = libperipheral.a +libperipheral_a_SOURCES = 16450.c dma.c mc.c eth.c crc32.c gpio.c vga.c fb.c ps2kbd.c +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libperipheral_a_LIBADD = +libperipheral_a_OBJECTS = 16450.o dma.o mc.o eth.o crc32.o gpio.o vga.o \ +fb.o ps2kbd.o +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +DEP_FILES = .deps/16450.P .deps/crc32.P .deps/dma.P .deps/eth.P \ +.deps/fb.P .deps/gpio.P .deps/mc.P .deps/ps2kbd.P .deps/vga.P +SOURCES = $(libperipheral_a_SOURCES) +OBJECTS = $(libperipheral_a_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu peripheral/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libperipheral.a: $(libperipheral_a_OBJECTS) $(libperipheral_a_DEPENDENCIES) + -rm -f libperipheral.a + $(AR) cru libperipheral.a $(libperipheral_a_OBJECTS) $(libperipheral_a_LIBADD) + $(RANLIB) libperipheral.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = peripheral + +distdir: $(DISTFILES) + here=`cd $(top_builddir) && pwd`; \ + top_distdir=`cd $(top_distdir) && pwd`; \ + distdir=`cd $(distdir) && pwd`; \ + cd $(top_srcdir) \ + && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu peripheral/Makefile + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$d/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :) + +-include $(DEP_FILES) + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf .deps + +maintainer-clean-depend: + +%.o: %.c + @echo '$(COMPILE) -c $<'; \ + $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-cp .deps/$(*F).pp .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm .deps/$(*F).pp + +%.lo: %.c + @echo '$(LTCOMPILE) -c $<'; \ + $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*F).pp > .deps/$(*F).P; \ + tr ' ' '\012' < .deps/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*F).P; \ + rm -f .deps/$(*F).pp +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-depend mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-depend \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-tags distclean-depend distclean-generic \ + clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-depend maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir mostlyclean-depend \ +distclean-depend clean-depend maintainer-clean-depend info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: Index: Makefile.am =================================================================== --- Makefile.am (nonexistent) +++ Makefile.am (revision 1765) @@ -0,0 +1,22 @@ +# Makefile -- Makefile for peripherals simulation +# Copyright (C) 1999 Damjan Lampret, lampret@opencores.org +# +# This file is part of OpenRISC 1000 Architectural Simulator. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# + +noinst_LIBRARIES = libperipheral.a +libperipheral_a_SOURCES = 16450.c dma.c mc.c eth.c crc32.c gpio.c vga.c fb.c ps2kbd.c Index: fields.h =================================================================== --- fields.h (nonexistent) +++ fields.h (revision 1765) @@ -0,0 +1,59 @@ +/* fields.h -- Some macros to help with bit field definitions + Copyright (C) 2001 by Erez Volk, erez@opencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#ifndef __FIELDS_H +#define __FIELDS_H + + +/* Macros to get/set a field in a register + * Example: + * unsigned long done, priority, channel_csr; + * + * priority = GET_FIELD( channel_csr, DMA_CH_CSR, PRIORITY ); + * SET_FIELD( channel_csr, DMA_CH_CSR, PRIORITY, priority ); + * + * done = TEST_FLAG( channel_csr, DMA_CH_CSR, DONE ); + * SET_FLAG( channel_csr, DMA_CH_CSR, DONE ); + * CLEAR_FLAG( channel_csr, DMA_CH_CSR, DONE ); + * ASSIGN_FLAG( channel_csr, DMA_CH_CSR, done ); + * + * For each field, we then define e.g. + * #define DMA_CH_CSR_PRIORITY_OFFSET 13 + * #define DMA_CH_CSR_PRIORITY_WIDTH 3 // not needed for flags, which always have width = 1 + */ + +#define FLAG_SHIFT(reg_name,flag_name) (reg_name##_##flag_name##_OFFSET) +#define FLAG_MASK(reg_name,flag_name) (1LU << reg_name##_##flag_name##_OFFSET) + +#define TEST_FLAG(reg_value,reg_name,flag_name) (((reg_value ) >> reg_name##_##flag_name##_OFFSET) & 1LU) +#define SET_FLAG(reg_value,reg_name,flag_name) { (reg_value) |= 1LU << reg_name##_##flag_name##_OFFSET; } +#define CLEAR_FLAG(reg_value,reg_name,flag_name) { (reg_value) &= ~(1LU << reg_name##_##flag_name##_OFFSET); } +#define ASSIGN_FLAG(reg_value,reg_name,flag_name,flag_value) { \ + (reg_value) = flag_value ? ((reg_value) | (1LU << reg_name##_##flag_name##_OFFSET)) : ((reg_value) & ~(1LU << reg_name##_##flag_name##_OFFSET)); } + +#define FIELD_SHIFT(reg_name,field_name) (reg_name##_##field_name##_OFFSET) +#define FIELD_MASK(reg_name,field_name) ((~(~0LU << reg_name##_##field_name##_WIDTH)) << reg_name##_##field_name##_OFFSET) + +#define GET_FIELD(reg_value,reg_name,field_name) (((reg_value) >> reg_name##_##field_name##_OFFSET) & (~(~0LU << reg_name##_##field_name##_WIDTH))) +#define SET_FIELD(reg_value,reg_name,field_name,field_value) { \ + (reg_value) = ((reg_value) & ~((~(~0LU << reg_name##_##field_name##_WIDTH)) << reg_name##_##field_name##_OFFSET)) | ((field_value) << reg_name##_##field_name##_OFFSET); } + +#endif /* __FIELDS_H */ Index: gpio.c =================================================================== --- gpio.c (nonexistent) +++ gpio.c (revision 1765) @@ -0,0 +1,291 @@ +/* gpio.h -- GPIO code simulation + Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "gpio.h" +#include "gpio_i.h" +#include "sim-config.h" +#include "pic.h" +#include "vapi.h" + +static struct gpio_device gpios[MAX_GPIOS]; + +static void gpio_vapi_read( unsigned long id, unsigned long data ); +static unsigned long gpio_read32( unsigned long addr ); +static void gpio_write32( unsigned long addr, unsigned long value ); + +static void gpio_external_clock( unsigned long value ); +static void gpio_device_clock( struct gpio_device *gpio ); +static int gpio_find_device( unsigned long addr, struct gpio_device **gpio, unsigned long *reladdr ); +static struct gpio_device *gpio_find_vapi_device( unsigned long id, unsigned *which_vapi ); + +/* Initialize all parameters and state */ +void gpio_reset( void ) +{ + static int first_time = 1; + unsigned i, j; + + if ( first_time ) { + memset( gpios, 0, sizeof(gpios) ); + first_time = 0; + } + + for ( i = 0; i < config.ngpios; ++ i ) { + struct gpio_device *gpio = &(gpios[i]); + + gpio->gpio_number = i; + gpio->baseaddr = config.gpios[i].baseaddr; + + if ( gpio->baseaddr != 0 ) { + /* Get IRQ */ + gpio->irq = config.gpios[i].irq; + + /* Register memory range */ + register_memoryarea( gpio->baseaddr, GPIO_ADDR_SPACE, 4, gpio_read32, gpio_write32 ); + + /* Possibly connect to VAPI */ + if ( config.gpios[i].base_vapi_id ) { + gpio->base_vapi_id = config.gpios[i].base_vapi_id; + vapi_install_multi_handler( gpio->base_vapi_id, GPIO_NUM_VAPI_IDS, gpio_vapi_read ); + } + } + } +} + + +/* Dump status */ +void gpio_status( void ) +{ + unsigned i; + + for ( i = 0; i < config.ngpios; ++ i ) { + struct gpio_device *gpio = &(gpios[i]); + + if ( gpio->baseaddr == 0 ) + continue; + + printf( "\nGPIO %u at 0x%08X:\n", i, gpio->baseaddr ); + printf( "RGPIO_IN : 0x%08lX\n", gpio->curr.in ); + printf( "RGPIO_OUT : 0x%08lX\n", gpio->curr.out ); + printf( "RGPIO_OE : 0x%08lX\n", gpio->curr.oe ); + printf( "RGPIO_INTE : 0x%08lX\n", gpio->curr.inte ); + printf( "RGPIO_PTRIG : 0x%08lX\n", gpio->curr.ptrig ); + printf( "RGPIO_AUX : 0x%08lX\n", gpio->curr.aux ); + printf( "RGPIO_CTRL : 0x%08lX\n", gpio->curr.ctrl ); + printf( "RGPIO_INTS : 0x%08lX\n", gpio->curr.ints ); + } +} + + +/* Convert a memory address to a device struct and relative address. + * Return nonzero on success */ +int gpio_find_device( unsigned long addr, struct gpio_device **gpio, unsigned long *reladdr ) +{ + unsigned i; + *gpio = NULL; + + for ( i = 0; i < config.ngpios && *gpio == NULL; ++ i ) { + if ( (addr >= gpios[i].baseaddr) && (addr < gpios[i].baseaddr + GPIO_ADDR_SPACE) ) + *gpio = &(gpios[i]); + } + + /* verify we found a device */ + if ( *gpio == NULL ) + return 0; + + /* Verify legal address */ + if ( (addr - (*gpio)->baseaddr) % 4 != 0 ) + return 0; + + *reladdr = addr - (*gpio)->baseaddr; + return 1; +} + + +/* Find device by vapi id */ +struct gpio_device *gpio_find_vapi_device( unsigned long id, unsigned *which ) +{ + unsigned i, j; + + for ( i = 0; i < config.ngpios; ++ i ) + if ( (id >= gpios[i].base_vapi_id) && (id < gpios[i].base_vapi_id + GPIO_NUM_VAPI_IDS) ) { + *which = id - gpios[i].base_vapi_id; + return &(gpios[i]); + } + + return NULL; +} + + +/* Wishbone read */ +unsigned long gpio_read32( unsigned long addr ) +{ + struct gpio_device *gpio; + if ( !gpio_find_device( addr, &gpio, &addr ) ) { + debug( 2, "gpio_read32( 0x%08lX ): Not in registered range(s)\n", addr ); + return 0; + } + + switch( addr ) { + case RGPIO_IN: return gpio->curr.in | gpio->curr.out; + case RGPIO_OUT: return gpio->curr.out; + case RGPIO_OE: return gpio->curr.oe; + case RGPIO_INTE: return gpio->curr.inte; + case RGPIO_PTRIG: return gpio->curr.ptrig; + case RGPIO_AUX: return gpio->curr.aux; + case RGPIO_CTRL: return gpio->curr.ctrl; + case RGPIO_INTS: return gpio->curr.ints; + } +} + + +/* Wishbone write */ +void gpio_write32( unsigned long addr, unsigned long value ) +{ + struct gpio_device *gpio; + if ( !gpio_find_device( addr, &gpio, &addr ) ) { + debug( 2, "gpio_write32( 0x%08lX ): Not in registered range(s)\n", addr ); + return; + } + + switch( addr ) { + case RGPIO_IN: debug( 5, "GPIO: Cannot write to RGPIO_IN\n" ); break; + case RGPIO_OUT: gpio->next.out = value; break; + case RGPIO_OE: gpio->next.oe = value; break; + case RGPIO_INTE: gpio->next.inte = value; break; + case RGPIO_PTRIG: gpio->next.ptrig = value; break; + case RGPIO_AUX: gpio->next.aux = value; break; + case RGPIO_CTRL: gpio->next.ctrl = value; break; + case RGPIO_INTS: gpio->next.ints = value; break; + } +} + + +/* Input from "outside world" */ +void gpio_vapi_read( unsigned long id, unsigned long data ) +{ + unsigned which; + struct gpio_device *gpio = gpio_find_vapi_device( id, &which ); + + debug( 5, "GPIO: id %08x, data %08x\n", id, data ); + + if ( !gpio ) { + debug( 1, "GPIO: VAPI ID %08x is not ours!\n", id ); + return; + } + + switch( which ) { + case GPIO_VAPI_DATA: + debug( 4, "GPIO: Next input from VAPI = 0x%08x (RGPIO_OE = 0x%08x)\n", data, gpio->next.oe ); + gpio->next.in = data; + break; + case GPIO_VAPI_AUX: + gpio->auxiliary_inputs = data; + break; + case GPIO_VAPI_RGPIO_OE: + gpio->next.oe = data; + break; + case GPIO_VAPI_RGPIO_INTE: + gpio->next.inte = data; + break; + case GPIO_VAPI_RGPIO_PTRIG: + gpio->next.ptrig = data; + break; + case GPIO_VAPI_RGPIO_AUX: + gpio->next.aux = data; + break; + case GPIO_VAPI_RGPIO_CTRL: + gpio->next.ctrl = data; + break; + case GPIO_VAPI_CLOCK: + gpio_external_clock( data ); + break; + } +} + +/* System Clock. */ +void gpio_clock( void ) +{ + unsigned i; + + for ( i = 0; i < config.ngpios; ++ i ) + if ( !(gpios[i].curr.ctrl & RGPIO_CTRL_ECLK) ) + gpio_device_clock( &(gpios[i]) ); +} + +/* External Clock. */ +void gpio_external_clock( unsigned long value ) +{ + unsigned i; + + /* "Normalize" clock value */ + value = (value != 0); + + for ( i = 0; i < config.ngpios; ++ i ) { + struct gpio_device *gpio = &(gpios[i]); + + int use_external_clock = ((gpio->curr.ctrl & RGPIO_CTRL_ECLK) == RGPIO_CTRL_ECLK); + int negative_edge = ((gpio->curr.ctrl & RGPIO_CTRL_NEC) == RGPIO_CTRL_NEC); + + gpio->next.external_clock = value; + + if ( use_external_clock && (gpio->next.external_clock != gpio->curr.external_clock) && (value != negative_edge) ) + gpio_device_clock( gpio ); + } +} + + +/* Clock as handld by one device. */ +void gpio_device_clock( struct gpio_device *gpio ) +{ + /* Calculate new inputs and outputs */ + gpio->next.in &= ~gpio->next.oe; /* Only input bits */ + /* Replace requested output bits with aux input */ + gpio->next.out = (gpio->next.out & ~gpio->next.aux) | (gpio->auxiliary_inputs & gpio->next.aux); + gpio->next.out &= gpio->next.oe; /* Only output-enabled bits */ + + /* If any outputs changed, notify the world (i.e. vapi) */ + if ( gpio->next.out != gpio->curr.out ) { + debug( 4, "GPIO: New output 0x%08x, RGPIO_OE = 0x%08x\n", gpio->next.out, gpio->next.oe ); + if ( gpio->base_vapi_id ) + vapi_send( gpio->base_vapi_id + GPIO_VAPI_DATA, gpio->next.out ); + } + + /* If any inputs changed and interrupt enabled, generate interrupt */ + if ( gpio->next.in != gpio->curr.in ) { + debug( 4, "GPIO: New input 0x%08x\n", gpio->next.in ); + + if ( gpio->next.ctrl & RGPIO_CTRL_INTE ) { + unsigned changed_bits = gpio->next.in ^ gpio->curr.in; /* inputs that have changed */ + unsigned set_bits = changed_bits & gpio->next.in; /* inputs that have been set */ + unsigned cleared_bits = changed_bits & gpio->curr.in; /* inputs that have been cleared */ + unsigned relevant_bits = (gpio->next.ptrig & set_bits) | (~gpio->next.ptrig & cleared_bits); + + if ( relevant_bits & gpio->next.inte ) { + debug( 3, "GPIO: Reporting interrupt %d\n", gpio->irq ); + report_interrupt( gpio->irq ); + gpio->next.ctrl |= RGPIO_CTRL_INTS; + gpio->next.ints |= relevant_bits & gpio->next.inte; + } + } + } + + /* Switch to values for next clock */ + memcpy( &(gpio->curr), &(gpio->next), sizeof(gpio->curr) ); +} Index: dma.c =================================================================== --- dma.c (nonexistent) +++ dma.c (revision 1765) @@ -0,0 +1,478 @@ +/* dma.c -- Simulation of DMA + Copyright (C) 2001 by Erez Volk, erez@opencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + * This simulation of the DMA core is not meant to be full. + * It is written only to allow simulating the Ethernet core. + * Of course, if anyone feels like perfecting it, feel free... + */ + +#include "dma.h" +#include "sim-config.h" +#include "pic.h" +#include "abstract.h" +#include "fields.h" + +/* The representation of the DMA controllers */ +static struct dma_controller dmas[MAX_DMAS]; + +static unsigned long dma_read32( unsigned long addr ); +static void dma_write32( unsigned long addr, unsigned long value ); + +static unsigned long dma_read_ch_csr( struct dma_channel *channel ); +static void dma_write_ch_csr( struct dma_channel *channel, unsigned long value ); +static void dma_controller_clock( struct dma_controller *dma ); +static void dma_load_descriptor( struct dma_channel *channel ); +static void dma_init_transfer( struct dma_channel *channel ); +static void dma_channel_terminate_transfer( struct dma_channel *channel, int generate_interrupt ); + +static void masked_increase( unsigned long *value, unsigned long mask ); + +#define CHANNEL_ND_I(ch) (TEST_FLAG(ch->regs.csr,DMA_CH_CSR,MODE) && TEST_FLAG(ch->regs.csr,DMA_CH_CSR,USE_ED) && ch->dma_nd_i) + + +/* Reset. Initializes all registers to default and places devices in memory address space. */ +void dma_reset() +{ + unsigned i; + + memset( dmas, 0, sizeof(dmas) ); + + for ( i = 0; i < config.ndmas; ++ i ) { + struct dma_controller *dma = &(dmas[i]); + unsigned channel_number; + + dma->baseaddr = config.dmas[i].baseaddr; + dma->irq = config.dmas[i].irq; + for ( channel_number = 0; channel_number < DMA_NUM_CHANNELS; ++ channel_number ) { + dma->ch[channel_number].controller = &(dmas[i]); + dma->ch[channel_number].channel_number = channel_number; + dma->ch[channel_number].channel_mask = 1LU << channel_number; + dma->ch[channel_number].regs.am0 = dma->ch[channel_number].regs.am1 = 0xFFFFFFFC; + } + if ( dma->baseaddr != 0 ) + register_memoryarea( dma->baseaddr, DMA_ADDR_SPACE, 4, dma_read32, dma_write32); + } +} + +/* Print register values on stdout */ +void dma_status( void ) +{ + unsigned i, j; + + for ( i = 0; i < config.ndmas; ++ i ) { + struct dma_controller *dma = &(dmas[i]); + + if ( dma->baseaddr == 0 ) + continue; + + printf( "\nDMA controller %u at 0x%08X:\n", i, dma->baseaddr ); + printf( "CSR : 0x%08lX\n", dma->regs.csr ); + printf( "INT_MSK_A : 0x%08lX\n", dma->regs.int_msk_a ); + printf( "INT_MSK_B : 0x%08lX\n", dma->regs.int_msk_b ); + printf( "INT_SRC_A : 0x%08lX\n", dma->regs.int_src_a ); + printf( "INT_SRC_B : 0x%08lX\n", dma->regs.int_src_b ); + + for ( j = 0; j < DMA_NUM_CHANNELS; ++ j ) { + struct dma_channel *channel = &(dma->ch[j]); + if ( !channel->referenced ) + continue; + printf( "CH%u_CSR : 0x%08lX\n", j, channel->regs.csr ); + printf( "CH%u_SZ : 0x%08lX\n", j, channel->regs.sz ); + printf( "CH%u_A0 : 0x%08lX\n", j, channel->regs.a0 ); + printf( "CH%u_AM0 : 0x%08lX\n", j, channel->regs.am0 ); + printf( "CH%u_A1 : 0x%08lX\n", j, channel->regs.a1 ); + printf( "CH%u_AM1 : 0x%08lX\n", j, channel->regs.am1 ); + printf( "CH%u_DESC : 0x%08lX\n", j, channel->regs.desc ); + printf( "CH%u_SWPTR : 0x%08lX\n", j, channel->regs.swptr ); + } + } +} + + +/* Read a register */ +unsigned long dma_read32( unsigned long addr ) +{ + unsigned i; + struct dma_controller *dma = NULL; + + for ( i = 0; i < MAX_DMAS && dma == NULL; ++ i ) { + if ( addr >= dmas[i].baseaddr && addr < dmas[i].baseaddr + DMA_ADDR_SPACE ) + dma = &(dmas[i]); + } + + /* verify we found a controller */ + if ( dma == NULL ) { + fprintf( stderr, "dma_read32( 0x%08lX ): Out of range\n", addr ); + cont_run = 0; + return 0; + } + + addr -= dma->baseaddr; + + if ( addr % 4 != 0 ) { + fprintf( stderr, "dma_read32( 0x%08lX ): Not register-aligned\n", addr + dma->baseaddr ); + cont_run = 0; + return 0; + } + + if ( addr < DMA_CH_BASE ) { + /* case of global (not per-channel) registers */ + switch( addr ) { + case DMA_CSR: return dma->regs.csr; + case DMA_INT_MSK_A: return dma->regs.int_msk_a; + case DMA_INT_MSK_B: return dma->regs.int_msk_b; + case DMA_INT_SRC_A: return dma->regs.int_src_a; + case DMA_INT_SRC_B: return dma->regs.int_src_b; + default: + fprintf( stderr, "dma_read32( 0x%08lX ): Illegal register\n", addr + dma->baseaddr ); + cont_run = 0; + return 0; + } + } else { + /* case of per-channel registers */ + unsigned chno = (addr - DMA_CH_BASE) / DMA_CH_SIZE; + addr = (addr - DMA_CH_BASE) % DMA_CH_SIZE; + switch( addr ) { + case DMA_CH_CSR: return dma_read_ch_csr( &(dma->ch[chno]) ); + case DMA_CH_SZ: return dma->ch[chno].regs.sz; + case DMA_CH_A0: return dma->ch[chno].regs.a0; + case DMA_CH_AM0: return dma->ch[chno].regs.am0; + case DMA_CH_A1: return dma->ch[chno].regs.a1; + case DMA_CH_AM1: return dma->ch[chno].regs.am1; + case DMA_CH_DESC: return dma->ch[chno].regs.desc; + case DMA_CH_SWPTR: return dma->ch[chno].regs.swptr; + } + } +} + + +/* Handle read from a channel CSR */ +unsigned long dma_read_ch_csr( struct dma_channel *channel ) +{ + unsigned long result = channel->regs.csr; + + /* before returning, clear all relevant bits */ + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, INT_CHUNK_DONE ); + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, INT_DONE ); + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, INT_ERR ); + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); + + return result; +} + + + +/* Write a register */ +void dma_write32( unsigned long addr, unsigned long value ) +{ + unsigned i; + struct dma_controller *dma = NULL; + + /* Find which controller this is */ + for ( i = 0; i < MAX_DMAS && dma == NULL; ++ i ) { + if ( (addr >= dmas[i].baseaddr) && (addr < dmas[i].baseaddr + DMA_ADDR_SPACE) ) + dma = &(dmas[i]); + } + + /* verify we found a controller */ + if ( dma == NULL ) { + fprintf( stderr, "dma_write32( 0x%08lX ): Out of range\n", addr ); + cont_run = 0; + return; + } + + addr -= dma->baseaddr; + + if ( addr % 4 != 0 ) { + fprintf( stderr, "dma_write32( 0x%08lX, 0x%08lX ): Not register-aligned\n", addr + dma->baseaddr, value ); + cont_run = 0; + return; + } + + /* case of global (not per-channel) registers */ + if ( addr < DMA_CH_BASE ) { + switch( addr ) { + case DMA_CSR: + if ( TEST_FLAG( value, DMA_CSR, PAUSE ) ) + fprintf( stderr, "dma: PAUSE not implemented\n" ); + break; + + case DMA_INT_MSK_A: dma->regs.int_msk_a = value; break; + case DMA_INT_MSK_B: dma->regs.int_msk_b = value; break; + case DMA_INT_SRC_A: dma->regs.int_src_a = value; break; + case DMA_INT_SRC_B: dma->regs.int_src_b = value; break; + default: + fprintf( stderr, "dma_write32( 0x%08lX ): Illegal register\n", addr + dma->baseaddr ); + cont_run = 0; + return; + } + } else { + /* case of per-channel registers */ + unsigned chno = (addr - DMA_CH_BASE) / DMA_CH_SIZE; + struct dma_channel *channel = &(dma->ch[chno]); + channel->referenced = 1; + addr = (addr - DMA_CH_BASE) % DMA_CH_SIZE; + switch( addr ) { + case DMA_CSR: dma_write_ch_csr( &(dma->ch[chno]), value ); break; + case DMA_CH_SZ: channel->regs.sz = value; break; + case DMA_CH_A0: channel->regs.a0 = value; break; + case DMA_CH_AM0: channel->regs.am0 = value; break; + case DMA_CH_A1: channel->regs.a1 = value; break; + case DMA_CH_AM1: channel->regs.am1 = value; break; + case DMA_CH_DESC: channel->regs.desc = value; break; + case DMA_CH_SWPTR: channel->regs.swptr = value; break; + } + } +} + + +/* Write a channel CSR + * This ensures only the writable bits are modified. + */ +void dma_write_ch_csr( struct dma_channel *channel, unsigned long value ) +{ + /* Copy the writable bits to the channel CSR */ + channel->regs.csr &= ~DMA_CH_CSR_WRITE_MASK; + channel->regs.csr |= value & DMA_CH_CSR_WRITE_MASK; +} + + +/* + * Simulation of control signals + * To be used by simulations for other devices, e.g. ethernet + */ + +void set_dma_req_i( unsigned dma_controller, unsigned channel ) +{ + dmas[dma_controller].ch[channel].dma_req_i = 1; +} + +void clear_dma_req_i( unsigned dma_controller, unsigned channel ) +{ + dmas[dma_controller].ch[channel].dma_req_i = 0; +} + +void set_dma_nd_i( unsigned dma_controller, unsigned channel ) +{ + dmas[dma_controller].ch[channel].dma_nd_i = 1; +} + +void clear_dma_nd_i( unsigned dma_controller, unsigned channel ) +{ + dmas[dma_controller].ch[channel].dma_nd_i = 0; +} + +unsigned check_dma_ack_o( unsigned dma_controller, unsigned channel ) +{ + return dmas[dma_controller].ch[channel].dma_ack_o; +} + + + +/* Simulation hook. Must be called every clock cycle to simulate DMA. */ +void dma_clock() +{ + unsigned i; + for ( i = 0; i < MAX_DMAS; ++ i ) { + if ( dmas[i].baseaddr != 0 ) + dma_controller_clock( &(dmas[i]) ); + } +} + + +/* Clock tick for one DMA controller. + * This does the actual "DMA" operation. + * One chunk is transferred per clock. + */ +void dma_controller_clock( struct dma_controller *dma ) +{ + unsigned chno, i; + int breakpoint = 0; + + for ( chno = 0; chno < DMA_NUM_CHANNELS; ++ chno ) { + struct dma_channel *channel = &(dma->ch[chno]); + + /* check if this channel is enabled */ + if ( !TEST_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ) ) + continue; + + /* Do we need to abort? */ + if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, STOP ) ) { + debug( 3, "DMA: STOP requested\n" ); + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ); + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ); + SET_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); + + if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INE_ERR ) && + (channel->controller->regs.int_msk_a & channel->channel_mask) ) { + SET_FLAG( channel->regs.csr, DMA_CH_CSR, INT_ERR ); + channel->controller->regs.int_src_a = channel->channel_mask; + report_interrupt( channel->controller->irq ); + } + + continue; + } + + /* In HW Handshake mode, only work when dma_req_i asserted */ + if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, MODE ) && + !channel->dma_req_i ) { + continue; + } + + /* If this is the first cycle of the transfer, initialize our state */ + if ( !TEST_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ) ) { + debug( 4, "DMA: Starting new transfer\n" ); + + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, DONE ); + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); + SET_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ); + + /* If using linked lists, copy the appropriate fields to our registers */ + if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, USE_ED ) ) + dma_load_descriptor( channel ); + else + channel->load_next_descriptor_when_done = 0; + + /* Set our internal status */ + dma_init_transfer( channel ); + + /* Might need to skip descriptor */ + if ( CHANNEL_ND_I( channel ) ) { + debug( 3, "DMA: dma_nd_i asserted before dma_req_i, skipping descriptor\n" ); + dma_channel_terminate_transfer( channel, 0 ); + continue; + } + } + + /* Transfer one word */ + set_mem32( channel->destination, eval_mem32( channel->source, &breakpoint ), &breakpoint ); + + /* Advance the source and destionation pointers */ + masked_increase( &(channel->source), channel->source_mask ); + masked_increase( &(channel->destination), channel->destination_mask ); + ++ channel->words_transferred; + + /* Have we finished a whole chunk? */ + channel->dma_ack_o = (channel->words_transferred % channel->chunk_size == 0); + + /* When done with a chunk, check for dma_nd_i */ + if ( CHANNEL_ND_I( channel ) ) { + debug( 3, "DMA: dma_nd_i asserted\n" ); + dma_channel_terminate_transfer( channel, 0 ); + continue; + } + + /* Are we done? */ + if ( channel->words_transferred >= channel->total_size ) + dma_channel_terminate_transfer( channel, 1 ); + } +} + + +/* Copy relevant valued from linked list descriptor to channel registers */ +void dma_load_descriptor( struct dma_channel *channel ) +{ + int breakpoint = 0; + unsigned long desc_csr = eval_mem32( channel->regs.desc + DMA_DESC_CSR, &breakpoint ); + + channel->load_next_descriptor_when_done = !TEST_FLAG( desc_csr, DMA_DESC_CSR, EOL ); + + ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, INC_SRC, TEST_FLAG( desc_csr, DMA_DESC_CSR, INC_SRC ) ); + ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, INC_DST, TEST_FLAG( desc_csr, DMA_DESC_CSR, INC_DST ) ); + ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, SRC_SEL, TEST_FLAG( desc_csr, DMA_DESC_CSR, SRC_SEL ) ); + ASSIGN_FLAG( channel->regs.csr, DMA_CH_CSR, DST_SEL, TEST_FLAG( desc_csr, DMA_DESC_CSR, DST_SEL ) ); + + SET_FIELD( channel->regs.sz, DMA_CH_SZ, TOT_SZ, GET_FIELD( desc_csr, DMA_DESC_CSR, TOT_SZ ) ); + + channel->regs.a0 = eval_mem32( channel->regs.desc + DMA_DESC_ADR0, &breakpoint ); + channel->regs.a1 = eval_mem32( channel->regs.desc + DMA_DESC_ADR1, &breakpoint ); + + channel->current_descriptor = channel->regs.desc; + channel->regs.desc = eval_mem32( channel->regs.desc + DMA_DESC_NEXT, &breakpoint ); +} + + +/* Initialize internal parameters used to implement transfers */ +void dma_init_transfer( struct dma_channel *channel ) +{ + channel->source = channel->regs.a0; + channel->destination = channel->regs.a1; + channel->source_mask = TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INC_SRC ) ? channel->regs.am0 : 0; + channel->destination_mask = TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INC_DST ) ? channel->regs.am1 : 0; + channel->total_size = GET_FIELD( channel->regs.sz, DMA_CH_SZ, TOT_SZ ); + channel->chunk_size = GET_FIELD( channel->regs.sz, DMA_CH_SZ, CHK_SZ ); + if ( !channel->chunk_size || (channel->chunk_size > channel->total_size) ) + channel->chunk_size = channel->total_size; + channel->words_transferred = 0; +} + + +/* Take care of transfer termination */ +void dma_channel_terminate_transfer( struct dma_channel *channel, int generate_interrupt ) +{ + debug( 4, "DMA: Terminating transfer\n" ); + + /* Might be working in a linked list */ + if ( channel->load_next_descriptor_when_done ) { + dma_load_descriptor( channel ); + dma_init_transfer( channel ); + return; + } + + /* Might be in auto-restart mode */ + if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, ARS ) ) { + dma_init_transfer( channel ); + return; + } + + /* If needed, write amount of data transferred back to memory */ + if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, SZ_WB ) && + TEST_FLAG( channel->regs.csr, DMA_CH_CSR, USE_ED ) ) { + int breakpoint = 0; + unsigned long desc_csr = eval_mem32( channel->regs.desc + DMA_DESC_CSR, &breakpoint ); + /* TODO: What should we write back? Doc says "total number of remaining bytes" !? */ + unsigned long remaining_words = channel->total_size - channel->words_transferred; + SET_FIELD( channel->regs.sz, DMA_DESC_CSR, TOT_SZ, remaining_words ); + } + + /* Mark end of transfer */ + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ); + SET_FLAG( channel->regs.csr, DMA_CH_CSR, DONE ); + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, ERR ); + CLEAR_FLAG( channel->regs.csr, DMA_CH_CSR, BUSY ); + + /* If needed, generate interrupt */ + if ( generate_interrupt ) { + /* TODO: Which channel should we interrupt? */ + if ( TEST_FLAG( channel->regs.csr, DMA_CH_CSR, INE_DONE ) && + (channel->controller->regs.int_msk_a & channel->channel_mask) ) { + SET_FLAG( channel->regs.csr, DMA_CH_CSR, INT_DONE ); + channel->controller->regs.int_src_a = channel->channel_mask; + report_interrupt( channel->controller->irq ); + } + } +} + +/* Utility function: Add 4 to a value with a mask */ +void masked_increase( unsigned long *value, unsigned long mask ) +{ + *value = (*value & ~mask) | ((*value + 4) & mask); +} Index: ethernet.c =================================================================== --- ethernet.c (nonexistent) +++ ethernet.c (revision 1765) @@ -0,0 +1,750 @@ +/* ethernet.c -- Simulation of Ethernet MAC + Copyright (C) 2001 by Erez Volk, erez@opencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "abstract.h" +#include "ethernet_i.h" +#include "dma.h" +#include "sim-config.h" +#include "fields.h" +#include "crc32.h" + + +static struct eth_device eths[MAX_ETHERNETS]; + +static void eth_write32( unsigned long addr, unsigned long value ); +static unsigned long eth_read32( unsigned long addr ); +static void eth_controller_tx_clock( struct eth_device * ); +static void eth_controller_rx_clock( struct eth_device * ); +static void eth_start_tx( struct eth_device * ); +static void eth_finish_tx( struct eth_device * ); +static void eth_start_rx( struct eth_device * ); +static void eth_finish_rx( struct eth_device * ); + +static void eth_write_tx_bd_num( struct eth_device *, unsigned long value ); +static unsigned long eth_rx( struct eth_device * ); +static void eth_tx( struct eth_device *, unsigned long ); +static void eth_rx_next_packet( struct eth_device * ); + +static ssize_t eth_initialize_tx_crc( struct eth_device * ); +static ssize_t eth_write_tx_file_and_accumulate_crc( struct eth_device *, const void *, size_t ); +static ssize_t eth_read_rx_file( struct eth_device *, void *, size_t ); +static void eth_skip_rx_file( struct eth_device *, off_t ); +static void eth_rewind_rx_file( struct eth_device *, off_t ); + +static int eth_find_controller( unsigned long addr, struct eth_device **eth, unsigned long *reladdr ); +static void eth_close_files( struct eth_device *eth ); + + + +/* Reset. Initializes all registers to default and places devices in memory address space. */ +void eth_reset() +{ + static int first_time = 1; + unsigned i; + + if (!config.nethernets) + return; + + if ( first_time ) { + memset( eths, 0, sizeof(eths) ); + first_time = 0; + } + + for ( i = 0; i < MAX_ETHERNETS; ++ i ) { + struct eth_device *eth = &(eths[i]); + + eth->eth_number = i; + eth->baseaddr = config.ethernets[i].baseaddr; + + if ( eth->baseaddr != 0 ) { + /* Mark which DMA controller and channels */ + eth->dma = config.ethernets[i].dma; + eth->tx_channel = config.ethernets[i].tx_channel; + eth->rx_channel = config.ethernets[i].rx_channel; + + /* (Re-)open TX/RX files */ + eth->rxfile = config.ethernets[i].rxfile; + eth->txfile = config.ethernets[i].txfile; + eth_close_files( eth ); + if ( (eth->rxfd = open( eth->rxfile, O_RDONLY )) < 0 ) + fprintf( stderr, "Cannot open Ethernet RX file \"%s\"\n", eth->rxfile ); + if ( (eth->txfd = open( eth->txfile, O_RDWR | O_CREAT | O_APPEND | O_SYNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH )) < 0 ) + fprintf( stderr, "Cannot open Ethernet TX file \"%s\"\n", eth->txfile ); + eth->loopback_offset = lseek( eth->txfd, 0, SEEK_END ); + + /* Set registers to default values */ + memset( &(eth->regs), 0, sizeof(eth->regs) ); + eth->regs.moder = 0x0000A000; + eth->regs.ipgt = 0x00000012; + eth->regs.ipgr1 = 0x0000000C; + eth->regs.ipgr2 = 0x00000012; + eth->regs.packetlen = 0x003C0600; + eth->regs.collconf = 0x000F0040; + eth->regs.miimoder = 0x00000064; + + /* Initialize TX/RX status */ + memset( &(eth->tx), 0, sizeof(eth->tx) ); + memset( &(eth->rx), 0, sizeof(eth->rx) ); + eth->rx.bd_index = eth->regs.tx_bd_num; + + /* Register memory range */ + register_memoryarea( eth->baseaddr, ETH_ADDR_SPACE, 4, eth_read32, eth_write32 ); + } + } +} + + +/* Close RX/TX files if open */ +void eth_close_files( struct eth_device *eth ) +{ + if ( eth->rxfd > 0 ) + close( eth->rxfd ); + if ( eth->txfd > 0 ) + close( eth->txfd ); + eth->rxfd = eth->txfd = -1; +} + + +/* Print register values on stdout */ +void eth_status( void ) +{ + unsigned i; + + for ( i = 0; i < MAX_ETHERNETS; ++ i ) { + struct eth_device *eth = &(eths[i]); + + if ( eth->baseaddr == 0 ) + continue; + + printf( "\nEthernet MAC %u at 0x%08X:\n", i, eth->baseaddr ); + printf( "MODER : 0x%08lX\n", eth->regs.moder ); + printf( "INT_SOURCE : 0x%08lX\n", eth->regs.int_source ); + printf( "INT_MASK : 0x%08lX\n", eth->regs.int_mask ); + printf( "IPGT : 0x%08lX\n", eth->regs.ipgt ); + printf( "IPGR1 : 0x%08lX\n", eth->regs.ipgr1 ); + printf( "IPGR2 : 0x%08lX\n", eth->regs.ipgr2 ); + printf( "PACKETLEN : 0x%08lX\n", eth->regs.packetlen ); + printf( "COLLCONF : 0x%08lX\n", eth->regs.collconf ); + printf( "TX_BD_NUM : 0x%08lX\n", eth->regs.tx_bd_num ); + printf( "CTRLMODER : 0x%08lX\n", eth->regs.controlmoder ); + printf( "MIIMODER : 0x%08lX\n", eth->regs.miimoder ); + printf( "MIICOMMAND : 0x%08lX\n", eth->regs.miicommand ); + printf( "MIIADDRESS : 0x%08lX\n", eth->regs.miiaddress ); + printf( "MIITX_DATA : 0x%08lX\n", eth->regs.miitx_data ); + printf( "MIIRX_DATA : 0x%08lX\n", eth->regs.miirx_data ); + printf( "MIISTATUS : 0x%08lX\n", eth->regs.miistatus ); + printf( "MAC Address : %02X:%02X:%02X:%02X:%02X:%02X\n", + eth->mac_address[0], eth->mac_address[1], eth->mac_address[2], + eth->mac_address[3], eth->mac_address[4], eth->mac_address[5] ); + } +} + + +/* Convert a memory address to a oontroller struct and relative address. + * Return nonzero on success */ +int eth_find_controller( unsigned long addr, struct eth_device **eth, unsigned long *reladdr ) +{ + unsigned i; + *eth = NULL; + + for ( i = 0; i < MAX_ETHERNETS && *eth == NULL; ++ i ) { + if ( (addr >= eths[i].baseaddr) && (addr < eths[i].baseaddr + ETH_ADDR_SPACE) ) + *eth = &(eths[i]); + } + + /* verify we found a controller */ + if ( *eth == NULL ) + return 0; + + /* Verify legal address */ + if ( (addr - (*eth)->baseaddr) % 4 != 0 ) + return 0; + + *reladdr = addr - (*eth)->baseaddr; + return 1; +} + + +/* Read a register */ +unsigned long eth_read32( unsigned long addr ) +{ + struct eth_device *eth; + if ( !eth_find_controller( addr, ð, &addr ) ) { + printf( "eth_read32( 0x%08lX ): Not in registered range(s)\n", addr ); + return 0; + } + + + switch( addr ) { + case ETH_MODER: return eth->regs.moder; + case ETH_INT_SOURCE: return eth->regs.int_source; + case ETH_INT_MASK: return eth->regs.int_mask; + case ETH_IPGT: return eth->regs.ipgt; + case ETH_IPGR1: return eth->regs.ipgr1; + case ETH_IPGR2: return eth->regs.ipgr2; + case ETH_PACKETLEN: return eth->regs.packetlen; + case ETH_COLLCONF: return eth->regs.collconf; + case ETH_TX_BD_NUM: return eth->regs.tx_bd_num; + case ETH_CTRLMODER: return eth->regs.controlmoder; + case ETH_MIIMODER: return eth->regs.miimoder; + case ETH_MIICOMMAND: return eth->regs.miicommand; + case ETH_MIIADDRESS: return eth->regs.miiaddress; + case ETH_MIITX_DATA: return eth->regs.miitx_data; + case ETH_MIIRX_DATA: return eth->regs.miirx_data; + case ETH_MIISTATUS: return eth->regs.miistatus; + case ETH_MAC_ADDR0: return (((unsigned long)eth->mac_address[3]) << 24) | + (((unsigned long)eth->mac_address[2]) << 16) | + (((unsigned long)eth->mac_address[1]) << 8) | + (unsigned long)eth->mac_address[0]; + case ETH_MAC_ADDR1: return (((unsigned long)eth->mac_address[5]) << 8) | + (unsigned long)eth->mac_address[4]; + case ETH_DMA_RX_TX: return eth_rx( eth ); + } + + if ( (addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE) ) + return eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4]; + + printf( "eth_read32( 0x%08lX ): Illegal address\n", addr + eth->baseaddr ); + cont_run = 0; + return 0; +} + + +/* Write a register */ +void eth_write32( unsigned long addr, unsigned long value ) +{ + struct eth_device *eth; + if ( !eth_find_controller( addr, ð, &addr ) ) { + printf( "eth_write32( 0x%08lX ): Not in registered range(s)\n", addr ); + return; + } + + switch( addr ) { + case ETH_MODER: eth->regs.moder = value; return; + case ETH_INT_SOURCE: eth->regs.int_source = value; return; + case ETH_INT_MASK: eth->regs.int_mask = value; return; + case ETH_IPGT: eth->regs.ipgt = value; return; + case ETH_IPGR1: eth->regs.ipgr1 = value; return; + case ETH_IPGR2: eth->regs.ipgr2 = value; return; + case ETH_PACKETLEN: eth->regs.packetlen = value; return; + case ETH_COLLCONF: eth->regs.collconf = value; return; + case ETH_TX_BD_NUM: eth_write_tx_bd_num( eth, value ); return; + case ETH_CTRLMODER: eth->regs.controlmoder = value; return; + case ETH_MIIMODER: eth->regs.miimoder = value; return; + case ETH_MIICOMMAND: eth->regs.miicommand = value; return; + case ETH_MIIADDRESS: eth->regs.miiaddress = value; return; + case ETH_MIITX_DATA: eth->regs.miitx_data = value; return; + case ETH_MIIRX_DATA: eth->regs.miirx_data = value; return; + case ETH_MIISTATUS: eth->regs.miistatus = value; return; + case ETH_MAC_ADDR0: + eth->mac_address[0] = value & 0xFF; + eth->mac_address[1] = (value >> 8) & 0xFF; + eth->mac_address[2] = (value >> 16) & 0xFF; + eth->mac_address[3] = (value >> 24) & 0xFF; + return; + case ETH_MAC_ADDR1: + eth->mac_address[4] = value & 0xFF; + eth->mac_address[5] = (value >> 8) & 0xFF; + return; + + case ETH_DMA_RX_TX: eth_tx( eth, value ); return; + } + + if ( (addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE) ) { + eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4] = value; + return; + } + + printf( "eth_write32( 0x%08lX ): Illegal address\n", addr + eth->baseaddr ); + cont_run = 0; + return; +} + + +/* When TX_BD_NUM is written, also reset current RX BD index */ +void eth_write_tx_bd_num( struct eth_device *eth, unsigned long value ) +{ + eth->rx.bd_index = eth->regs.tx_bd_num = value & 0xFF; +} + + +/* + * "Receive" one dword + */ +unsigned long eth_rx( struct eth_device *eth ) +{ + unsigned char bytes[4]; + unsigned read_count; + ssize_t nread; + + if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, RXEN ) || + !TEST_FLAG( eth->regs.moder, ETH_MODER, DMAEN ) || + (eth->rx.fd <= 0) || !eth->rx.working || eth->rx.error || + !eth->rx.bytes_left ) + return; + + /* How many bytes should we actually read? */ + read_count = (eth->rx.bytes_left >= 4) ? 4 : eth->rx.bytes_left; + + /* Actually read */ + memset( bytes, 0, sizeof(bytes) ); + nread = eth_read_rx_file( eth, bytes, read_count ); + + if ( nread < read_count ) + eth->rx.error = 1; + + /* update counters */ + eth->rx.bytes_left -= nread; + eth->rx.bytes_read += nread; + + /* build word */ + return + (((unsigned long)bytes[0]) << 24) | + (((unsigned long)bytes[1]) << 16) | + (((unsigned long)bytes[2]) << 8) | + (((unsigned long)bytes[3]) ); +} + + + +/* + * Do "transmission" of one dword + */ +void eth_tx( struct eth_device *eth, unsigned long data ) +{ + unsigned char bytes[4]; + unsigned send_count, ignore_count; + ssize_t written; + + if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, TXEN ) || + !TEST_FLAG( eth->regs.moder, ETH_MODER, DMAEN ) || + (eth->txfd <= 0) || !eth->tx.working || eth->tx.error ) + return; + + /* How many bytes of the four are valid */ + send_count = (eth->tx.bytes_left >= 4) ? 4 : eth->tx.bytes_left; + + /* If we've passed the maximum frame length, discard extra bytes */ + if ( eth->tx.bytes_sent + send_count <= eth->tx.maximum_length ) + ignore_count = 0; + else { + /* How many of the bytes should we ignore? */ + unsigned ignore_count = eth->tx.bytes_sent + send_count - eth->tx.maximum_length; + if ( ignore_count > send_count ) + ignore_count = send_count; + send_count -= ignore_count; + } + + if ( send_count ) { + /* Convert to four bytes in the order they're to be sent */ + bytes[0] = (unsigned char)((data >> 24) & 0xFF); + bytes[1] = (unsigned char)((data >> 16) & 0xFF); + bytes[2] = (unsigned char)((data >> 8) & 0xFF); + bytes[3] = (unsigned char)((data ) & 0xFF); + + /* And "transmit" */ + written = eth_write_tx_file_and_accumulate_crc( eth, bytes, send_count ); + if ( written > 0 ) { + eth->tx.bytes_left -= written; + eth->tx.bytes_sent += written; + } + if ( written < send_count ) { + printf( "Ethernet: Error writing %u bytes to \"%s\"\n", send_count, eth->txfile ); + eth->tx.error = 1; + cont_run = 0; + return; + } + } + + if ( !eth->tx.error && ignore_count ) { + eth->tx.bytes_left -= ignore_count; + eth->tx.bytes_sent += ignore_count; + } + + /* Possibly add padding at end of packet */ + if ( !eth->tx.bytes_left && (eth->tx.minimum_length > eth->tx.packet_length) ) { + send_count = eth->tx.minimum_length - eth->tx.packet_length; + bytes[0] = 0; + while ( send_count -- ) + if ( eth_write_tx_file_and_accumulate_crc( eth, bytes, 1 ) < 1 ) { + printf( "Ethernet: Error writing padding to \"%s\"\n", send_count, eth->txfile ); + eth->tx.error = 1; + cont_run = 0; + return; + } + } +} + + +/* Simulation hook. Must be called every clock cycle to simulate Ethernet MAC. */ +void eth_clock() +{ + unsigned i; + + for ( i = 0; i < config.nethernets; ++ i ) { + eth_controller_tx_clock( &(eths[i]) ); + eth_controller_rx_clock( &(eths[i]) ); + } +} + + +/* + * TX clock + * Responsible for starting and finishing TX + */ +void eth_controller_tx_clock( struct eth_device *eth ) +{ + if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, TXEN ) || + !TEST_FLAG( eth->regs.moder, ETH_MODER, DMAEN ) ) + return; + + if ( eth->txfd <= 0 ) + return; + + /* If this is the first time, initialize TX state */ + if ( !eth->tx.working ) + eth_start_tx( eth ); + + /* Check for end of transmission */ + if ( eth->tx.working && (eth->tx.error || eth->tx.bytes_sent >= eth->tx.packet_length) ) + eth_finish_tx( eth ); +} + + +/* Initialize state for packet transmission */ +void eth_start_tx( struct eth_device *eth ) +{ + unsigned long length_with_crc; + + /* Read buffer descriptor */ + eth->tx.bd = eth->regs.bd_ram[eth->tx.bd_index]; + + if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, READY ) ) { + eth->tx.bytes_left = eth->tx.packet_length = GET_FIELD( eth->tx.bd, ETH_TX_BD, LENGTH ); + eth->tx.bytes_sent = 0; + + /* Initialize error status bits */ + CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, DEFER ); + CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, COLLISION ); + CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, RETRANSMIT ); + CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, UNDERRUN ); + CLEAR_FLAG( eth->tx.bd, ETH_TX_BD, NO_CARRIER ); + SET_FIELD( eth->tx.bd, ETH_TX_BD, RETRY, 0 ); + + /* Find out minimum length */ + if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, PAD ) || + TEST_FLAG( eth->regs.moder, ETH_MODER, PAD ) ) + eth->tx.minimum_length = GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MINFL ); + else + eth->tx.minimum_length = eth->tx.packet_length; + + /* Find out maximum length */ + if ( TEST_FLAG( eth->regs.moder, ETH_MODER, HUGEN ) ) + eth->tx.maximum_length = eth->tx.packet_length; + else + eth->tx.maximum_length = GET_FIELD( eth->regs.packetlen, ETH_PACKETLEN, MAXFL ); + + /* Do we need CRC on this packet? */ + if ( TEST_FLAG( eth->regs.moder, ETH_MODER, CRCEN ) || + (TEST_FLAG( eth->tx.bd, ETH_TX_BD, CRC) && + TEST_FLAG( eth->tx.bd, ETH_TX_BD, LAST)) ) + eth->tx.add_crc = 1; + else + eth->tx.add_crc = 0; + eth_initialize_tx_crc( eth ); + + debug( 3, "Ethernet: Starting TX of %u bytes (min. %u, max. %u)\n", eth->tx.packet_length, + eth->tx.minimum_length, eth->tx.maximum_length ); + + /* Write "header" to file */ + length_with_crc = eth->tx.add_crc ? (eth->tx.packet_length + 4) : eth->tx.packet_length; + write( eth->txfd, &length_with_crc, sizeof(length_with_crc) ); + + /* Tell DMA to start work */ + set_dma_req_i( eth->dma, eth->tx_channel ); + + /* Signal to ourselves */ + eth->tx.working = 1; + eth->tx.waiting_for_dma = 0; + } +} + + +/* Handle termination of sent packet */ +void eth_finish_tx( struct eth_device *eth ) +{ + /* + * TODO: + * handle error state! + * somehow notify user (or does DMA take care of that?) + */ + + if ( eth->tx.waiting_for_dma && + check_dma_ack_o( eth->dma, eth->tx_channel ) ) { + clear_dma_nd_i( eth->dma, eth->tx_channel ); + clear_dma_req_i( eth->dma, eth->tx_channel ); + + eth->tx.working = eth->tx.waiting_for_dma = 0; + + /* advance to next BD */ + if ( TEST_FLAG( eth->tx.bd, ETH_TX_BD, WRAP ) || + eth->tx.bd_index >= ETH_BD_COUNT ) + eth->tx.bd_index = 0; + else + ++ eth->tx.bd_index; + } + + if ( !eth->tx.waiting_for_dma ) { + debug( 3, "Ethernet: TX of %u bytes: %s\n", eth->tx.packet_length, + eth->tx.error ? "Error" : "Done" ); + + /* Add CRC if needed */ + if ( eth->tx.add_crc ) { + crc32_close( &(eth->tx.crc_value) ); + write( eth->txfd, &(eth->tx.crc_value), sizeof(eth->tx.crc_value) ); + } + + /* Write result to bd */ + eth->regs.bd_ram[eth->tx.bd_index] = eth->tx.bd; + + /* DMA flow control */ + set_dma_nd_i( eth->dma, eth->tx_channel ); + eth->tx.waiting_for_dma = 1; + } +} + + +/* Initialize calculation of packet CRC */ +ssize_t eth_initialize_tx_crc( struct eth_device *eth ) +{ + crc32_init( &(eth->tx.crc_value) ); +} + +/* Write to TX file and update CRC value */ +ssize_t eth_write_tx_file_and_accumulate_crc( struct eth_device *eth, const void *buf, size_t count ) +{ + ssize_t written = write( eth->txfd, buf, count ); + if ( written > 0 ) + crc32_feed_bytes( &(eth->tx.crc_value), buf, written ); + return written; +} + + +/* + * Clock for RX + * Responsible for starting and finisihing RX + */ +void eth_controller_rx_clock( struct eth_device *eth ) +{ + if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, RXEN ) || + !TEST_FLAG( eth->regs.moder, ETH_MODER, DMAEN ) ) + return; + + if ( eth->rxfd <= 0 && !TEST_FLAG( eth->regs.moder, ETH_MODER, LOOPBCK ) ) + return; + + /* If this is the first time, initialize RX state */ + if ( !eth->rx.working ) + eth_start_rx( eth ); + + /* Check for end of packet */ + if ( eth->rx.working && (eth->rx.error || eth->rx.bytes_read >= eth->rx.packet_length) ) + eth_finish_rx( eth ); +} + + +/* + * Utility function to read from the ethernet RX file + * This function moves the file pointer to the current place in the packet before reading + */ +ssize_t eth_read_rx_file( struct eth_device *eth, void *buf, size_t count ) +{ + ssize_t result; + + if ( eth->rx.fd <= 0 ) { + debug( 3, "Ethernet: No RX file\n" ); + return 0; + } + + if ( eth->rx.offset ) + if ( lseek( eth->rx.fd, *(eth->rx.offset), SEEK_SET ) == (off_t)-1 ) { + debug( 3, "Ethernet: Error seeking RX file\n" ); + return 0; + } + + result = read( eth->rx.fd, buf, count ); + + if ( eth->rx.offset && result >= 0 ) + *(eth->rx.offset) += result; + + return result; +} + + +/* "Skip" bytes in RX file */ +void eth_skip_rx_file( struct eth_device *eth, off_t count ) +{ + eth->rx.offset += count; +} + +/* Move RX file position back */ +void eth_rewind_rx_file( struct eth_device *eth, off_t count ) +{ + eth->rx.offset -= count; +} + + +/* Initialize RX */ +void eth_start_rx( struct eth_device *eth ) +{ + struct ether_header header; + static const unsigned char bcast_address[ETH_HLEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + /* Read buffer descriptor */ + eth->rx.bd = eth->regs.bd_ram[eth->rx.bd_index]; + + if ( TEST_FLAG( eth->rx.bd, ETH_TX_BD, READY ) ) { + /* Initialize error status bits */ + CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, DEFER ); + CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, COLLISION ); + CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, RETRANSMIT ); + CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, UNDERRUN ); + CLEAR_FLAG( eth->rx.bd, ETH_TX_BD, NO_CARRIER ); + SET_FIELD( eth->rx.bd, ETH_TX_BD, RETRY, 0 ); + + debug( 3, "Ethernet: Starting RX\n" ); + + /* Setup file to read from */ + if ( TEST_FLAG( eth->regs.moder, ETH_MODER, LOOPBCK ) ) { + eth->rx.fd = eth->txfd; + eth->rx.offset = &(eth->loopback_offset); + } else { + eth->rx.fd = eth->rxfd; + eth->rx.offset = 0; + } + + /* Read packet length */ + if ( eth_read_rx_file( eth, &(eth->rx.packet_length), sizeof(eth->rx.packet_length) ) + < sizeof(eth->rx.packet_length) ) { + /* TODO: just do what real ethernet would do (some kind of error state) */ + printf( "eth_start_rx(): File does not have a packet ready for RX\n" ); + cont_run = 0; + return; + } + + /* Packet must be big enough to hold a header */ + if ( eth->rx.packet_length < ETH_HLEN ){ + debug( 3, "eth_start_rx(): Packet too small\n" ); + eth_rx_next_packet( eth ); + return; + } + + if ( eth_read_rx_file( eth, &header, ETH_HLEN ) < ETH_HLEN ) { + printf( "eth_start_rx(): Error reading packet header\n" ); + cont_run = 0; + return; + } + + /* We haven't formally "received" the header yet */ + eth_rewind_rx_file( eth, ETH_HLEN ); + + eth->rx.bytes_read = 0; + eth->rx.bytes_left = eth->rx.packet_length; + + /* Unless promiscous, don't accept all packets */ + if ( !TEST_FLAG( eth->regs.moder, ETH_MODER, PRO ) ) { + int for_us = (memcmp( header.ether_dhost, eth->mac_address, ETH_HLEN ) == 0); + int for_all = (memcmp( header.ether_dhost, bcast_address, ETH_HLEN ) == 0); + int good = for_us || (for_all && !TEST_FLAG( eth->regs.moder, ETH_MODER, BRO ) ); + if ( !good ) { + debug( 3, "eth_start_rx(): Packet destination is %02X:%02X:%02X:%02X:%02X:%02x, rejecting\n", + header.ether_dhost[0], header.ether_dhost[1], header.ether_dhost[2], + header.ether_dhost[3], header.ether_dhost[4], header.ether_dhost[5] ); + eth_rx_next_packet( eth ); + return; + } + } + + /* TODO: Check CRC on RX? */ + + /* Tell DMA to start work */ + set_dma_req_i( eth->dma, eth->rx_channel ); + + /* Signal to ourselves */ + eth->rx.working = 1; + eth->rx.waiting_for_dma = 0; + } +} + + +/* Finish RX */ +void eth_finish_rx( struct eth_device *eth ) +{ + if ( eth->rx.waiting_for_dma && + check_dma_ack_o( eth->dma, eth->rx_channel ) ) { + clear_dma_nd_i( eth->dma, eth->rx_channel ); + clear_dma_req_i( eth->dma, eth->rx_channel ); + + eth->rx.working = eth->rx.waiting_for_dma = 0; + + eth_rx_next_packet( eth ); + } + + if ( !eth->rx.waiting_for_dma ) { + debug( 3, "Ethernet: RX of %u bytes: %s\n", eth->rx.packet_length, + eth->rx.error ? "Error" : "Done" ); + + /* Write result to bd */ + SET_FIELD( eth->rx.bd, ETH_RX_BD, LENGTH, eth->rx.packet_length ); + eth->regs.bd_ram[eth->rx.bd_index] = eth->rx.bd; + + /* DMA flow control */ + set_dma_nd_i( eth->dma, eth->rx_channel ); + eth->rx.waiting_for_dma = 1; + } +} + + +/* Move to next RX BD */ +void eth_rx_next_packet( struct eth_device *eth ) +{ + /* Skip any possible leftovers */ + if ( eth->rx.bytes_left ) + eth_skip_rx_file( eth, eth->rx.bytes_left ); + + /* advance to next BD */ + if ( TEST_FLAG( eth->rx.bd, ETH_TX_BD, WRAP ) || + eth->rx.bd_index >= ETH_BD_COUNT ) + eth->rx.bd_index = eth->regs.tx_bd_num; + else + ++ eth->rx.bd_index; +} Index: gpio.h =================================================================== --- gpio.h (nonexistent) +++ gpio.h (revision 1765) @@ -0,0 +1,50 @@ +/* gpio.h -- Definition of types and structures for the GPIO code + Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __OR1KSIM_PERIPHERAL_GPIO_H +#define __OR1KSIM_PERIPHERAL_GPIO_H + +/* Exported function prototypes */ +void gpio_reset( void ); +void gpio_clock( void ); +void gpio_status( void ); + + +/* Address space required by one Ethernet MAC */ +#define GPIO_ADDR_SPACE 0x20 + +/* Relative Register Addresses */ +#define RGPIO_IN 0x00 +#define RGPIO_OUT 0x04 +#define RGPIO_OE 0x08 +#define RGPIO_INTE 0x0C +#define RGPIO_PTRIG 0x10 +#define RGPIO_AUX 0x14 +#define RGPIO_CTRL 0x18 +#define RGPIO_INTS 0x1C + +/* Fields inside RGPIO_CTRL */ +#define RGPIO_CTRL_ECLK 0x00000001 +#define RGPIO_CTRL_NEC 0x00000002 +#define RGPIO_CTRL_INTE 0x00000004 +#define RGPIO_CTRL_INTS 0x00000008 + + +#endif /* __OR1KSIM_PERIPHERAL_GPIO_H */ Index: gpio_i.h =================================================================== --- gpio_i.h (nonexistent) +++ gpio_i.h (revision 1765) @@ -0,0 +1,80 @@ +/* gpio_i.h -- Definition of internal types and structures for GPIO code + Copyright (C) 2001 Erez Volk, erez@mailandnews.comopencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __OR1KSIM_PERIPHERAL_GPIO_I_H +#define __OR1KSIM_PERIPHERAL_GPIO_I_H + +#include "gpio.h" +#include "config.h" + +/* + * The various VAPI IDs each GPIO device has + */ +enum { GPIO_VAPI_DATA = 0, + GPIO_VAPI_AUX, + GPIO_VAPI_CLOCK, + GPIO_VAPI_RGPIO_OE, + GPIO_VAPI_RGPIO_INTE, + GPIO_VAPI_RGPIO_PTRIG, + GPIO_VAPI_RGPIO_AUX, + GPIO_VAPI_RGPIO_CTRL, + GPIO_NUM_VAPI_IDS }; + + +/* + * Implementatino of GPIO Code Registers and State + */ +struct gpio_device +{ + /* Base address in memory */ + unsigned long baseaddr; + + /* Which IRQ to generate */ + int irq; + + /* Which GPIO is this? */ + unsigned gpio_number; + + /* VAPI IDs */ + unsigned long base_vapi_id; + + /* Auxiliary inputs */ + unsigned long auxiliary_inputs; + + /* Visible registers */ + struct + { + unsigned long in; + unsigned long out; + unsigned long oe; + unsigned long inte; + unsigned long ptrig; + unsigned long aux; + unsigned long ctrl; + unsigned long ints; + + int external_clock; + } curr, next; +}; + + + + +#endif /* __OR1KSIM_PERIPHERAL_GPIO_I_H */ Index: crc32.c =================================================================== --- crc32.c (nonexistent) +++ crc32.c (revision 1765) @@ -0,0 +1,67 @@ +#include "crc32.h" + +static unsigned long crc32_table[256] = +{ + 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, + 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, + 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, + 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, + 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, + 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, + 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, + 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, + 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, + 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, + 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, + 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, + 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, + 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, + 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, + 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, + 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, + 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, + 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, + 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, + 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, + 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, + 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, + 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, + 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, + 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, + 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, + 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, + 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, + 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, + 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, + 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL +}; + + +unsigned long crc32( const void *buf, unsigned len ) +{ + unsigned long crc; + + crc32_init( &crc ); + crc32_feed_bytes( &crc, buf, len ); + crc32_close( &crc ); + return crc; +} + + +void crc32_init( unsigned long *value ) +{ + *value = 0xFFFFFFFF; +} + +void crc32_feed_bytes( unsigned long *value, const void *buf, unsigned len ) +{ + const unsigned char *p; + + for ( p = (const unsigned char *)buf; len > 0; ++ p, -- len ) + *value = (*value >> 8) ^ crc32_table[(*value ^ *p) & 0xFF]; +} + +void crc32_close( unsigned long *value ) +{ + *value = ~*value; +} Index: crc32.h =================================================================== --- crc32.h (nonexistent) +++ crc32.h (revision 1765) @@ -0,0 +1,13 @@ +#ifndef __CRC32_H +#define __CRC32_H + + +/* Calculate CRC of buffer in one go */ +unsigned long crc32( const void *buf, unsigned len ); + +/* Calculate incrementally */ +void crc32_init( unsigned long *value ); +void crc32_feed_bytes( unsigned long *value, const void *buf, unsigned len ); +void crc32_close( unsigned long *value ); + +#endif /* ___CRC32_H */ Index: dma.h =================================================================== --- dma.h (nonexistent) +++ dma.h (revision 1765) @@ -0,0 +1,195 @@ +/* dma.h -- Definition of types and structures for DMA + Copyright (C) 2001 by Erez Volk, erez@opencores.org + + This file is part of OpenRISC 1000 Architectural Simulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* Exported function prototypes */ +void dma_reset( void ); +void dma_clock( void ); + +void set_dma_req_i( unsigned dma_controller, unsigned channel ); +void clear_dma_req_i( unsigned dma_controller, unsigned channel ); +void set_dma_nd_i( unsigned dma_controller, unsigned channel ); +void clear_dma_nd_i( unsigned dma_controller, unsigned channel ); +unsigned check_dma_ack_o( unsigned dma_controller, unsigned channel ); + +/* Number of channel per DMA controller */ +#define DMA_NUM_CHANNELS 31 + + +/* Address space required by one DMA controller */ +#define DMA_ADDR_SPACE 0x400 + +/* Relative Register Addresses */ +#define DMA_CSR 0x00 +#define DMA_INT_MSK_A 0x04 +#define DMA_INT_MSK_B 0x08 +#define DMA_INT_SRC_A 0x0C +#define DMA_INT_SRC_B 0x10 + +/* Channel registers definitions */ +#define DMA_CH_BASE 0x20 /* Offset of first channel registers */ +#define DMA_CH_SIZE 0x20 /* Per-channel address space */ + +/* Per-channel Register Addresses, relative to channel start */ +#define DMA_CH_CSR 0x00 +#define DMA_CH_SZ 0x04 +#define DMA_CH_A0 0x08 +#define DMA_CH_AM0 0x0C +#define DMA_CH_A1 0x10 +#define DMA_CH_AM1 0x14 +#define DMA_CH_DESC 0x18 +#define DMA_CH_SWPTR 0x1C + +/* Field Definitions for the Main CSR */ +#define DMA_CSR_PAUSE_OFFSET 0 + +/* Field Definitions for the Channel CSR(s) */ +#define DMA_CH_CSR_CH_EN_OFFSET 0 +#define DMA_CH_CSR_DST_SEL_OFFSET 1 +#define DMA_CH_CSR_SRC_SEL_OFFSET 2 +#define DMA_CH_CSR_INC_DST_OFFSET 3 +#define DMA_CH_CSR_INC_SRC_OFFSET 4 +#define DMA_CH_CSR_MODE_OFFSET 5 +#define DMA_CH_CSR_ARS_OFFSET 6 +#define DMA_CH_CSR_USE_ED_OFFSET 7 +#define DMA_CH_CSR_SZ_WB_OFFSET 8 +#define DMA_CH_CSR_STOP_OFFSET 9 +#define DMA_CH_CSR_BUSY_OFFSET 10 +#define DMA_CH_CSR_DONE_OFFSET 11 +#define DMA_CH_CSR_ERR_OFFSET 12 +#define DMA_CH_CSR_PRIORITY_OFFSET 13 +#define DMA_CH_CSR_PRIORITY_WIDTH 3 +#define DMA_CH_CSR_REST_EN_OFFSET 16 +#define DMA_CH_CSR_INE_ERR_OFFSET 17 +#define DMA_CH_CSR_INE_DONE_OFFSET 18 +#define DMA_CH_CSR_INE_CHK_DONE_OFFSET 19 +#define DMA_CH_CSR_INT_ERR_OFFSET 20 +#define DMA_CH_CSR_INT_DONE_OFFSET 21 +#define DMA_CH_CSR_INT_CHUNK_DONE_OFFSET 22 +#define DMA_CH_CSR_RESERVED_OFFSET 23 +#define DMA_CH_CSR_RESERVED_WIDTH 9 + +/* Masks -- Writable and readonly parts of the register */ +#define DMA_CH_CSR_WRITE_MASK 0x000FE3FF + +/* Field definitions for Channel Size Registers */ +#define DMA_CH_SZ_TOT_SZ_OFFSET 0 +#define DMA_CH_SZ_TOT_SZ_WIDTH 12 +#define DMA_CH_SZ_CHK_SZ_OFFSET 16 +#define DMA_CH_SZ_CHK_SZ_WIDTH 9 + +/* Field definitions for Channel Address Registers CHn_Am */ +#define DMA_CH_A0_ADDR_OFFSET 2 +#define DMA_CH_A0_ADDR_WIDTH 30 +#define DMA_CH_A1_ADDR_OFFSET 2 +#define DMA_CH_A1_ADDR_WIDTH 30 + +/* Field definitions for Channel Address Mask Registers CHn_AMm */ +#define DMA_CH_AM0_MASK_OFFSET 4 +#define DMA_CH_AM0_MASK_WIDTH 28 +#define DMA_CH_AM1_MASK_OFFSET 4 +#define DMA_CH_AM1_MASK_WIDTH 28 + +/* Field definitions for Channel Linked List descriptor Pointer CHn_DESC */ +#define DMA_CH_DESC_ADDR_OFFSET 2 +#define DMA_CH_DESC_ADDR_WIDTH 30 + +/* Field definitions for Channel Software Pointer */ +#define DMA_CH_SWPTR_PTR_OFFSET 2 +#define DMA_CH_SWPTR_PTR_WIDTH 29 +#define DMA_CH_SWPTR_EN_OFFSET 31 + + +/* Structure of linked list descriptors (offsets of elements) */ +#define DMA_DESC_CSR 0x00 +#define DMA_DESC_ADR0 0x04 +#define DMA_DESC_ADR1 0x08 +#define DMA_DESC_NEXT 0x0C + +/* Field definitions for linked list descriptor DESC_CSR */ +#define DMA_DESC_CSR_EOL_OFFSET 20 +#define DMA_DESC_CSR_INC_SRC_OFFSET 19 +#define DMA_DESC_CSR_INC_DST_OFFSET 18 +#define DMA_DESC_CSR_SRC_SEL_OFFSET 17 +#define DMA_DESC_CSR_DST_SEL_OFFSET 16 +#define DMA_DESC_CSR_TOT_SZ_OFFSET 0 +#define DMA_DESC_CSR_TOT_SZ_WIDTH 12 + + +/* Implementation of DMA Channel Registers and State */ +struct dma_channel +{ + /* The controller we belong to */ + struct dma_controller *controller; + + /* Our channel number and bit mask */ + unsigned channel_number; + unsigned long channel_mask; + + /* Used for dump, to save dumping all 32 channels */ + unsigned referenced; + + /* Inner state of transfer etc. */ + unsigned load_next_descriptor_when_done; + unsigned long current_descriptor; + unsigned long source, destination, source_mask, destination_mask; + unsigned long chunk_size, total_size, words_transferred; + + /* The interface registers */ + struct + { + unsigned long csr; + unsigned long sz; + unsigned long a0; + unsigned long am0; + unsigned long a1; + unsigned long am1; + unsigned long desc; + unsigned long swptr; + } regs; + + /* Some control signals */ + unsigned dma_req_i; + unsigned dma_ack_o; + unsigned dma_nd_i; +}; + + +/* Implementation of DMA Controller Registers and State */ +struct dma_controller +{ + /* Base address in memory */ + unsigned long baseaddr; + + /* Which interrupt number we generate */ + unsigned irq; + + /* Controller Registers */ + struct + { + unsigned long csr; + unsigned long int_msk_a; + unsigned long int_msk_b; + unsigned long int_src_a; + unsigned long int_src_b; + } regs; + + /* Channels */ + struct dma_channel ch[DMA_NUM_CHANNELS]; +}; Index: . =================================================================== --- . (nonexistent) +++ . (revision 1765)
. Property changes : Added: svn:ignore ## -0,0 +1 ## +Makefile

powered by: WebSVN 2.1.0

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