📄 drive42.cpp
字号:
DWORD boundary = 0x80; // A byte offset.
DWORD blockSize = 0x4; // DWORDs
// int guardbandSize = 0; // DWORDs // In this test, we put the guardband (if any) on the Local side.
//
// testSMguardband_PL
//
//
// P over L (PCI-side block is higher in mem than Local side block)
//
DWORD testSMguardband_PL (DWORD comemID)
{
DWORD reportBase, base, i, dRead1, dRead2, dRead3, dRead4, dWrote;
base = getlinBAR0(comemID) + (SMbase + boundary); // Compute a byte address
reportBase = (SMbase + boundary);
// DWORD WRWR...
for (i = 0 ; i < blockSize ; i++)
{
dWrote = 0x22222220 | i ;
((long *) base)[i] = dWrote;
if ( (dRead1 = ((long *) base)[i]) != dWrote)
{
dRead2 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
globalErrorCnt++;
errorHandler (reportBase + i*4, dRead1, dRead2, dWrote);
for (DWORD j = 0 ; j < 1000000 ; j++) // We want totally different circumstances when we do the next read.
;
dRead3 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
dRead4 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
errorHandler (reportBase + i*4, dRead3, dRead4, dWrote);
}
dWrote = 0xddddddd0 | i ;
((long *) base)[i] = dWrote;
if ( (dRead1 = ((long *) base)[i]) != dWrote)
{
dRead2 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
globalErrorCnt++;
errorHandler (reportBase + i*4, dRead1, dRead2, dWrote);
for (DWORD j = 0 ; j < 1000000 ; j++) // We want totally different circumstances when we do the next read.
;
dRead3 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
dRead4 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
errorHandler (reportBase + i*4, dRead3, dRead4, dWrote);
}
}
// DWORD Block (!!!) WRWR...
for (i = 0 ; i < blockSize ; i++)
{
dWrote = 0x22222220 | i ;
((long *) base)[i] = dWrote;
}
for (i = 0 ; i < blockSize ; i++)
{
dWrote = 0x22222220 | i ;
if ( (dRead1 = ((long *) base)[i]) != dWrote)
{
dRead2 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
globalErrorCnt++;
errorHandler (reportBase + i*4, dRead1, dRead2, dWrote);
for (DWORD j = 0 ; j < 1000000 ; j++) // We want totally different circumstances when we do the next read.
;
dRead3 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
dRead4 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
errorHandler (reportBase + i*4, dRead3, dRead4, dWrote);
}
}
// DWORD Block (!!!) WRWR...
for (i = 0 ; i < blockSize ; i++)
{
dWrote = 0xddddddd0 | i ;
((long *) base)[i] = dWrote;
}
for (i = 0 ; i < blockSize ; i++)
{
dWrote = 0xddddddd0 | i ;
if ( (dRead1 = ((long *) base)[i]) != dWrote)
{
dRead2 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
globalErrorCnt++;
errorHandler (reportBase + i*4, dRead1, dRead2, dWrote);
for (DWORD j = 0 ; j < 1000000 ; j++) // We want totally different circumstances when we do the next read.
;
dRead3 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
dRead4 = ((long *) base)[i]; // Unconditionally read again and call the error handler.
errorHandler (reportBase + i*4, dRead3, dRead4, dWrote);
}
}
return (0);
} // end testSMguardband_PL
*/
//
// doDMA
//
// Transfer up to 16KB via the 3042's DMA controller.
//
// Although in this example, we transfer between Host Mem and the 3042's Shared Mem, we could
// use doDMA *unchanged* to do peer-to-peer transfers between devices on the PCI bus.
//
DWORD doDMA (DWORD * PCIphysMem, // The PCI (physical) Memory space address (as opposed to I/O or Config space addresses).
// The 3042 needs this because it knows nothing (directly) about linear addresses.
DWORD SMstart, // Shared Mem start. Is 0 to point to the zeroth DWORD of 3042 Shared Mem.
DWORD length, // Length in bytes. Gets converted to DWORDs below.
DWORD direction, // To or From Host Mem.
DWORD comemID) // Which 3042 we're driving.
{
DWORD errorCnt = 0;
// Set the starting Shared Mem address in DMALBASE register.
g_regp->dmalbase = SMstart; // Give it a byte address, but since DMALBASE bits 0 and 1 are dead,
// this loads a DWORD address. The L in DMALBASE means Local, as in the
// Local-side interface.
// Set the DMASIZE.
g_regp->dmasize = length - 4; // Give it a byte size, but since DMASIZE bits 0 and 1 are dead,
// actually loads a DWORD size. Also, the value written to the DMASIZE register
// must be reduced by one DWORD (4 bytes).
// Set the DMAHBASE to the PCI (physical) Memory address
g_regp->dmahbase = (DWORD) PCIphysMem; // Once again, we give it a byte address, but because bits 0 and 1 are dead
// loads a DWORD address.
// Clear the DMA complete bit.
g_regp->hint &= DMA_COMPLETE_BIT;
// Write low-order byte of DMACTL to set the direction, and to KICK OFF the DMA.
// The only operations that MUST be done on each DMA transfer are the kick off and the wait for DMA_COMPLETE_BIT.
g_regp->dmactl_v.dmactl_bytes[0] = (unsigned char) direction;
// Now the 3042 DMA masters the PCI bus and moves the data.
// Looking at the PCI bus, you'd see mostly bursts of data moved by the DMA, with occasional polls of HINT.
// The length of the bursts is determined by the value in the 3042's Latency Timer,
// and other PCI bus activity (including our HINT polling).
// Wait for the DMA complete bit to be set.
//
// We also want to check for a timeout here, because we don't want our thread to hang with no notification
// if something goes wrong.
const DWORD loopsPerByte = 0x100; // Number of times through this 'while' loop per byte of DMA.
int timeout = length * loopsPerByte; // Give lots of time to complete.
while ( ((g_regp->hint & DMA_COMPLETE_BIT) != DMA_COMPLETE_BIT)
&& timeout
)
{
// Reduce the frequency of HINT polling to improve performance, but poll often enough
// that a poll occurs soon after the end of the DMA transfer (ideally just after the end).
//
// The optimal delay to be inserted here is dependent on:
// - your processor speed
// - the length of DMA transfer
// - characteristics of the PCI bus arbiter, the Latency Timer setting, and other PCI bus traffic
// - etc., etc.
// A loop count of 150 works well for the 16 KB blocks, 200 MHz Pentium Pro and 440FX Chipset used to tune this example.
for (volatile DWORD i = 0 ; i < 150 ; i++)
;
timeout--;
}
if (timeout <= 0)
{
errorCnt++;
printf ("Error: timed out before DMA_COMPLETE_BIT set. errorCnt=%d\n", errorCnt);
}
return (errorCnt);
} // end doDMA
//
// Send a WORD to the designated 3042 via the HL mailbox (HLDATA).
// Assumes that the Local processor has been started earlier, and that it is waiting (intently) for
// this WORD to be sent from the host.
//
// theWORD may be any value *except* the following:
// #define GOT_IT 0xFEDC // Some data pattern that is not likely to occur at random. Must be the same as in 860 code.
DWORD putWORD (DWORD theWORD, DWORD comemID)
{
int timeout = 1000000; // Give mucho time to complete.
g_regp->hldata = theWORD & 0x0000ffff;
while ( (g_regp->hldata == theWORD) && timeout)
timeout--;
if (timeout <= 0)
{
printf ("Timed out waiting for Local. Is probably dead.\n");
return LOCALDEAD;
}
else
return NO_ERROR;
} // putWORD
/*
//
// Wait for theWORD to be stuffed into the HLDATA register by the 860.
//
DWORD waitWORD (DWORD theWORD, DWORD comemID)
{
int timeout = 10000000; // Give mucho time to complete.
theWORD &= 0x0000ffff; // Mask in the lower-order word.
while ( (g_regp->hldata != theWORD) && timeout)
timeout--;
if (timeout <= 0)
{
printf ("Timed out waiting for Local. Is probably dead.\n");
return LOCALDEAD;
}
else
{
return NO_ERROR;
}
} // waitWORD
*/
int init3042(int comemID)
{
blockT map[MAX_BLOCK] = {0}; // Initialize this to all zeroes in case there is an incomplete .ini file
DWORD returnCode;
const int endianFlag = 3; // Use 0 for little endian
// char * iniFileName = ".\\3042\\map42.ini" ;
// char * logFileBase = ".\\debug\\log" ;
// char * hexFileName = argv[2];
//////////////////////////////////////////////////////////////////////
// Contact the driver
//////////////////////////////////////////////////////////////////////
returnCode = comemOpenDriverL(comemID);
if (returnCode != NO_ERROR)
{
reportErrorCode(returnCode, " opening driver");
return(1);
}
// Get the linear BAR0 and BAR1 pointers (we only use BAR0 here) so we can access the 3042's registers.
// You may want to move this out of testDMA, doing it only once at the start of your application.
//
// Throughout this code, 'L' at the end of function names means Lite, as in CO-MEM Lite.
returnCode = comemCopyBarPtrL(g_linBAR, comemID);
if (returnCode != NO_ERROR)
{
reportErrorCode(returnCode, "creating BAR pointers.");
// errorCnt++;
}
// Setup the structure template we use to access the 3042 op regs.
// Note well: For the 3042 structure used in this drive42.cpp module, we must NOT
// add in the 0x460 offset.
g_regp = (struct op_regs_struct_42_zerobased_t *) (g_linBAR[0]);
// Allocate 4 Pages (4 KB each, 16 KB total = size of 3042 Shared Mem) which are (must be!)
// contiguous in Physical (and Linear) memory space.
//
// We pass the Physical address to the 3042's DMA controller DMAHBASE register.
// We need the Linear address to reference the Pages from this program, which runs on the 'Linear side' of
// the x86's MMU (Memory Management Unit).
//
// This allocation may be done once when the application is launched. However, here we chose to
// allocate and deallocate for each invocation of testDMA. Remember to pair allocations with
// deallocations.
//
returnCode = comemAllocContigMemL (4, // In: Number of pages. Can be 1 to 4. Must be 4 for this test.
&g_lin, // Out: Returns the Linear address of the allocated Pages.
&g_phys, // Out: Returns the Physical address of the allocated Pages.
comemID); // In: The 3042 that 'owns' the pages.
if (returnCode != NO_ERROR)
{
printf("Error in comemAllocContigMemL.");
// return (++errorCnt);
}
g_hostLin = (DWORD *) g_lin;
g_hostPhys = (DWORD *) g_phys;
g_regp->i2ohimr = 0x8; // Turn off the I2O interrupt for safety.
// ********* The following line must be removed for end-to-end tests !!! ************
g_regp->hctl = 0x1; // Hold the 860 in reset (S=0, R=1) while running this Application.
PCI_CONFIG_HEADER_0 temp;
returnCode = comemGetPCIInfoL(&temp, comemID);
temp.LatencyTimer = 0xff; // Set Latency Timer to the max
returnCode = comemSetPCIInfoL(&temp, comemID);
// tortureMem(comemID); // Torture the shared memory (what's the emoticon for a sadistic laugh?).
return (NO_ERROR);
}
// Kick off and complete a DMA transfer.
// Called only from the demo app idle loop.
int run3042(int direction, int DMAsize, int endToEnd, int comemID)
{
DWORD SMstart = 0;
// Note: 'Host Mem' can be PCI Memory (physical) addresses other than those assigned to Host Memory.
// In this example, we use Host Mem as the source and destination. But the 3042 does
// support peer-to-peer DMA transfers. Get the physical addresses of the peer PCI devices from their BARs.
// We don't handle the error return from doDMA for speed, but this is not,
// in general, recommended practice.
if (endToEnd)
{
doDMA ( g_hostPhys, // host-side physical address
SMstart, // Shared Mem start (first byte of shared mem = address 0)
DMAsize, // size of DMA transfer (in bytes)
direction, // the direction of the transfer
comemID); // which 3042 are we driving
putWORD (111, comemID); // Tell the 860 to copy the data to its local mem.
// waitWORD (444, comemID); // Wait for the 860 to complete its copy.
}
else
{
doDMA ( g_hostPhys, // host-side physical address
SMstart, // Shared Mem start (first byte of shared mem = address 0)
DMAsize, // size of DMA transfer (in bytes)
direction, // the direction of the transfer
comemID); // which 3042 are we driving
}
return (NO_ERROR);
}
DWORD closeDriver(DWORD comemID)
{
DWORD returnCode = NO_ERROR;
// Deallocate the 4 Pages we allocated above.
comemDeAllocContigMemL(&g_lin, &g_phys, comemID);
comemCloseDriverL(comemID);
return (returnCode);
}
int close3042(int comemID)
{
return (closeDriver(comemID)); // Frees memory, closes driver.
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -