Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /**
  2.  * @file
  3.  * DGen v1.13+
  4.  * Megadrive's VDP C++ module
  5.  *
  6.  * A useful resource for the Genesis VDP:
  7.  * http://cgfm2.emuviews.com/txt/genvdp.txt
  8.  * Thanks to Charles MacDonald for writing these docs.
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <limits.h>
  15. #include "md.h"
  16.  
  17. /** Reset the VDP. */
  18. void md_vdp::reset()
  19. {
  20.         hint_pending = false;
  21.         vint_pending = false;
  22.         cmd_pending = false;
  23.         rw_mode = 0x00;
  24.         rw_addr = 0;
  25.         rw_dma = 0;
  26.         memset(mem, 0, sizeof(mem));
  27.         memset(reg, 0, 0x20);
  28.         memset(dirt, 0xff, 0x35); // mark everything as changed
  29.         memset(highpal, 0, sizeof(highpal));
  30.         memset(sprite_order, 0, sizeof(sprite_order));
  31.         memset(sprite_mask, 0xff, sizeof(sprite_mask));
  32.         sprite_base = NULL;
  33.         sprite_count = 0;
  34.         masking_sprite_index_cache = -1;
  35.         dots_cache = 0;
  36.         sprite_overflow_line = INT_MIN;
  37.         dest = NULL;
  38.         bmap = NULL;
  39. }
  40.  
  41. /**
  42.  * VDP constructor.
  43.  *
  44.  * @param md The md instance this VDP belongs to.
  45.  */
  46. md_vdp::md_vdp(md& md): belongs(md)
  47. {
  48.         vram = (mem + 0x00000);
  49.         cram = (mem + 0x10000);
  50.         vsram = (mem + 0x10080);
  51.         dirt = (mem + 0x10100); // VRAM/CRAM/Reg dirty buffer bitfield
  52.         // Also in 0x34 are global dirt flags (inclduing VSRAM this time)
  53.         Bpp = Bpp_times8 = 0;
  54.         reset();
  55. }
  56.  
  57. /**
  58.  * VDP destructor.
  59.  */
  60. md_vdp::~md_vdp()
  61. {
  62.         vram = cram = vsram = NULL;
  63. }
  64.  
  65. /** Calculate the DMA length. */
  66. int md_vdp::dma_len()
  67. { return (reg[0x14]<<8)+reg[0x13]; }
  68.  
  69. /** Calculate DMA start address. */
  70. int md_vdp::dma_addr()
  71. {
  72.   int addr=0;
  73.   addr=(reg[0x17]&0x7f)<<17;
  74.   addr+=reg[0x16]<<9;
  75.   addr+=reg[0x15]<<1;
  76.   return addr;
  77. }
  78.  
  79.  
  80. /**
  81.  * Do a DMA read.
  82.  * DMA can read from anywhere.
  83.  *
  84.  * @param addr Address where to read from.
  85.  * @return Byte read at "addr".
  86.  */
  87. unsigned char md_vdp::dma_mem_read(int addr)
  88. {
  89.   return belongs.misc_readbyte(addr);
  90. }
  91.  
  92. /**
  93.  * Set value in VRAM.
  94.  * Must go through these calls to update the dirty flags.
  95.  *
  96.  * @param addr Address to write to.
  97.  * @param d Byte to write.
  98.  * @return Always 0.
  99.  */
  100. int md_vdp::poke_vram(int addr,unsigned char d)
  101. {
  102.   addr&=0xffff;
  103.   if (vram[addr]!=d)
  104.   {
  105.     // Store dirty information down to 256 byte level in bits
  106.     int byt,bit;
  107.     byt=addr>>8; bit=byt&7; byt>>=3; byt&=0x1f;
  108.     dirt[0x00+byt]|=(1<<bit); dirt[0x34]|=1;
  109.     vram[addr]=d;
  110.   }
  111.   return 0;
  112. }
  113.  
  114. /**
  115.  * Set value in CRAM.
  116.  *
  117.  * @param addr Address to write to.
  118.  * @param d Byte to write.
  119.  * @return Always 0.
  120.  */
  121. int md_vdp::poke_cram(int addr,unsigned char d)
  122. {
  123.   addr&=0x007f;
  124.   if (cram[addr]!=d)
  125.   {
  126.     // Store dirty information down to 1byte level in bits
  127.     int byt,bit;
  128.     byt=addr; bit=byt&7; byt>>=3; byt&=0x0f;
  129.     dirt[0x20+byt]|=(1<<bit); dirt[0x34]|=2;
  130.     cram[addr]=d;
  131.   }
  132.  
  133.   return 0;
  134. }
  135.  
  136. /**
  137.  * Set value in VSRAM.
  138.  *
  139.  * @param addr Address to write to.
  140.  * @param d Byte to write.
  141.  * @return Always 0.
  142.  */
  143. int md_vdp::poke_vsram(int addr,unsigned char d)
  144. {
  145. //  int diff=0;
  146.   addr&=0x007f;
  147.   if (vsram[addr]!=d)
  148.   { dirt[0x34]|=4; vsram[addr]=d; }
  149.   return 0;
  150. }
  151.  
  152. /**
  153.  * Write a word to memory and update dirty flags.
  154.  *
  155.  * @param d 16-bit data to write.
  156.  * @return Always 0.
  157.  */
  158. int md_vdp::putword(unsigned short d)
  159. {
  160.   // Called by dma or a straight write
  161.   switch(rw_mode)
  162.   {
  163.         case 0x04:
  164.                 if (rw_addr & 0x0001) {
  165.                         poke_vram((rw_addr + 0), (d & 0xff));
  166.                         poke_vram((rw_addr + 1), (d >> 8));
  167.                 }
  168.                 else {
  169.                         poke_vram((rw_addr + 0), (d >> 8));
  170.                         poke_vram((rw_addr + 1), (d & 0xff));
  171.                 }
  172.                 break;
  173.         case 0x0c:
  174.                 poke_cram((rw_addr + 0), (d >> 8));
  175.                 poke_cram((rw_addr + 1), (d & 0xff));
  176.                 break;
  177.         case 0x14:
  178.                 poke_vsram((rw_addr + 0), (d >> 8));
  179.                 poke_vsram((rw_addr + 1), (d & 0xff));
  180.                 break;
  181.   }
  182.   rw_addr+=reg[15];
  183.   return 0;
  184. }
  185.  
  186. /**
  187.  * Write a byte to memory and update dirty flags.
  188.  *
  189.  * @param d 8-bit data to write.
  190.  * @return Always 0.
  191.  */
  192. int md_vdp::putbyte(unsigned char d)
  193. {
  194.   // Called by dma or a straight write
  195.   switch(rw_mode)
  196.   {
  197.     case 0x04: poke_vram (rw_addr,d); break;
  198.     case 0x0c: poke_cram (rw_addr,d); break;
  199.     case 0x14: poke_vsram(rw_addr,d); break;
  200.   }
  201.   rw_addr+=reg[15];
  202.   return 0;
  203. }
  204.  
  205. #undef MAYCHANGE
  206.  
  207. /**
  208.  * Read a word from memory.
  209.  *
  210.  * @return Read word.
  211.  */
  212. unsigned short md_vdp::readword()
  213. {
  214.   // Called by a straight read only
  215.   unsigned short result=0x0000;
  216.   switch(rw_mode)
  217.   {
  218.     case 0x00: result=( vram[(rw_addr+0)&0xffff]<<8)+
  219.                         vram[(rw_addr+1)&0xffff]; break;
  220.     case 0x20: result=( cram[(rw_addr+0)&0x007f]<<8)+
  221.                         cram[(rw_addr+1)&0x007f]; break;
  222.     case 0x10: result=(vsram[(rw_addr+0)&0x007f]<<8)+
  223.                        vsram[(rw_addr+1)&0x007f]; break;
  224.   }
  225.   rw_addr+=reg[15];
  226.   return result;
  227. }
  228.  
  229. /**
  230.  * Read a byte from memory.
  231.  *
  232.  * @return Read byte.
  233.  */
  234. unsigned char md_vdp::readbyte()
  235. {
  236.   // Called by a straight read only
  237.   unsigned char result=0x00;
  238.   switch(rw_mode)
  239.   {
  240.     case 0x00: result= vram[(rw_addr+0)&0xffff]; break;
  241.     case 0x20: result= cram[(rw_addr+0)&0x007f]; break;
  242.     case 0x10: result=vsram[(rw_addr+0)&0x007f]; break;
  243.   }
  244.   rw_addr+=reg[15];
  245.   return result;
  246. }
  247.  
  248. /**
  249.  * VDP commands
  250.  *
  251.  * A VDP command is 32-bits in length written into the control port
  252.  * as two 16-bit words. The VDP maintains a pending flag so that it knows
  253.  * what to expect next.
  254.  *
  255.  *  CD1 CD0 A13 A12 A11 A10 A09 A08     (D31-D24)
  256.  *  A07 A06 A05 A04 A03 A02 A01 A00     (D23-D16)
  257.  *   ?   ?   ?   ?   ?   ?   ?   ?      (D15-D8)
  258.  *  CD5 CD4 CD3 CD2  ?   ?  A15 A14     (D7-D0)
  259.  *
  260.  * Where CD* indicates which ram is read or written in subsequent
  261.  * data port read/writes. A* is an address.
  262.  *
  263.  * Note that the command is not cached, but rather, the lower 14 address bits
  264.  * are commited as soon as the first half of the command arrives. Then when
  265.  * the second word arrives, the remaining two address bits are commited.
  266.  *
  267.  * It is possible to cancel (but not roll back) a pending command by:
  268.  *  - reading or writing to the data port.
  269.  *  - reading the control port.
  270.  *
  271.  * In these cases the pending flag is cleared, and the first half of
  272.  * the command remains comitted.
  273.  *
  274.  * @return Always 0.
  275.  */
  276. int md_vdp::command(uint16_t cmd)
  277. {
  278.   if (cmd_pending) // If this is the second word of a command
  279.   {
  280.     uint16_t A14_15 = (cmd & 0x0003) << 14;
  281.     rw_addr = (rw_addr & 0xffff3fff) | A14_15;
  282.  
  283.     // Copy rw_addr to mirror register
  284.     rw_addr = (rw_addr & 0x0000ffff) | (rw_addr << 16);
  285.  
  286.     // CD{4,3,2}
  287.     uint16_t CD4_2 = (cmd & 0x0070);
  288.     rw_mode |= CD4_2;
  289.  
  290.     // if CD5 == 1
  291.     rw_dma = ((cmd & 0x80) == 0x80);
  292.  
  293.     cmd_pending = false;
  294.   }
  295.   else // This is the first word of a command
  296.   {
  297.     // masking away command bits CD1 CD0
  298.     uint16_t A00_13 = cmd & 0x3fff;
  299.     rw_addr = (rw_addr & 0xffffc000) | A00_13;
  300.  
  301.     // Copy rw_addr to mirror register
  302.     rw_addr = (rw_addr & 0x0000ffff) | (rw_addr << 16);
  303.  
  304.     // CD {1,0}
  305.     uint16_t CD0_1 = (cmd & 0xc000) >> 12;
  306.     rw_mode = CD0_1;
  307.     rw_dma = 0;
  308.  
  309.     // we will expect the second half of the command next
  310.     cmd_pending = true;
  311.  
  312.     return 0;
  313.   }
  314.  
  315.   // if it's a dma request do it straight away
  316.   if (rw_dma)
  317.   {
  318.     int mode=(reg[0x17]>>6)&3;
  319.     int s=0,d=0,i=0,len=0;
  320.     s=dma_addr(); d=rw_addr; len=dma_len();
  321.     (void)d;
  322.     switch (mode)
  323.     {
  324.       case 0: case 1:
  325.         for (i=0;i<len;i++)
  326.         {
  327.           unsigned short val;
  328.           val= dma_mem_read(s++); val<<=8;
  329.           val|=dma_mem_read(s++); putword(val);
  330.         }
  331.       break;
  332.       case 2:
  333.         // Done later on (VRAM fill I believe)
  334.       break;
  335.       case 3:
  336.         for (i=0;i<len;i++)
  337.         {
  338.           unsigned short val;
  339.           val= vram[(s++)&0xffff]; val<<=8;
  340.           val|=vram[(s++)&0xffff]; putword(val);
  341.         }
  342.       break;
  343.     }
  344.   }
  345.  
  346.   return 0;
  347. }
  348.  
  349. /**
  350.  * Write a word to the VDP.
  351.  *
  352.  * @param d 16-bit data to write.
  353.  * @return Always 0.
  354.  */
  355. int md_vdp::writeword(unsigned short d)
  356. {
  357.   if (rw_dma)
  358.   {
  359.     // This is the 'done later on' bit for words
  360.     // Do a dma fill if it's set up:
  361.     if (((reg[0x17]>>6)&3)==2)
  362.     {
  363.       int i,len;
  364.       len=dma_len();
  365.       for (i=0;i<len;i++)
  366.         putword(d);
  367.       return 0;
  368.     }
  369.   }
  370.   else
  371.   {
  372.     putword(d);
  373.     return 0;
  374.   }
  375.   return 0;
  376. }
  377.  
  378. /**
  379.  * Write a byte to the VDP.
  380.  *
  381.  * @param d 8-bit data to write.
  382.  * @return Always 0.
  383.  */
  384. int md_vdp::writebyte(unsigned char d)
  385. {
  386.   if (rw_dma)
  387.   {
  388.     // This is the 'done later on' bit for bytes
  389.     // Do a dma fill if it's set up:
  390.     if (((reg[0x17]>>6)&3)==2)
  391.     {
  392.       int i,len;
  393.       len=dma_len();
  394.       for (i=0;i<len;i++)
  395.         putbyte(d);
  396.       return 0;
  397.     }
  398.   }
  399.   else
  400.   {
  401.     putbyte(d);
  402.     return 0;
  403.   }
  404.  
  405.   return 0;
  406. }
  407.  
  408. /**
  409.  * Write away a VDP register.
  410.  *
  411.  * @param addr Address of register.
  412.  * @param data 8-bit data to write.
  413.  */
  414. void md_vdp::write_reg(uint8_t addr, uint8_t data)
  415. {
  416.         uint8_t byt, bit;
  417.  
  418.         // store dirty information down to 1 byte level in bits
  419.         if (reg[addr] != data) {
  420.                 byt = addr;
  421.                 bit = (byt & 7);
  422.                 byt >>= 3;
  423.                 byt &= 0x03;
  424.                 dirt[(0x30 + byt)] |= (1 << bit);
  425.                 dirt[0x34] |= 8;
  426.         }
  427.         reg[addr] = data;
  428.         // "Writing to a VDP register will clear the code register."
  429.         rw_mode = 0;
  430. }
  431.