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, ð, &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, ð, &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