1/1

|
[or1ksim #25] Cleanup dma peripheral
by Unknown on Feb 5, 2005 |
Not available! | ||
|
Hi,
This cleans up the dma peripheral. One less *_clock in the main loop! This
also fixes compilation of the dmatest test.
ChangeLog:
* Cleanup dma peripheral useing the new callbacks.
nog.
-------------- next part --------------
--- peripheral/dma.h 2005-02-04 15:55:27.000000000 +0100
+++ ../or1ksim-ac/peripheral/dma.h 2005-02-05 11:15:04.000000000 +0100
@@ -1,4 +1,4 @@
-/* dma.h -- Definition of types and structures for DMA
+/* dma.h -- Definition of DMAperipheral interface
Copyright (C) 2001 by Erez Volk, erez@opencores.org
This file is part of OpenRISC 1000 Architectural Simulator.
@@ -18,120 +18,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* Exported function prototypes */
-void dma_reset( void );
-void dma_clock( void );
-void dma_status( 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
-
+#include "dma_defs.h"
/* Implementation of DMA Channel Registers and State */
struct dma_channel
@@ -149,7 +36,7 @@
/* Inner state of transfer etc. */
unsigned load_next_descriptor_when_done;
unsigned long current_descriptor;
- unsigned long source, destination, source_mask, destination_mask;
+ oraddr_t source, destination, source_mask, destination_mask;
unsigned long chunk_size, total_size, words_transferred;
/* The interface registers */
@@ -181,6 +68,9 @@
/* Which interrupt number we generate */
unsigned irq;
+ /* VAPI id */
+ int vapi_id;
+
/* Controller Registers */
struct
{
@@ -193,4 +83,14 @@
/* Channels */
struct dma_channel ch[DMA_NUM_CHANNELS];
+
+ struct dma_controller *next;
};
+
+void set_dma_req_i( struct dma_channel *channel );
+void clear_dma_req_i( struct dma_channel *channel );
+void set_dma_nd_i( struct dma_channel *channel );
+void clear_dma_nd_i( struct dma_channel *channel );
+unsigned check_dma_ack_o( struct dma_channel *channel );
+struct dma_channel *find_dma_controller_ch( unsigned controller,
+ unsigned channel );
--- sim-config.h 2005-02-04 16:25:08.000000000 +0100
+++ ../or1ksim-ac/sim-config.h 2005-02-05 10:17:30.000000000 +0100
@@ -24,7 +24,6 @@
/* Simulator configuration macros. Eventually this one will be a lot bigger. */
-#define MAX_DMAS 4 /* Max. number of DMA controllers */
#define MAX_ETHERNETS 4 /* Max. number of Ethernet MACs */
#define MAX_GPIOS 4 /* Max. number of GPIO modules */
#define MAX_MEMORIES 16 /* Max. number of memory devices attached */
@@ -42,13 +41,6 @@
int enabled; /* Is tick timer enabled? */
} tick;
- int ndmas;
- struct {
- unsigned long baseaddr;
- int irq; /* IRQ of this device */
- unsigned long vapi_id; /* VAPI id for this instance */
- } dmas[MAX_DMAS];
-
int nethernets;
struct {
unsigned long baseaddr;
--- sim-cmd.c 2005-02-04 15:55:48.000000000 +0100
+++ ../or1ksim-ac/sim-cmd.c 2005-02-05 10:18:25.000000000 +0100
@@ -60,7 +60,6 @@
#include "icache_model.h"
#include "dcache_model.h"
#include "branch_predict.h"
-#include "dma.h"
#include "ethernet.h"
#include "gpio.h"
#include "ps2kbd.h"
@@ -423,7 +432,6 @@
if (config.bpb.btic) btic_info();
if (config.mc.enabled) mc_status();
- if (config.ndmas) dma_status();
if (config.nethernets) eth_status();
if (config.ngpios) gpio_status();
kbd_info();
--- sim.cfg 2005-02-04 16:25:08.000000000 +0100
+++ ../or1ksim-ac/sim.cfg 2005-02-05 11:19:39.000000000 +0100
@@ -643,11 +643,6 @@
This section configures the DMAs
- ndmas =
- make specified number of instances, configure each
- instance within device - enddevice construct.
-
- instance specific:
baseaddr =
address of first DMA register for this device
@@ -659,14 +654,8 @@
*/
section dma
- ndmas = 0
-
- /*
- device 0
- baseaddr = 0x9a000000
- irq = 11
- enddevice
- */
+ baseaddr = 0x9a000000
+ irq = 11
end
--- sim-config.c 2005-02-05 11:26:28.000000000 +0100
+++ ../or1ksim-ac/sim-config.c 2005-02-05 10:18:09.000000000 +0100
@@ -124,9 +126,6 @@
/* Memory Controller */
config.mc.enabled = 0;
- /* DMAs */
- config.ndmas = 0;
-
/* CPU */
config.cpu.superscalar = 0;
config.sim.history = 0;
@@ -898,15 +902,6 @@
fprintf (f, " tick:{enabled:%i},\n", config.tick.enabled);
- fprintf (f, " ndmas:%i, dmas:{", config.ndmas);
- comma = 0;
- for (i = 0; i next;
}
- dma_reset();
eth_reset();
gpio_reset();
kbd_reset ();
@@ -446,7 +444,6 @@
if (config.ic.enabled) ic_clock();
}
- if (config.dmas) dma_clock();
if (config.ethernets) eth_clock();
if (config.ngpios) gpio_clock();
if (config.vapi.enabled && runtime.vapi.enabled) vapi_check();
--- testbench/dmatest.c 2002-09-04 13:29:25.000000000 +0200
+++ ../or1ksim-ac/testbench/dmatest.c 2005-02-05 11:16:28.000000000 +0100
@@ -3,7 +3,7 @@
#include "support.h"
#include "board.h"
#include "../peripheral/fields.h"
-#include "../peripheral/dma.h"
+#include "../peripheral/dma_defs.h"
typedef volatile unsigned long *DMA_REG;
--- /dev/null 2003-01-07 18:22:11.000000000 +0100
+++ peripheral/dma_defs.h 2005-02-05 11:15:01.000000000 +0100
@@ -0,0 +1,124 @@
+/* dma_defs.h -- Definition of relative addresses/register bits 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.
+*/
+
+/* 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
+
--- peripheral/dma.c 2005-02-05 15:06:48.000000000 +0100
+++ ../or1ksim-ac/peripheral/dma.c 2005-02-05 14:55:29.000000000 +0100
@@ -39,102 +39,88 @@
#include "pic.h"
#include "abstract.h"
#include "fields.h"
+#include "sched.h"
#include "debug.h"
-/* The representation of the DMA controllers */
-static struct dma_controller dmas[MAX_DMAS];
+/* We keep a copy of all our controllers because we have to export an interface
+ * to other peripherals eg. ethernet */
+static struct dma_controller *dmas = NULL;
static uint32_t dma_read32( oraddr_t addr, void *dat );
static void dma_write32( oraddr_t addr, uint32_t value, void *dat );
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 );
+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 );
+void dma_channel_clock( void *dat );
+
+static void masked_increase( oraddr_t *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()
+void dma_reset(void *dat)
{
- unsigned i;
+ struct dma_controller *dma = dat;
+ unsigned channel_number;
+
+ memset( dma->ch, 0, sizeof(dma->ch) );
- memset( dmas, 0, sizeof(dmas) );
+ dma->regs.csr = 0;
+ dma->regs.int_msk_a = 0;
+ dma->regs.int_msk_b = 0;
+ dma->regs.int_src_a = 0;
+ dma->regs.int_src_b = 0;
- for ( i = 0; i baseaddr = config.dmas.baseaddr;
- dma->irq = config.dmas.irq;
- for ( channel_number = 0; channel_number ch[channel_number].controller = &(dmas);
- dma->ch[channel_number].channel_number = channel_number;
- dma->ch[channel_number].channel_mask = 1LU ch[channel_number].regs.am0 = dma->ch[channel_number].regs.am1 = 0xFFFFFFFC;
- }
- if ( dma->baseaddr != 0 )
- register_memoryarea( dma->baseaddr, DMA_ADDR_SPACE, 4, 0, dma_read32, dma_write32, NULL );
+ for ( channel_number = 0; channel_number ch[channel_number].controller = dma;
+ dma->ch[channel_number].channel_number = channel_number;
+ dma->ch[channel_number].channel_mask = 1LU ch[channel_number].regs.am0 = dma->ch[channel_number].regs.am1 = 0xFFFFFFFC;
}
}
/* Print register values on stdout */
-void dma_status( void )
+void dma_status( void *dat )
{
unsigned i, j;
+ struct dma_controller *dma = dat;
- for ( i = 0; i baseaddr == 0 )
- continue;
+ if ( dma->baseaddr == 0 )
+ return;
- PRINTF( "\nDMA controller %u at 0x%"PRIxADDR":\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 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 );
- }
+ PRINTF( "\nDMA controller %u at 0x%"PRIxADDR":\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 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 */
uint32_t dma_read32( oraddr_t addr, void *dat )
{
- unsigned i;
- struct dma_controller *dma = NULL;
-
- for ( i = 0; i = dmas.baseaddr && addr baseaddr;
@@ -174,6 +160,7 @@
case DMA_CH_SWPTR: return dma->ch[chno].regs.swptr;
}
}
+ return 0;
}
@@ -196,21 +183,7 @@
/* Write a register */
void dma_write32( oraddr_t addr, uint32_t value, void *dat )
{
- unsigned i;
- struct dma_controller *dma = NULL;
-
- /* Find which controller this is */
- for ( i = 0; i = dmas.baseaddr) && (addr baseaddr;
@@ -263,141 +236,106 @@
*/
void dma_write_ch_csr( struct dma_channel *channel, unsigned long value )
{
+ /* Check if we should *start* a transfer */
+ if ( !TEST_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ) &&
+ TEST_FLAG( value, DMA_CH_CSR, CH_EN ))
+ SCHED_ADD( dma_channel_clock, channel, runtime.sim.cycles + 1 );
+ else if ( !TEST_FLAG( value, DMA_CH_CSR, CH_EN ) )
+ /* The CH_EN flag is clear, check if we have a transfer in progress and
+ * clear it */
+ SCHED_FIND_REMOVE( dma_channel_clock, channel );
+
/* 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 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;
+ /* 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 );
}
- /* 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;
- }
- }
+ return;
+ }
- /* Transfer one word */
- set_mem32( channel->destination, eval_mem32( channel->source, &breakpoint ), &breakpoint );
+ /* 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 ) {
+ /* Reschedule */
+ SCHED_ADD( dma_channel_clock, dat, runtime.sim.cycles + 1 );
+ return;
+ }
- /* Advance the source and destionation pointers */
- masked_increase( &(channel->source), channel->source_mask );
- masked_increase( &(channel->destination), channel->destination_mask );
- ++ channel->words_transferred;
+ /* 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;
- /* Have we finished a whole chunk? */
- channel->dma_ack_o = (channel->words_transferred % channel->chunk_size == 0);
+ /* Set our internal status */
+ dma_init_transfer( channel );
- /* When done with a chunk, check for dma_nd_i */
+ /* Might need to skip descriptor */
if ( CHANNEL_ND_I( channel ) ) {
- debug( 3, "DMA: dma_nd_i asserted\n" );
+ debug( 3, "DMA: dma_nd_i asserted before dma_req_i, skipping descriptor\n" );
dma_channel_terminate_transfer( channel, 0 );
- continue;
+ return;
}
+ }
+
+ /* Transfer one word */
+ set_mem32( channel->destination, eval_mem32( channel->source, &breakpoint ), &breakpoint );
- /* Are we done? */
- if ( channel->words_transferred >= channel->total_size )
- dma_channel_terminate_transfer( channel, 1 );
+ /* 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 );
+ return;
+ }
+
+ /* Are we done? */
+ if ( channel->words_transferred >= channel->total_size ) {
+ dma_channel_terminate_transfer( channel, 1 );
+ return;
}
+
+ /* Reschedule to transfer the next chunk */
+ SCHED_ADD( dma_channel_clock, dat, runtime.sim.cycles + 1 );
}
@@ -448,6 +386,8 @@
if ( channel->load_next_descriptor_when_done ) {
dma_load_descriptor( channel );
dma_init_transfer( channel );
+ /* Reschedule */
+ SCHED_ADD( dma_channel_clock, channel, runtime.sim.cycles + 1 );
return;
}
@@ -460,7 +400,7 @@
/* 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 ) ) {
- /* TODO: What should we write back? Doc says "total number of remaining bytes" !? */
+ /* 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 );
}
@@ -484,51 +424,112 @@
}
/* Utility function: Add 4 to a value with a mask */
-void masked_increase( unsigned long *value, unsigned long mask )
+static void masked_increase( oraddr_t *value, unsigned long mask )
{
*value = (*value & ~mask) | ((*value + 4) & mask);
}
-/*----------------------------------------------------[ DMA configuration ]---*/
-void dma_ndmas(union param_val val, void *dat)
+/*-------------------------------------------[ DMAPeripheral interface ]---*/
+/*
+ * Simulation of control signals
+ * To be used by simulations for other devices, e.g. ethernet
+ */
+
+void set_dma_req_i( struct dma_channel *channel )
{
- if (val.int_val >= 0 && val.int_val dma_req_i = 1;
}
+void clear_dma_req_i( struct dma_channel *channel )
+{
+ channel->dma_req_i = 0;
+}
+
+void set_dma_nd_i( struct dma_channel *channel )
+{
+ channel->dma_nd_i = 1;
+}
+
+void clear_dma_nd_i( struct dma_channel *channel )
+{
+ channel->dma_nd_i = 0;
+}
+
+unsigned check_dma_ack_o( struct dma_channel *channel )
+{
+ return channel->dma_ack_o;
+}
+
+struct dma_channel *find_dma_controller_ch( unsigned controller,
+ unsigned channel )
+{
+ struct dma_controller *cur = dmas;
+
+ while( cur && controller ) {
+ cur = cur->next;
+ controller--;
+ }
+
+ if( !cur )
+ return NULL;
+
+ return &(cur->ch[channel]);
+}
+
+
+/*----------------------------------------------------[ DMA configuration ]---*/
void dma_baseaddr(union param_val val, void *dat)
{
- if (current_device >= 0 && current_device baseaddr = val.addr_val;
}
void dma_irq(union param_val val, void *dat)
{
- if (current_device >= 0 && current_device irq = val.int_val;
}
void dma_vapi_id(union param_val val, void *dat)
{
- if (current_device >= 0 && current_device vapi_id = val.int_val;
+}
+
+void *dma_sec_start(void)
+{
+ struct dma_controller *new = malloc(sizeof(struct dma_controller));
+
+ if(!new) {
+ fprintf(stderr, "Peripheral DMA: Run out of memory\n");
+ exit(-1);
+ }
+
+ new->next = NULL;
+
+ return new;
+}
+
+void dma_sec_end(void *dat)
+{
+ struct dma_controller *dma = dat;
+ struct dma_controller *cur;
+
+ register_memoryarea( dma->baseaddr, DMA_ADDR_SPACE, 4, 0, dma_read32, dma_write32, dat );
+ reg_sim_reset( dma_reset, dat );
+ reg_sim_stat( dma_status, dat );
+
+ if(dmas) {
+ for(cur = dmas; cur->next; cur = cur->next);
+ cur->next = dma;
+ } else
+ dmas = dma;
}
void reg_dma_sec(void)
{
- struct config_section *sec = reg_config_sec("dma", NULL, NULL);
+ struct config_section *sec = reg_config_sec("dma", dma_sec_start, dma_sec_end);
- reg_config_param(sec, "ndmas", paramt_int, dma_ndmas);
- reg_config_param(sec, "device", paramt_int, change_device);
- reg_config_param(sec, "enddevice", paramt_none, end_device);
reg_config_param(sec, "irq", paramt_int, dma_irq);
reg_config_param(sec, "baseaddr", paramt_addr, dma_baseaddr);
reg_config_param(sec, "vapi_id", paramt_addr, dma_vapi_id);
|
|||
|
[or1ksim #25] Cleanup dma peripheral
by Unknown on Feb 11, 2005 |
Not available! | ||
|
This cleans up the dma peripheral. One less *_clock in the main loop! This
also fixes compilation of the dmatest test. The DMA test fixes have gone into cvs. Here's a patch that will apply cleanly against current cvs.
ChangeLog:
nog.
-------------- next part --------------
--- sim-config.h 2005-02-04 16:25:08.000000000 +0100
+++ ../or1ksim-ac/sim-config.h 2005-02-05 10:17:30.000000000 +0100
@@ -24,7 +24,6 @@
/* Simulator configuration macros. Eventually this one will be a lot bigger. */
-#define MAX_DMAS 4 /* Max. number of DMA controllers */
#define MAX_ETHERNETS 4 /* Max. number of Ethernet MACs */
#define MAX_GPIOS 4 /* Max. number of GPIO modules */
#define MAX_MEMORIES 16 /* Max. number of memory devices attached */
@@ -42,13 +41,6 @@
int enabled; /* Is tick timer enabled? */
} tick;
- int ndmas;
- struct {
- unsigned long baseaddr;
- int irq; /* IRQ of this device */
- unsigned long vapi_id; /* VAPI id for this instance */
- } dmas[MAX_DMAS];
-
int nethernets;
struct {
unsigned long baseaddr;
--- sim-cmd.c 2005-02-04 15:55:48.000000000 +0100
+++ ../or1ksim-ac/sim-cmd.c 2005-02-05 10:18:25.000000000 +0100
@@ -60,7 +60,6 @@
#include "icache_model.h"
#include "dcache_model.h"
#include "branch_predict.h"
-#include "dma.h"
#include "ethernet.h"
#include "gpio.h"
#include "ps2kbd.h"
@@ -423,7 +432,6 @@
if (config.bpb.btic) btic_info();
if (config.mc.enabled) mc_status();
- if (config.ndmas) dma_status();
if (config.nethernets) eth_status();
if (config.ngpios) gpio_status();
kbd_info();
--- sim.cfg 2005-02-04 16:25:08.000000000 +0100
+++ ../or1ksim-ac/sim.cfg 2005-02-05 11:19:39.000000000 +0100
@@ -643,11 +643,6 @@
This section configures the DMAs
- ndmas =
- make specified number of instances, configure each
- instance within device - enddevice construct.
-
- instance specific:
baseaddr =
address of first DMA register for this device
@@ -659,14 +654,8 @@
*/
section dma
- ndmas = 0
-
- /*
- device 0
- baseaddr = 0x9a000000
- irq = 11
- enddevice
- */
+ baseaddr = 0x9a000000
+ irq = 11
end
--- sim-config.c 2005-02-05 11:26:28.000000000 +0100
+++ ../or1ksim-ac/sim-config.c 2005-02-05 10:18:09.000000000 +0100
@@ -124,9 +126,6 @@
/* Memory Controller */
config.mc.enabled = 0;
- /* DMAs */
- config.ndmas = 0;
-
/* CPU */
config.cpu.superscalar = 0;
config.sim.history = 0;
@@ -898,15 +902,6 @@
fprintf (f, " tick:{enabled:%i},\n", config.tick.enabled);
- fprintf (f, " ndmas:%i, dmas:{", config.ndmas);
- comma = 0;
- for (i = 0; i next;
}
- dma_reset();
eth_reset();
gpio_reset();
kbd_reset ();
@@ -446,7 +444,6 @@
if (config.ic.enabled) ic_clock();
}
- if (config.dmas) dma_clock();
if (config.ethernets) eth_clock();
if (config.ngpios) gpio_clock();
if (config.vapi.enabled && runtime.vapi.enabled) vapi_check();
--- peripheral/dma.c 2005-02-05 15:06:48.000000000 +0100
+++ ../or1ksim-ac/peripheral/dma.c 2005-02-05 14:55:29.000000000 +0100
@@ -39,102 +39,88 @@
#include "pic.h"
#include "abstract.h"
#include "fields.h"
+#include "sched.h"
#include "debug.h"
-/* The representation of the DMA controllers */
-static struct dma_controller dmas[MAX_DMAS];
+/* We keep a copy of all our controllers because we have to export an interface
+ * to other peripherals eg. ethernet */
+static struct dma_controller *dmas = NULL;
static uint32_t dma_read32( oraddr_t addr, void *dat );
static void dma_write32( oraddr_t addr, uint32_t value, void *dat );
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 );
+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 );
+void dma_channel_clock( void *dat );
+
+static void masked_increase( oraddr_t *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()
+void dma_reset(void *dat)
{
- unsigned i;
+ struct dma_controller *dma = dat;
+ unsigned channel_number;
+
+ memset( dma->ch, 0, sizeof(dma->ch) );
- memset( dmas, 0, sizeof(dmas) );
+ dma->regs.csr = 0;
+ dma->regs.int_msk_a = 0;
+ dma->regs.int_msk_b = 0;
+ dma->regs.int_src_a = 0;
+ dma->regs.int_src_b = 0;
- for ( i = 0; i baseaddr = config.dmas.baseaddr;
- dma->irq = config.dmas.irq;
- for ( channel_number = 0; channel_number ch[channel_number].controller = &(dmas);
- dma->ch[channel_number].channel_number = channel_number;
- dma->ch[channel_number].channel_mask = 1LU ch[channel_number].regs.am0 = dma->ch[channel_number].regs.am1 = 0xFFFFFFFC;
- }
- if ( dma->baseaddr != 0 )
- register_memoryarea( dma->baseaddr, DMA_ADDR_SPACE, 4, 0, dma_read32, dma_write32, NULL );
+ for ( channel_number = 0; channel_number ch[channel_number].controller = dma;
+ dma->ch[channel_number].channel_number = channel_number;
+ dma->ch[channel_number].channel_mask = 1LU ch[channel_number].regs.am0 = dma->ch[channel_number].regs.am1 = 0xFFFFFFFC;
}
}
/* Print register values on stdout */
-void dma_status( void )
+void dma_status( void *dat )
{
unsigned i, j;
+ struct dma_controller *dma = dat;
- for ( i = 0; i baseaddr == 0 )
- continue;
+ if ( dma->baseaddr == 0 )
+ return;
- PRINTF( "\nDMA controller %u at 0x%"PRIxADDR":\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 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 );
- }
+ PRINTF( "\nDMA controller %u at 0x%"PRIxADDR":\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 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 */
uint32_t dma_read32( oraddr_t addr, void *dat )
{
- unsigned i;
- struct dma_controller *dma = NULL;
-
- for ( i = 0; i = dmas.baseaddr && addr baseaddr;
@@ -174,6 +160,7 @@
case DMA_CH_SWPTR: return dma->ch[chno].regs.swptr;
}
}
+ return 0;
}
@@ -196,21 +183,7 @@
/* Write a register */
void dma_write32( oraddr_t addr, uint32_t value, void *dat )
{
- unsigned i;
- struct dma_controller *dma = NULL;
-
- /* Find which controller this is */
- for ( i = 0; i = dmas.baseaddr) && (addr baseaddr;
@@ -263,141 +236,106 @@
*/
void dma_write_ch_csr( struct dma_channel *channel, unsigned long value )
{
+ /* Check if we should *start* a transfer */
+ if ( !TEST_FLAG( channel->regs.csr, DMA_CH_CSR, CH_EN ) &&
+ TEST_FLAG( value, DMA_CH_CSR, CH_EN ))
+ SCHED_ADD( dma_channel_clock, channel, runtime.sim.cycles + 1 );
+ else if ( !TEST_FLAG( value, DMA_CH_CSR, CH_EN ) )
+ /* The CH_EN flag is clear, check if we have a transfer in progress and
+ * clear it */
+ SCHED_FIND_REMOVE( dma_channel_clock, channel );
+
/* 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 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;
+ /* 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 );
}
- /* 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;
- }
- }
+ return;
+ }
- /* Transfer one word */
- set_mem32( channel->destination, eval_mem32( channel->source, &breakpoint ), &breakpoint );
+ /* 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 ) {
+ /* Reschedule */
+ SCHED_ADD( dma_channel_clock, dat, runtime.sim.cycles + 1 );
+ return;
+ }
- /* Advance the source and destionation pointers */
- masked_increase( &(channel->source), channel->source_mask );
- masked_increase( &(channel->destination), channel->destination_mask );
- ++ channel->words_transferred;
+ /* 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;
- /* Have we finished a whole chunk? */
- channel->dma_ack_o = (channel->words_transferred % channel->chunk_size == 0);
+ /* Set our internal status */
+ dma_init_transfer( channel );
- /* When done with a chunk, check for dma_nd_i */
+ /* Might need to skip descriptor */
if ( CHANNEL_ND_I( channel ) ) {
- debug( 3, "DMA: dma_nd_i asserted\n" );
+ debug( 3, "DMA: dma_nd_i asserted before dma_req_i, skipping descriptor\n" );
dma_channel_terminate_transfer( channel, 0 );
- continue;
+ return;
}
+ }
+
+ /* Transfer one word */
+ set_mem32( channel->destination, eval_mem32( channel->source, &breakpoint ), &breakpoint );
- /* Are we done? */
- if ( channel->words_transferred >= channel->total_size )
- dma_channel_terminate_transfer( channel, 1 );
+ /* 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 );
+ return;
+ }
+
+ /* Are we done? */
+ if ( channel->words_transferred >= channel->total_size ) {
+ dma_channel_terminate_transfer( channel, 1 );
+ return;
}
+
+ /* Reschedule to transfer the next chunk */
+ SCHED_ADD( dma_channel_clock, dat, runtime.sim.cycles + 1 );
}
@@ -448,6 +386,8 @@
if ( channel->load_next_descriptor_when_done ) {
dma_load_descriptor( channel );
dma_init_transfer( channel );
+ /* Reschedule */
+ SCHED_ADD( dma_channel_clock, channel, runtime.sim.cycles + 1 );
return;
}
@@ -460,7 +400,7 @@
/* 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 ) ) {
- /* TODO: What should we write back? Doc says "total number of remaining bytes" !? */
+ /* 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 );
}
@@ -484,51 +424,112 @@
}
/* Utility function: Add 4 to a value with a mask */
-void masked_increase( unsigned long *value, unsigned long mask )
+static void masked_increase( oraddr_t *value, unsigned long mask )
{
*value = (*value & ~mask) | ((*value + 4) & mask);
}
-/*----------------------------------------------------[ DMA configuration ]---*/
-void dma_ndmas(union param_val val, void *dat)
+/*-------------------------------------------[ DMAPeripheral interface ]---*/
+/*
+ * Simulation of control signals
+ * To be used by simulations for other devices, e.g. ethernet
+ */
+
+void set_dma_req_i( struct dma_channel *channel )
{
- if (val.int_val >= 0 && val.int_val dma_req_i = 1;
}
+void clear_dma_req_i( struct dma_channel *channel )
+{
+ channel->dma_req_i = 0;
+}
+
+void set_dma_nd_i( struct dma_channel *channel )
+{
+ channel->dma_nd_i = 1;
+}
+
+void clear_dma_nd_i( struct dma_channel *channel )
+{
+ channel->dma_nd_i = 0;
+}
+
+unsigned check_dma_ack_o( struct dma_channel *channel )
+{
+ return channel->dma_ack_o;
+}
+
+struct dma_channel *find_dma_controller_ch( unsigned controller,
+ unsigned channel )
+{
+ struct dma_controller *cur = dmas;
+
+ while( cur && controller ) {
+ cur = cur->next;
+ controller--;
+ }
+
+ if( !cur )
+ return NULL;
+
+ return &(cur->ch[channel]);
+}
+
+
+/*----------------------------------------------------[ DMA configuration ]---*/
void dma_baseaddr(union param_val val, void *dat)
{
- if (current_device >= 0 && current_device baseaddr = val.addr_val;
}
void dma_irq(union param_val val, void *dat)
{
- if (current_device >= 0 && current_device irq = val.int_val;
}
void dma_vapi_id(union param_val val, void *dat)
{
- if (current_device >= 0 && current_device vapi_id = val.int_val;
+}
+
+void *dma_sec_start(void)
+{
+ struct dma_controller *new = malloc(sizeof(struct dma_controller));
+
+ if(!new) {
+ fprintf(stderr, "Peripheral DMA: Run out of memory\n");
+ exit(-1);
+ }
+
+ new->next = NULL;
+
+ return new;
+}
+
+void dma_sec_end(void *dat)
+{
+ struct dma_controller *dma = dat;
+ struct dma_controller *cur;
+
+ register_memoryarea( dma->baseaddr, DMA_ADDR_SPACE, 4, 0, dma_read32, dma_write32, dat );
+ reg_sim_reset( dma_reset, dat );
+ reg_sim_stat( dma_status, dat );
+
+ if(dmas) {
+ for(cur = dmas; cur->next; cur = cur->next);
+ cur->next = dma;
+ } else
+ dmas = dma;
}
void reg_dma_sec(void)
{
- struct config_section *sec = reg_config_sec("dma", NULL, NULL);
+ struct config_section *sec = reg_config_sec("dma", dma_sec_start, dma_sec_end);
- reg_config_param(sec, "ndmas", paramt_int, dma_ndmas);
- reg_config_param(sec, "device", paramt_int, change_device);
- reg_config_param(sec, "enddevice", paramt_none, end_device);
reg_config_param(sec, "irq", paramt_int, dma_irq);
reg_config_param(sec, "baseaddr", paramt_addr, dma_baseaddr);
reg_config_param(sec, "vapi_id", paramt_addr, dma_vapi_id);
--- peripheral/dma.h 2005-02-11 08:49:27.000000000 +0100
+++ ../or1ksim-ac/peripheral/dma.h 2005-02-05 11:15:04.000000000 +0100
@@ -1,4 +1,4 @@
-/* dma.h -- Definition of types and structures for DMA
+/* dma.h -- Definition of DMAperipheral interface
Copyright (C) 2001 by Erez Volk, erez@opencores.org
This file is part of OpenRISC 1000 Architectural Simulator.
@@ -20,17 +20,6 @@
#include "dma_defs.h"
-/* Exported function prototypes */
-void dma_reset( void );
-void dma_clock( void );
-void dma_status( 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 );
-
/* Implementation of DMA Channel Registers and State */
struct dma_channel
{
@@ -47,7 +36,7 @@
/* Inner state of transfer etc. */
unsigned load_next_descriptor_when_done;
unsigned long current_descriptor;
- unsigned long source, destination, source_mask, destination_mask;
+ oraddr_t source, destination, source_mask, destination_mask;
unsigned long chunk_size, total_size, words_transferred;
/* The interface registers */
@@ -79,6 +68,9 @@
/* Which interrupt number we generate */
unsigned irq;
+ /* VAPI id */
+ int vapi_id;
+
/* Controller Registers */
struct
{
@@ -91,4 +83,14 @@
/* Channels */
struct dma_channel ch[DMA_NUM_CHANNELS];
+
+ struct dma_controller *next;
};
+
+void set_dma_req_i( struct dma_channel *channel );
+void clear_dma_req_i( struct dma_channel *channel );
+void set_dma_nd_i( struct dma_channel *channel );
+void clear_dma_nd_i( struct dma_channel *channel );
+unsigned check_dma_ack_o( struct dma_channel *channel );
+struct dma_channel *find_dma_controller_ch( unsigned controller,
+ unsigned channel );
* Cleanup dma peripheral useing the new callbacks. |
|||
1/1

