Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

813 lines
24 KiB

  1. // $Header: G:/SwDev/WDM/Video/bt848/rcs/Riscprog.cpp 1.14 1998/05/04 17:53:37 tomz Exp $
  2. #include "riscprog.h"
  3. #include "physaddr.h"
  4. #define ClearMem( a ) memset( &##a, '\0', sizeof( a ) )
  5. DWORD RISCProgram::GetDataBuffer( )
  6. {
  7. return dwLinBufAddr_;
  8. }
  9. void RISCProgram::SetDataBuffer( DWORD addr )
  10. {
  11. dwLinBufAddr_ = addr;
  12. }
  13. void RISCProgram::Dump( )
  14. {
  15. if( bAlreadyDumped_ ) {
  16. return;
  17. }
  18. DebugOut((0, "; RiscProgram(%x) ProgAddr(%x) PhysProgAddr(%x)\n",
  19. this,
  20. GetProgAddress( ),
  21. GetPhysProgAddr( )));
  22. DebugOut((0, " RiscProgram(%x) dwBufAddr_(%x) dwLinBufAddr_(%x)\n",
  23. this,
  24. dwBufAddr_,
  25. dwLinBufAddr_));
  26. return;
  27. dwSize_ = 0;
  28. DWORD* pProgLoc = (DWORD*) GetProgAddress( );
  29. while( *pProgLoc++ != PROGRAM_TERMINATOR ) {
  30. dwSize_++;
  31. if( dwSize_ > 1024 ) {
  32. dwSize_ = 0;
  33. break;
  34. }
  35. }
  36. DWORD dwTmpSize_ = dwSize_;
  37. DebugOut((0, "; size = %d\n", dwSize_));
  38. if( dwSize_ ) {
  39. DebugOut((0, "%x ", GetPhysProgAddr( )));
  40. }
  41. PULONG pulProg = (PULONG) (ProgramSpace_->getLinearBase());
  42. while( dwTmpSize_ >= 4 ) {
  43. DebugOut((0, " %08x %08x %08x %08x\n",
  44. pulProg[0],
  45. pulProg[1],
  46. pulProg[2],
  47. pulProg[3]));
  48. pulProg += 4;
  49. dwTmpSize_ -= 4;
  50. }
  51. switch( dwTmpSize_ ) {
  52. case 3:
  53. DebugOut((0, " %08x %08x %08x\n",
  54. pulProg[0],
  55. pulProg[1],
  56. pulProg[2]
  57. ));
  58. break;
  59. case 2:
  60. DebugOut((0, " %08x %08x\n",
  61. pulProg[0],
  62. pulProg[1]
  63. ));
  64. break;
  65. case 1:
  66. DebugOut((0, " %08x\n",
  67. pulProg[0]
  68. ));
  69. break;
  70. }
  71. bAlreadyDumped_ = TRUE;
  72. #if 0
  73. if( pChild_ != NULL ) {
  74. // *** warning - recursion ***
  75. pChild_->Dump();
  76. }
  77. #endif
  78. bAlreadyDumped_ = FALSE;
  79. }
  80. /*
  81. {
  82. // Input
  83. // DWORD : RiscProg ndx
  84. // CreatedProgs : 12 elements ndx 0..11
  85. // ActiveProgs : 12 elements ndx 12..23
  86. // Skippers : 8 elements ndx 24..31
  87. // Output
  88. // Buffer filled with riscprog
  89. int i = 0;
  90. if ( !pDIOCParams->dioc_cbOutBuf || (pDIOCParams->dioc_cbInBuf != 4))
  91. return -1; // invalid parameters
  92. // pause
  93. // CaptureContrll_->Pause() ;
  94. // dump a prog
  95. DWORD WhichProg = *((PDWORD) pDIOCParams->dioc_InBuf);
  96. RiscPrgHandle hProg ;
  97. if (WhichProg < 12) // CreatedProgs
  98. {
  99. hProg = CaptureContrll_->CreatedProgs_[WhichProg] ;
  100. }
  101. else if (WhichProg < 24) // Active
  102. {
  103. hProg = CaptureContrll_->ActiveProgs_[WhichProg % 12] ;
  104. }
  105. else // Skippers
  106. {
  107. hProg = CaptureContrll_->Skippers_[WhichProg % 12] ;
  108. }
  109. if(hProg)
  110. {
  111. char * pRetAddr = (char *)pDIOCParams->dioc_OutBuf;
  112. DWORD physAddr = hProg->GetPhysProgAddr() ;
  113. DWORD progSize = hProg->GetProgramSize();
  114. char * linBuf = (char *) MapPhysToLinear((void *)physAddr, progSize, 0) ;
  115. *((DWORD *) pRetAddr) = physAddr ;
  116. pRetAddr+=4 ;
  117. for (i = 0 ; i < progSize && i < pDIOCParams->dioc_cbOutBuf ; i++)
  118. {
  119. *pRetAddr++ = linBuf[i] ;
  120. }
  121. }
  122. if ( pDIOCParams->dioc_bytesret )
  123. *pDIOCParams->dioc_bytesret = i;
  124. // and resume
  125. // CaptureContrll_->Continue() ;
  126. }
  127. */
  128. /* Method: RISCProgram::ChangeAddress
  129. * Purpose: Modifies existing program to use new destination address
  130. * Input: dwNewAddr: DWORD - new buffer address
  131. * Output: None
  132. */
  133. void RISCProgram::ChangeAddress( DataBuf &buf )
  134. {
  135. Trace t("RISCProgram::ChangeAddress()");
  136. //DebugOut((1, "RISCProgram::ChangeAddress(): this(%x), buf.pData_(%x)\n", this, buf.pData_));
  137. Create( Interrupting_, buf, dwPlanarAdjust_, GenerateResync_, false );
  138. }
  139. /* Function: CreatePrologEpilog
  140. * Purpose: Called from Create function to put proper sync codes at the beginning
  141. * and at the end of a RISC program
  142. * Input: pProgLoc: PDWORD - pointer to the instruction memory
  143. * SyncBits: SyncCode
  144. * CurCommand: Command & - reference to a command object
  145. * Output: PDWORD - address of the next instruction
  146. */
  147. inline PDWORD RISCProgram::CreatePrologEpilog( PDWORD pProgLoc, SyncCode SyncBits,
  148. Command &CurCommand, bool Resync )
  149. {
  150. Trace t("RISCProgram::CreatePrologEpilog()");
  151. CurCommand.Create( pProgLoc, SYNC, NULL, NULL, false );//, false, false );
  152. CurCommand.SetSync( pProgLoc, SyncBits, Resync );
  153. // advance to the next command's position
  154. return pProgLoc + CurCommand.GetInstrSize();
  155. }
  156. inline bool IsWithin( int coord, int top, int bot )
  157. {
  158. Trace t("IsWithin()");
  159. return bool( coord >= top && coord < bot );
  160. }
  161. inline PDWORD FinishWithSkip( int pixels, int bpp, PDWORD pProgLoc, Command &com )
  162. {
  163. Trace t("FinishWithSkip()");
  164. WORD awByteCounts [1];
  165. awByteCounts [0] = WORD( pixels * bpp );
  166. return (LPDWORD)com.Create( pProgLoc, SKIP, awByteCounts, NULL,
  167. true, false, true, false ); // safety, SOL, EOL, Intr
  168. }
  169. ErrorCode RISCProgram::GetDataBufPhys( DataBuf &buf )
  170. {
  171. Trace t("RISCProgram::GetDataBufPhys()");
  172. dwBufAddr_ = GetPhysAddr( buf );
  173. if ( dwBufAddr_ == (DWORD)-1 ) {
  174. return Fail;
  175. }
  176. return Success;
  177. }
  178. /* Method: RISCProgram::AllocateStorage
  179. * Purpose: Allocates a number of pages ( locked and physically contiguous ) to
  180. * hold the new program
  181. * Input: None
  182. * Output: ErrorCode
  183. */
  184. ErrorCode RISCProgram::AllocateStorage( bool extra, int )
  185. {
  186. Trace t("RISCProgram::AllocateStorage()");
  187. if ( ProgramSpace_ )
  188. return Success;
  189. // figure out size of the memory to hold the program
  190. // at least as many DWORDs as lines
  191. DWORD dwProgramSize = ImageSize_.cy * sizeof( DWORD );
  192. // scale up according to the data format
  193. switch ( BufFormat_.GetColorFormat() ) {
  194. case CF_RGB32:
  195. case CF_RGB24:
  196. case CF_RGB16:
  197. case CF_RGB15:
  198. case CF_Y8:
  199. case CF_YUY2:
  200. case CF_UYVY:
  201. case CF_BTYUV:
  202. case CF_RGB8:
  203. case CF_RAW:
  204. case CF_VBI:
  205. dwProgramSize *= 2; // size of 'Write' command is 2 DWORDs
  206. if ( extra == true ) // doing clipping
  207. dwProgramSize *= 3;
  208. break;
  209. case CF_PL_422:
  210. case CF_PL_411:
  211. case CF_YUV9:
  212. case CF_YUV12:
  213. case CF_I420:
  214. dwProgramSize *= 5; // Planar WRITE is 5 DWORDs
  215. }
  216. // add extra for page crossings
  217. dwProgramSize += ImageSize_.cx * ImageSize_.cy * BufFormat_.GetBitCount() / 8
  218. / PAGE_SIZE * sizeof( DWORD ) * 5;
  219. ProgramSpace_ = new PsPageBlock( dwProgramSize );
  220. if ( ProgramSpace_ && ProgramSpace_->getLinearBase() != 0 )
  221. return Success;
  222. return Fail;
  223. }
  224. /* Function: GetAlternateSwitch
  225. * Purpose: Chooses alternative instruction frequency
  226. * Input: AlternateSwitch: int
  227. * col: ColFmt, color format
  228. * Output: None
  229. */
  230. inline void GetAlternateSwitch( int &AlternateSwitch, ColFmt col )
  231. {
  232. Trace t("GetAlternateSwitch()");
  233. AlternateSwitch = col == CF_YUV9 ? 4 :
  234. col == CF_YUV12 ? 2 : 1;
  235. }
  236. /* Function: GetSplitAddr
  237. * Purpose: Calculates page-aligned address
  238. * Input: dwLinBufAddr: DWORD - linear address
  239. * Output: DWORD
  240. */
  241. inline DWORD GetSplitAddr( DWORD dwLinBufAddr )
  242. {
  243. Trace t("GetSplitAddr()");
  244. return ( dwLinBufAddr + PAGE_SIZE ) & ~( PAGE_SIZE - 1 );//0xFFFFF000L;
  245. // return ( dwLinBufAddr + 0x1000 ) & 0xFFFFF000L;
  246. }
  247. /* Function: GetSplitByteCount
  248. * Purpose: Calculates number of bytes before the page boundary
  249. * Input: dwLinBufAddr: DWORD, address
  250. * Output: WORD, byte count
  251. */
  252. inline WORD GetSplitByteCount( DWORD dwLinBufAddr )
  253. {
  254. Trace t("GetSplitByteCount()");
  255. return WORD( PAGE_SIZE - BYTE_OFFSET( dwLinBufAddr ) );
  256. // return WORD( 0x1000 - ( dwLinBufAddr & 0xFFF ) );
  257. }
  258. /* Function: GetSplitNumbers
  259. * Purpose: Calculates addresses and byte counts when scan line crosses a page boundary
  260. * Input: dwLinAddr: DWORD, starting linear address
  261. * wByteCount: WORD &, number of bytes to move before page crossing
  262. * wByteCSplit: WORD &, number of bytes to move after page crossing
  263. * SecondAddr: DWORD &, reference to the DWORD contatining address of the starting
  264. * address for the second 'write' instruction
  265. * FirstAddr: DWORD &,
  266. */
  267. void GetSplitNumbers( DataBuf buf, WORD &wFirstByteCount, WORD &wSecondByteCount,
  268. DWORD &SecondAddr, DWORD &FirstAddr )
  269. {
  270. Trace t("GetSplitNumbers()");
  271. // maybe can have some optimization here: if within the same page as previous
  272. // call ( no split ), don't call out for the physical address - just
  273. // increment the old physical address by difference in virtual addresses
  274. FirstAddr = GetPhysAddr( buf );
  275. if ( Need2Split( buf, wFirstByteCount ) ) {
  276. wSecondByteCount = wFirstByteCount;
  277. // lin address of the second write command ( page aligned )
  278. SecondAddr = GetSplitAddr( DWORD( buf.pData_ ) );
  279. // byte count of first write command
  280. wFirstByteCount = GetSplitByteCount( DWORD( buf.pData_ ) );
  281. wSecondByteCount -= wFirstByteCount;
  282. // get the physical addresses
  283. buf.pData_ = PBYTE( SecondAddr );
  284. SecondAddr = GetPhysAddr( buf );
  285. } else {
  286. wSecondByteCount = 0;
  287. SecondAddr = 0;
  288. }
  289. }
  290. /* Function: AdjustByteCounts
  291. * Purpose: This function is used to calculate 2 byte counts based on the given ratio
  292. * Purpose:
  293. */
  294. void AdjustByteCounts( WORD &smaller, WORD &larger, WORD total, WORD ratio )
  295. {
  296. Trace t("AdjustByteCounts()");
  297. if ( ratio <= 1 ) {
  298. smaller = WORD( total >> 1 );
  299. } else
  300. smaller = WORD( total / ratio );
  301. smaller += (WORD)3;
  302. smaller &= ~3;
  303. larger = WORD( total - smaller );
  304. }
  305. /* Method: RISCProgram::Create
  306. * Purpose: Creates a RISC program
  307. * Input: NeedInterrupt: bool - flag
  308. * Output: None
  309. * Note: It is likely this function is used to simply change dst addresses of
  310. * an already existing program. It does not seem to make much sense to write
  311. * basically the same function ( or the one that has to parse existing program)
  312. * to change addresses
  313. */
  314. ErrorCode RISCProgram::Create( bool NeedInterrupt, DataBuf buf, DWORD dwPlanrAdjust,
  315. bool rsync, bool LoopOnItself )
  316. {
  317. Trace t("RISCProgram::Create(2)");
  318. dwPlanarAdjust_ = dwPlanrAdjust;
  319. Interrupting_ = NeedInterrupt;
  320. GenerateResync_ = rsync;
  321. // allocate memory for the program first
  322. if ( AllocateStorage() != Success )
  323. return Fail;
  324. // store the buffer address in case somebody will want to change clipping
  325. if ( buf.pData_ && GetDataBufPhys( buf ) != Success )
  326. return Fail;
  327. // keep the linear address around
  328. dwLinBufAddr_ = DWORD( buf.pData_ );
  329. pSrb_ = buf.pSrb_;
  330. DebugOut((1, "dwLinBufAddr_ = %x\n", dwLinBufAddr_));
  331. // bad naming ?
  332. DWORD dwLinBufAddr = dwLinBufAddr_;
  333. // probably should create a class to handle these arrays
  334. WORD awByteCounts [3];
  335. DWORD adwAddresses [3];
  336. Instruction MainInstrToUse, AltInstrToUse;
  337. int AlternateSwitch = 1;
  338. // used to increment planes' addresses
  339. LONG PlanePitch1 = dwBufPitch_, ChromaPitch = dwBufPitch_;
  340. // get size in bytes
  341. DWORD dwYPlaneSize = ImageSize_.cy * dwBufPitch_;
  342. // DebugOut((1, "buf addr = %x\n", dwLinBufAddr ) );
  343. // this is a physical address
  344. DWORD Plane1 = dwLinBufAddr_ + dwYPlaneSize, Plane2;
  345. // initialize byte count for all planar modes
  346. awByteCounts [0] = (WORD)ImageSize_.cx;
  347. if ( !dwLinBufAddr_ ) { // hack to handle special case of creating a skipper for VBI streams
  348. MainInstrToUse = SKIP123;
  349. AltInstrToUse = SKIP123;
  350. } else {
  351. MainInstrToUse = WRITE1S23;
  352. AltInstrToUse = WRITE123;
  353. }
  354. // handle all planar modes here
  355. SyncCode SyncBits = SC_FM3;
  356. // these guys used for the calculation of addresses
  357. // for different planar mode combinations ( pitch > witdh, interleaving )
  358. DWORD dwEqualPitchDivider = 1;
  359. DWORD dwByteCountDivider = 1;
  360. bool flip = false;
  361. // prepare all the ugly things
  362. switch ( BufFormat_.GetColorFormat() ) {
  363. case CF_RGB32:
  364. case CF_RGB24:
  365. case CF_RGB16:
  366. case CF_RGB15:
  367. case CF_BTYUV:
  368. case CF_RGB8:
  369. flip = Interrupting_;
  370. case CF_Y8:
  371. case CF_YUY2:
  372. case CF_UYVY:
  373. case CF_RAW:
  374. case CF_VBI:
  375. if ( !dwLinBufAddr_ ) { // hack to handle special case of creating a skipper for VBI streams
  376. MainInstrToUse = SKIP;
  377. AltInstrToUse = SKIP;
  378. } else {
  379. MainInstrToUse = WRIT;
  380. AltInstrToUse = WRIT;
  381. }
  382. awByteCounts [0] = (WORD)(ImageSize_.cx * BufFormat_.GetBitCount() / 8 );
  383. // packed data to follow
  384. SyncBits = SC_FM1;
  385. break;
  386. case CF_PL_422:
  387. dwEqualPitchDivider = 2;
  388. dwByteCountDivider = 2;
  389. break;
  390. case CF_PL_411:
  391. dwEqualPitchDivider = 4;
  392. dwByteCountDivider = 4;
  393. break;
  394. case CF_YUV9:
  395. AlternateSwitch = 4;
  396. dwEqualPitchDivider = 16;
  397. dwByteCountDivider = 4;
  398. break;
  399. case CF_I420:
  400. case CF_YUV12:
  401. AlternateSwitch = 2;
  402. dwEqualPitchDivider = 4;
  403. dwByteCountDivider = 2;
  404. } /*endswitch*/
  405. awByteCounts [1] = awByteCounts [2] =
  406. WORD( awByteCounts [0] / dwByteCountDivider );
  407. Plane2 = Plane1 + dwYPlaneSize / dwEqualPitchDivider;
  408. ChromaPitch /= dwByteCountDivider;
  409. // need to adjust if doing a full-size planar capture.
  410. Plane2 -= dwPlanarAdjust_;
  411. Plane1 -= dwPlanarAdjust_;
  412. Plane2 += dwPlanarAdjust_ / dwByteCountDivider;
  413. Plane1 += dwPlanarAdjust_ / dwByteCountDivider;
  414. // U goes first for this color format
  415. if ( BufFormat_.GetColorFormat() == CF_I420 ) {
  416. DWORD dwTmp = Plane1;
  417. Plane1 = Plane2;
  418. Plane2 = dwTmp;
  419. }
  420. // that's were the instructions are going
  421. LPDWORD pProgLoc = (LPDWORD)(DWORD)ProgramSpace_->getLinearBase();
  422. LPDWORD pProgStart = pProgLoc;
  423. Command CurCommand; // this will create every command we need - yahoo !
  424. // put one of the FM codes here if this program is for image data only
  425. pProgLoc = CreatePrologEpilog( pProgLoc, SyncBits, CurCommand );
  426. // init the destination address
  427. if ( flip ) {
  428. dwLinBufAddr += dwYPlaneSize;
  429. PlanePitch1 = -PlanePitch1;
  430. } else {
  431. dwLinBufAddr -= PlanePitch1;
  432. ;
  433. }
  434. // initial adjustment of chroma pointers
  435. Plane1 -= ChromaPitch;
  436. Plane2 -= ChromaPitch;
  437. // now go into a loop (up to the hight of the image) and create
  438. // a command for every line. Commands depend on the data format
  439. unsigned int i = 0;
  440. while ( i < (unsigned)ImageSize_.cy ) {
  441. Instruction CurInstr;
  442. // now take care of vertically sub-sampled planar modes
  443. if ( i % AlternateSwitch != 0 ) {
  444. CurInstr = AltInstrToUse;
  445. } else {
  446. CurInstr = MainInstrToUse;
  447. Plane2 += ChromaPitch;
  448. Plane1 += ChromaPitch;
  449. }
  450. // advance the linear address to the next scan line
  451. dwLinBufAddr += PlanePitch1;
  452. // these arrays contain values for the second instruction
  453. DWORD adwSecondAddr [3];
  454. WORD FirstByteCount [3];
  455. WORD SecondByteCount [3];
  456. adwSecondAddr [0] = adwSecondAddr [1] = adwSecondAddr [2] =
  457. SecondByteCount [0] = SecondByteCount [1] = SecondByteCount [2] = 0;
  458. // initialize byte counts
  459. memmove( FirstByteCount, awByteCounts, sizeof( FirstByteCount ) );
  460. buf.pData_ = PBYTE( dwLinBufAddr );
  461. if ( dwLinBufAddr_ ) // don't bother with the addresses, if we are SKIPping them !
  462. GetSplitNumbers( buf, FirstByteCount [0], SecondByteCount [0],
  463. adwSecondAddr [0], adwAddresses [0] );
  464. PVOID pEOLLoc; // this is needed to set EOL bit in split instructions
  465. if ( AlternateSwitch > 1 && dwLinBufAddr_ ) {
  466. int split = 1;
  467. // Y plane is already done
  468. // now check if we better split instructions
  469. // just make width half of original and create 2 instructions
  470. if ( ImageSize_.cx > 320 && SecondByteCount [0 ] )
  471. split = 2;
  472. // temps for the loop
  473. DWORD dwYPlane = dwLinBufAddr;
  474. DWORD dwVPlane = Plane2;
  475. DWORD dwUPlane = Plane1;
  476. for ( int k = 0; k < split; k++ ) {
  477. // initialize byte counts
  478. memmove( FirstByteCount, awByteCounts, sizeof( FirstByteCount ) );
  479. // and split them in half
  480. for ( int l = 0; l < sizeof FirstByteCount / sizeof FirstByteCount [0]; l++ )
  481. FirstByteCount [l] = WORD (FirstByteCount [l] / split); //create 2 instructions with half the pixels
  482. // see if any of the planes crosses a page boundary
  483. // very ugly... must use the bad structure
  484. buf.pData_ = PBYTE( dwYPlane );
  485. GetSplitNumbers( buf, FirstByteCount [0], SecondByteCount [0],
  486. adwSecondAddr [0], adwAddresses [0] );
  487. // V plane
  488. buf.pData_ = PBYTE( dwVPlane );
  489. GetSplitNumbers( buf, FirstByteCount [1], SecondByteCount [1],
  490. adwSecondAddr [1], adwAddresses [1] );
  491. // U plane
  492. buf.pData_ = PBYTE( dwUPlane );
  493. GetSplitNumbers( buf, FirstByteCount [2], SecondByteCount [2],
  494. adwSecondAddr [2], adwAddresses [2] );
  495. // can not have zero Y byte count
  496. if ( !SecondByteCount [0] && ( SecondByteCount [1] || SecondByteCount [2] ) ) {
  497. FirstByteCount [0] -= max( SecondByteCount [1], SecondByteCount [2] );
  498. FirstByteCount [0] &= ~3; // need to align for the second address
  499. SecondByteCount [0] = WORD( awByteCounts [0] / split - FirstByteCount [0] );
  500. // second addr starts where first ends; no page crossing
  501. adwSecondAddr [0] = adwAddresses [0] + FirstByteCount [0];
  502. }
  503. // now make sure that there are no zero chroma byte counts
  504. // adjust chroma byte counts in proportion to luma byte counts split
  505. if ( SecondByteCount [0] ) {
  506. if ( !SecondByteCount [1] ) {
  507. if ( SecondByteCount [0] > FirstByteCount [0] )
  508. AdjustByteCounts( FirstByteCount [1], SecondByteCount [1], FirstByteCount [1],
  509. WORD( SecondByteCount [0] / FirstByteCount [0] ) );
  510. else
  511. AdjustByteCounts( SecondByteCount [1], FirstByteCount [1], FirstByteCount [1],
  512. WORD( FirstByteCount [0] / SecondByteCount [0] ) );
  513. adwSecondAddr [1] = adwAddresses [1] + FirstByteCount [1];
  514. }
  515. if ( !SecondByteCount [2] ) {
  516. if ( SecondByteCount [0] > FirstByteCount [0] )
  517. AdjustByteCounts( FirstByteCount [2], SecondByteCount [2], FirstByteCount [2],
  518. WORD( SecondByteCount [0] / FirstByteCount [0] ) );
  519. else
  520. AdjustByteCounts( SecondByteCount [2], FirstByteCount [2], FirstByteCount [2],
  521. WORD( FirstByteCount [0] / SecondByteCount [0] ) );
  522. adwSecondAddr [2] = adwAddresses [2] + FirstByteCount [2];
  523. }
  524. }
  525. // now write out the instructions
  526. // first command. SOL==true, EOL==false
  527. pProgLoc = (LPDWORD)CurCommand.Create( pProgLoc, CurInstr,
  528. FirstByteCount, adwAddresses, LoopOnItself, k == 0, false );
  529. pEOLLoc = CurCommand.GetInstrAddr();
  530. if ( SecondByteCount [0] || SecondByteCount [1] || SecondByteCount [2] ) {
  531. // second command
  532. pProgLoc = (LPDWORD)CurCommand.Create( pProgLoc, CurInstr,
  533. SecondByteCount, adwSecondAddr, LoopOnItself, false, false );
  534. pEOLLoc = CurCommand.GetInstrAddr();
  535. }
  536. // adjust starting addresses
  537. dwYPlane += awByteCounts [0] / 2;
  538. dwVPlane += awByteCounts [1] / 2;
  539. dwUPlane += awByteCounts [2] / 2;
  540. } /* endfor */
  541. // do not forget the EOL bit !
  542. CurCommand.SetEOL( pEOLLoc );
  543. } else {
  544. // first command. SOL==true, EOL==false
  545. pProgLoc = (LPDWORD)CurCommand.Create( pProgLoc, CurInstr,
  546. FirstByteCount, adwAddresses, LoopOnItself, true, false );
  547. pEOLLoc = CurCommand.GetInstrAddr();
  548. if ( SecondByteCount [0] || SecondByteCount [1] || SecondByteCount [2] ) {
  549. // second command
  550. pProgLoc = (LPDWORD)CurCommand.Create( pProgLoc, CurInstr,
  551. SecondByteCount, adwSecondAddr, LoopOnItself, false );
  552. } else
  553. CurCommand.SetEOL( pEOLLoc );
  554. } /* endif */
  555. i++;
  556. } /* endwhile */
  557. pChainAddress_ = pProgLoc;
  558. pIRQAddress_ = pProgLoc;
  559. PutInChain();
  560. Skipped_ = false;
  561. dwSize_ = (DWORD)pProgLoc - (DWORD)pProgStart;
  562. return Success;
  563. }
  564. /* Method: RISCProgram::PutInChain
  565. * Purpose: Restores the chain of programs this program was in.
  566. * Input: None
  567. * Output: None
  568. * Note: The chain is destroyed when clipping is set or buffer address is changed
  569. */
  570. void RISCProgram::PutInChain()
  571. {
  572. Trace t("RISCProgram::PutInChain()");
  573. if ( pChild_ )
  574. SetChain( pChild_ );
  575. if ( pParent_ )
  576. pParent_->SetChain( this );
  577. }
  578. /* Method: RISCProgram::SetChain
  579. * Purpose: Chains this program to another one
  580. * Input: dwProgAddr: DWORD - address of a first instruction in the next program
  581. * Output: None
  582. */
  583. void RISCProgram::SetChain( RISCProgram *ChainTo )
  584. {
  585. Trace t("RISCProgram::SetChain()");
  586. if ( !ChainTo )
  587. return;
  588. // now we know where we are chaining to
  589. pChild_ = ChainTo;
  590. // now child knows who chains to it.Does it really want to know its parent?<g>
  591. pChild_->SetParent( this );
  592. SetJump( (PDWORD)pChild_->GetPhysProgAddr() );
  593. }
  594. /* Method: RISCProgram::Skip
  595. * Purpose: Changes first instruction so program jumps over itself and to the child
  596. * Input: None
  597. * Output: None
  598. * Note: This functionality is useful when there are not enough data buffers
  599. * to supply for this program
  600. */
  601. void RISCProgram::Skip()
  602. {
  603. Trace t("RISCProgram::Skip()");
  604. // change first SYNC into JUMP
  605. PDWORD pTmpAddr = pChainAddress_;
  606. pChainAddress_ = (PDWORD)GetProgAddress();
  607. ULONG len;
  608. DWORD PhysAddr = StreamClassGetPhysicalAddress( gpHwDeviceExtension, NULL,
  609. pTmpAddr, DmaBuffer, &len ).LowPart;
  610. SetJump( (PDWORD)PhysAddr );
  611. pChainAddress_ = pTmpAddr;
  612. Skipped_ = true;
  613. }
  614. /* Method: RISCProgram::SetJump
  615. * Purpose: Creates a JUMP instruction to chain some place
  616. * Input: JumpAddr: PDWORD - target address
  617. * Output: None
  618. */
  619. void RISCProgram::SetJump( PDWORD JumpAddr )
  620. {
  621. Trace t("RISCProgram::SetJump()");
  622. Command JumpCommand;
  623. DWORD adwAddresses [1];
  624. adwAddresses [0] = (DWORD)JumpAddr;
  625. JumpCommand.Create( pChainAddress_, JUMP, NULL, adwAddresses, false );
  626. // make the last JUMP interrupt
  627. if ( Interrupting_ ) {
  628. JumpCommand.SetIRQ( pIRQAddress_ );
  629. if ( Counting_ )
  630. SetToCount();
  631. else
  632. ResetStatus();
  633. }
  634. }
  635. /* Method: RISCProgram::CreateLoop
  636. * Purpose: Creates a closed loop at the end of a RISC program
  637. * Input: resync: bool - value of the resync bit
  638. * Output: None
  639. */
  640. void RISCProgram::CreateLoop( bool resync )
  641. {
  642. Trace t("RISCProgram::CreateLoop()");
  643. Command SyncCommand( SYNC );
  644. SyncCommand.SetResync( pChainAddress_, resync );
  645. if ( resync == true ) {
  646. DWORD adwAddresses [1];
  647. ULONG len;
  648. DWORD PhysAddr = StreamClassGetPhysicalAddress( gpHwDeviceExtension, NULL,
  649. pChainAddress_, DmaBuffer, &len ).LowPart;
  650. adwAddresses [0] = PhysAddr;
  651. SyncCommand.Create( pChainAddress_, JUMP, NULL, adwAddresses );
  652. }
  653. }
  654. /* Method: RISCProgram::Create
  655. * Purpose: Creates a simple SYNC and JUMP program
  656. * Input: SyncBits: SyncCode - defines what code to do resync with
  657. * Output: None
  658. */
  659. ErrorCode RISCProgram::Create( SyncCode SyncBits, bool resync )
  660. {
  661. Trace t("RISCProgram::Create(3)");
  662. // allocate memory for the program first
  663. if ( AllocateStorage() != Success )
  664. return Fail;
  665. Command CurCommand; // this will create every command we need - yahoo !
  666. // that's were the instructions are going
  667. LPDWORD pProgLoc = (LPDWORD)ProgramSpace_->getLinearBase();
  668. LPDWORD pProgStart = pProgLoc;
  669. // put one of the FM or VRx codes here
  670. pProgLoc = CreatePrologEpilog( pProgLoc, SyncBits, CurCommand, resync );
  671. pChainAddress_ = pProgLoc;
  672. CreateLoop( true );
  673. dwSize_ = (DWORD)pProgLoc - (DWORD)pProgStart;
  674. return Success;
  675. }
  676. RISCProgram::~RISCProgram()
  677. {
  678. Trace t("RISCProgram::~RISCProgram(3)");
  679. delete ProgramSpace_;
  680. ProgramSpace_ = NULL;
  681. if ( pParent_ )
  682. pParent_->SetChild( NULL );
  683. }